diff --git a/include/Clang/Clang.h b/include/Clang/Clang.h index 1458f55d..56974ed3 100644 --- a/include/Clang/Clang.h +++ b/include/Clang/Clang.h @@ -9,6 +9,7 @@ #include #include + namespace clice { using llvm::StringRef; diff --git a/include/Clang/Compiler.h b/include/Clang/Compiler.h index fbe2eff9..5df44468 100644 --- a/include/Clang/Compiler.h +++ b/include/Clang/Compiler.h @@ -4,12 +4,15 @@ namespace clice { -inline CompilerInvocation createCompilerInvocation() { - -} +auto createCompilerInvocation(clang::tooling::CompileCommand& command, + std::vector* extraArgs, + llvm::IntrusiveRefCntPtr vfs, + clang::DiagnosticConsumer& consumer) -> std::unique_ptr; -inline CompilerInstance createCompilerInstance() { - -} +auto createCompilerInstance(std::unique_ptr invocation, + const clang::PrecompiledPreamble* preamble, + std::unique_ptr content, + llvm::IntrusiveRefCntPtr vfs, + clang::DiagnosticConsumer& consumer) -> std::unique_ptr; } // namespace clice diff --git a/src/Clang/CodeCompletion.cpp b/src/Clang/CodeCompletion.cpp deleted file mode 100644 index db1696c6..00000000 --- a/src/Clang/CodeCompletion.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include - -namespace tooling = clang::tooling; -int line = 0; -int column = 0; -std::unique_ptr datebase; - -class CodeCompleteConsumer : public clang::CodeCompleteConsumer { -public: - std::shared_ptr Allocator; - clang::CodeCompletionTUInfo CCTUInfo; - - CodeCompleteConsumer() : - clang::CodeCompleteConsumer(clang::CodeCompleteOptions{}), - Allocator(std::make_shared()), CCTUInfo(Allocator) {} - - void ProcessCodeCompleteResults(clang::Sema& S, - clang::CodeCompletionContext Context, - clang::CodeCompletionResult* Results, - unsigned NumResults) override { - - auto type = Context.getBaseType(); - type.dump(); - if(type->isDependentType()) { - const auto dependentType = type->getAs(); - // TODO: improve - } - - for(unsigned i = 0; i < NumResults; ++i) { - clang::CodeCompletionResult& Result = Results[i]; - - switch(Result.Kind) { - case clang::CodeCompletionResult::RK_Declaration: { - llvm::outs() << "Declaration: "; - llvm::outs() << Result.Declaration->getNameAsString() << "\n"; - break; - } - - case clang::CodeCompletionResult::RK_Keyword: { - llvm::outs() << "Keyword: "; - llvm::outs() << Result.Keyword << "\n"; - break; - } - - case clang::CodeCompletionResult::RK_Macro: { - llvm::outs() << "Macro: "; - llvm::outs() << Result.Macro->getName() << "\n"; - break; - } - - case clang::CodeCompletionResult::RK_Pattern: { - llvm::outs() << "Pattern: "; - llvm::outs() << Result.Pattern->getAsString() << "\n"; - break; - } - } - } - } - - virtual clang::CodeCompletionAllocator& getAllocator() override { return *Allocator; } - - virtual clang::CodeCompletionTUInfo& getCodeCompletionTUInfo() override { return CCTUInfo; } -}; - -auto GetCommands(std::string_view path, - std::string_view compile_commands_path) -> std::vector { - if(!datebase) { - std::string error; - datebase = tooling::CompilationDatabase::loadFromDirectory(compile_commands_path, error); - - if(!datebase) { - llvm::errs() << "Failed to load compilation database. " << error << "\n"; - std::terminate(); - } - } - - return datebase->getCompileCommands(path); -} - -auto createDiagnostic() { - clang::DiagnosticOptions DiagOpts; - - clang::TextDiagnosticPrinter* DiagClient = new clang::TextDiagnosticPrinter(llvm::errs(), &DiagOpts); - - llvm::IntrusiveRefCntPtr DiagID = new clang::DiagnosticIDs(); - - return clang::DiagnosticsEngine(DiagID, &DiagOpts, DiagClient); -} - -auto createInvocation(std::string_view path, std::string_view compile_commands) { - auto commands = GetCommands(path, compile_commands); - llvm::ArrayRef command = commands[0].CommandLine; - - std::vector args = {command.front().c_str(), "-Xclang", "-no-round-trip-args"}; - - for(auto& arg: command.drop_front()) { - args.push_back(arg.c_str()); - } - - static auto engine = createDiagnostic(); - auto invocation = clang::createInvocation(args); - - // set input file - auto& inputs = invocation->getFrontendOpts().Inputs; - inputs.push_back(clang::FrontendInputFile(path, clang::InputKind{clang::Language::CXX})); - - // set code completion - auto& completionAt = invocation->getFrontendOpts().CodeCompletionAt; - completionAt.FileName = path.data(); - completionAt.Line = line; - completionAt.Column = column; - - return invocation; -} - -struct DiagnosticConsumer : clang::DiagnosticConsumer { - void BeginSourceFile(const clang::LangOptions& LangOpts, const clang::Preprocessor* PP) override {} - - void EndSourceFile() override {} - - void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic& Info) override { - if(DiagLevel == clang::DiagnosticsEngine::Level::Note) { - return; - } - - llvm::errs() << "Diagnostic: "; - llvm::SmallVector buf; - Info.FormatDiagnostic(buf); - llvm::errs().write(buf.data(), buf.size()); - llvm::errs() << "\n"; - } -}; - -auto createInstance(std::string_view path, std::string_view compile_commands) { - std::unique_ptr instance = std::make_unique(); - - auto invocation = createInvocation(path, compile_commands); - instance->setInvocation(std::make_shared(*invocation)); - - instance->createDiagnostics(new DiagnosticConsumer(), true); - - if(!instance->createTarget()) { - llvm::errs() << "Failed to create target\n"; - std::terminate(); - } - - if(auto manager = instance->createFileManager()) { - instance->createSourceManager(*manager); - } else { - llvm::errs() << "Failed to create file manager\n"; - std::terminate(); - } - - instance->createPreprocessor(clang::TranslationUnitKind::TU_Complete); - - instance->createASTContext(); - - instance->setCodeCompletionConsumer(new CodeCompleteConsumer()); - - return instance; -} - -class AST { - clang::FrontendAction* action; - clang::CompilerInstance* instance; - -private: - AST() = default; - -public: - AST(const AST&) = delete; - - AST(AST&& other) noexcept : action(other.action), instance(other.instance) { - other.action = nullptr; - other.instance = nullptr; - } - - ~AST() { - if(action) { - action->EndSourceFile(); - delete action; - delete instance; - } - } - - static AST create(std::string_view path, std::string_view compile_commands) { - AST ast; - - ast.instance = createInstance(path, compile_commands).release(); - ast.action = new clang::SyntaxOnlyAction(); - - const auto& input = ast.instance->getFrontendOpts().Inputs[0]; - - if(!ast.action->BeginSourceFile(*ast.instance, input)) { - llvm::errs() << "Failed to begin source file\n"; - std::terminate(); - } - - if(llvm::Error error = ast.action->Execute()) { - llvm::errs() << "Failed to execute action: " << error << "\n"; - std::terminate(); - } - - return ast; - } - - auto& getASTContext() { return instance->getASTContext(); } - - auto& getSourceManager() { return instance->getSourceManager(); } -}; - -struct Visitor : clang::RecursiveASTVisitor { - bool VisitTranslationUnitDecl(clang::TranslationUnitDecl* tu) { - tu->dump(); - return true; - } - - bool VisitCXXMethodDecl(clang::CXXMethodDecl* decl) { return true; } -}; diff --git a/src/Clang/Compiler.cpp b/src/Clang/Compiler.cpp index 139597f9..5b0ee618 100644 --- a/src/Clang/Compiler.cpp +++ b/src/Clang/Compiler.cpp @@ -1,2 +1,108 @@ +#include +#include +namespace clice { + +void setOptions(CompilerInvocation& invocation) { + // TODO: add comments for reason of setting these options + clang::DiagnosticOptions& diagnostic = invocation.getDiagnosticOpts(); + diagnostic.VerifyDiagnostics = false; + diagnostic.ShowColors = false; + + clang::DependencyOutputOptions& dependency = invocation.getDependencyOutputOpts(); + dependency.ShowIncludesDest = clang::ShowIncludesDestination::None; + dependency.OutputFile.clear(); + dependency.HeaderIncludeOutputFile.clear(); + dependency.DOTOutputFile.clear(); + dependency.ModuleDependencyOutputDir.clear(); + + clang::PreprocessorOptions& preprocessor = invocation.getPreprocessorOpts(); + preprocessor.ImplicitPCHInclude.clear(); + preprocessor.PrecompiledPreambleBytes = {0, false}; + preprocessor.PCHThroughHeader.clear(); + preprocessor.PCHWithHdrStop = false; + preprocessor.PCHWithHdrStopCreate = false; + + clang::FrontendOptions& frontend = invocation.getFrontendOpts(); + frontend.DisableFree = false; + frontend.Plugins.clear(); + frontend.PluginArgs.clear(); + frontend.AddPluginActions.clear(); + frontend.ActionName.clear(); + frontend.ProgramAction = clang::frontend::ActionKind::ParseSyntaxOnly; + + clang::LangOptions& lang = invocation.getLangOpts(); + lang.CommentOpts.ParseAllComments = true; + lang.RetainCommentsFromSystemHeaders = true; + lang.NoSanitizeFiles.clear(); + lang.ProfileListFiles.clear(); + lang.XRayAttrListFiles.clear(); + lang.XRayAlwaysInstrumentFiles.clear(); + lang.XRayNeverInstrumentFiles.clear(); +} + +auto createCompilerInvocation(clang::tooling::CompileCommand& command, + std::vector* extraArgs, + llvm::IntrusiveRefCntPtr vfs, + clang::DiagnosticConsumer& consumer) -> std::unique_ptr { + clang::CreateInvocationOptions options; + options.VFS = vfs; + options.CC1Args = extraArgs; + options.RecoverOnError = true; + options.Diags = CompilerInstance::createDiagnostics(new clang::DiagnosticOptions(), &consumer, false); + options.ProbePrecompiled = false; + + llvm::ArrayRef argv = command.CommandLine; + assert(argv.size() > 0 && "command line is empty"); + + std::vector args; + args.reserve(argv.size() + 1); + args = {argv.front().c_str(), "-Xclang", "-no-round-trip-args"}; + // TODO: add comment for why do this + for(const auto& arg: argv.drop_front()) { + args.push_back(arg.c_str()); + } + + auto invocation = clang::createInvocation(args, options); + assert(invocation && "failed to create invocation"); + + setOptions(*invocation); + return invocation; +} + +auto createCompilerInstance(std::unique_ptr invocation, + const clang::PrecompiledPreamble* preamble, + std::unique_ptr content, + llvm::IntrusiveRefCntPtr vfs, + clang::DiagnosticConsumer& consumer) -> std::unique_ptr { + assert(vfs && "vfs cannot be null"); + + if(preamble) { + auto bounds = clang::ComputePreambleBounds(invocation->getLangOpts(), *content, false); + if(preamble->CanReuse(*invocation, *content, bounds, *vfs)) { + preamble->AddImplicitPreamble(*invocation, vfs, content.release()); + } else { + // TODO: + } + } + + auto instance = std::make_unique(std::make_shared()); + instance->setInvocation(std::move(invocation)); + instance->createDiagnostics(&consumer, false); + + if(auto remappedVFS = clang::createVFSFromCompilerInvocation(instance->getInvocation(), + instance->getDiagnostics(), + vfs)) { + vfs = remappedVFS; + } + instance->createFileManager(vfs); + + if(!instance->createTarget()) { + // TODO: report an error + } + + return instance; +} + +} // namespace clice diff --git a/src/Clang/SemanticTokens.cpp b/src/Clang/SemanticTokens.cpp deleted file mode 100644 index 5bb452d7..00000000 --- a/src/Clang/SemanticTokens.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include - -namespace tooling = clang::tooling; - -namespace { - -std::unique_ptr datebase; - -auto GetCommands(std::string_view path, - std::string_view compile_commands_path) -> std::vector { - if(!datebase) { - std::string error; - datebase = tooling::CompilationDatabase::loadFromDirectory(compile_commands_path, error); - - if(!datebase) { - llvm::errs() << "Failed to load compilation database. " << error << "\n"; - std::terminate(); - } - } - - return datebase->getCompileCommands(path); -} - -auto createDiagnostic() { - clang::DiagnosticOptions DiagOpts; - - clang::TextDiagnosticPrinter* DiagClient = - new clang::TextDiagnosticPrinter(llvm::errs(), &DiagOpts); - - llvm::IntrusiveRefCntPtr DiagID = new clang::DiagnosticIDs(); - - return clang::DiagnosticsEngine(DiagID, &DiagOpts, DiagClient); -} - -auto createInvocation(std::string_view path, std::string_view compile_commands) { - auto commands = GetCommands(path, compile_commands); - llvm::ArrayRef command = commands[0].CommandLine; - - std::vector args = {command.front().c_str(), "-Xclang", "-no-round-trip-args"}; - - for(auto& arg: command.drop_front()) { - args.push_back(arg.c_str()); - } - - static auto engine = createDiagnostic(); - auto invocation = clang::createInvocation(args); - - // set input file - auto& inputs = invocation->getFrontendOpts().Inputs; - inputs.push_back(clang::FrontendInputFile(path, clang::InputKind{clang::Language::CXX})); - - return invocation; -} - -struct DiagnosticConsumer : clang::DiagnosticConsumer { - void BeginSourceFile(const clang::LangOptions& LangOpts, - const clang::Preprocessor* PP) override {} - - void EndSourceFile() override {} - - void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, - const clang::Diagnostic& Info) override { - if(DiagLevel == clang::DiagnosticsEngine::Level::Note) { - return; - } - - llvm::errs() << "Diagnostic: "; - llvm::SmallVector buf; - Info.FormatDiagnostic(buf); - llvm::errs().write(buf.data(), buf.size()); - llvm::errs() << "\n"; - } -}; - -auto createInstance(std::string_view path, std::string_view compile_commands) { - std::unique_ptr instance = std::make_unique(); - - auto invocation = createInvocation(path, compile_commands); - instance->setInvocation(std::make_shared(*invocation)); - - instance->createDiagnostics(new DiagnosticConsumer(), true); - - if(!instance->createTarget()) { - llvm::errs() << "Failed to create target\n"; - std::terminate(); - } - - if(auto manager = instance->createFileManager()) { - instance->createSourceManager(*manager); - } else { - llvm::errs() << "Failed to create file manager\n"; - std::terminate(); - } - - instance->createPreprocessor(clang::TranslationUnitKind::TU_Complete); - - instance->createASTContext(); - - return instance; -} - -class AST { - clang::FrontendAction* action; - clang::CompilerInstance* instance; - clang::syntax::TokenBuffer* tokens; - -private: - AST() = default; - -public: - AST(const AST&) = delete; - - AST(AST&& other) noexcept : - action(other.action), instance(other.instance), tokens(other.tokens) { - other.action = nullptr; - other.instance = nullptr; - other.tokens = nullptr; - } - - ~AST() { - if(action) { - action->EndSourceFile(); - delete action; - delete instance; - delete tokens; - } - } - - static AST create(std::string_view path, std::string_view compile_commands) { - AST ast; - - ast.instance = createInstance(path, compile_commands).release(); - ast.action = new clang::SyntaxOnlyAction(); - - const auto& input = ast.instance->getFrontendOpts().Inputs[0]; - - if(!ast.action->BeginSourceFile(*ast.instance, input)) { - llvm::errs() << "Failed to begin source file\n"; - std::terminate(); - } - - clang::syntax::TokenCollector collector = {ast.instance->getPreprocessor()}; - - if(llvm::Error error = ast.action->Execute()) { - llvm::errs() << "Failed to execute action: " << error << "\n"; - std::terminate(); - } - - ast.tokens = new auto(std::move(collector).consume()); - - return ast; - } - - auto& getASTContext() { return instance->getASTContext(); } - - auto& getSourceManager() { return instance->getSourceManager(); } - - auto getTokens() { return tokens->expandedTokens(); } -}; - -struct Visitor : clang::RecursiveASTVisitor { - bool VisitTranslationUnitDecl(clang::TranslationUnitDecl* tu) { - tu->dump(); - return true; - } - - bool VisitCXXMethodDecl(clang::CXXMethodDecl* decl) { return true; } -}; - -} // namespace