summaryrefslogtreecommitdiff
path: root/clang-tools-extra/clangd/ClangdUnit.cpp
diff options
context:
space:
mode:
authorMarc-Andre Laperle <marc-andre.laperle@ericsson.com>2018-02-21 02:39:08 +0000
committerMarc-Andre Laperle <marc-andre.laperle@ericsson.com>2018-02-21 02:39:08 +0000
commit5b5056e714e1d4f0fcdbe22372420c75589e5ad3 (patch)
tree942f25b513de94ed9d2a28efa2902b81bc3ae784 /clang-tools-extra/clangd/ClangdUnit.cpp
parent2d834e0bd9d98ea30dba832ee71e8341fccd42a1 (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.cpp110
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;