Refactor AST and PCH building.
This commit is contained in:
@@ -130,18 +130,11 @@ void Compiler::ExecuteAction() {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
llvm::outs() << instance->getLangOpts().Modules << "\n";
|
||||
llvm::outs() << instance->getLangOpts().CPlusPlusModules << "\n";
|
||||
|
||||
if(!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
|
||||
llvm::errs() << "Failed to begin source file\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
/// llvm::outs() << instance->getPreprocessorOpts().ImplicitPCHInclude << "\n";
|
||||
|
||||
/// instance->getASTContext().setExternalSource(nullptr);
|
||||
|
||||
auto& preproc = instance->getPreprocessor();
|
||||
// FIXME: add PPCallbacks to collect information.
|
||||
|
||||
@@ -167,4 +160,133 @@ Compiler::~Compiler() {
|
||||
}
|
||||
}
|
||||
|
||||
static auto createInstance(llvm::ArrayRef<const char*> args) {
|
||||
auto instance = std::make_unique<clang::CompilerInstance>();
|
||||
|
||||
/// TODO: Figure out `CreateInvocationOptions`.
|
||||
clang::CreateInvocationOptions options = {};
|
||||
instance->setInvocation(clang::createInvocation(args, options));
|
||||
|
||||
/// TODO: use a thread safe filesystem and our customized `DiagnosticConsumer`.
|
||||
instance->createDiagnostics(
|
||||
*llvm::vfs::getRealFileSystem(),
|
||||
new clang::TextDiagnosticPrinter(llvm::outs(), new clang::DiagnosticOptions()),
|
||||
true);
|
||||
|
||||
adjustInvocation(instance->getInvocation());
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static llvm::Expected<ASTInfo> ExecuteAction(std::unique_ptr<clang::CompilerInstance> instance,
|
||||
clang::frontend::ActionKind kind) {
|
||||
std::unique_ptr<clang::ASTFrontendAction> action;
|
||||
if(kind == clang::frontend::ActionKind::ParseSyntaxOnly) {
|
||||
action = std::make_unique<clang::SyntaxOnlyAction>();
|
||||
} else if(kind == clang::frontend::ActionKind::GeneratePCH) {
|
||||
action = std::make_unique<clang::GeneratePCHAction>();
|
||||
} else if(kind == clang::frontend::ActionKind::GenerateReducedModuleInterface) {
|
||||
action = std::make_unique<clang::GenerateReducedModuleInterfaceAction>();
|
||||
} else {
|
||||
llvm::errs() << "Unsupported action kind\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
if(!instance->createTarget()) {
|
||||
return error("Failed to create target");
|
||||
}
|
||||
|
||||
if(!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
|
||||
return error("Failed to begin source file");
|
||||
}
|
||||
|
||||
// FIXME: clang-tidy, include-fixer, etc?
|
||||
|
||||
// `BeginSourceFile` may create new preprocessor, so all operations related to preprocessor
|
||||
// should be done after `BeginSourceFile`.
|
||||
auto& PP = instance->getPreprocessor();
|
||||
clang::syntax::TokenCollector collector{PP};
|
||||
|
||||
if(auto error = action->Execute()) {
|
||||
return clice::error("Failed to execute action, because {} ", error);
|
||||
}
|
||||
|
||||
auto tokBuf = std::make_unique<clang::syntax::TokenBuffer>(std::move(collector).consume());
|
||||
tokBuf->indexExpandedTokens();
|
||||
|
||||
return ASTInfo(std::move(action), std::move(instance), std::move(tokBuf));
|
||||
}
|
||||
|
||||
llvm::Expected<ASTInfo> buildAST(llvm::StringRef path,
|
||||
llvm::StringRef content,
|
||||
llvm::ArrayRef<const char*> args,
|
||||
Preamble* preamble) {
|
||||
auto instance = createInstance(args);
|
||||
|
||||
auto& PPOpts = instance->getPreprocessorOpts();
|
||||
|
||||
auto buffer = llvm::MemoryBuffer::getMemBufferCopy(content);
|
||||
/// FIXME: Check PPOpts.RetainRemappedFileBuffers.
|
||||
PPOpts.addRemappedFile(path, buffer.release());
|
||||
|
||||
if(preamble) {
|
||||
auto& [pch, bounds, pcms] = *preamble;
|
||||
if(bounds.Size != 0) {
|
||||
PPOpts.UsePredefines = false;
|
||||
PPOpts.ImplicitPCHInclude = std::move(pch);
|
||||
PPOpts.PrecompiledPreambleBytes.first = bounds.Size;
|
||||
PPOpts.PrecompiledPreambleBytes.second = bounds.PreambleEndsAtStartOfLine;
|
||||
PPOpts.DisablePCHOrModuleValidation = clang::DisableValidationForModuleKind::PCH;
|
||||
}
|
||||
|
||||
for(auto& [name, path]: pcms) {
|
||||
auto& HSOpts = instance->getHeaderSearchOpts();
|
||||
HSOpts.PrebuiltModuleFiles.try_emplace(std::move(name), std::move(path));
|
||||
}
|
||||
}
|
||||
|
||||
return ExecuteAction(std::move(instance), clang::frontend::ActionKind::ParseSyntaxOnly);
|
||||
}
|
||||
|
||||
llvm::Expected<PCHInfo> buildPCH(llvm::StringRef path,
|
||||
llvm::StringRef content,
|
||||
llvm::StringRef outpath,
|
||||
llvm::StringRef mainpath,
|
||||
std::size_t index,
|
||||
llvm::ArrayRef<const char*> args) {
|
||||
auto instance = createInstance(args);
|
||||
|
||||
clang::PreambleBounds bounds = {0, false};
|
||||
if(mainpath == path) {
|
||||
/// If mainpath is equal to path, just tokenize the content to get preamble bounds.
|
||||
bounds = clang::Lexer::ComputePreamble(content, {}, false);
|
||||
} else {
|
||||
/// FIXME: if the mainpath is not equal to path, we need to preprocess the mainpath to get
|
||||
/// the preamble bounds.
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
instance->getFrontendOpts().OutputFile = outpath;
|
||||
instance->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH;
|
||||
instance->getPreprocessorOpts().PrecompiledPreambleBytes = {0, false};
|
||||
instance->getPreprocessorOpts().GeneratePreamble = true;
|
||||
instance->getLangOpts().CompilingPCH = true;
|
||||
|
||||
auto buffer = llvm::MemoryBuffer::getMemBufferCopy(content.substr(0, bounds.Size));
|
||||
instance->getPreprocessorOpts().addRemappedFile(path, buffer.release());
|
||||
|
||||
if(auto info = ExecuteAction(std::move(instance), clang::frontend::ActionKind::GeneratePCH)) {
|
||||
return PCHInfo(std::move(*info), outpath, mainpath, content, bounds);
|
||||
} else {
|
||||
return info.takeError();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Expected<PCHInfo> buildPCH(llvm::StringRef path,
|
||||
llvm::StringRef content,
|
||||
llvm::StringRef outpath,
|
||||
llvm::ArrayRef<const char*> args) {
|
||||
return buildPCH(path, content, outpath, path, 0, args);
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
|
||||
Reference in New Issue
Block a user