diff options
author | Marc-Andre Laperle <marc-andre.laperle@ericsson.com> | 2018-02-21 02:39:08 +0000 |
---|---|---|
committer | Marc-Andre Laperle <marc-andre.laperle@ericsson.com> | 2018-02-21 02:39:08 +0000 |
commit | 5b5056e714e1d4f0fcdbe22372420c75589e5ad3 (patch) | |
tree | 942f25b513de94ed9d2a28efa2902b81bc3ae784 /clang-tools-extra/clangd/ClangdUnit.cpp | |
parent | 2d834e0bd9d98ea30dba832ee71e8341fccd42a1 (diff) |
[clangd] #include statements support for Open definition
Summary: ctrl-clicking on #include statements now opens the file being pointed by that statement.
Reviewers: malaperle, krasimir, bkramer, ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: jkorous-apple, ioeric, mgrang, klimek, ilya-biryukov, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D38639
Diffstat (limited to 'clang-tools-extra/clangd/ClangdUnit.cpp')
-rw-r--r-- | clang-tools-extra/clangd/ClangdUnit.cpp | 110 |
1 files changed, 87 insertions, 23 deletions
diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp index df2a4e8c912..4ad95c4dc5d 100644 --- a/clang-tools-extra/clangd/ClangdUnit.cpp +++ b/clang-tools-extra/clangd/ClangdUnit.cpp @@ -81,12 +81,60 @@ private: std::vector<const Decl *> TopLevelDecls; }; +// Converts a half-open clang source range to an LSP range. +// Note that clang also uses closed source ranges, which this can't handle! +Range toRange(CharSourceRange R, const SourceManager &M) { + // Clang is 1-based, LSP uses 0-based indexes. + Position Begin; + Begin.line = static_cast<int>(M.getSpellingLineNumber(R.getBegin())) - 1; + Begin.character = + static_cast<int>(M.getSpellingColumnNumber(R.getBegin())) - 1; + + Position End; + End.line = static_cast<int>(M.getSpellingLineNumber(R.getEnd())) - 1; + End.character = static_cast<int>(M.getSpellingColumnNumber(R.getEnd())) - 1; + + return {Begin, End}; +} + +class InclusionLocationsCollector : public PPCallbacks { +public: + InclusionLocationsCollector(SourceManager &SourceMgr, + InclusionLocations &IncLocations) + : SourceMgr(SourceMgr), IncLocations(IncLocations) {} + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported) override { + auto SR = FilenameRange.getAsRange(); + if (SR.isInvalid() || !File || File->tryGetRealPathName().empty()) + return; + + if (SourceMgr.isInMainFile(SR.getBegin())) { + // Only inclusion directives in the main file make sense. The user cannot + // select directives not in the main file. + IncLocations.emplace_back(toRange(FilenameRange, SourceMgr), + File->tryGetRealPathName()); + } + } + +private: + SourceManager &SourceMgr; + InclusionLocations &IncLocations; +}; + class CppFilePreambleCallbacks : public PreambleCallbacks { public: std::vector<serialization::DeclID> takeTopLevelDeclIDs() { return std::move(TopLevelDeclIDs); } + InclusionLocations takeInclusionLocations() { + return std::move(IncLocations); + } + void AfterPCHEmitted(ASTWriter &Writer) override { TopLevelDeclIDs.reserve(TopLevelDecls.size()); for (Decl *D : TopLevelDecls) { @@ -105,9 +153,21 @@ public: } } + void BeforeExecute(CompilerInstance &CI) override { + SourceMgr = &CI.getSourceManager(); + } + + std::unique_ptr<PPCallbacks> createPPCallbacks() override { + assert(SourceMgr && "SourceMgr must be set at this point"); + return llvm::make_unique<InclusionLocationsCollector>(*SourceMgr, + IncLocations); + } + private: std::vector<Decl *> TopLevelDecls; std::vector<serialization::DeclID> TopLevelDeclIDs; + InclusionLocations IncLocations; + SourceManager *SourceMgr = nullptr; }; /// Convert from clang diagnostic level to LSP severity. @@ -139,22 +199,6 @@ bool locationInRange(SourceLocation L, CharSourceRange R, return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd()); } -// Converts a half-open clang source range to an LSP range. -// Note that clang also uses closed source ranges, which this can't handle! -Range toRange(CharSourceRange R, const SourceManager &M) { - // Clang is 1-based, LSP uses 0-based indexes. - Position Begin; - Begin.line = static_cast<int>(M.getSpellingLineNumber(R.getBegin())) - 1; - Begin.character = - static_cast<int>(M.getSpellingColumnNumber(R.getBegin())) - 1; - - Position End; - End.line = static_cast<int>(M.getSpellingLineNumber(R.getEnd())) - 1; - End.character = static_cast<int>(M.getSpellingColumnNumber(R.getEnd())) - 1; - - return {Begin, End}; -} - // Clang diags have a location (shown as ^) and 0 or more ranges (~~~~). // LSP needs a single range. Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) { @@ -267,6 +311,17 @@ ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI, MainInput.getFile()); return llvm::None; } + + InclusionLocations IncLocations; + // Copy over the includes from the preamble, then combine with the + // non-preamble includes below. + if (Preamble) + IncLocations = Preamble->IncLocations; + + Clang->getPreprocessor().addPPCallbacks( + llvm::make_unique<InclusionLocationsCollector>(Clang->getSourceManager(), + IncLocations)); + if (!Action->Execute()) log("Execute() failed when building AST for " + MainInput.getFile()); @@ -276,7 +331,8 @@ ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI, std::vector<const Decl *> ParsedDecls = Action->takeTopLevelDecls(); return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action), - std::move(ParsedDecls), std::move(ASTDiags)); + std::move(ParsedDecls), std::move(ASTDiags), + std::move(IncLocations)); } namespace { @@ -355,21 +411,28 @@ std::size_t ParsedAST::getUsedBytes() const { ::getUsedBytes(TopLevelDecls) + ::getUsedBytes(Diags); } +const InclusionLocations &ParsedAST::getInclusionLocations() const { + return IncLocations; +} + PreambleData::PreambleData(PrecompiledPreamble Preamble, std::vector<serialization::DeclID> TopLevelDeclIDs, - std::vector<DiagWithFixIts> Diags) + std::vector<DiagWithFixIts> Diags, + InclusionLocations IncLocations) : Preamble(std::move(Preamble)), - TopLevelDeclIDs(std::move(TopLevelDeclIDs)), Diags(std::move(Diags)) {} + TopLevelDeclIDs(std::move(TopLevelDeclIDs)), Diags(std::move(Diags)), + IncLocations(std::move(IncLocations)) {} ParsedAST::ParsedAST(std::shared_ptr<const PreambleData> Preamble, std::unique_ptr<CompilerInstance> Clang, std::unique_ptr<FrontendAction> Action, std::vector<const Decl *> TopLevelDecls, - std::vector<DiagWithFixIts> Diags) + std::vector<DiagWithFixIts> Diags, + InclusionLocations IncLocations) : Preamble(std::move(Preamble)), Clang(std::move(Clang)), Action(std::move(Action)), Diags(std::move(Diags)), - TopLevelDecls(std::move(TopLevelDecls)), - PreambleDeclsDeserialized(false) { + TopLevelDecls(std::move(TopLevelDecls)), PreambleDeclsDeserialized(false), + IncLocations(std::move(IncLocations)) { assert(this->Clang); assert(this->Action); } @@ -521,7 +584,8 @@ CppFile::rebuildPreamble(CompilerInvocation &CI, return std::make_shared<PreambleData>( std::move(*BuiltPreamble), SerializedDeclsCollector.takeTopLevelDeclIDs(), - std::move(PreambleDiags)); + std::move(PreambleDiags), + SerializedDeclsCollector.takeInclusionLocations()); } else { log("Could not build a preamble for file " + Twine(FileName)); return nullptr; |