From f7093b5ae812fc5122b0c1c60cfc61de2a17a048 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 13 Nov 2009 09:36:05 +0000 Subject: [PATCH] Add CodeCompletion consumer to CompilerInvocation. llvm-svn: 87100 --- .../include/clang/Frontend/CompilerInstance.h | 43 +++++++++++++++++++ clang/lib/Frontend/CompilerInstance.cpp | 43 ++++++++++++++++++- clang/tools/clang-cc/clang-cc.cpp | 32 +++----------- 3 files changed, 90 insertions(+), 28 deletions(-) diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 2e19822fa0e7..5bb6de8345ae 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -17,10 +17,12 @@ namespace llvm { class LLVMContext; +class raw_ostream; } namespace clang { class ASTContext; +class CodeCompleteConsumer; class Diagnostic; class DiagnosticClient; class ExternalASTSource; @@ -77,6 +79,9 @@ class CompilerInstance { /// The AST context. llvm::OwningPtr Context; + /// The code completion consumer. + llvm::OwningPtr CompletionConsumer; + public: /// Create a new compiler instance with the given LLVM context, optionally /// taking ownership of it. @@ -302,6 +307,30 @@ public: /// takes ownership of \arg Value. void setASTContext(ASTContext *Value) { Context.reset(Value); } + /// } + /// @name Code Completion + /// { + + bool hasCodeCompletionConsumer() const { return CompletionConsumer != 0; } + + CodeCompleteConsumer &getCodeCompletionConsumer() const { + assert(CompletionConsumer && + "Compiler instance has no code completion consumer!"); + return *CompletionConsumer; + } + + /// takeCodeCompletionConsumer - Remove the current code completion consumer + /// and give ownership to the caller. + CodeCompleteConsumer *takeCodeCompletionConsumer() { + return CompletionConsumer.take(); + } + + /// setCodeCompletionConsumer - Replace the current code completion consumer; + /// the compiler instance takes ownership of \arg Value. + void setCodeCompletionConsumer(CodeCompleteConsumer *Value) { + CompletionConsumer.reset(Value); + } + /// } /// @name Construction Utility Methods /// { @@ -363,6 +392,20 @@ public: createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, Preprocessor &PP, ASTContext &Context); + /// Create a code completion consumer using the invocation; note that this + /// will cause the source manager to truncate the input source file at the + /// completion point. + void createCodeCompletionConsumer(); + + /// Create a code completion consumer to print code completion results, at + /// \arg Filename, \arg Line, and \arg Column, to the given output stream \arg + /// OS. + static CodeCompleteConsumer * + createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, + unsigned Line, unsigned Column, + bool UseDebugPrinter, bool ShowMacros, + llvm::raw_ostream &OS); + /// } }; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index e7c3611f0fd1..ce7c54f39866 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -18,9 +18,11 @@ #include "clang/Lex/PTHManager.h" #include "clang/Frontend/ChainedDiagnosticClient.h" #include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" +#include "clang/Sema/CodeCompleteConsumer.h" #include "llvm/LLVMContext.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -29,7 +31,7 @@ CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, bool _OwnsLLVMContext) : LLVMContext(_LLVMContext), OwnsLLVMContext(_OwnsLLVMContext) { -} + } CompilerInstance::~CompilerInstance() { if (OwnsLLVMContext) @@ -202,3 +204,42 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, return 0; } + +// Code Completion + +void CompilerInstance::createCodeCompletionConsumer() { + const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; + CompletionConsumer.reset( + createCodeCompletionConsumer(getPreprocessor(), + Loc.FileName, Loc.Line, Loc.Column, + getFrontendOpts().DebugCodeCompletionPrinter, + getFrontendOpts().ShowMacrosInCodeCompletion, + llvm::outs())); +} + +CodeCompleteConsumer * +CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, + const std::string &Filename, + unsigned Line, + unsigned Column, + bool UseDebugPrinter, + bool ShowMacros, + llvm::raw_ostream &OS) { + // Tell the source manager to chop off the given file at a specific + // line and column. + const FileEntry *Entry = PP.getFileManager().getFile(Filename); + if (!Entry) { + PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) + << Filename; + return 0; + } + + // Truncate the named file at the given line/column. + PP.getSourceManager().truncateFileAt(Entry, Line, Column); + + // Set up the creation routine for code-completion. + if (UseDebugPrinter) + return new PrintingCodeCompleteConsumer(ShowMacros, OS); + else + return new CIndexCodeCompleteConsumer(ShowMacros, OS); +} diff --git a/clang/tools/clang-cc/clang-cc.cpp b/clang/tools/clang-cc/clang-cc.cpp index 5092e1ab3286..8e969479e7e1 100644 --- a/clang/tools/clang-cc/clang-cc.cpp +++ b/clang/tools/clang-cc/clang-cc.cpp @@ -481,36 +481,14 @@ static void ProcessInputFile(CompilerInstance &CI, const std::string &InFile, if (InitializeSourceManager(PP, CI.getFrontendOpts(), InFile)) return; - llvm::OwningPtr CCConsumer; - if (!FEOpts.CodeCompletionAt.FileName.empty()) { - // Tell the source manager to chop off the given file at a specific - // line and column. - if (const FileEntry *Entry - = PP.getFileManager().getFile(FEOpts.CodeCompletionAt.FileName)) { - // Truncate the named file at the given line/column. - PP.getSourceManager().truncateFileAt(Entry, - FEOpts.CodeCompletionAt.Line, - FEOpts.CodeCompletionAt.Column); - - // Set up the creation routine for code-completion. - if (FEOpts.DebugCodeCompletionPrinter) - CCConsumer.reset( - new PrintingCodeCompleteConsumer(FEOpts.ShowMacrosInCodeCompletion, - llvm::outs())); - else - CCConsumer.reset( - new CIndexCodeCompleteConsumer(FEOpts.ShowMacrosInCodeCompletion, - llvm::outs())); - } else { - PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) - << FEOpts.CodeCompletionAt.FileName; - } - } + if (!FEOpts.CodeCompletionAt.FileName.empty()) + CI.createCodeCompletionConsumer(); // Run the AST consumer action. + CodeCompleteConsumer *CompletionConsumer = + CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer() : 0; ParseAST(PP, Consumer.get(), CI.getASTContext(), FEOpts.ShowStats, - CompleteTranslationUnit, - CCConsumer.get()); + CompleteTranslationUnit, CompletionConsumer); } else { // Initialize builtin info. PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),