Nebiroth updated this revision to Diff 125814.
Nebiroth added a comment.
Fixed re-added include
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D38639
Files:
clangd/ClangdServer.cpp
clangd/ClangdUnit.cpp
clangd/ClangdUnit.h
clangd/Protocol.h
unittests/clangd/ClangdTests.cpp
Index: unittests/clangd/ClangdTests.cpp
===================================================================
--- unittests/clangd/ClangdTests.cpp
+++ unittests/clangd/ClangdTests.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "ClangdLSPServer.h"
#include "ClangdServer.h"
#include "Logger.h"
#include "TestFS.h"
@@ -620,7 +619,7 @@
AddDocument(FileIndex);
Position Pos{LineDist(RandGen), ColumnDist(RandGen)};
- ASSERT_TRUE(!!Server.findDefinitions(FilePaths[FileIndex], Pos));
+ Server.findDefinitions(FilePaths[FileIndex], Pos);
};
std::vector<std::function<void()>> AsyncRequests = {
@@ -749,6 +748,58 @@
EXPECT_FALSE(PathResult.hasValue());
}
+TEST_F(ClangdVFSTest, CheckDefinitionIncludes) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+
+ ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
+ /*StorePreamblesInMemory=*/true,
+ EmptyLogger::getInstance());
+
+ auto FooCpp = getVirtualTestFilePath("foo.cpp");
+ const auto SourceContents = R"cpp(
+ #include "foo.h"
+ #include "invalid.h"
+ int b = a;
+ )cpp";
+ FS.Files[FooCpp] = SourceContents;
+ auto FooH = getVirtualTestFilePath("foo.h");
+ const auto HeaderContents = "int a;";
+
+ FS.Files[FooCpp] = SourceContents;
+ FS.Files[FooH] = HeaderContents;
+
+ Server.addDocument(FooH, HeaderContents);
+ Server.addDocument(FooCpp, SourceContents);
+
+ Position P = Position{1, 11};
+
+ std::vector<Location> Locations = Server.findDefinitions(FooCpp, P).get().Value;
+ EXPECT_TRUE(!Locations.empty());
+ std::string s("file:///");
+ std::string check = Locations[0].uri.uri;
+ check = check.erase(0, s.size());
+ check = check.substr(0, check.size() - 1);
+ ASSERT_EQ(check, FooH);
+ ASSERT_EQ(Locations[0].range.start.line, 0);
+ ASSERT_EQ(Locations[0].range.start.character, 0);
+ ASSERT_EQ(Locations[0].range.end.line, 0);
+ ASSERT_EQ(Locations[0].range.end.character, 0);
+
+ // Test ctrl-clicking on the #include part on the statement
+ Position P3 = Position{1, 3};
+
+ Locations = Server.findDefinitions(FooCpp, P3).get().Value;
+ EXPECT_TRUE(!Locations.empty());
+
+ // Test invalid include
+ Position P2 = Position{2, 11};
+
+ Locations = Server.findDefinitions(FooCpp, P2).get().Value;
+ EXPECT_TRUE(Locations.empty());
+}
+
TEST_F(ClangdThreadingTest, NoConcurrentDiagnostics) {
class NoConcurrentAccessDiagConsumer : public DiagnosticsConsumer {
public:
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -108,6 +108,14 @@
bool fromJSON(const json::Expr &, Range &);
json::Expr toJSON(const Range &);
+class RangeHash {
+public:
+ std::size_t operator()(const Range &R) const {
+ return ((R.start.line & 0x18) << 3) | ((R.start.character & 0x18) << 1) |
+ ((R.end.line & 0x18) >> 1) | ((R.end.character & 0x18) >> 3);
+ }
+};
+
struct Location {
/// The text document's URI.
URI uri;
Index: clangd/ClangdUnit.h
===================================================================
--- clangd/ClangdUnit.h
+++ clangd/ClangdUnit.h
@@ -22,6 +22,7 @@
#include <future>
#include <memory>
#include <mutex>
+#include <unordered_map>
namespace llvm {
class raw_ostream;
@@ -59,6 +60,15 @@
std::vector<DiagWithFixIts> Diags;
};
+class IncludeReferenceMap {
+ llvm::Optional<PathRef> findIncludeTargetAtLoc(Location Loc);
+
+public:
+ std::unordered_map<Range, Path, RangeHash> IncludeLocationMap;
+ std::vector<std::pair<SourceRange, std::string>> DataVector;
+ std::vector<Range> RangeVector;
+};
+
/// Stores and provides access to parsed AST.
class ParsedAST {
public:
@@ -69,7 +79,8 @@
std::shared_ptr<const PreambleData> Preamble,
std::unique_ptr<llvm::MemoryBuffer> Buffer,
std::shared_ptr<PCHContainerOperations> PCHs,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS, clangd::Logger &Logger);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS, clangd::Logger &Logger,
+ IncludeReferenceMap IRM);
ParsedAST(ParsedAST &&Other);
ParsedAST &operator=(ParsedAST &&Other);
@@ -89,12 +100,14 @@
const std::vector<DiagWithFixIts> &getDiagnostics() const;
+ IncludeReferenceMap takeIRM() { return IRM; };
+
private:
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, IncludeReferenceMap IRM);
private:
void ensurePreambleDeclsDeserialized();
@@ -114,6 +127,8 @@
std::vector<DiagWithFixIts> Diags;
std::vector<const Decl *> TopLevelDecls;
bool PreambleDeclsDeserialized;
+ std::vector<serialization::DeclID> PendingTopLevelDecls;
+ IncludeReferenceMap IRM;
};
// Provides thread-safe access to ParsedAST.
@@ -256,14 +271,14 @@
clangd::Logger &Logger;
};
-
/// Get the beginning SourceLocation at a specified \p Pos.
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
const FileEntry *FE);
/// Get definition of symbol at a specified \p Pos.
-std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
- clangd::Logger &Logger);
+std::vector<Location>
+findDefinitions(ParsedAST &AST, Position Pos, clangd::Logger &Logger,
+ std::unordered_map<Range, Path, RangeHash> IncludeLocationMap);
/// For testing/debugging purposes. Note that this method deserializes all
/// unserialized Decls, so use with care.
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -31,10 +31,30 @@
#include <algorithm>
#include <chrono>
+#include <iostream>
using namespace clang::clangd;
using namespace clang;
+class DelegatingPPCallbacks : public PPCallbacks {
+
+public:
+ DelegatingPPCallbacks(PPCallbacks &PPCallbacks) : Callbacks(PPCallbacks) {}
+
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override {
+ Callbacks.InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled,
+ FilenameRange, File, SearchPath, RelativePath,
+ Imported);
+ }
+
+private:
+ PPCallbacks &Callbacks;
+};
+
namespace {
class DeclTrackingASTConsumer : public ASTConsumer {
@@ -73,12 +93,58 @@
std::vector<const Decl *> TopLevelDecls;
};
-class CppFilePreambleCallbacks : public PreambleCallbacks {
+void fillRangeVector(
+ const SourceManager &SM,
+ std::vector<std::pair<SourceRange, std::string>> DataVector,
+ std::vector<Range> &RangeVector) {
+ if (RangeVector.empty()) {
+ for (unsigned I = 0; I < DataVector.size(); I++) {
+ Position Begin;
+ Begin.line = SM.getSpellingLineNumber(DataVector[I].first.getBegin());
+ Begin.character =
+ SM.getSpellingColumnNumber(DataVector[I].first.getBegin());
+ Position End;
+ End.line = SM.getSpellingLineNumber(DataVector[I].first.getEnd());
+ End.character = SM.getSpellingColumnNumber(DataVector[I].first.getEnd());
+ Range R = {Begin, End};
+ RangeVector.push_back(R);
+ }
+ }
+}
+
+void findPreambleIncludes(
+ const SourceManager &SM,
+ std::unordered_map<Range, Path, RangeHash> &IncludeLocationMap,
+ std::vector<std::pair<SourceRange, std::string>> DataVector,
+ std::vector<Range> RangeVector) {
+
+ for (unsigned I = 0; I < DataVector.size(); I++) {
+ auto fileID = DataVector[I].first.getBegin();
+ if (fileID.isValid() &&
+ SM.getMainFileID() == SM.getFileID(DataVector[I].first.getBegin())) {
+ IncludeLocationMap.insert({RangeVector[I], DataVector[I].second});
+ }
+ }
+}
+
+class CppFilePreambleCallbacks : public PreambleCallbacks, public PPCallbacks {
public:
std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
return std::move(TopLevelDeclIDs);
}
+ CppFilePreambleCallbacks(SourceManager *SourceMgr, IncludeReferenceMap &IRM)
+ : SourceMgr(SourceMgr), IRM(IRM) {}
+
+ IncludeReferenceMap takeIRM() {
+ fillRangeVector(*SourceMgr, IRM.DataVector, IRM.RangeVector);
+ findPreambleIncludes(*SourceMgr, IRM.IncludeLocationMap, IRM.DataVector,
+ IRM.RangeVector);
+ return std::move(IRM);
+ };
+
+ IncludeReferenceMap getIRM() { return IRM; };
+
void AfterPCHEmitted(ASTWriter &Writer) override {
TopLevelDeclIDs.reserve(TopLevelDecls.size());
for (Decl *D : TopLevelDecls) {
@@ -97,9 +163,46 @@
}
}
+ void AfterExecute(CompilerInstance &CI) override {
+
+ SourceMgr = &CI.getSourceManager();
+
+ fillRangeVector(CI.getSourceManager(), IRM.DataVector, IRM.RangeVector);
+ findPreambleIncludes(CI.getSourceManager(), IRM.IncludeLocationMap,
+ IRM.DataVector, IRM.RangeVector);
+ }
+
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override {
+ if (!SourceMgr) {
+ if (File && !File->tryGetRealPathName().empty())
+ IRM.DataVector.push_back(std::pair<SourceRange, std::string>(
+ FilenameRange.getAsRange(), File->tryGetRealPathName()));
+ } else {
+ Position Begin;
+ Begin.line = SourceMgr->getSpellingLineNumber(
+ FilenameRange.getAsRange().getBegin());
+ Begin.character = SourceMgr->getSpellingColumnNumber(
+ FilenameRange.getAsRange().getBegin());
+ Position End;
+ End.line =
+ SourceMgr->getSpellingLineNumber(FilenameRange.getAsRange().getEnd());
+ End.character = SourceMgr->getSpellingColumnNumber(
+ FilenameRange.getAsRange().getEnd());
+ Range R = {Begin, End};
+ if (File && !File->tryGetRealPathName().empty())
+ IRM.IncludeLocationMap.insert({R, File->tryGetRealPathName()});
+ }
+ }
+
private:
std::vector<Decl *> TopLevelDecls;
std::vector<serialization::DeclID> TopLevelDeclIDs;
+ IncludeReferenceMap IRM;
+ SourceManager *SourceMgr;
};
/// Convert from clang diagnostic level to LSP severity.
@@ -155,6 +258,12 @@
std::vector<DiagWithFixIts> &Output;
};
+class EmptyDiagsConsumer : public DiagnosticConsumer {
+public:
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) override {}
+};
+
template <class T> bool futureIsReady(std::shared_future<T> const &Future) {
return Future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
@@ -171,7 +280,7 @@
std::unique_ptr<llvm::MemoryBuffer> Buffer,
std::shared_ptr<PCHContainerOperations> PCHs,
IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- clangd::Logger &Logger) {
+ clangd::Logger &Logger, IncludeReferenceMap IRM) {
std::vector<DiagWithFixIts> ASTDiags;
StoreDiagsConsumer UnitDiagsConsumer(/*ref*/ ASTDiags);
@@ -193,16 +302,24 @@
MainInput.getFile());
return llvm::None;
}
+
+ CppFilePreambleCallbacks SerializedDeclsCollector(&Clang->getSourceManager(),
+ IRM);
+ std::unique_ptr<DelegatingPPCallbacks> DelegatedPPCallbacks =
+ llvm::make_unique<DelegatingPPCallbacks>(SerializedDeclsCollector);
+
+ Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
+
if (!Action->Execute())
Logger.log("Execute() failed when building AST for " + MainInput.getFile());
-
// UnitDiagsConsumer is local, we can not store it in CompilerInstance that
// has a longer lifetime.
Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
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(SerializedDeclsCollector.getIRM()));
}
namespace {
@@ -227,12 +344,15 @@
const SourceLocation &SearchedLocation;
const ASTContext &AST;
Preprocessor &PP;
+ std::unordered_map<Range, Path, RangeHash> IncludeLocationMap;
public:
- DeclarationLocationsFinder(raw_ostream &OS,
- const SourceLocation &SearchedLocation,
- ASTContext &AST, Preprocessor &PP)
- : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
+ DeclarationLocationsFinder(
+ raw_ostream &OS, const SourceLocation &SearchedLocation, ASTContext &AST,
+ Preprocessor &PP,
+ std::unordered_map<Range, Path, RangeHash> IncludeLocationMap)
+ : SearchedLocation(SearchedLocation), AST(AST), PP(PP),
+ IncludeLocationMap(IncludeLocationMap) {}
std::vector<Location> takeLocations() {
// Don't keep the same location multiple times.
@@ -262,6 +382,11 @@
SourceMgr.getFileID(SearchedLocation) == FID;
}
+ bool isSameLine(unsigned Line) const {
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ return Line == SourceMgr.getSpellingLineNumber(SearchedLocation);
+ }
+
void addDeclarationLocation(const SourceRange &ValSourceRange) {
const SourceManager &SourceMgr = AST.getSourceManager();
const LangOptions &LangOpts = AST.getLangOpts();
@@ -275,19 +400,28 @@
End.line = SourceMgr.getSpellingLineNumber(LocEnd) - 1;
End.character = SourceMgr.getSpellingColumnNumber(LocEnd) - 1;
Range R = {Begin, End};
+ addLocation(URI::fromFile(
+ SourceMgr.getFilename(SourceMgr.getSpellingLoc(LocStart))),
+ R);
+ }
+
+ void addLocation(URI Uri, Range R) {
Location L;
- if (const FileEntry *F =
- SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart))) {
- StringRef FilePath = F->tryGetRealPathName();
- if (FilePath.empty())
- FilePath = F->getName();
- L.uri = URI::fromFile(FilePath);
- L.range = R;
- DeclarationLocations.push_back(L);
- }
+ L.uri = Uri;
+ L.range = R;
+ DeclarationLocations.push_back(L);
}
void finish() override {
+
+ for (auto It = IncludeLocationMap.begin(); It != IncludeLocationMap.end();
+ ++It) {
+ Range R = It->first;
+ Path P = It->second;
+ if (isSameLine(R.start.line))
+ addLocation(URI::fromFile(P), R);
+ }
+
// Also handle possible macro at the searched location.
Token Result;
if (!Lexer::getRawToken(SearchedLocation, Result, AST.getSourceManager(),
@@ -319,8 +453,9 @@
} // namespace
-std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
- clangd::Logger &Logger) {
+std::vector<Location> clangd::findDefinitions(
+ ParsedAST &AST, Position Pos, clangd::Logger &Logger,
+ std::unordered_map<Range, Path, RangeHash> IncludeLocationMap) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
if (!FE)
@@ -330,7 +465,7 @@
auto DeclLocationsFinder = std::make_shared<DeclarationLocationsFinder>(
llvm::errs(), SourceLocationBeg, AST.getASTContext(),
- AST.getPreprocessor());
+ AST.getPreprocessor(), IncludeLocationMap);
index::IndexingOptions IndexOpts;
IndexOpts.SystemSymbolFilter =
index::IndexingOptions::SystemSymbolFilterKind::All;
@@ -405,11 +540,11 @@
std::unique_ptr<CompilerInstance> Clang,
std::unique_ptr<FrontendAction> Action,
std::vector<const Decl *> TopLevelDecls,
- std::vector<DiagWithFixIts> Diags)
+ std::vector<DiagWithFixIts> Diags, IncludeReferenceMap IRM)
: 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),
+ IRM(std::move(IRM)) {
assert(this->Clang);
assert(this->Action);
}
@@ -565,6 +700,8 @@
}
assert(CI && "Couldn't create CompilerInvocation");
+ IncludeReferenceMap IRM;
+ CppFilePreambleCallbacks SerializedDeclsCollector(nullptr, IRM);
std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
llvm::MemoryBuffer::getMemBufferCopy(NewContents, That->FileName);
@@ -590,11 +727,13 @@
IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
CompilerInstance::createDiagnostics(
&CI->getDiagnosticOpts(), &PreambleDiagnosticsConsumer, false);
- CppFilePreambleCallbacks SerializedDeclsCollector;
+
+ std::unique_ptr<DelegatingPPCallbacks> DelegatedPPCallbacks =
+ llvm::make_unique<DelegatingPPCallbacks>(SerializedDeclsCollector);
auto BuiltPreamble = PrecompiledPreamble::Build(
*CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, VFS, PCHs,
/*StoreInMemory=*/That->StorePreamblesInMemory,
- SerializedDeclsCollector);
+ SerializedDeclsCollector, std::move(DelegatedPPCallbacks));
if (BuiltPreamble) {
return std::make_shared<PreambleData>(
@@ -631,9 +770,9 @@
{
trace::Span Tracer("Build");
SPAN_ATTACH(Tracer, "File", That->FileName);
- NewAST =
- ParsedAST::Build(std::move(CI), std::move(NewPreamble),
- std::move(ContentsBuffer), PCHs, VFS, That->Logger);
+ NewAST = ParsedAST::Build(
+ std::move(CI), std::move(NewPreamble), std::move(ContentsBuffer),
+ PCHs, VFS, That->Logger, SerializedDeclsCollector.getIRM());
}
if (NewAST) {
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <future>
+#include <unordered_map>
using namespace clang;
using namespace clang::clangd;
@@ -442,10 +443,16 @@
llvm::errc::invalid_argument);
std::vector<Location> Result;
- Resources->getAST().get()->runUnderLock([Pos, &Result, this](ParsedAST *AST) {
+ std::shared_future<std::shared_ptr<const PreambleData>> Preamble =
+ Resources->getPreamble();
+
+ Resources->getAST().get()->runUnderLock([Pos, &Result, Preamble,
+ this](ParsedAST *AST) {
if (!AST)
return;
- Result = clangd::findDefinitions(*AST, Pos, Logger);
+
+ IncludeReferenceMap IRM = std::move(AST->takeIRM());
+ Result = clangd::findDefinitions(*AST, Pos, Logger, IRM.IncludeLocationMap);
});
return make_tagged(std::move(Result), TaggedFS.Tag);
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits