Skip to content

Commit 188cbf1

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 5d38a34 commit 188cbf1

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,14 +114,14 @@ 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
}
121121

122122
// Convert a SymbolLocation to LSP's Location.
123123
// TUPath is used to resolve the path of URI.
124-
std::optional<Location> toLSPLocation(const SymbolLocation &Loc,
124+
std::optional<Location> toLSPLocation(const SymbolNameLocation &Loc,
125125
llvm::StringRef TUPath) {
126126
if (!Loc)
127127
return std::nullopt;
@@ -134,8 +134,9 @@ std::optional<Location> toLSPLocation(const SymbolLocation &Loc,
134134
return *LSPLoc;
135135
}
136136

137-
SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
138-
SymbolLocation SymLoc;
137+
SymbolNameLocation toIndexLocation(const Location &Loc,
138+
std::string &URIStorage) {
139+
SymbolNameLocation SymLoc;
139140
URIStorage = Loc.uri.uri();
140141
SymLoc.FileURI = URIStorage.c_str();
141142
SymLoc.Start.setLine(Loc.range.start.line);
@@ -146,17 +147,17 @@ SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
146147
}
147148

148149
// Returns the preferred location between an AST location and an index location.
149-
SymbolLocation getPreferredLocation(const Location &ASTLoc,
150-
const SymbolLocation &IdxLoc,
151-
std::string &Scratch) {
150+
SymbolNameLocation getPreferredLocation(const Location &ASTLoc,
151+
const SymbolNameLocation &IdxLoc,
152+
std::string &Scratch) {
152153
// Also use a mock symbol for the index location so that other fields (e.g.
153154
// definition) are not factored into the preference.
154155
Symbol ASTSym, IdxSym;
155156
ASTSym.ID = IdxSym.ID = SymbolID("mock_symbol_id");
156-
ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
157-
IdxSym.CanonicalDeclaration = IdxLoc;
157+
ASTSym.CanonicalDeclaration.NameLocation = toIndexLocation(ASTLoc, Scratch);
158+
IdxSym.CanonicalDeclaration.NameLocation = IdxLoc;
158159
auto Merged = mergeSymbol(ASTSym, IdxSym);
159-
return Merged.CanonicalDeclaration;
160+
return Merged.CanonicalDeclaration.NameLocation;
160161
}
161162

162163
std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
@@ -309,16 +310,17 @@ std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
309310
Req.Subjects = std::move(IDs);
310311
std::vector<LocatedSymbol> Results;
311312
Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
312-
auto DeclLoc =
313-
indexToLSPLocation(Object.CanonicalDeclaration, MainFilePath);
313+
auto DeclLoc = indexToLSPLocation(Object.CanonicalDeclaration.NameLocation,
314+
MainFilePath);
314315
if (!DeclLoc) {
315316
elog("Find overrides: {0}", DeclLoc.takeError());
316317
return;
317318
}
318319
Results.emplace_back();
319320
Results.back().Name = Object.Name.str();
320321
Results.back().PreferredDeclaration = *DeclLoc;
321-
auto DefLoc = indexToLSPLocation(Object.Definition, MainFilePath);
322+
auto DefLoc =
323+
indexToLSPLocation(Object.Definition.NameLocation, MainFilePath);
322324
if (!DefLoc) {
323325
elog("Failed to convert location: {0}", DefLoc.takeError());
324326
return;
@@ -350,23 +352,26 @@ void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
350352
if (R.Definition) { // from AST
351353
// Special case: if the AST yielded a definition, then it may not be
352354
// the right *declaration*. Prefer the one from the index.
353-
if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
355+
if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration.NameLocation,
356+
MainFilePath))
354357
R.PreferredDeclaration = *Loc;
355358

356359
// We might still prefer the definition from the index, e.g. for
357360
// generated symbols.
358361
if (auto Loc = toLSPLocation(
359-
getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
362+
getPreferredLocation(*R.Definition, Sym.Definition.NameLocation,
363+
Scratch),
360364
MainFilePath))
361365
R.Definition = *Loc;
362366
} else {
363-
R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
367+
R.Definition = toLSPLocation(Sym.Definition.NameLocation, MainFilePath);
364368

365369
// Use merge logic to choose AST or index declaration.
366-
if (auto Loc = toLSPLocation(
367-
getPreferredLocation(R.PreferredDeclaration,
368-
Sym.CanonicalDeclaration, Scratch),
369-
MainFilePath))
370+
if (auto Loc =
371+
toLSPLocation(getPreferredLocation(
372+
R.PreferredDeclaration,
373+
Sym.CanonicalDeclaration.NameLocation, Scratch),
374+
MainFilePath))
370375
R.PreferredDeclaration = *Loc;
371376
}
372377
});
@@ -592,7 +597,7 @@ std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word,
592597
return;
593598

594599
auto MaybeDeclLoc =
595-
indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);
600+
indexToLSPLocation(Sym.CanonicalDeclaration.NameLocation, MainFilePath);
596601
if (!MaybeDeclLoc) {
597602
log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
598603
return;
@@ -602,7 +607,8 @@ std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word,
602607
Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
603608
Located.ID = Sym.ID;
604609
if (Sym.Definition) {
605-
auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);
610+
auto MaybeDefLoc =
611+
indexToLSPLocation(Sym.Definition.NameLocation, MainFilePath);
606612
if (!MaybeDefLoc) {
607613
log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
608614
return;
@@ -1481,9 +1487,10 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
14811487
Results.HasMore = true;
14821488
return;
14831489
}
1484-
const auto LSPLocDecl =
1485-
toLSPLocation(Object.CanonicalDeclaration, MainFilePath);
1486-
const auto LSPLocDef = toLSPLocation(Object.Definition, MainFilePath);
1490+
const auto LSPLocDecl = toLSPLocation(
1491+
Object.CanonicalDeclaration.NameLocation, MainFilePath);
1492+
const auto LSPLocDef =
1493+
toLSPLocation(Object.Definition.NameLocation, MainFilePath);
14871494
if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
14881495
ReferencesResult::Reference Result;
14891496
Result.Loc = {std::move(*LSPLocDecl), std::nullopt};
@@ -1740,11 +1747,9 @@ static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
17401747
HierarchyItem HI;
17411748
HI.name = std::string(S.Name);
17421749
HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
1743-
HI.selectionRange = Loc->range;
1744-
// FIXME: Populate 'range' correctly
1745-
// (https://github.com/clangd/clangd/issues/59).
1746-
HI.range = HI.selectionRange;
1747-
HI.uri = Loc->uri;
1750+
HI.selectionRange = Loc->first.range;
1751+
HI.range = Loc->second;
1752+
HI.uri = Loc->first.uri;
17481753

17491754
return HI;
17501755
}

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)