Skip to content

Commit 99e7189

Browse files
committed
[clangd] Store full decl/def range with symbol locations
Apart from fixing the linked issue, this is also necessary for supporting LSP's LocationLink feature and for finding proper insertion locations in the DefineOutline tweak. Memory consumption of the background index grows by about ~2.5%. Closes clangd/clangd#59
1 parent 66126c3 commit 99e7189

32 files changed

+388
-239
lines changed

clang-tools-extra/clangd/CodeComplete.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ struct CodeCompletionBuilder {
418418
auto Inserted = [&](llvm::StringRef Header)
419419
-> llvm::Expected<std::pair<std::string, bool>> {
420420
auto ResolvedDeclaring =
421-
URI::resolve(C.IndexResult->CanonicalDeclaration.FileURI, FileName);
421+
URI::resolve(C.IndexResult->CanonicalDeclaration.fileURI(), FileName);
422422
if (!ResolvedDeclaring)
423423
return ResolvedDeclaring.takeError();
424424
auto ResolvedInserted = toHeaderFile(Header, FileName);
@@ -451,7 +451,7 @@ struct CodeCompletionBuilder {
451451
} else
452452
log("Failed to generate include insertion edits for adding header "
453453
"(FileURI='{0}', IncludeHeader='{1}') into {2}: {3}",
454-
C.IndexResult->CanonicalDeclaration.FileURI, Inc.Header, FileName,
454+
C.IndexResult->CanonicalDeclaration.fileURI(), Inc.Header, FileName,
455455
ToInclude.takeError());
456456
}
457457
// Prefer includes that do not need edits (i.e. already exist).

clang-tools-extra/clangd/FindSymbols.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,27 +54,41 @@ bool approximateScopeMatch(llvm::StringRef Scope, llvm::StringRef Query) {
5454
return Query.empty();
5555
}
5656

57+
Range indexToLSPRange(const SymbolPosition &SrcStart,
58+
const SymbolPosition &SrcEnd) {
59+
Position Start, End;
60+
Start.line = SrcStart.line();
61+
Start.character = SrcStart.column();
62+
End.line = SrcEnd.line();
63+
End.character = SrcEnd.column();
64+
return {Start, End};
65+
}
66+
5767
} // namespace
5868

59-
llvm::Expected<Location> indexToLSPLocation(const SymbolLocation &Loc,
69+
llvm::Expected<Location> indexToLSPLocation(const SymbolNameLocation &Loc,
6070
llvm::StringRef TUPath) {
6171
auto Path = URI::resolve(Loc.FileURI, TUPath);
6272
if (!Path)
6373
return error("Could not resolve path for file '{0}': {1}", Loc.FileURI,
6474
Path.takeError());
6575
Location L;
6676
L.uri = URIForFile::canonicalize(*Path, TUPath);
67-
Position Start, End;
68-
Start.line = Loc.Start.line();
69-
Start.character = Loc.Start.column();
70-
End.line = Loc.End.line();
71-
End.character = Loc.End.column();
72-
L.range = {Start, End};
77+
L.range = indexToLSPRange(Loc.Start, Loc.End);
7378
return L;
7479
}
7580

76-
llvm::Expected<Location> symbolToLocation(const Symbol &Sym,
77-
llvm::StringRef TUPath) {
81+
llvm::Expected<std::pair<Location, Range>>
82+
indexToLSPLocation(const SymbolDeclDefLocation &Loc, StringRef TUPath) {
83+
auto L = indexToLSPLocation(Loc.NameLocation, TUPath);
84+
if (!L)
85+
return L.takeError();
86+
return std::make_pair(L.get(),
87+
indexToLSPRange(Loc.DeclDefStart, Loc.DeclDefEnd));
88+
}
89+
90+
llvm::Expected<std::pair<Location, Range>>
91+
symbolToLocation(const Symbol &Sym, llvm::StringRef TUPath) {
7892
// Prefer the definition over e.g. a function declaration in a header
7993
return indexToLSPLocation(
8094
Sym.Definition ? Sym.Definition : Sym.CanonicalDeclaration, TUPath);
@@ -152,7 +166,7 @@ getWorkspaceSymbols(llvm::StringRef Query, int Limit,
152166
SymbolInformation Info;
153167
Info.name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
154168
Info.kind = indexSymbolKindToSymbolKind(Sym.SymInfo.Kind);
155-
Info.location = *Loc;
169+
Info.location = Loc->first;
156170
Scope.consume_back("::");
157171
Info.containerName = Scope.str();
158172

clang-tools-extra/clangd/FindSymbols.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ class ParsedAST;
2222
class SymbolIndex;
2323

2424
/// Helper function for deriving an LSP Location from an index SymbolLocation.
25-
llvm::Expected<Location> indexToLSPLocation(const SymbolLocation &Loc,
25+
llvm::Expected<Location> indexToLSPLocation(const SymbolNameLocation &Loc,
2626
llvm::StringRef TUPath);
27+
llvm::Expected<std::pair<Location, Range>>
28+
indexToLSPLocation(const SymbolDeclDefLocation &Loc, llvm::StringRef TUPath);
2729

2830
/// Helper function for deriving an LSP Location for a Symbol.
29-
llvm::Expected<Location> symbolToLocation(const Symbol &Sym,
30-
llvm::StringRef TUPath);
31+
llvm::Expected<std::pair<Location, Range>>
32+
symbolToLocation(const Symbol &Sym, llvm::StringRef TUPath);
3133

3234
/// Searches for the symbols matching \p Query. The syntax of \p Query can be
3335
/// the non-qualified name or fully qualified of a symbol. For example,

clang-tools-extra/clangd/HeaderSourceSwitch.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ std::optional<Path> getCorrespondingHeaderOrSource(PathRef OriginalFile,
9595
bool IsHeader = isHeaderFile(OriginalFile, AST.getLangOpts());
9696
Index->lookup(Request, [&](const Symbol &Sym) {
9797
if (IsHeader)
98-
AwardTarget(Sym.Definition.FileURI);
98+
AwardTarget(Sym.Definition.fileURI());
9999
else
100-
AwardTarget(Sym.CanonicalDeclaration.FileURI);
100+
AwardTarget(Sym.CanonicalDeclaration.fileURI());
101101
});
102102
// FIXME: our index doesn't have any interesting information (this could be
103103
// that the background-index is not finished), we should use the decl/def

clang-tools-extra/clangd/IncludeFixer.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ std::vector<Fix> IncludeFixer::fixIncompleteType(const Type &T) const {
289289
if (!Syms.empty()) {
290290
auto &Matched = *Syms.begin();
291291
if (!Matched.IncludeHeaders.empty() && Matched.Definition &&
292-
Matched.CanonicalDeclaration.FileURI == Matched.Definition.FileURI)
292+
Matched.CanonicalDeclaration.fileURI() == Matched.Definition.fileURI())
293293
Fixes = fixesForSymbols(Syms);
294294
}
295295
return Fixes;
@@ -299,7 +299,7 @@ std::vector<Fix> IncludeFixer::fixesForSymbols(const SymbolSlab &Syms) const {
299299
auto Inserted = [&](const Symbol &Sym, llvm::StringRef Header)
300300
-> llvm::Expected<std::pair<std::string, bool>> {
301301
auto ResolvedDeclaring =
302-
URI::resolve(Sym.CanonicalDeclaration.FileURI, File);
302+
URI::resolve(Sym.CanonicalDeclaration.fileURI(), File);
303303
if (!ResolvedDeclaring)
304304
return ResolvedDeclaring.takeError();
305305
auto ResolvedInserted = toHeaderFile(Header, File);
@@ -616,7 +616,7 @@ IncludeFixer::lookupCached(const SymbolID &ID) const {
616616
if (!Syms.empty()) {
617617
auto &Matched = *Syms.begin();
618618
if (!Matched.IncludeHeaders.empty() && Matched.Definition &&
619-
Matched.CanonicalDeclaration.FileURI == Matched.Definition.FileURI)
619+
Matched.CanonicalDeclaration.fileURI() == Matched.Definition.fileURI())
620620
Fixes = fixesForSymbols(Syms);
621621
}
622622
auto E = LookupCache.try_emplace(ID, std::move(Syms));

clang-tools-extra/clangd/Quality.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ computeScope(const NamedDecl *D) {
281281
}
282282

283283
void SymbolRelevanceSignals::merge(const Symbol &IndexResult) {
284-
SymbolURI = IndexResult.CanonicalDeclaration.FileURI;
284+
SymbolURI = IndexResult.CanonicalDeclaration.fileURI();
285285
SymbolScope = IndexResult.Scope;
286286
IsInstanceMember |= isInstanceMember(IndexResult.SymInfo);
287287
if (!(IndexResult.Flags & Symbol::VisibleOutsideFile)) {

clang-tools-extra/clangd/XRefs.cpp

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ const NamedDecl *getDefinition(const NamedDecl *D) {
114114
return nullptr; // except cases above
115115
}
116116

117-
void logIfOverflow(const SymbolLocation &Loc) {
117+
void logIfOverflow(const SymbolNameLocation &Loc) {
118118
if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
119119
log("Possible overflow in symbol location: {0}", Loc);
120120
}
@@ -123,7 +123,7 @@ void logIfOverflow(const SymbolLocation &Loc) {
123123
// TUPath is used to resolve the path of URI.
124124
// FIXME: figure out a good home for it, and share the implementation with
125125
// FindSymbols.
126-
std::optional<Location> toLSPLocation(const SymbolLocation &Loc,
126+
std::optional<Location> toLSPLocation(const SymbolNameLocation &Loc,
127127
llvm::StringRef TUPath) {
128128
if (!Loc)
129129
return std::nullopt;
@@ -148,8 +148,9 @@ std::optional<Location> toLSPLocation(const SymbolLocation &Loc,
148148
return LSPLoc;
149149
}
150150

151-
SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
152-
SymbolLocation SymLoc;
151+
SymbolNameLocation toIndexLocation(const Location &Loc,
152+
std::string &URIStorage) {
153+
SymbolNameLocation SymLoc;
153154
URIStorage = Loc.uri.uri();
154155
SymLoc.FileURI = URIStorage.c_str();
155156
SymLoc.Start.setLine(Loc.range.start.line);
@@ -160,17 +161,17 @@ SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
160161
}
161162

162163
// Returns the preferred location between an AST location and an index location.
163-
SymbolLocation getPreferredLocation(const Location &ASTLoc,
164-
const SymbolLocation &IdxLoc,
165-
std::string &Scratch) {
164+
SymbolNameLocation getPreferredLocation(const Location &ASTLoc,
165+
const SymbolNameLocation &IdxLoc,
166+
std::string &Scratch) {
166167
// Also use a mock symbol for the index location so that other fields (e.g.
167168
// definition) are not factored into the preference.
168169
Symbol ASTSym, IdxSym;
169170
ASTSym.ID = IdxSym.ID = SymbolID("mock_symbol_id");
170-
ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
171-
IdxSym.CanonicalDeclaration = IdxLoc;
171+
ASTSym.CanonicalDeclaration.NameLocation = toIndexLocation(ASTLoc, Scratch);
172+
IdxSym.CanonicalDeclaration.NameLocation = IdxLoc;
172173
auto Merged = mergeSymbol(ASTSym, IdxSym);
173-
return Merged.CanonicalDeclaration;
174+
return Merged.CanonicalDeclaration.NameLocation;
174175
}
175176

176177
std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
@@ -323,16 +324,17 @@ std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
323324
Req.Subjects = std::move(IDs);
324325
std::vector<LocatedSymbol> Results;
325326
Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
326-
auto DeclLoc =
327-
indexToLSPLocation(Object.CanonicalDeclaration, MainFilePath);
327+
auto DeclLoc = indexToLSPLocation(Object.CanonicalDeclaration.NameLocation,
328+
MainFilePath);
328329
if (!DeclLoc) {
329330
elog("Find overrides: {0}", DeclLoc.takeError());
330331
return;
331332
}
332333
Results.emplace_back();
333334
Results.back().Name = Object.Name.str();
334335
Results.back().PreferredDeclaration = *DeclLoc;
335-
auto DefLoc = indexToLSPLocation(Object.Definition, MainFilePath);
336+
auto DefLoc =
337+
indexToLSPLocation(Object.Definition.NameLocation, MainFilePath);
336338
if (!DefLoc) {
337339
elog("Failed to convert location: {0}", DefLoc.takeError());
338340
return;
@@ -364,23 +366,26 @@ void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
364366
if (R.Definition) { // from AST
365367
// Special case: if the AST yielded a definition, then it may not be
366368
// the right *declaration*. Prefer the one from the index.
367-
if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
369+
if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration.NameLocation,
370+
MainFilePath))
368371
R.PreferredDeclaration = *Loc;
369372

370373
// We might still prefer the definition from the index, e.g. for
371374
// generated symbols.
372375
if (auto Loc = toLSPLocation(
373-
getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
376+
getPreferredLocation(*R.Definition, Sym.Definition.NameLocation,
377+
Scratch),
374378
MainFilePath))
375379
R.Definition = *Loc;
376380
} else {
377-
R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
381+
R.Definition = toLSPLocation(Sym.Definition.NameLocation, MainFilePath);
378382

379383
// Use merge logic to choose AST or index declaration.
380-
if (auto Loc = toLSPLocation(
381-
getPreferredLocation(R.PreferredDeclaration,
382-
Sym.CanonicalDeclaration, Scratch),
383-
MainFilePath))
384+
if (auto Loc =
385+
toLSPLocation(getPreferredLocation(
386+
R.PreferredDeclaration,
387+
Sym.CanonicalDeclaration.NameLocation, Scratch),
388+
MainFilePath))
384389
R.PreferredDeclaration = *Loc;
385390
}
386391
});
@@ -606,7 +611,7 @@ std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word,
606611
return;
607612

608613
auto MaybeDeclLoc =
609-
indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);
614+
indexToLSPLocation(Sym.CanonicalDeclaration.NameLocation, MainFilePath);
610615
if (!MaybeDeclLoc) {
611616
log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
612617
return;
@@ -616,7 +621,8 @@ std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word,
616621
Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
617622
Located.ID = Sym.ID;
618623
if (Sym.Definition) {
619-
auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);
624+
auto MaybeDefLoc =
625+
indexToLSPLocation(Sym.Definition.NameLocation, MainFilePath);
620626
if (!MaybeDefLoc) {
621627
log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
622628
return;
@@ -1495,9 +1501,10 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
14951501
Results.HasMore = true;
14961502
return;
14971503
}
1498-
const auto LSPLocDecl =
1499-
toLSPLocation(Object.CanonicalDeclaration, MainFilePath);
1500-
const auto LSPLocDef = toLSPLocation(Object.Definition, MainFilePath);
1504+
const auto LSPLocDecl = toLSPLocation(
1505+
Object.CanonicalDeclaration.NameLocation, MainFilePath);
1506+
const auto LSPLocDef =
1507+
toLSPLocation(Object.Definition.NameLocation, MainFilePath);
15011508
if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
15021509
ReferencesResult::Reference Result;
15031510
Result.Loc = {std::move(*LSPLocDecl), std::nullopt};
@@ -1754,11 +1761,9 @@ static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
17541761
HierarchyItem HI;
17551762
HI.name = std::string(S.Name);
17561763
HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
1757-
HI.selectionRange = Loc->range;
1758-
// FIXME: Populate 'range' correctly
1759-
// (https://github.com/clangd/clangd/issues/59).
1760-
HI.range = HI.selectionRange;
1761-
HI.uri = Loc->uri;
1764+
HI.selectionRange = Loc->first.range;
1765+
HI.range = Loc->second;
1766+
HI.uri = Loc->first.uri;
17621767

17631768
return HI;
17641769
}

clang-tools-extra/clangd/index/FileIndex.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ FileShardedIndex::FileShardedIndex(IndexFileIn Input)
132132
// Attribute each Symbol to both their declaration and definition locations.
133133
if (Index.Symbols) {
134134
for (const auto &S : *Index.Symbols) {
135-
auto It = Shards.try_emplace(S.CanonicalDeclaration.FileURI);
135+
auto It = Shards.try_emplace(S.CanonicalDeclaration.fileURI());
136136
It.first->getValue().Symbols.insert(&S);
137137
SymbolIDToFile[S.ID] = &It.first->getValue();
138138
// Only bother if definition file is different than declaration file.
139139
if (S.Definition &&
140-
S.Definition.FileURI != S.CanonicalDeclaration.FileURI) {
141-
auto It = Shards.try_emplace(S.Definition.FileURI);
140+
S.Definition.fileURI() != S.CanonicalDeclaration.fileURI()) {
141+
auto It = Shards.try_emplace(S.Definition.fileURI());
142142
It.first->getValue().Symbols.insert(&S);
143143
}
144144
}

clang-tools-extra/clangd/index/Merge.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ bool isIndexAuthoritative(const SymbolIndex::IndexedFiles &Index,
2626
// We expect the definition to see the canonical declaration, so it seems to
2727
// be enough to check only the definition if it exists.
2828
const char *OwningFile =
29-
S.Definition ? S.Definition.FileURI : S.CanonicalDeclaration.FileURI;
29+
S.Definition ? S.Definition.fileURI() : S.CanonicalDeclaration.fileURI();
3030
return (Index(OwningFile) & IndexContents::Symbols) != IndexContents::None;
3131
}
3232
} // namespace
@@ -189,15 +189,16 @@ void MergedIndex::relations(
189189

190190
// Returns true if \p L is (strictly) preferred to \p R (e.g. by file paths). If
191191
// neither is preferred, this returns false.
192-
static bool prefer(const SymbolLocation &L, const SymbolLocation &R) {
192+
static bool prefer(const SymbolDeclDefLocation &L,
193+
const SymbolDeclDefLocation &R) {
193194
if (!L)
194195
return false;
195196
if (!R)
196197
return true;
197-
auto HasCodeGenSuffix = [](const SymbolLocation &Loc) {
198+
auto HasCodeGenSuffix = [](const SymbolDeclDefLocation &Loc) {
198199
constexpr static const char *CodegenSuffixes[] = {".proto"};
199200
return llvm::any_of(CodegenSuffixes, [&](llvm::StringRef Suffix) {
200-
return llvm::StringRef(Loc.FileURI).ends_with(Suffix);
201+
return llvm::StringRef(Loc.fileURI()).ends_with(Suffix);
201202
});
202203
};
203204
return HasCodeGenSuffix(L) && !HasCodeGenSuffix(R);
@@ -211,9 +212,9 @@ Symbol mergeSymbol(const Symbol &L, const Symbol &R) {
211212
bool PreferR = R.Definition && !L.Definition;
212213
// Merge include headers only if both have definitions or both have no
213214
// definition; otherwise, only accumulate references of common includes.
214-
assert(L.Definition.FileURI && R.Definition.FileURI);
215+
assert(L.Definition.fileURI() && R.Definition.fileURI());
215216
bool MergeIncludes =
216-
bool(*L.Definition.FileURI) == bool(*R.Definition.FileURI);
217+
bool(*L.Definition.fileURI()) == bool(*R.Definition.fileURI());
217218
Symbol S = PreferR ? R : L; // The target symbol we're merging into.
218219
const Symbol &O = PreferR ? L : R; // The "other" less-preferred symbol.
219220

clang-tools-extra/clangd/index/Ref.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <cstdint>
1919
#include <set>
2020
#include <utility>
21+
#include <variant>
2122

2223
namespace clang {
2324
namespace clangd {
@@ -84,7 +85,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &, RefKind);
8485
/// WARNING: Location does not own the underlying data - Copies are shallow.
8586
struct Ref {
8687
/// The source location where the symbol is named.
87-
SymbolLocation Location;
88+
SymbolNameLocation Location;
8889
RefKind Kind = RefKind::Unknown;
8990
/// The ID of the symbol whose definition contains this reference.
9091
/// For example, for a reference inside a function body, this would
@@ -182,12 +183,8 @@ template <> struct DenseMapInfo<clang::clangd::RefSlab::Builder::Entry> {
182183
Val.Reference.Location.Start.rep(), Val.Reference.Location.End.rep());
183184
}
184185
static bool isEqual(const Entry &LHS, const Entry &RHS) {
185-
return std::tie(LHS.Symbol, LHS.Reference.Location.FileURI,
186-
LHS.Reference.Kind) ==
187-
std::tie(RHS.Symbol, RHS.Reference.Location.FileURI,
188-
RHS.Reference.Kind) &&
189-
LHS.Reference.Location.Start == RHS.Reference.Location.Start &&
190-
LHS.Reference.Location.End == RHS.Reference.Location.End;
186+
return std::tie(LHS.Symbol, LHS.Reference) ==
187+
std::tie(RHS.Symbol, RHS.Reference);
191188
}
192189
};
193190
} // namespace llvm

0 commit comments

Comments
 (0)