ioeric updated this revision to Diff 187205.
ioeric marked 4 inline comments as done.
ioeric added a comment.
- address review comments
Repository:
rCTE Clang Tools Extra
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D58239/new/
https://reviews.llvm.org/D58239
Files:
clangd/IncludeFixer.cpp
clangd/IncludeFixer.h
unittests/clangd/DiagnosticsTests.cpp
Index: unittests/clangd/DiagnosticsTests.cpp
===================================================================
--- unittests/clangd/DiagnosticsTests.cpp
+++ unittests/clangd/DiagnosticsTests.cpp
@@ -449,6 +449,44 @@
UnorderedElementsAre(Diag(Test.range(), "no member named 'xy' in 'X'")));
}
+TEST(IncludeFixerTest, UseCachedIndexResults) {
+ // As index results for the identical request are cached, more than 5 fixes
+ // are generated.
+ Annotations Test(R"cpp(
+$insert[[]]void foo() {
+ $x1[[X]] x;
+ $x2[[X]] x;
+ $x3[[X]] x;
+ $x4[[X]] x;
+ $x5[[X]] x;
+ $x6[[X]] x;
+ $x7[[X]] x;
+}
+
+class X;
+void bar(X *x) {
+ x$a1[[->]]f();
+ x$a2[[->]]f();
+ x$a3[[->]]f();
+ x$a4[[->]]f();
+ x$a5[[->]]f();
+ x$a6[[->]]f();
+ x$a7[[->]]f();
+}
+ )cpp");
+ auto TU = TestTU::withCode(Test.code());
+ auto Index =
+ buildIndexWithSymbol(SymbolWithHeader{"X", "unittest:///a.h", "\"a.h\""});
+ TU.ExternalIndex = Index.get();
+
+ auto Parsed = TU.build();
+ for (const auto &D : Parsed.getDiagnostics()) {
+ EXPECT_EQ(D.Fixes.size(), 1u);
+ EXPECT_EQ(D.Fixes[0].Message,
+ std::string("Add include \"a.h\" for symbol X"));
+ }
+}
+
} // namespace
} // namespace clangd
} // namespace clang
Index: clangd/IncludeFixer.h
===================================================================
--- clangd/IncludeFixer.h
+++ clangd/IncludeFixer.h
@@ -21,6 +21,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
@@ -51,7 +52,7 @@
std::vector<Fix> fixIncompleteType(const Type &T) const;
/// Generates header insertion fixes for all symbols. Fixes are deduplicated.
- std::vector<Fix> fixesForSymbols(llvm::ArrayRef<Symbol> Syms) const;
+ std::vector<Fix> fixesForSymbols(const SymbolSlab &Syms) const;
struct UnresolvedName {
std::string Name; // E.g. "X" in foo::X.
@@ -79,6 +80,14 @@
// These collect the last unresolved name so that we can associate it with the
// diagnostic.
llvm::Optional<UnresolvedName> LastUnresolvedName;
+
+ // There can be multiple diagnostics that are caused by the same unresolved
+ // name or incomplete type in one parse, especially when code is
+ // copy-and-pasted without #includes. We cache the index results based on
+ // index requests (assuming index results are consistent during the single AST
+ // parse).
+ mutable llvm::StringMap<SymbolSlab> FuzzyFindCache;
+ mutable llvm::DenseMap<SymbolID, SymbolSlab> LookupCache;
};
} // namespace clangd
Index: clangd/IncludeFixer.cpp
===================================================================
--- clangd/IncludeFixer.cpp
+++ clangd/IncludeFixer.cpp
@@ -57,8 +57,6 @@
std::vector<Fix> IncludeFixer::fix(DiagnosticsEngine::Level DiagLevel,
const clang::Diagnostic &Info) const {
- if (IndexRequestCount >= IndexRequestLimit)
- return {}; // Avoid querying index too many times in a single parse.
switch (Info.getID()) {
case diag::err_incomplete_type:
case diag::err_incomplete_member_access:
@@ -118,26 +116,34 @@
auto ID = getSymbolID(TD);
if (!ID)
return {};
- ++IndexRequestCount;
- // FIXME: consider batching the requests for all diagnostics.
- // FIXME: consider caching the lookup results.
LookupRequest Req;
Req.IDs.insert(*ID);
- llvm::Optional<Symbol> Matched;
- Index.lookup(Req, [&](const Symbol &Sym) {
- if (Matched)
- return;
- Matched = Sym;
- });
- if (!Matched || Matched->IncludeHeaders.empty() || !Matched->Definition ||
- Matched->CanonicalDeclaration.FileURI != Matched->Definition.FileURI)
+ auto I = LookupCache.find(*ID);
+ if (I != LookupCache.end())
+ return fixesForSymbols(I->second);
+
+ if (IndexRequestCount >= IndexRequestLimit)
return {};
- return fixesForSymbols({*Matched});
+ IndexRequestCount++;
+
+ // FIXME: consider batching the requests for all diagnostics.
+ SymbolSlab::Builder Matches;
+ Index.lookup(Req, [&](const Symbol &Sym) { Matches.insert(Sym); });
+ auto Syms = std::move(Matches).build();
+
+ std::vector<Fix> Fixes;
+ if (!Syms.empty()) {
+ auto &Matched = *Syms.begin();
+ if (!Matched.IncludeHeaders.empty() && Matched.Definition &&
+ Matched.CanonicalDeclaration.FileURI == Matched.Definition.FileURI)
+ Fixes = fixesForSymbols(Syms);
+ }
+ LookupCache[*ID] = std::move(Syms);
+ return Fixes;
}
-std::vector<Fix>
-IncludeFixer::fixesForSymbols(llvm::ArrayRef<Symbol> Syms) const {
+std::vector<Fix> IncludeFixer::fixesForSymbols(const SymbolSlab &Syms) const {
auto Inserted = [&](const Symbol &Sym, llvm::StringRef Header)
-> llvm::Expected<std::pair<std::string, bool>> {
auto ResolvedDeclaring =
@@ -289,6 +295,14 @@
Req.RestrictForCodeCompletion = true;
Req.Limit = 100;
+ auto ReqStr = llvm::formatv("{0}", toJSON(Req)).str();
+ auto I = FuzzyFindCache.find(ReqStr);
+ if (I != FuzzyFindCache.end())
+ return fixesForSymbols(I->second);
+
+ if (IndexRequestCount >= IndexRequestLimit)
+ return {};
+ IndexRequestCount++;
SymbolSlab::Builder Matches;
Index.fuzzyFind(Req, [&](const Symbol &Sym) {
if (Sym.Name != Req.Query)
@@ -297,7 +311,10 @@
Matches.insert(Sym);
});
auto Syms = std::move(Matches).build();
- return fixesForSymbols(std::vector<Symbol>(Syms.begin(), Syms.end()));
+ auto Fixes = fixesForSymbols(Syms);
+ FuzzyFindCache[ReqStr] = std::move(Syms);
+
+ return Fixes;
}
} // namespace clangd
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits