1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "XRefs.h"
9 #include "AST.h"
10 #include "FindSymbols.h"
11 #include "FindTarget.h"
12 #include "HeuristicResolver.h"
13 #include "ParsedAST.h"
14 #include "Protocol.h"
15 #include "Quality.h"
16 #include "Selection.h"
17 #include "SourceCode.h"
18 #include "URI.h"
19 #include "index/Index.h"
20 #include "index/Merge.h"
21 #include "index/Relation.h"
22 #include "index/SymbolID.h"
23 #include "index/SymbolLocation.h"
24 #include "support/Logger.h"
25 #include "clang/AST/ASTContext.h"
26 #include "clang/AST/ASTTypeTraits.h"
27 #include "clang/AST/Attr.h"
28 #include "clang/AST/Attrs.inc"
29 #include "clang/AST/Decl.h"
30 #include "clang/AST/DeclCXX.h"
31 #include "clang/AST/DeclObjC.h"
32 #include "clang/AST/DeclTemplate.h"
33 #include "clang/AST/DeclVisitor.h"
34 #include "clang/AST/ExprCXX.h"
35 #include "clang/AST/RecursiveASTVisitor.h"
36 #include "clang/AST/Stmt.h"
37 #include "clang/AST/StmtCXX.h"
38 #include "clang/AST/StmtVisitor.h"
39 #include "clang/AST/Type.h"
40 #include "clang/Basic/LLVM.h"
41 #include "clang/Basic/LangOptions.h"
42 #include "clang/Basic/SourceLocation.h"
43 #include "clang/Basic/SourceManager.h"
44 #include "clang/Basic/TokenKinds.h"
45 #include "clang/Index/IndexDataConsumer.h"
46 #include "clang/Index/IndexSymbol.h"
47 #include "clang/Index/IndexingAction.h"
48 #include "clang/Index/IndexingOptions.h"
49 #include "clang/Index/USRGeneration.h"
50 #include "clang/Tooling/Syntax/Tokens.h"
51 #include "llvm/ADT/ArrayRef.h"
52 #include "llvm/ADT/DenseMap.h"
53 #include "llvm/ADT/None.h"
54 #include "llvm/ADT/Optional.h"
55 #include "llvm/ADT/STLExtras.h"
56 #include "llvm/ADT/ScopeExit.h"
57 #include "llvm/ADT/SmallSet.h"
58 #include "llvm/ADT/SmallVector.h"
59 #include "llvm/ADT/StringRef.h"
60 #include "llvm/Support/Casting.h"
61 #include "llvm/Support/Error.h"
62 #include "llvm/Support/Path.h"
63 #include "llvm/Support/raw_ostream.h"
64 #include <vector>
65
66 namespace clang {
67 namespace clangd {
68 namespace {
69
70 // Returns the single definition of the entity declared by D, if visible.
71 // In particular:
72 // - for non-redeclarable kinds (e.g. local vars), return D
73 // - for kinds that allow multiple definitions (e.g. namespaces), return nullptr
74 // Kinds of nodes that always return nullptr here will not have definitions
75 // reported by locateSymbolAt().
getDefinition(const NamedDecl * D)76 const NamedDecl *getDefinition(const NamedDecl *D) {
77 assert(D);
78 // Decl has one definition that we can find.
79 if (const auto *TD = dyn_cast<TagDecl>(D))
80 return TD->getDefinition();
81 if (const auto *VD = dyn_cast<VarDecl>(D))
82 return VD->getDefinition();
83 if (const auto *FD = dyn_cast<FunctionDecl>(D))
84 return FD->getDefinition();
85 if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
86 if (const auto *RD = CTD->getTemplatedDecl())
87 return RD->getDefinition();
88 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
89 if (MD->isThisDeclarationADefinition())
90 return MD;
91 // Look for the method definition inside the implementation decl.
92 auto *DeclCtx = cast<Decl>(MD->getDeclContext());
93 if (DeclCtx->isInvalidDecl())
94 return nullptr;
95
96 if (const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
97 if (const auto *Impl = getCorrespondingObjCImpl(CD))
98 return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
99 }
100 if (const auto *CD = dyn_cast<ObjCContainerDecl>(D))
101 return getCorrespondingObjCImpl(CD);
102 // Only a single declaration is allowed.
103 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
104 isa<TemplateTemplateParmDecl>(D)) // except cases above
105 return D;
106 // Multiple definitions are allowed.
107 return nullptr; // except cases above
108 }
109
logIfOverflow(const SymbolLocation & Loc)110 void logIfOverflow(const SymbolLocation &Loc) {
111 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
112 log("Possible overflow in symbol location: {0}", Loc);
113 }
114
115 // Convert a SymbolLocation to LSP's Location.
116 // TUPath is used to resolve the path of URI.
117 // FIXME: figure out a good home for it, and share the implementation with
118 // FindSymbols.
toLSPLocation(const SymbolLocation & Loc,llvm::StringRef TUPath)119 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
120 llvm::StringRef TUPath) {
121 if (!Loc)
122 return None;
123 auto Uri = URI::parse(Loc.FileURI);
124 if (!Uri) {
125 elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
126 return None;
127 }
128 auto U = URIForFile::fromURI(*Uri, TUPath);
129 if (!U) {
130 elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
131 return None;
132 }
133
134 Location LSPLoc;
135 LSPLoc.uri = std::move(*U);
136 LSPLoc.range.start.line = Loc.Start.line();
137 LSPLoc.range.start.character = Loc.Start.column();
138 LSPLoc.range.end.line = Loc.End.line();
139 LSPLoc.range.end.character = Loc.End.column();
140 logIfOverflow(Loc);
141 return LSPLoc;
142 }
143
toIndexLocation(const Location & Loc,std::string & URIStorage)144 SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
145 SymbolLocation SymLoc;
146 URIStorage = Loc.uri.uri();
147 SymLoc.FileURI = URIStorage.c_str();
148 SymLoc.Start.setLine(Loc.range.start.line);
149 SymLoc.Start.setColumn(Loc.range.start.character);
150 SymLoc.End.setLine(Loc.range.end.line);
151 SymLoc.End.setColumn(Loc.range.end.character);
152 return SymLoc;
153 }
154
155 // Returns the preferred location between an AST location and an index location.
getPreferredLocation(const Location & ASTLoc,const SymbolLocation & IdxLoc,std::string & Scratch)156 SymbolLocation getPreferredLocation(const Location &ASTLoc,
157 const SymbolLocation &IdxLoc,
158 std::string &Scratch) {
159 // Also use a mock symbol for the index location so that other fields (e.g.
160 // definition) are not factored into the preference.
161 Symbol ASTSym, IdxSym;
162 ASTSym.ID = IdxSym.ID = SymbolID("mock_symbol_id");
163 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
164 IdxSym.CanonicalDeclaration = IdxLoc;
165 auto Merged = mergeSymbol(ASTSym, IdxSym);
166 return Merged.CanonicalDeclaration;
167 }
168
169 std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
getDeclAtPositionWithRelations(ParsedAST & AST,SourceLocation Pos,DeclRelationSet Relations,ASTNodeKind * NodeKind=nullptr)170 getDeclAtPositionWithRelations(ParsedAST &AST, SourceLocation Pos,
171 DeclRelationSet Relations,
172 ASTNodeKind *NodeKind = nullptr) {
173 unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
174 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
175 auto ResultFromTree = [&](SelectionTree ST) {
176 if (const SelectionTree::Node *N = ST.commonAncestor()) {
177 if (NodeKind)
178 *NodeKind = N->ASTNode.getNodeKind();
179 // Attributes don't target decls, look at the
180 // thing it's attached to.
181 // We still report the original NodeKind!
182 // This makes the `override` hack work.
183 if (N->ASTNode.get<Attr>() && N->Parent)
184 N = N->Parent;
185 llvm::copy_if(allTargetDecls(N->ASTNode, AST.getHeuristicResolver()),
186 std::back_inserter(Result),
187 [&](auto &Entry) { return !(Entry.second & ~Relations); });
188 }
189 return !Result.empty();
190 };
191 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,
192 Offset, ResultFromTree);
193 return Result;
194 }
195
196 std::vector<const NamedDecl *>
getDeclAtPosition(ParsedAST & AST,SourceLocation Pos,DeclRelationSet Relations,ASTNodeKind * NodeKind=nullptr)197 getDeclAtPosition(ParsedAST &AST, SourceLocation Pos, DeclRelationSet Relations,
198 ASTNodeKind *NodeKind = nullptr) {
199 std::vector<const NamedDecl *> Result;
200 for (auto &Entry :
201 getDeclAtPositionWithRelations(AST, Pos, Relations, NodeKind))
202 Result.push_back(Entry.first);
203 return Result;
204 }
205
206 // Expects Loc to be a SpellingLocation, will bail out otherwise as it can't
207 // figure out a filename.
makeLocation(const ASTContext & AST,SourceLocation Loc,llvm::StringRef TUPath)208 llvm::Optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc,
209 llvm::StringRef TUPath) {
210 const auto &SM = AST.getSourceManager();
211 const FileEntry *F = SM.getFileEntryForID(SM.getFileID(Loc));
212 if (!F)
213 return None;
214 auto FilePath = getCanonicalPath(F, SM);
215 if (!FilePath) {
216 log("failed to get path!");
217 return None;
218 }
219 Location L;
220 L.uri = URIForFile::canonicalize(*FilePath, TUPath);
221 // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens
222 // outside the main file.
223 auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts());
224 L.range = halfOpenToRange(
225 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
226 return L;
227 }
228
229 // Treat #included files as symbols, to enable go-to-definition on them.
locateFileReferent(const Position & Pos,ParsedAST & AST,llvm::StringRef MainFilePath)230 llvm::Optional<LocatedSymbol> locateFileReferent(const Position &Pos,
231 ParsedAST &AST,
232 llvm::StringRef MainFilePath) {
233 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
234 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
235 LocatedSymbol File;
236 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
237 File.PreferredDeclaration = {
238 URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};
239 File.Definition = File.PreferredDeclaration;
240 // We're not going to find any further symbols on #include lines.
241 return File;
242 }
243 }
244 return llvm::None;
245 }
246
247 // Macros are simple: there's no declaration/definition distinction.
248 // As a consequence, there's no need to look them up in the index either.
249 llvm::Optional<LocatedSymbol>
locateMacroReferent(const syntax::Token & TouchedIdentifier,ParsedAST & AST,llvm::StringRef MainFilePath)250 locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
251 llvm::StringRef MainFilePath) {
252 if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {
253 if (auto Loc =
254 makeLocation(AST.getASTContext(), M->NameLoc, MainFilePath)) {
255 LocatedSymbol Macro;
256 Macro.Name = std::string(M->Name);
257 Macro.PreferredDeclaration = *Loc;
258 Macro.Definition = Loc;
259 Macro.ID = getSymbolID(M->Name, M->Info, AST.getSourceManager());
260 return Macro;
261 }
262 }
263 return llvm::None;
264 }
265
266 // A wrapper around `Decl::getCanonicalDecl` to support cases where Clang's
267 // definition of a canonical declaration doesn't match up to what a programmer
268 // would expect. For example, Objective-C classes can have three types of
269 // declarations:
270 //
271 // - forward declaration(s): @class MyClass;
272 // - true declaration (interface definition): @interface MyClass ... @end
273 // - true definition (implementation): @implementation MyClass ... @end
274 //
275 // Clang will consider the forward declaration to be the canonical declaration
276 // because it is first. We actually want the class definition if it is
277 // available since that is what a programmer would consider the primary
278 // declaration to be.
getPreferredDecl(const NamedDecl * D)279 const NamedDecl *getPreferredDecl(const NamedDecl *D) {
280 // FIXME: Canonical declarations of some symbols might refer to built-in
281 // decls with possibly-invalid source locations (e.g. global new operator).
282 // In such cases we should pick up a redecl with valid source location
283 // instead of failing.
284 D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
285
286 // Prefer Objective-C class/protocol definitions over the forward declaration.
287 if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
288 if (const auto *DefinitionID = ID->getDefinition())
289 return DefinitionID;
290 if (const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
291 if (const auto *DefinitionID = PD->getDefinition())
292 return DefinitionID;
293
294 return D;
295 }
296
findImplementors(llvm::DenseSet<SymbolID> IDs,RelationKind Predicate,const SymbolIndex * Index,llvm::StringRef MainFilePath)297 std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
298 RelationKind Predicate,
299 const SymbolIndex *Index,
300 llvm::StringRef MainFilePath) {
301 if (IDs.empty() || !Index)
302 return {};
303 static constexpr trace::Metric FindImplementorsMetric(
304 "find_implementors", trace::Metric::Counter, "case");
305 switch (Predicate) {
306 case RelationKind::BaseOf:
307 FindImplementorsMetric.record(1, "find-base");
308 break;
309 case RelationKind::OverriddenBy:
310 FindImplementorsMetric.record(1, "find-override");
311 break;
312 }
313
314 RelationsRequest Req;
315 Req.Predicate = Predicate;
316 Req.Subjects = std::move(IDs);
317 std::vector<LocatedSymbol> Results;
318 Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
319 auto DeclLoc =
320 indexToLSPLocation(Object.CanonicalDeclaration, MainFilePath);
321 if (!DeclLoc) {
322 elog("Find overrides: {0}", DeclLoc.takeError());
323 return;
324 }
325 Results.emplace_back();
326 Results.back().Name = Object.Name.str();
327 Results.back().PreferredDeclaration = *DeclLoc;
328 auto DefLoc = indexToLSPLocation(Object.Definition, MainFilePath);
329 if (!DefLoc) {
330 elog("Failed to convert location: {0}", DefLoc.takeError());
331 return;
332 }
333 Results.back().Definition = *DefLoc;
334 });
335 return Results;
336 }
337
338 // Decls are more complicated.
339 // The AST contains at least a declaration, maybe a definition.
340 // These are up-to-date, and so generally preferred over index results.
341 // We perform a single batch index lookup to find additional definitions.
342 std::vector<LocatedSymbol>
locateASTReferent(SourceLocation CurLoc,const syntax::Token * TouchedIdentifier,ParsedAST & AST,llvm::StringRef MainFilePath,const SymbolIndex * Index,ASTNodeKind & NodeKind)343 locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
344 ParsedAST &AST, llvm::StringRef MainFilePath,
345 const SymbolIndex *Index, ASTNodeKind &NodeKind) {
346 const SourceManager &SM = AST.getSourceManager();
347 // Results follow the order of Symbols.Decls.
348 std::vector<LocatedSymbol> Result;
349 // Keep track of SymbolID -> index mapping, to fill in index data later.
350 llvm::DenseMap<SymbolID, size_t> ResultIndex;
351
352 static constexpr trace::Metric LocateASTReferentMetric(
353 "locate_ast_referent", trace::Metric::Counter, "case");
354 auto AddResultDecl = [&](const NamedDecl *D) {
355 D = getPreferredDecl(D);
356 auto Loc =
357 makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
358 if (!Loc)
359 return;
360
361 Result.emplace_back();
362 Result.back().Name = printName(AST.getASTContext(), *D);
363 Result.back().PreferredDeclaration = *Loc;
364 Result.back().ID = getSymbolID(D);
365 if (const NamedDecl *Def = getDefinition(D))
366 Result.back().Definition = makeLocation(
367 AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);
368
369 // Record SymbolID for index lookup later.
370 if (auto ID = getSymbolID(D))
371 ResultIndex[ID] = Result.size() - 1;
372 };
373
374 // Emit all symbol locations (declaration or definition) from AST.
375 DeclRelationSet Relations =
376 DeclRelation::TemplatePattern | DeclRelation::Alias;
377 auto Candidates =
378 getDeclAtPositionWithRelations(AST, CurLoc, Relations, &NodeKind);
379 llvm::DenseSet<SymbolID> VirtualMethods;
380 for (const auto &E : Candidates) {
381 const NamedDecl *D = E.first;
382 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
383 // Special case: virtual void ^method() = 0: jump to all overrides.
384 // FIXME: extend it to ^virtual, unfortunately, virtual location is not
385 // saved in the AST.
386 if (CMD->isPure()) {
387 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
388 TouchedIdentifier->location()) {
389 VirtualMethods.insert(getSymbolID(CMD));
390 LocateASTReferentMetric.record(1, "method-to-override");
391 }
392 }
393 // Special case: void foo() ^override: jump to the overridden method.
394 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
395 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
396 // We may be overridding multiple methods - offer them all.
397 for (const NamedDecl *ND : CMD->overridden_methods())
398 AddResultDecl(ND);
399 continue;
400 }
401 }
402
403 // Special case: the cursor is on an alias, prefer other results.
404 // This targets "using ns::^Foo", where the target is more interesting.
405 // This does not trigger on renaming aliases:
406 // `using Foo = ^Bar` already targets Bar via a TypeLoc
407 // `using ^Foo = Bar` has no other results, as Underlying is filtered.
408 if (E.second & DeclRelation::Alias && Candidates.size() > 1 &&
409 // beginLoc/endLoc are a token range, so rewind the identifier we're in.
410 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
411 : CurLoc,
412 D->getBeginLoc(), D->getEndLoc()))
413 continue;
414
415 // Special case: the point of declaration of a template specialization,
416 // it's more useful to navigate to the template declaration.
417 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
418 if (TouchedIdentifier &&
419 D->getLocation() == TouchedIdentifier->location()) {
420 LocateASTReferentMetric.record(1, "template-specialization-to-primary");
421 AddResultDecl(CTSD->getSpecializedTemplate());
422 continue;
423 }
424 }
425
426 // Special case: if the class name is selected, also map Objective-C
427 // categories and category implementations back to their class interface.
428 //
429 // Since `TouchedIdentifier` might refer to the `ObjCCategoryImplDecl`
430 // instead of the `ObjCCategoryDecl` we intentionally check the contents
431 // of the locs when checking for class name equivalence.
432 if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
433 if (const auto *ID = CD->getClassInterface())
434 if (TouchedIdentifier &&
435 (CD->getLocation() == TouchedIdentifier->location() ||
436 ID->getName() == TouchedIdentifier->text(SM))) {
437 LocateASTReferentMetric.record(1, "objc-category-to-class");
438 AddResultDecl(ID);
439 }
440
441 LocateASTReferentMetric.record(1, "regular");
442 // Otherwise the target declaration is the right one.
443 AddResultDecl(D);
444 }
445
446 // Now query the index for all Symbol IDs we found in the AST.
447 if (Index && !ResultIndex.empty()) {
448 LookupRequest QueryRequest;
449 for (auto It : ResultIndex)
450 QueryRequest.IDs.insert(It.first);
451 std::string Scratch;
452 Index->lookup(QueryRequest, [&](const Symbol &Sym) {
453 auto &R = Result[ResultIndex.lookup(Sym.ID)];
454
455 if (R.Definition) { // from AST
456 // Special case: if the AST yielded a definition, then it may not be
457 // the right *declaration*. Prefer the one from the index.
458 if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
459 R.PreferredDeclaration = *Loc;
460
461 // We might still prefer the definition from the index, e.g. for
462 // generated symbols.
463 if (auto Loc = toLSPLocation(
464 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
465 MainFilePath))
466 R.Definition = *Loc;
467 } else {
468 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
469
470 // Use merge logic to choose AST or index declaration.
471 if (auto Loc = toLSPLocation(
472 getPreferredLocation(R.PreferredDeclaration,
473 Sym.CanonicalDeclaration, Scratch),
474 MainFilePath))
475 R.PreferredDeclaration = *Loc;
476 }
477 });
478 }
479
480 auto Overrides = findImplementors(VirtualMethods, RelationKind::OverriddenBy,
481 Index, MainFilePath);
482 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
483 return Result;
484 }
485
locateSymbolForType(const ParsedAST & AST,const QualType & Type)486 std::vector<LocatedSymbol> locateSymbolForType(const ParsedAST &AST,
487 const QualType &Type) {
488 const auto &SM = AST.getSourceManager();
489 auto MainFilePath =
490 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
491 if (!MainFilePath) {
492 elog("Failed to get a path for the main file, so no symbol.");
493 return {};
494 }
495
496 // FIXME: this sends unique_ptr<Foo> to unique_ptr<T>.
497 // Likely it would be better to send it to Foo (heuristically) or to both.
498 auto Decls = targetDecl(DynTypedNode::create(Type.getNonReferenceType()),
499 DeclRelation::TemplatePattern | DeclRelation::Alias,
500 AST.getHeuristicResolver());
501 if (Decls.empty())
502 return {};
503
504 std::vector<LocatedSymbol> Results;
505 const auto &ASTContext = AST.getASTContext();
506
507 for (const NamedDecl *D : Decls) {
508 D = getPreferredDecl(D);
509
510 auto Loc = makeLocation(ASTContext, nameLocation(*D, SM), *MainFilePath);
511 if (!Loc)
512 continue;
513
514 Results.emplace_back();
515 Results.back().Name = printName(ASTContext, *D);
516 Results.back().PreferredDeclaration = *Loc;
517 Results.back().ID = getSymbolID(D);
518 if (const NamedDecl *Def = getDefinition(D))
519 Results.back().Definition =
520 makeLocation(ASTContext, nameLocation(*Def, SM), *MainFilePath);
521 }
522
523 return Results;
524 }
525
tokenSpelledAt(SourceLocation SpellingLoc,const syntax::TokenBuffer & TB)526 bool tokenSpelledAt(SourceLocation SpellingLoc, const syntax::TokenBuffer &TB) {
527 auto ExpandedTokens = TB.expandedTokens(
528 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
529 return !ExpandedTokens.empty();
530 }
531
sourcePrefix(SourceLocation Loc,const SourceManager & SM)532 llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) {
533 auto D = SM.getDecomposedLoc(Loc);
534 bool Invalid = false;
535 llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);
536 if (Invalid || D.second > Buf.size())
537 return "";
538 return Buf.substr(0, D.second);
539 }
540
isDependentName(ASTNodeKind NodeKind)541 bool isDependentName(ASTNodeKind NodeKind) {
542 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
543 NodeKind.isSame(
544 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
545 NodeKind.isSame(
546 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
547 }
548
549 } // namespace
550
551 std::vector<LocatedSymbol>
locateSymbolTextually(const SpelledWord & Word,ParsedAST & AST,const SymbolIndex * Index,const std::string & MainFilePath,ASTNodeKind NodeKind)552 locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST,
553 const SymbolIndex *Index, const std::string &MainFilePath,
554 ASTNodeKind NodeKind) {
555 // Don't use heuristics if this is a real identifier, or not an
556 // identifier.
557 // Exception: dependent names, because those may have useful textual
558 // matches that AST-based heuristics cannot find.
559 if ((Word.ExpandedToken && !isDependentName(NodeKind)) ||
560 !Word.LikelyIdentifier || !Index)
561 return {};
562 // We don't want to handle words in string literals. (It'd be nice to list
563 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
564 if (Word.PartOfSpelledToken &&
565 isStringLiteral(Word.PartOfSpelledToken->kind()))
566 return {};
567
568 const auto &SM = AST.getSourceManager();
569 // Look up the selected word in the index.
570 FuzzyFindRequest Req;
571 Req.Query = Word.Text.str();
572 Req.ProximityPaths = {MainFilePath};
573 // Find the namespaces to query by lexing the file.
574 Req.Scopes =
575 visibleNamespaces(sourcePrefix(Word.Location, SM), AST.getLangOpts());
576 // FIXME: For extra strictness, consider AnyScope=false.
577 Req.AnyScope = true;
578 // We limit the results to 3 further below. This limit is to avoid fetching
579 // too much data, while still likely having enough for 3 results to remain
580 // after additional filtering.
581 Req.Limit = 10;
582 bool TooMany = false;
583 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
584 std::vector<ScoredLocatedSymbol> ScoredResults;
585 Index->fuzzyFind(Req, [&](const Symbol &Sym) {
586 // Only consider exact name matches, including case.
587 // This is to avoid too many false positives.
588 // We could relax this in the future (e.g. to allow for typos) if we make
589 // the query more accurate by other means.
590 if (Sym.Name != Word.Text)
591 return;
592
593 // Exclude constructor results. They have the same name as the class,
594 // but we don't have enough context to prefer them over the class.
595 if (Sym.SymInfo.Kind == index::SymbolKind::Constructor)
596 return;
597
598 auto MaybeDeclLoc =
599 indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);
600 if (!MaybeDeclLoc) {
601 log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
602 return;
603 }
604 LocatedSymbol Located;
605 Located.PreferredDeclaration = *MaybeDeclLoc;
606 Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
607 Located.ID = Sym.ID;
608 if (Sym.Definition) {
609 auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);
610 if (!MaybeDefLoc) {
611 log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
612 return;
613 }
614 Located.PreferredDeclaration = *MaybeDefLoc;
615 Located.Definition = *MaybeDefLoc;
616 }
617
618 if (ScoredResults.size() >= 5) {
619 // If we have more than 5 results, don't return anything,
620 // as confidence is too low.
621 // FIXME: Alternatively, try a stricter query?
622 TooMany = true;
623 return;
624 }
625
626 SymbolQualitySignals Quality;
627 Quality.merge(Sym);
628 SymbolRelevanceSignals Relevance;
629 Relevance.Name = Sym.Name;
630 Relevance.Query = SymbolRelevanceSignals::Generic;
631 Relevance.merge(Sym);
632 auto Score = evaluateSymbolAndRelevance(Quality.evaluateHeuristics(),
633 Relevance.evaluateHeuristics());
634 dlog("locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.Scope,
635 Sym.Name, Score, Quality, Relevance);
636
637 ScoredResults.push_back({Score, std::move(Located)});
638 });
639
640 if (TooMany) {
641 vlog("Heuristic index lookup for {0} returned too many candidates, ignored",
642 Word.Text);
643 return {};
644 }
645
646 llvm::sort(ScoredResults,
647 [](const ScoredLocatedSymbol &A, const ScoredLocatedSymbol &B) {
648 return A.first > B.first;
649 });
650 std::vector<LocatedSymbol> Results;
651 for (auto &Res : std::move(ScoredResults))
652 Results.push_back(std::move(Res.second));
653 if (Results.empty())
654 vlog("No heuristic index definition for {0}", Word.Text);
655 else
656 log("Found definition heuristically in index for {0}", Word.Text);
657 return Results;
658 }
659
findNearbyIdentifier(const SpelledWord & Word,const syntax::TokenBuffer & TB)660 const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,
661 const syntax::TokenBuffer &TB) {
662 // Don't use heuristics if this is a real identifier.
663 // Unlikely identifiers are OK if they were used as identifiers nearby.
664 if (Word.ExpandedToken)
665 return nullptr;
666 // We don't want to handle words in string literals. (It'd be nice to list
667 // *allowed* token kinds explicitly, but comment Tokens aren't retained).
668 if (Word.PartOfSpelledToken &&
669 isStringLiteral(Word.PartOfSpelledToken->kind()))
670 return {};
671
672 const SourceManager &SM = TB.sourceManager();
673 // We prefer the closest possible token, line-wise. Backwards is penalized.
674 // Ties are implicitly broken by traversal order (first-one-wins).
675 auto File = SM.getFileID(Word.Location);
676 unsigned WordLine = SM.getSpellingLineNumber(Word.Location);
677 auto Cost = [&](SourceLocation Loc) -> unsigned {
678 assert(SM.getFileID(Loc) == File && "spelled token in wrong file?");
679 unsigned Line = SM.getSpellingLineNumber(Loc);
680 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
681 };
682 const syntax::Token *BestTok = nullptr;
683 unsigned BestCost = -1;
684 // Search bounds are based on word length:
685 // - forward: 2^N lines
686 // - backward: 2^(N-1) lines.
687 unsigned MaxDistance =
688 1U << std::min<unsigned>(Word.Text.size(),
689 std::numeric_limits<unsigned>::digits - 1);
690 // Line number for SM.translateLineCol() should be one-based, also
691 // SM.translateLineCol() can handle line number greater than
692 // number of lines in the file.
693 // - LineMin = max(1, WordLine + 1 - 2^(N-1))
694 // - LineMax = WordLine + 1 + 2^N
695 unsigned LineMin =
696 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
697 unsigned LineMax = WordLine + 1 + MaxDistance;
698 SourceLocation LocMin = SM.translateLineCol(File, LineMin, 1);
699 assert(LocMin.isValid());
700 SourceLocation LocMax = SM.translateLineCol(File, LineMax, 1);
701 assert(LocMax.isValid());
702
703 // Updates BestTok and BestCost if Tok is a good candidate.
704 // May return true if the cost is too high for this token.
705 auto Consider = [&](const syntax::Token &Tok) {
706 if (Tok.location() < LocMin || Tok.location() > LocMax)
707 return true; // we are too far from the word, break the outer loop.
708 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.Text))
709 return false;
710 // No point guessing the same location we started with.
711 if (Tok.location() == Word.Location)
712 return false;
713 // We've done cheap checks, compute cost so we can break the caller's loop.
714 unsigned TokCost = Cost(Tok.location());
715 if (TokCost >= BestCost)
716 return true; // causes the outer loop to break.
717 // Allow locations that might be part of the AST, and macros (even if empty)
718 // but not things like disabled preprocessor sections.
719 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
720 return false;
721 // We already verified this token is an improvement.
722 BestCost = TokCost;
723 BestTok = &Tok;
724 return false;
725 };
726 auto SpelledTokens = TB.spelledTokens(File);
727 // Find where the word occurred in the token stream, to search forward & back.
728 auto *I = llvm::partition_point(SpelledTokens, [&](const syntax::Token &T) {
729 assert(SM.getFileID(T.location()) == SM.getFileID(Word.Location));
730 return T.location() < Word.Location; // Comparison OK: same file.
731 });
732 // Search for matches after the cursor.
733 for (const syntax::Token &Tok : llvm::makeArrayRef(I, SpelledTokens.end()))
734 if (Consider(Tok))
735 break; // costs of later tokens are greater...
736 // Search for matches before the cursor.
737 for (const syntax::Token &Tok :
738 llvm::reverse(llvm::makeArrayRef(SpelledTokens.begin(), I)))
739 if (Consider(Tok))
740 break;
741
742 if (BestTok)
743 vlog(
744 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
745 Word.Text, Word.Location.printToString(SM),
746 BestTok->location().printToString(SM));
747
748 return BestTok;
749 }
750
locateSymbolAt(ParsedAST & AST,Position Pos,const SymbolIndex * Index)751 std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
752 const SymbolIndex *Index) {
753 const auto &SM = AST.getSourceManager();
754 auto MainFilePath =
755 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
756 if (!MainFilePath) {
757 elog("Failed to get a path for the main file, so no references");
758 return {};
759 }
760
761 if (auto File = locateFileReferent(Pos, AST, *MainFilePath))
762 return {std::move(*File)};
763
764 auto CurLoc = sourceLocationInMainFile(SM, Pos);
765 if (!CurLoc) {
766 elog("locateSymbolAt failed to convert position to source location: {0}",
767 CurLoc.takeError());
768 return {};
769 }
770
771 const syntax::Token *TouchedIdentifier = nullptr;
772 auto TokensTouchingCursor =
773 syntax::spelledTokensTouching(*CurLoc, AST.getTokens());
774 for (const syntax::Token &Tok : TokensTouchingCursor) {
775 if (Tok.kind() == tok::identifier) {
776 if (auto Macro = locateMacroReferent(Tok, AST, *MainFilePath))
777 // Don't look at the AST or index if we have a macro result.
778 // (We'd just return declarations referenced from the macro's
779 // expansion.)
780 return {*std::move(Macro)};
781
782 TouchedIdentifier = &Tok;
783 break;
784 }
785
786 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
787 // go-to-definition on auto should find the definition of the deduced
788 // type, if possible
789 if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) {
790 auto LocSym = locateSymbolForType(AST, *Deduced);
791 if (!LocSym.empty())
792 return LocSym;
793 }
794 }
795 }
796
797 ASTNodeKind NodeKind;
798 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier, AST,
799 *MainFilePath, Index, NodeKind);
800 if (!ASTResults.empty())
801 return ASTResults;
802
803 // If the cursor can't be resolved directly, try fallback strategies.
804 auto Word =
805 SpelledWord::touching(*CurLoc, AST.getTokens(), AST.getLangOpts());
806 if (Word) {
807 // Is the same word nearby a real identifier that might refer to something?
808 if (const syntax::Token *NearbyIdent =
809 findNearbyIdentifier(*Word, AST.getTokens())) {
810 if (auto Macro = locateMacroReferent(*NearbyIdent, AST, *MainFilePath)) {
811 log("Found macro definition heuristically using nearby identifier {0}",
812 Word->Text);
813 return {*std::move(Macro)};
814 }
815 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent, AST,
816 *MainFilePath, Index, NodeKind);
817 if (!ASTResults.empty()) {
818 log("Found definition heuristically using nearby identifier {0}",
819 NearbyIdent->text(SM));
820 return ASTResults;
821 }
822 vlog("No definition found using nearby identifier {0} at {1}", Word->Text,
823 Word->Location.printToString(SM));
824 }
825 // No nearby word, or it didn't refer to anything either. Try the index.
826 auto TextualResults =
827 locateSymbolTextually(*Word, AST, Index, *MainFilePath, NodeKind);
828 if (!TextualResults.empty())
829 return TextualResults;
830 }
831
832 return {};
833 }
834
getDocumentLinks(ParsedAST & AST)835 std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
836 const auto &SM = AST.getSourceManager();
837 auto MainFilePath =
838 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
839 if (!MainFilePath) {
840 elog("Failed to get a path for the main file, so no links");
841 return {};
842 }
843
844 std::vector<DocumentLink> Result;
845 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
846 if (Inc.Resolved.empty())
847 continue;
848 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
849 const auto *HashTok = AST.getTokens().spelledTokenAt(HashLoc);
850 assert(HashTok && "got inclusion at wrong offset");
851 const auto *IncludeTok = std::next(HashTok);
852 const auto *FileTok = std::next(IncludeTok);
853 // FileTok->range is not sufficient here, as raw lexing wouldn't yield
854 // correct tokens for angled filenames. Hence we explicitly use
855 // Inc.Written's length.
856 auto FileRange =
857 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
858 .toCharRange(SM);
859
860 Result.push_back(
861 DocumentLink({halfOpenToRange(SM, FileRange),
862 URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
863 }
864
865 return Result;
866 }
867
868 namespace {
869
870 /// Collects references to symbols within the main file.
871 class ReferenceFinder : public index::IndexDataConsumer {
872 public:
873 struct Reference {
874 syntax::Token SpelledTok;
875 index::SymbolRoleSet Role;
876 SymbolID Target;
877
rangeclang::clangd::__anond43782d30c11::ReferenceFinder::Reference878 Range range(const SourceManager &SM) const {
879 return halfOpenToRange(SM, SpelledTok.range(SM).toCharRange(SM));
880 }
881 };
882
ReferenceFinder(const ParsedAST & AST,const llvm::ArrayRef<const NamedDecl * > Targets,bool PerToken)883 ReferenceFinder(const ParsedAST &AST,
884 const llvm::ArrayRef<const NamedDecl *> Targets,
885 bool PerToken)
886 : PerToken(PerToken), AST(AST) {
887 for (const NamedDecl *ND : Targets) {
888 const Decl *CD = ND->getCanonicalDecl();
889 TargetDeclToID[CD] = getSymbolID(CD);
890 }
891 }
892
take()893 std::vector<Reference> take() && {
894 llvm::sort(References, [](const Reference &L, const Reference &R) {
895 auto LTok = L.SpelledTok.location();
896 auto RTok = R.SpelledTok.location();
897 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
898 });
899 // We sometimes see duplicates when parts of the AST get traversed twice.
900 References.erase(std::unique(References.begin(), References.end(),
901 [](const Reference &L, const Reference &R) {
902 auto LTok = L.SpelledTok.location();
903 auto RTok = R.SpelledTok.location();
904 return std::tie(LTok, L.Role) ==
905 std::tie(RTok, R.Role);
906 }),
907 References.end());
908 return std::move(References);
909 }
910
911 bool
handleDeclOccurrence(const Decl * D,index::SymbolRoleSet Roles,llvm::ArrayRef<index::SymbolRelation> Relations,SourceLocation Loc,index::IndexDataConsumer::ASTNodeInfo ASTNode)912 handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
913 llvm::ArrayRef<index::SymbolRelation> Relations,
914 SourceLocation Loc,
915 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
916 auto DeclID = TargetDeclToID.find(D->getCanonicalDecl());
917 if (DeclID == TargetDeclToID.end())
918 return true;
919 const SourceManager &SM = AST.getSourceManager();
920 if (!isInsideMainFile(Loc, SM))
921 return true;
922 const auto &TB = AST.getTokens();
923
924 llvm::SmallVector<SourceLocation, 1> Locs;
925 if (PerToken) {
926 // Check whether this is one of the few constructs where the reference
927 // can be split over several tokens.
928 if (auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
929 OME->getSelectorLocs(Locs);
930 } else if (auto *OMD =
931 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
932 OMD->getSelectorLocs(Locs);
933 }
934 // Sanity check: we expect the *first* token to match the reported loc.
935 // Otherwise, maybe it was e.g. some other kind of reference to a Decl.
936 if (!Locs.empty() && Locs.front() != Loc)
937 Locs.clear(); // First token doesn't match, assume our guess was wrong.
938 }
939 if (Locs.empty())
940 Locs.push_back(Loc);
941
942 for (SourceLocation L : Locs) {
943 L = SM.getFileLoc(L);
944 if (const auto *Tok = TB.spelledTokenAt(L))
945 References.push_back({*Tok, Roles, DeclID->getSecond()});
946 }
947 return true;
948 }
949
950 private:
951 bool PerToken; // If true, report 3 references for split ObjC selector names.
952 std::vector<Reference> References;
953 const ParsedAST &AST;
954 llvm::DenseMap<const Decl *, SymbolID> TargetDeclToID;
955 };
956
957 std::vector<ReferenceFinder::Reference>
findRefs(const llvm::ArrayRef<const NamedDecl * > TargetDecls,ParsedAST & AST,bool PerToken)958 findRefs(const llvm::ArrayRef<const NamedDecl *> TargetDecls, ParsedAST &AST,
959 bool PerToken) {
960 ReferenceFinder RefFinder(AST, TargetDecls, PerToken);
961 index::IndexingOptions IndexOpts;
962 IndexOpts.SystemSymbolFilter =
963 index::IndexingOptions::SystemSymbolFilterKind::All;
964 IndexOpts.IndexFunctionLocals = true;
965 IndexOpts.IndexParametersInDeclarations = true;
966 IndexOpts.IndexTemplateParameters = true;
967 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
968 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
969 return std::move(RefFinder).take();
970 }
971
getFunctionBody(DynTypedNode N)972 const Stmt *getFunctionBody(DynTypedNode N) {
973 if (const auto *FD = N.get<FunctionDecl>())
974 return FD->getBody();
975 if (const auto *FD = N.get<BlockDecl>())
976 return FD->getBody();
977 if (const auto *FD = N.get<LambdaExpr>())
978 return FD->getBody();
979 if (const auto *FD = N.get<ObjCMethodDecl>())
980 return FD->getBody();
981 return nullptr;
982 }
983
getLoopBody(DynTypedNode N)984 const Stmt *getLoopBody(DynTypedNode N) {
985 if (const auto *LS = N.get<ForStmt>())
986 return LS->getBody();
987 if (const auto *LS = N.get<CXXForRangeStmt>())
988 return LS->getBody();
989 if (const auto *LS = N.get<WhileStmt>())
990 return LS->getBody();
991 if (const auto *LS = N.get<DoStmt>())
992 return LS->getBody();
993 return nullptr;
994 }
995
996 // AST traversal to highlight control flow statements under some root.
997 // Once we hit further control flow we prune the tree (or at least restrict
998 // what we highlight) so we capture e.g. breaks from the outer loop only.
999 class FindControlFlow : public RecursiveASTVisitor<FindControlFlow> {
1000 // Types of control-flow statements we might highlight.
1001 enum Target {
1002 Break = 1,
1003 Continue = 2,
1004 Return = 4,
1005 Case = 8,
1006 Throw = 16,
1007 Goto = 32,
1008 All = Break | Continue | Return | Case | Throw | Goto,
1009 };
1010 int Ignore = 0; // bitmask of Target - what are we *not* highlighting?
1011 SourceRange Bounds; // Half-open, restricts reported targets.
1012 std::vector<SourceLocation> &Result;
1013 const SourceManager &SM;
1014
1015 // Masks out targets for a traversal into D.
1016 // Traverses the subtree using Delegate() if any targets remain.
1017 template <typename Func>
filterAndTraverse(DynTypedNode D,const Func & Delegate)1018 bool filterAndTraverse(DynTypedNode D, const Func &Delegate) {
1019 auto RestoreIgnore = llvm::make_scope_exit(
1020 [OldIgnore(Ignore), this] { Ignore = OldIgnore; });
1021 if (getFunctionBody(D))
1022 Ignore = All;
1023 else if (getLoopBody(D))
1024 Ignore |= Continue | Break;
1025 else if (D.get<SwitchStmt>())
1026 Ignore |= Break | Case;
1027 // Prune tree if we're not looking for anything.
1028 return (Ignore == All) ? true : Delegate();
1029 }
1030
found(Target T,SourceLocation Loc)1031 void found(Target T, SourceLocation Loc) {
1032 if (T & Ignore)
1033 return;
1034 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1035 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1036 return;
1037 Result.push_back(Loc);
1038 }
1039
1040 public:
FindControlFlow(SourceRange Bounds,std::vector<SourceLocation> & Result,const SourceManager & SM)1041 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1042 const SourceManager &SM)
1043 : Bounds(Bounds), Result(Result), SM(SM) {}
1044
1045 // When traversing function or loops, limit targets to those that still
1046 // refer to the original root.
TraverseDecl(Decl * D)1047 bool TraverseDecl(Decl *D) {
1048 return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1049 return RecursiveASTVisitor::TraverseDecl(D);
1050 });
1051 }
TraverseStmt(Stmt * S)1052 bool TraverseStmt(Stmt *S) {
1053 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1054 return RecursiveASTVisitor::TraverseStmt(S);
1055 });
1056 }
1057
1058 // Add leaves that we found and want.
VisitReturnStmt(ReturnStmt * R)1059 bool VisitReturnStmt(ReturnStmt *R) {
1060 found(Return, R->getReturnLoc());
1061 return true;
1062 }
VisitBreakStmt(BreakStmt * B)1063 bool VisitBreakStmt(BreakStmt *B) {
1064 found(Break, B->getBreakLoc());
1065 return true;
1066 }
VisitContinueStmt(ContinueStmt * C)1067 bool VisitContinueStmt(ContinueStmt *C) {
1068 found(Continue, C->getContinueLoc());
1069 return true;
1070 }
VisitSwitchCase(SwitchCase * C)1071 bool VisitSwitchCase(SwitchCase *C) {
1072 found(Case, C->getKeywordLoc());
1073 return true;
1074 }
VisitCXXThrowExpr(CXXThrowExpr * T)1075 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1076 found(Throw, T->getThrowLoc());
1077 return true;
1078 }
VisitGotoStmt(GotoStmt * G)1079 bool VisitGotoStmt(GotoStmt *G) {
1080 // Goto is interesting if its target is outside the root.
1081 if (const auto *LD = G->getLabel()) {
1082 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1083 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1084 found(Goto, G->getGotoLoc());
1085 }
1086 return true;
1087 }
1088 };
1089
1090 // Given a location within a switch statement, return the half-open range that
1091 // covers the case it's contained in.
1092 // We treat `case X: case Y: ...` as one case, and assume no other fallthrough.
findCaseBounds(const SwitchStmt & Switch,SourceLocation Loc,const SourceManager & SM)1093 SourceRange findCaseBounds(const SwitchStmt &Switch, SourceLocation Loc,
1094 const SourceManager &SM) {
1095 // Cases are not stored in order, sort them first.
1096 // (In fact they seem to be stored in reverse order, don't rely on this)
1097 std::vector<const SwitchCase *> Cases;
1098 for (const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1099 Case = Case->getNextSwitchCase())
1100 Cases.push_back(Case);
1101 llvm::sort(Cases, [&](const SwitchCase *L, const SwitchCase *R) {
1102 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1103 });
1104
1105 // Find the first case after the target location, the end of our range.
1106 auto CaseAfter = llvm::partition_point(Cases, [&](const SwitchCase *C) {
1107 return !SM.isBeforeInTranslationUnit(Loc, C->getKeywordLoc());
1108 });
1109 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1110 : (*CaseAfter)->getKeywordLoc();
1111
1112 // Our target can be before the first case - cases are optional!
1113 if (CaseAfter == Cases.begin())
1114 return SourceRange(Switch.getBeginLoc(), End);
1115 // The start of our range is usually the previous case, but...
1116 auto CaseBefore = std::prev(CaseAfter);
1117 // ... rewind CaseBefore to the first in a `case A: case B: ...` sequence.
1118 while (CaseBefore != Cases.begin() &&
1119 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1120 --CaseBefore;
1121 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1122 }
1123
1124 // Returns the locations of control flow statements related to N. e.g.:
1125 // for => branches: break/continue/return/throw
1126 // break => controlling loop (forwhile/do), and its related control flow
1127 // return => all returns/throws from the same function
1128 // When an inner block is selected, we include branches bound to outer blocks
1129 // as these are exits from the inner block. e.g. return in a for loop.
1130 // FIXME: We don't analyze catch blocks, throw is treated the same as return.
relatedControlFlow(const SelectionTree::Node & N)1131 std::vector<SourceLocation> relatedControlFlow(const SelectionTree::Node &N) {
1132 const SourceManager &SM =
1133 N.getDeclContext().getParentASTContext().getSourceManager();
1134 std::vector<SourceLocation> Result;
1135
1136 // First, check if we're at a node that can resolve to a root.
1137 enum class Cur { None, Break, Continue, Return, Case, Throw } Cursor;
1138 if (N.ASTNode.get<BreakStmt>()) {
1139 Cursor = Cur::Break;
1140 } else if (N.ASTNode.get<ContinueStmt>()) {
1141 Cursor = Cur::Continue;
1142 } else if (N.ASTNode.get<ReturnStmt>()) {
1143 Cursor = Cur::Return;
1144 } else if (N.ASTNode.get<CXXThrowExpr>()) {
1145 Cursor = Cur::Throw;
1146 } else if (N.ASTNode.get<SwitchCase>()) {
1147 Cursor = Cur::Case;
1148 } else if (const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1149 // We don't know what root to associate with, but highlight the goto/label.
1150 Result.push_back(GS->getGotoLoc());
1151 if (const auto *LD = GS->getLabel())
1152 Result.push_back(LD->getLocation());
1153 Cursor = Cur::None;
1154 } else {
1155 Cursor = Cur::None;
1156 }
1157
1158 const Stmt *Root = nullptr; // Loop or function body to traverse.
1159 SourceRange Bounds;
1160 // Look up the tree for a root (or just at this node if we didn't find a leaf)
1161 for (const auto *P = &N; P; P = P->Parent) {
1162 // return associates with enclosing function
1163 if (const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
1164 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1165 Root = FunctionBody;
1166 }
1167 break; // other leaves don't cross functions.
1168 }
1169 // break/continue associate with enclosing loop.
1170 if (const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
1171 if (Cursor == Cur::None || Cursor == Cur::Break ||
1172 Cursor == Cur::Continue) {
1173 Root = LoopBody;
1174 // Highlight the loop keyword itself.
1175 // FIXME: for do-while, this only covers the `do`..
1176 Result.push_back(P->ASTNode.getSourceRange().getBegin());
1177 break;
1178 }
1179 }
1180 // For switches, users think of case statements as control flow blocks.
1181 // We highlight only occurrences surrounded by the same case.
1182 // We don't detect fallthrough (other than 'case X, case Y').
1183 if (const auto *SS = P->ASTNode.get<SwitchStmt>()) {
1184 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1185 Result.push_back(SS->getSwitchLoc()); // Highlight the switch.
1186 Root = SS->getBody();
1187 // Limit to enclosing case, if there is one.
1188 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1189 break;
1190 }
1191 }
1192 // If we didn't start at some interesting node, we're done.
1193 if (Cursor == Cur::None)
1194 break;
1195 }
1196 if (Root) {
1197 if (!Bounds.isValid())
1198 Bounds = Root->getSourceRange();
1199 FindControlFlow(Bounds, Result, SM).TraverseStmt(const_cast<Stmt *>(Root));
1200 }
1201 return Result;
1202 }
1203
toHighlight(const ReferenceFinder::Reference & Ref,const SourceManager & SM)1204 DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
1205 const SourceManager &SM) {
1206 DocumentHighlight DH;
1207 DH.range = Ref.range(SM);
1208 if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1209 DH.kind = DocumentHighlightKind::Write;
1210 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1211 DH.kind = DocumentHighlightKind::Read;
1212 else
1213 DH.kind = DocumentHighlightKind::Text;
1214 return DH;
1215 }
1216
toHighlight(SourceLocation Loc,const syntax::TokenBuffer & TB)1217 llvm::Optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1218 const syntax::TokenBuffer &TB) {
1219 Loc = TB.sourceManager().getFileLoc(Loc);
1220 if (const auto *Tok = TB.spelledTokenAt(Loc)) {
1221 DocumentHighlight Result;
1222 Result.range = halfOpenToRange(
1223 TB.sourceManager(),
1224 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1225 return Result;
1226 }
1227 return llvm::None;
1228 }
1229
1230 } // namespace
1231
findDocumentHighlights(ParsedAST & AST,Position Pos)1232 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
1233 Position Pos) {
1234 const SourceManager &SM = AST.getSourceManager();
1235 // FIXME: show references to macro within file?
1236 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1237 if (!CurLoc) {
1238 llvm::consumeError(CurLoc.takeError());
1239 return {};
1240 }
1241 std::vector<DocumentHighlight> Result;
1242 auto TryTree = [&](SelectionTree ST) {
1243 if (const SelectionTree::Node *N = ST.commonAncestor()) {
1244 DeclRelationSet Relations =
1245 DeclRelation::TemplatePattern | DeclRelation::Alias;
1246 auto TargetDecls =
1247 targetDecl(N->ASTNode, Relations, AST.getHeuristicResolver());
1248 if (!TargetDecls.empty()) {
1249 // FIXME: we may get multiple DocumentHighlights with the same location
1250 // and different kinds, deduplicate them.
1251 for (const auto &Ref : findRefs(TargetDecls, AST, /*PerToken=*/true))
1252 Result.push_back(toHighlight(Ref, SM));
1253 return true;
1254 }
1255 auto ControlFlow = relatedControlFlow(*N);
1256 if (!ControlFlow.empty()) {
1257 for (SourceLocation Loc : ControlFlow)
1258 if (auto Highlight = toHighlight(Loc, AST.getTokens()))
1259 Result.push_back(std::move(*Highlight));
1260 return true;
1261 }
1262 }
1263 return false;
1264 };
1265
1266 unsigned Offset =
1267 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1268 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,
1269 Offset, TryTree);
1270 return Result;
1271 }
1272
findImplementations(ParsedAST & AST,Position Pos,const SymbolIndex * Index)1273 std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos,
1274 const SymbolIndex *Index) {
1275 // We rely on index to find the implementations in subclasses.
1276 // FIXME: Index can be stale, so we may loose some latest results from the
1277 // main file.
1278 if (!Index)
1279 return {};
1280 const SourceManager &SM = AST.getSourceManager();
1281 auto MainFilePath =
1282 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1283 if (!MainFilePath) {
1284 elog("Failed to get a path for the main file, so no implementations.");
1285 return {};
1286 }
1287 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1288 if (!CurLoc) {
1289 elog("Failed to convert position to source location: {0}",
1290 CurLoc.takeError());
1291 return {};
1292 }
1293 DeclRelationSet Relations =
1294 DeclRelation::TemplatePattern | DeclRelation::Alias;
1295 llvm::DenseSet<SymbolID> IDs;
1296 RelationKind QueryKind = RelationKind::OverriddenBy;
1297 for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) {
1298 if (const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1299 if (CXXMD->isVirtual()) {
1300 IDs.insert(getSymbolID(ND));
1301 QueryKind = RelationKind::OverriddenBy;
1302 }
1303 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1304 IDs.insert(getSymbolID(RD));
1305 QueryKind = RelationKind::BaseOf;
1306 }
1307 }
1308 return findImplementors(std::move(IDs), QueryKind, Index, *MainFilePath);
1309 }
1310
1311 namespace {
1312 // Recursively finds all the overridden methods of `CMD` in complete type
1313 // hierarchy.
getOverriddenMethods(const CXXMethodDecl * CMD,llvm::DenseSet<SymbolID> & OverriddenMethods)1314 void getOverriddenMethods(const CXXMethodDecl *CMD,
1315 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1316 if (!CMD)
1317 return;
1318 for (const CXXMethodDecl *Base : CMD->overridden_methods()) {
1319 if (auto ID = getSymbolID(Base))
1320 OverriddenMethods.insert(ID);
1321 getOverriddenMethods(Base, OverriddenMethods);
1322 }
1323 }
1324 } // namespace
1325
findReferences(ParsedAST & AST,Position Pos,uint32_t Limit,const SymbolIndex * Index)1326 ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
1327 const SymbolIndex *Index) {
1328 ReferencesResult Results;
1329 const SourceManager &SM = AST.getSourceManager();
1330 auto MainFilePath =
1331 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1332 if (!MainFilePath) {
1333 elog("Failed to get a path for the main file, so no references");
1334 return Results;
1335 }
1336 auto URIMainFile = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
1337 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1338 if (!CurLoc) {
1339 llvm::consumeError(CurLoc.takeError());
1340 return {};
1341 }
1342
1343 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1344
1345 const auto *IdentifierAtCursor =
1346 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1347 llvm::Optional<DefinedMacro> Macro;
1348 if (IdentifierAtCursor)
1349 Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());
1350 if (Macro) {
1351 // Handle references to macro.
1352 if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
1353 // Collect macro references from main file.
1354 const auto &IDToRefs = AST.getMacros().MacroRefs;
1355 auto Refs = IDToRefs.find(MacroSID);
1356 if (Refs != IDToRefs.end()) {
1357 for (const auto &Ref : Refs->second) {
1358 ReferencesResult::Reference Result;
1359 Result.Loc.range = Ref.Rng;
1360 Result.Loc.uri = URIMainFile;
1361 if (Ref.IsDefinition) {
1362 Result.Attributes |= ReferencesResult::Declaration;
1363 Result.Attributes |= ReferencesResult::Definition;
1364 }
1365 Results.References.push_back(std::move(Result));
1366 }
1367 }
1368 IDsToQuery.insert(MacroSID);
1369 }
1370 } else {
1371 // Handle references to Decls.
1372
1373 DeclRelationSet Relations =
1374 DeclRelation::TemplatePattern | DeclRelation::Alias;
1375 std::vector<const NamedDecl *> Decls =
1376 getDeclAtPosition(AST, *CurLoc, Relations);
1377 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1378 for (const NamedDecl *D : Decls) {
1379 auto ID = getSymbolID(D);
1380 if (!ID)
1381 continue;
1382 TargetsInMainFile.push_back(D);
1383 // Not all symbols can be referenced from outside (e.g. function-locals).
1384 // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
1385 // we know this file isn't a header. The details might be tricky.
1386 if (D->getParentFunctionOrMethod())
1387 continue;
1388 IDsToQuery.insert(ID);
1389 }
1390
1391 RelationsRequest OverriddenBy;
1392 if (Index) {
1393 OverriddenBy.Predicate = RelationKind::OverriddenBy;
1394 for (const NamedDecl *ND : Decls) {
1395 // Special case: For virtual methods, report decl/def of overrides and
1396 // references to all overridden methods in complete type hierarchy.
1397 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1398 if (CMD->isVirtual()) {
1399 if (auto ID = getSymbolID(CMD))
1400 OverriddenBy.Subjects.insert(ID);
1401 getOverriddenMethods(CMD, OverriddenMethods);
1402 }
1403 }
1404 }
1405 }
1406
1407 // We traverse the AST to find references in the main file.
1408 auto MainFileRefs = findRefs(TargetsInMainFile, AST, /*PerToken=*/false);
1409 // We may get multiple refs with the same location and different Roles, as
1410 // cross-reference is only interested in locations, we deduplicate them
1411 // by the location to avoid emitting duplicated locations.
1412 MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
1413 [](const ReferenceFinder::Reference &L,
1414 const ReferenceFinder::Reference &R) {
1415 return L.SpelledTok.location() ==
1416 R.SpelledTok.location();
1417 }),
1418 MainFileRefs.end());
1419 for (const auto &Ref : MainFileRefs) {
1420 ReferencesResult::Reference Result;
1421 Result.Loc.range = Ref.range(SM);
1422 Result.Loc.uri = URIMainFile;
1423 if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Declaration))
1424 Result.Attributes |= ReferencesResult::Declaration;
1425 // clang-index doesn't report definitions as declarations, but they are.
1426 if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Definition))
1427 Result.Attributes |=
1428 ReferencesResult::Definition | ReferencesResult::Declaration;
1429 Results.References.push_back(std::move(Result));
1430 }
1431 // Add decl/def of overridding methods.
1432 if (Index && !OverriddenBy.Subjects.empty()) {
1433 Index->relations(OverriddenBy, [&](const SymbolID &Subject,
1434 const Symbol &Object) {
1435 if (Limit && Results.References.size() >= Limit) {
1436 Results.HasMore = true;
1437 return;
1438 }
1439 const auto LSPLocDecl =
1440 toLSPLocation(Object.CanonicalDeclaration, *MainFilePath);
1441 const auto LSPLocDef = toLSPLocation(Object.Definition, *MainFilePath);
1442 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1443 ReferencesResult::Reference Result;
1444 Result.Loc = std::move(*LSPLocDecl);
1445 Result.Attributes =
1446 ReferencesResult::Declaration | ReferencesResult::Override;
1447 Results.References.push_back(std::move(Result));
1448 }
1449 if (LSPLocDef) {
1450 ReferencesResult::Reference Result;
1451 Result.Loc = std::move(*LSPLocDef);
1452 Result.Attributes = ReferencesResult::Declaration |
1453 ReferencesResult::Definition |
1454 ReferencesResult::Override;
1455 Results.References.push_back(std::move(Result));
1456 }
1457 });
1458 }
1459 }
1460 // Now query the index for references from other files.
1461 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool AllowAttributes,
1462 bool AllowMainFileSymbols) {
1463 if (IDs.empty() || !Index || Results.HasMore)
1464 return;
1465 RefsRequest Req;
1466 Req.IDs = std::move(IDs);
1467 if (Limit) {
1468 if (Limit < Results.References.size()) {
1469 // We've already filled our quota, still check the index to correctly
1470 // return the `HasMore` info.
1471 Req.Limit = 0;
1472 } else {
1473 // Query index only for the remaining size.
1474 Req.Limit = Limit - Results.References.size();
1475 }
1476 }
1477 Results.HasMore |= Index->refs(Req, [&](const Ref &R) {
1478 auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
1479 // Avoid indexed results for the main file - the AST is authoritative.
1480 if (!LSPLoc ||
1481 (!AllowMainFileSymbols && LSPLoc->uri.file() == *MainFilePath))
1482 return;
1483 ReferencesResult::Reference Result;
1484 Result.Loc = std::move(*LSPLoc);
1485 if (AllowAttributes) {
1486 if ((R.Kind & RefKind::Declaration) == RefKind::Declaration)
1487 Result.Attributes |= ReferencesResult::Declaration;
1488 // FIXME: our index should definitely store def | decl separately!
1489 if ((R.Kind & RefKind::Definition) == RefKind::Definition)
1490 Result.Attributes |=
1491 ReferencesResult::Declaration | ReferencesResult::Definition;
1492 }
1493 Results.References.push_back(std::move(Result));
1494 });
1495 };
1496 QueryIndex(std::move(IDsToQuery), /*AllowAttributes=*/true,
1497 /*AllowMainFileSymbols=*/false);
1498 // For a virtual method: Occurrences of BaseMethod should be treated as refs
1499 // and not as decl/def. Allow symbols from main file since AST does not report
1500 // these.
1501 QueryIndex(std::move(OverriddenMethods), /*AllowAttributes=*/false,
1502 /*AllowMainFileSymbols=*/true);
1503 return Results;
1504 }
1505
getSymbolInfo(ParsedAST & AST,Position Pos)1506 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
1507 const SourceManager &SM = AST.getSourceManager();
1508 auto CurLoc = sourceLocationInMainFile(SM, Pos);
1509 if (!CurLoc) {
1510 llvm::consumeError(CurLoc.takeError());
1511 return {};
1512 }
1513
1514 std::vector<SymbolDetails> Results;
1515
1516 // We also want the targets of using-decls, so we include
1517 // DeclRelation::Underlying.
1518 DeclRelationSet Relations = DeclRelation::TemplatePattern |
1519 DeclRelation::Alias | DeclRelation::Underlying;
1520 for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
1521 SymbolDetails NewSymbol;
1522 std::string QName = printQualifiedName(*D);
1523 auto SplitQName = splitQualifiedName(QName);
1524 NewSymbol.containerName = std::string(SplitQName.first);
1525 NewSymbol.name = std::string(SplitQName.second);
1526
1527 if (NewSymbol.containerName.empty()) {
1528 if (const auto *ParentND =
1529 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1530 NewSymbol.containerName = printQualifiedName(*ParentND);
1531 }
1532 llvm::SmallString<32> USR;
1533 if (!index::generateUSRForDecl(D, USR)) {
1534 NewSymbol.USR = std::string(USR.str());
1535 NewSymbol.ID = SymbolID(NewSymbol.USR);
1536 }
1537 Results.push_back(std::move(NewSymbol));
1538 }
1539
1540 const auto *IdentifierAtCursor =
1541 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1542 if (!IdentifierAtCursor)
1543 return Results;
1544
1545 if (auto M = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {
1546 SymbolDetails NewMacro;
1547 NewMacro.name = std::string(M->Name);
1548 llvm::SmallString<32> USR;
1549 if (!index::generateUSRForMacro(NewMacro.name, M->Info->getDefinitionLoc(),
1550 SM, USR)) {
1551 NewMacro.USR = std::string(USR.str());
1552 NewMacro.ID = SymbolID(NewMacro.USR);
1553 }
1554 Results.push_back(std::move(NewMacro));
1555 }
1556
1557 return Results;
1558 }
1559
operator <<(llvm::raw_ostream & OS,const LocatedSymbol & S)1560 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {
1561 OS << S.Name << ": " << S.PreferredDeclaration;
1562 if (S.Definition)
1563 OS << " def=" << *S.Definition;
1564 return OS;
1565 }
1566
operator <<(llvm::raw_ostream & OS,const ReferencesResult::Reference & R)1567 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
1568 const ReferencesResult::Reference &R) {
1569 OS << R.Loc;
1570 if (R.Attributes & ReferencesResult::Declaration)
1571 OS << " [decl]";
1572 if (R.Attributes & ReferencesResult::Definition)
1573 OS << " [def]";
1574 if (R.Attributes & ReferencesResult::Override)
1575 OS << " [override]";
1576 return OS;
1577 }
1578
1579 template <typename HierarchyItem>
declToHierarchyItem(const NamedDecl & ND)1580 static llvm::Optional<HierarchyItem> declToHierarchyItem(const NamedDecl &ND) {
1581 ASTContext &Ctx = ND.getASTContext();
1582 auto &SM = Ctx.getSourceManager();
1583 SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager());
1584 SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc()));
1585 SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc()));
1586 const auto DeclRange =
1587 toHalfOpenFileRange(SM, Ctx.getLangOpts(), {BeginLoc, EndLoc});
1588 if (!DeclRange)
1589 return llvm::None;
1590 auto FilePath =
1591 getCanonicalPath(SM.getFileEntryForID(SM.getFileID(NameLoc)), SM);
1592 auto TUPath = getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1593 if (!FilePath || !TUPath)
1594 return llvm::None; // Not useful without a uri.
1595
1596 Position NameBegin = sourceLocToPosition(SM, NameLoc);
1597 Position NameEnd = sourceLocToPosition(
1598 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1599
1600 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1601 // FIXME: This is not classifying constructors, destructors and operators
1602 // correctly.
1603 SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
1604
1605 HierarchyItem HI;
1606 HI.name = printName(Ctx, ND);
1607 HI.kind = SK;
1608 HI.range = Range{sourceLocToPosition(SM, DeclRange->getBegin()),
1609 sourceLocToPosition(SM, DeclRange->getEnd())};
1610 HI.selectionRange = Range{NameBegin, NameEnd};
1611 if (!HI.range.contains(HI.selectionRange)) {
1612 // 'selectionRange' must be contained in 'range', so in cases where clang
1613 // reports unrelated ranges we need to reconcile somehow.
1614 HI.range = HI.selectionRange;
1615 }
1616
1617 HI.uri = URIForFile::canonicalize(*FilePath, *TUPath);
1618
1619 return HI;
1620 }
1621
1622 static llvm::Optional<TypeHierarchyItem>
declToTypeHierarchyItem(const NamedDecl & ND,llvm::StringRef TUPath)1623 declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
1624 auto Result = declToHierarchyItem<TypeHierarchyItem>(ND);
1625 if (Result) {
1626 Result->deprecated = ND.isDeprecated();
1627 // Compute the SymbolID and store it in the 'data' field.
1628 // This allows typeHierarchy/resolve to be used to
1629 // resolve children of items returned in a previous request
1630 // for parents.
1631 Result->data.symbolID = getSymbolID(&ND);
1632 }
1633 return Result;
1634 }
1635
1636 static llvm::Optional<CallHierarchyItem>
declToCallHierarchyItem(const NamedDecl & ND)1637 declToCallHierarchyItem(const NamedDecl &ND) {
1638 auto Result = declToHierarchyItem<CallHierarchyItem>(ND);
1639 if (!Result)
1640 return Result;
1641 if (ND.isDeprecated())
1642 Result->tags.push_back(SymbolTag::Deprecated);
1643 if (auto ID = getSymbolID(&ND))
1644 Result->data = ID.str();
1645 return Result;
1646 }
1647
1648 template <typename HierarchyItem>
symbolToHierarchyItem(const Symbol & S,PathRef TUPath)1649 static llvm::Optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
1650 PathRef TUPath) {
1651 auto Loc = symbolToLocation(S, TUPath);
1652 if (!Loc) {
1653 elog("Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1654 return llvm::None;
1655 }
1656 HierarchyItem HI;
1657 HI.name = std::string(S.Name);
1658 HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
1659 HI.selectionRange = Loc->range;
1660 // FIXME: Populate 'range' correctly
1661 // (https://github.com/clangd/clangd/issues/59).
1662 HI.range = HI.selectionRange;
1663 HI.uri = Loc->uri;
1664
1665 return HI;
1666 }
1667
1668 static llvm::Optional<TypeHierarchyItem>
symbolToTypeHierarchyItem(const Symbol & S,PathRef TUPath)1669 symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath) {
1670 auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);
1671 if (Result) {
1672 Result->deprecated = (S.Flags & Symbol::Deprecated);
1673 Result->data.symbolID = S.ID;
1674 }
1675 return Result;
1676 }
1677
1678 static llvm::Optional<CallHierarchyItem>
symbolToCallHierarchyItem(const Symbol & S,PathRef TUPath)1679 symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath) {
1680 auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);
1681 if (!Result)
1682 return Result;
1683 Result->data = S.ID.str();
1684 if (S.Flags & Symbol::Deprecated)
1685 Result->tags.push_back(SymbolTag::Deprecated);
1686 return Result;
1687 }
1688
fillSubTypes(const SymbolID & ID,std::vector<TypeHierarchyItem> & SubTypes,const SymbolIndex * Index,int Levels,PathRef TUPath)1689 static void fillSubTypes(const SymbolID &ID,
1690 std::vector<TypeHierarchyItem> &SubTypes,
1691 const SymbolIndex *Index, int Levels, PathRef TUPath) {
1692 RelationsRequest Req;
1693 Req.Subjects.insert(ID);
1694 Req.Predicate = RelationKind::BaseOf;
1695 Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
1696 if (Optional<TypeHierarchyItem> ChildSym =
1697 symbolToTypeHierarchyItem(Object, TUPath)) {
1698 if (Levels > 1) {
1699 ChildSym->children.emplace();
1700 fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);
1701 }
1702 SubTypes.emplace_back(std::move(*ChildSym));
1703 }
1704 });
1705 }
1706
1707 using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
1708
1709 // Extracts parents from AST and populates the type hierarchy item.
fillSuperTypes(const CXXRecordDecl & CXXRD,llvm::StringRef TUPath,TypeHierarchyItem & Item,RecursionProtectionSet & RPSet)1710 static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,
1711 TypeHierarchyItem &Item,
1712 RecursionProtectionSet &RPSet) {
1713 Item.parents.emplace();
1714 Item.data.parents.emplace();
1715 // typeParents() will replace dependent template specializations
1716 // with their class template, so to avoid infinite recursion for
1717 // certain types of hierarchies, keep the templates encountered
1718 // along the parent chain in a set, and stop the recursion if one
1719 // starts to repeat.
1720 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;
1721 if (Pattern) {
1722 if (!RPSet.insert(Pattern).second) {
1723 return;
1724 }
1725 }
1726
1727 for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {
1728 if (Optional<TypeHierarchyItem> ParentSym =
1729 declToTypeHierarchyItem(*ParentDecl, TUPath)) {
1730 fillSuperTypes(*ParentDecl, TUPath, *ParentSym, RPSet);
1731 Item.data.parents->emplace_back(ParentSym->data);
1732 Item.parents->emplace_back(std::move(*ParentSym));
1733 }
1734 }
1735
1736 if (Pattern) {
1737 RPSet.erase(Pattern);
1738 }
1739 }
1740
findRecordTypeAt(ParsedAST & AST,Position Pos)1741 std::vector<const CXXRecordDecl *> findRecordTypeAt(ParsedAST &AST,
1742 Position Pos) {
1743 auto RecordFromNode = [&AST](const SelectionTree::Node *N) {
1744 std::vector<const CXXRecordDecl *> Records;
1745 if (!N)
1746 return Records;
1747
1748 // Note: explicitReferenceTargets() will search for both template
1749 // instantiations and template patterns, and prefer the former if available
1750 // (generally, one will be available for non-dependent specializations of a
1751 // class template).
1752 auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Underlying,
1753 AST.getHeuristicResolver());
1754 for (const NamedDecl *D : Decls) {
1755
1756 if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1757 // If this is a variable, use the type of the variable.
1758 Records.push_back(VD->getType().getTypePtr()->getAsCXXRecordDecl());
1759 continue;
1760 }
1761
1762 if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
1763 // If this is a method, use the type of the class.
1764 Records.push_back(Method->getParent());
1765 continue;
1766 }
1767
1768 // We don't handle FieldDecl because it's not clear what behaviour
1769 // the user would expect: the enclosing class type (as with a
1770 // method), or the field's type (as with a variable).
1771
1772 if (auto *RD = dyn_cast<CXXRecordDecl>(D))
1773 Records.push_back(RD);
1774 }
1775 return Records;
1776 };
1777
1778 const SourceManager &SM = AST.getSourceManager();
1779 std::vector<const CXXRecordDecl *> Result;
1780 auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
1781 if (!Offset) {
1782 llvm::consumeError(Offset.takeError());
1783 return Result;
1784 }
1785 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,
1786 *Offset, [&](SelectionTree ST) {
1787 Result = RecordFromNode(ST.commonAncestor());
1788 return !Result.empty();
1789 });
1790 return Result;
1791 }
1792
1793 // Return the type most associated with an AST node.
1794 // This isn't precisely defined: we want "go to type" to do something useful.
typeForNode(const SelectionTree::Node * N)1795 static QualType typeForNode(const SelectionTree::Node *N) {
1796 // If we're looking at a namespace qualifier, walk up to what it's qualifying.
1797 // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
1798 while (N && N->ASTNode.get<NestedNameSpecifierLoc>())
1799 N = N->Parent;
1800 if (!N)
1801 return QualType();
1802
1803 // If we're pointing at a type => return it.
1804 if (const TypeLoc *TL = N->ASTNode.get<TypeLoc>()) {
1805 if (llvm::isa<DeducedType>(TL->getTypePtr()))
1806 if (auto Deduced = getDeducedType(
1807 N->getDeclContext().getParentASTContext(), TL->getBeginLoc()))
1808 return *Deduced;
1809 // Exception: an alias => underlying type.
1810 if (llvm::isa<TypedefType>(TL->getTypePtr()))
1811 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1812 return TL->getType();
1813 }
1814
1815 // Constructor initializers => the type of thing being initialized.
1816 if (const auto *CCI = N->ASTNode.get<CXXCtorInitializer>()) {
1817 if (const FieldDecl *FD = CCI->getAnyMember())
1818 return FD->getType();
1819 if (const Type *Base = CCI->getBaseClass())
1820 return QualType(Base, 0);
1821 }
1822
1823 // Base specifier => the base type.
1824 if (const auto *CBS = N->ASTNode.get<CXXBaseSpecifier>())
1825 return CBS->getType();
1826
1827 if (const Decl *D = N->ASTNode.get<Decl>()) {
1828 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
1829 QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); }
1830 // Declaration of a type => that type.
1831 QualType VisitTypeDecl(const TypeDecl *D) {
1832 return QualType(D->getTypeForDecl(), 0);
1833 }
1834 // Exception: alias declaration => the underlying type, not the alias.
1835 QualType VisitTypedefNameDecl(const TypedefNameDecl *D) {
1836 return D->getUnderlyingType();
1837 }
1838 // Look inside templates.
1839 QualType VisitTemplateDecl(const TemplateDecl *D) {
1840 return Visit(D->getTemplatedDecl());
1841 }
1842 } V;
1843 return V.Visit(D);
1844 }
1845
1846 if (const Stmt *S = N->ASTNode.get<Stmt>()) {
1847 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
1848 // Null-safe version of visit simplifies recursive calls below.
1849 QualType type(const Stmt *S) { return S ? Visit(S) : QualType(); }
1850
1851 // In general, expressions => type of expression.
1852 QualType VisitExpr(const Expr *S) {
1853 return S->IgnoreImplicitAsWritten()->getType();
1854 }
1855 // Exceptions for void expressions that operate on a type in some way.
1856 QualType VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
1857 return S->getDestroyedType();
1858 }
1859 QualType VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
1860 return S->getDestroyedType();
1861 }
1862 QualType VisitCXXThrowExpr(const CXXThrowExpr *S) {
1863 return S->getSubExpr()->getType();
1864 }
1865 QualType VisitCoyieldExpr(const CoyieldExpr *S) {
1866 return type(S->getOperand());
1867 }
1868 // Treat a designated initializer like a reference to the field.
1869 QualType VisitDesignatedInitExpr(const DesignatedInitExpr *S) {
1870 // In .foo.bar we want to jump to bar's type, so find *last* field.
1871 for (auto &D : llvm::reverse(S->designators()))
1872 if (D.isFieldDesignator())
1873 if (const auto *FD = D.getField())
1874 return FD->getType();
1875 return QualType();
1876 }
1877
1878 // Control flow statements that operate on data: use the data type.
1879 QualType VisitSwitchStmt(const SwitchStmt *S) {
1880 return type(S->getCond());
1881 }
1882 QualType VisitWhileStmt(const WhileStmt *S) { return type(S->getCond()); }
1883 QualType VisitDoStmt(const DoStmt *S) { return type(S->getCond()); }
1884 QualType VisitIfStmt(const IfStmt *S) { return type(S->getCond()); }
1885 QualType VisitCaseStmt(const CaseStmt *S) { return type(S->getLHS()); }
1886 QualType VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
1887 return S->getLoopVariable()->getType();
1888 }
1889 QualType VisitReturnStmt(const ReturnStmt *S) {
1890 return type(S->getRetValue());
1891 }
1892 QualType VisitCoreturnStmt(const CoreturnStmt *S) {
1893 return type(S->getOperand());
1894 }
1895 QualType VisitCXXCatchStmt(const CXXCatchStmt *S) {
1896 return S->getCaughtType();
1897 }
1898 QualType VisitObjCAtThrowStmt(const ObjCAtThrowStmt *S) {
1899 return type(S->getThrowExpr());
1900 }
1901 QualType VisitObjCAtCatchStmt(const ObjCAtCatchStmt *S) {
1902 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
1903 : QualType();
1904 }
1905 } V;
1906 return V.Visit(S);
1907 }
1908
1909 return QualType();
1910 }
1911
1912 // Given a type targeted by the cursor, return one or more types that are more interesting
1913 // to target.
unwrapFindType(QualType T,const HeuristicResolver * H,llvm::SmallVector<QualType> & Out)1914 static void unwrapFindType(
1915 QualType T, const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
1916 if (T.isNull())
1917 return;
1918
1919 // If there's a specific type alias, point at that rather than unwrapping.
1920 if (const auto* TDT = T->getAs<TypedefType>())
1921 return Out.push_back(QualType(TDT, 0));
1922
1923 // Pointers etc => pointee type.
1924 if (const auto *PT = T->getAs<PointerType>())
1925 return unwrapFindType(PT->getPointeeType(), H, Out);
1926 if (const auto *RT = T->getAs<ReferenceType>())
1927 return unwrapFindType(RT->getPointeeType(), H, Out);
1928 if (const auto *AT = T->getAsArrayTypeUnsafe())
1929 return unwrapFindType(AT->getElementType(), H, Out);
1930
1931 // Function type => return type.
1932 if (auto *FT = T->getAs<FunctionType>())
1933 return unwrapFindType(FT->getReturnType(), H, Out);
1934 if (auto *CRD = T->getAsCXXRecordDecl()) {
1935 if (CRD->isLambda())
1936 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H, Out);
1937 // FIXME: more cases we'd prefer the return type of the call operator?
1938 // std::function etc?
1939 }
1940
1941 // For smart pointer types, add the underlying type
1942 if (H)
1943 if (const auto* PointeeType = H->getPointeeType(T.getNonReferenceType().getTypePtr())) {
1944 unwrapFindType(QualType(PointeeType, 0), H, Out);
1945 return Out.push_back(T);
1946 }
1947
1948 return Out.push_back(T);
1949 }
1950
1951 // Convenience overload, to allow calling this without the out-parameter
unwrapFindType(QualType T,const HeuristicResolver * H)1952 static llvm::SmallVector<QualType> unwrapFindType(
1953 QualType T, const HeuristicResolver* H) {
1954 llvm::SmallVector<QualType> Result;
1955 unwrapFindType(T, H, Result);
1956 return Result;
1957 }
1958
1959
findType(ParsedAST & AST,Position Pos)1960 std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos) {
1961 const SourceManager &SM = AST.getSourceManager();
1962 auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);
1963 std::vector<LocatedSymbol> Result;
1964 if (!Offset) {
1965 elog("failed to convert position {0} for findTypes: {1}", Pos,
1966 Offset.takeError());
1967 return Result;
1968 }
1969 // The general scheme is: position -> AST node -> type -> declaration.
1970 auto SymbolsFromNode =
1971 [&AST](const SelectionTree::Node *N) -> std::vector<LocatedSymbol> {
1972 std::vector<LocatedSymbol> LocatedSymbols;
1973
1974 // NOTE: unwrapFindType might return duplicates for something like
1975 // unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some
1976 // information about the type you may have not known before
1977 // (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).
1978 for (const QualType& Type : unwrapFindType(typeForNode(N), AST.getHeuristicResolver()))
1979 llvm::copy(locateSymbolForType(AST, Type), std::back_inserter(LocatedSymbols));
1980
1981 return LocatedSymbols;
1982 };
1983 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,
1984 *Offset, [&](SelectionTree ST) {
1985 Result = SymbolsFromNode(ST.commonAncestor());
1986 return !Result.empty();
1987 });
1988 return Result;
1989 }
1990
typeParents(const CXXRecordDecl * CXXRD)1991 std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {
1992 std::vector<const CXXRecordDecl *> Result;
1993
1994 // If this is an invalid instantiation, instantiation of the bases
1995 // may not have succeeded, so fall back to the template pattern.
1996 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
1997 if (CTSD->isInvalidDecl())
1998 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
1999 }
2000
2001 // Can't query bases without a definition.
2002 if (!CXXRD->hasDefinition())
2003 return Result;
2004
2005 for (auto Base : CXXRD->bases()) {
2006 const CXXRecordDecl *ParentDecl = nullptr;
2007
2008 const Type *Type = Base.getType().getTypePtr();
2009 if (const RecordType *RT = Type->getAs<RecordType>()) {
2010 ParentDecl = RT->getAsCXXRecordDecl();
2011 }
2012
2013 if (!ParentDecl) {
2014 // Handle a dependent base such as "Base<T>" by using the primary
2015 // template.
2016 if (const TemplateSpecializationType *TS =
2017 Type->getAs<TemplateSpecializationType>()) {
2018 TemplateName TN = TS->getTemplateName();
2019 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2020 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2021 }
2022 }
2023 }
2024
2025 if (ParentDecl)
2026 Result.push_back(ParentDecl);
2027 }
2028
2029 return Result;
2030 }
2031
2032 std::vector<TypeHierarchyItem>
getTypeHierarchy(ParsedAST & AST,Position Pos,int ResolveLevels,TypeHierarchyDirection Direction,const SymbolIndex * Index,PathRef TUPath)2033 getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
2034 TypeHierarchyDirection Direction, const SymbolIndex *Index,
2035 PathRef TUPath) {
2036 std::vector<TypeHierarchyItem> Results;
2037 for (const auto *CXXRD : findRecordTypeAt(AST, Pos)) {
2038
2039 bool WantChildren = Direction == TypeHierarchyDirection::Children ||
2040 Direction == TypeHierarchyDirection::Both;
2041
2042 // If we're looking for children, we're doing the lookup in the index.
2043 // The index does not store relationships between implicit
2044 // specializations, so if we have one, use the template pattern instead.
2045 // Note that this needs to be done before the declToTypeHierarchyItem(),
2046 // otherwise the type hierarchy item would misleadingly contain the
2047 // specialization parameters, while the children would involve classes
2048 // that derive from other specializations of the template.
2049 if (WantChildren) {
2050 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2051 CXXRD = CTSD->getTemplateInstantiationPattern();
2052 }
2053
2054 Optional<TypeHierarchyItem> Result =
2055 declToTypeHierarchyItem(*CXXRD, TUPath);
2056 if (!Result)
2057 continue;
2058
2059 RecursionProtectionSet RPSet;
2060 fillSuperTypes(*CXXRD, TUPath, *Result, RPSet);
2061
2062 if (WantChildren && ResolveLevels > 0) {
2063 Result->children.emplace();
2064
2065 if (Index) {
2066 if (auto ID = getSymbolID(CXXRD))
2067 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2068 }
2069 }
2070 Results.emplace_back(std::move(*Result));
2071 }
2072
2073 return Results;
2074 }
2075
2076 llvm::Optional<std::vector<TypeHierarchyItem>>
superTypes(const TypeHierarchyItem & Item,const SymbolIndex * Index)2077 superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index) {
2078 std::vector<TypeHierarchyItem> Results;
2079 if (!Item.data.parents)
2080 return llvm::None;
2081 if (Item.data.parents->empty())
2082 return Results;
2083 LookupRequest Req;
2084 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2085 for (const auto &Parent : *Item.data.parents) {
2086 Req.IDs.insert(Parent.symbolID);
2087 IDToData[Parent.symbolID] = &Parent;
2088 }
2089 Index->lookup(Req, [&Item, &Results, &IDToData](const Symbol &S) {
2090 if (auto THI = symbolToTypeHierarchyItem(S, Item.uri.file())) {
2091 THI->data = *IDToData.lookup(S.ID);
2092 Results.emplace_back(std::move(*THI));
2093 }
2094 });
2095 return Results;
2096 }
2097
subTypes(const TypeHierarchyItem & Item,const SymbolIndex * Index)2098 std::vector<TypeHierarchyItem> subTypes(const TypeHierarchyItem &Item,
2099 const SymbolIndex *Index) {
2100 std::vector<TypeHierarchyItem> Results;
2101 fillSubTypes(Item.data.symbolID, Results, Index, 1, Item.uri.file());
2102 for (auto &ChildSym : Results)
2103 ChildSym.data.parents = {Item.data};
2104 return Results;
2105 }
2106
resolveTypeHierarchy(TypeHierarchyItem & Item,int ResolveLevels,TypeHierarchyDirection Direction,const SymbolIndex * Index)2107 void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
2108 TypeHierarchyDirection Direction,
2109 const SymbolIndex *Index) {
2110 // We only support typeHierarchy/resolve for children, because for parents
2111 // we ignore ResolveLevels and return all levels of parents eagerly.
2112 if (!Index || Direction == TypeHierarchyDirection::Parents ||
2113 ResolveLevels == 0)
2114 return;
2115
2116 Item.children.emplace();
2117 fillSubTypes(Item.data.symbolID, *Item.children, Index, ResolveLevels,
2118 Item.uri.file());
2119 }
2120
2121 std::vector<CallHierarchyItem>
prepareCallHierarchy(ParsedAST & AST,Position Pos,PathRef TUPath)2122 prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath) {
2123 std::vector<CallHierarchyItem> Result;
2124 const auto &SM = AST.getSourceManager();
2125 auto Loc = sourceLocationInMainFile(SM, Pos);
2126 if (!Loc) {
2127 elog("prepareCallHierarchy failed to convert position to source location: "
2128 "{0}",
2129 Loc.takeError());
2130 return Result;
2131 }
2132 for (const NamedDecl *Decl : getDeclAtPosition(AST, *Loc, {})) {
2133 if (!(isa<DeclContext>(Decl) &&
2134 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2135 Decl->getKind() != Decl::Kind::FunctionTemplate)
2136 continue;
2137 if (auto CHI = declToCallHierarchyItem(*Decl))
2138 Result.emplace_back(std::move(*CHI));
2139 }
2140 return Result;
2141 }
2142
2143 std::vector<CallHierarchyIncomingCall>
incomingCalls(const CallHierarchyItem & Item,const SymbolIndex * Index)2144 incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
2145 std::vector<CallHierarchyIncomingCall> Results;
2146 if (!Index || Item.data.empty())
2147 return Results;
2148 auto ID = SymbolID::fromStr(Item.data);
2149 if (!ID) {
2150 elog("incomingCalls failed to find symbol: {0}", ID.takeError());
2151 return Results;
2152 }
2153 // In this function, we find incoming calls based on the index only.
2154 // In principle, the AST could have more up-to-date information about
2155 // occurrences within the current file. However, going from a SymbolID
2156 // to an AST node isn't cheap, particularly when the declaration isn't
2157 // in the main file.
2158 // FIXME: Consider also using AST information when feasible.
2159 RefsRequest Request;
2160 Request.IDs.insert(*ID);
2161 Request.WantContainer = true;
2162 // We could restrict more specifically to calls by introducing a new RefKind,
2163 // but non-call references (such as address-of-function) can still be
2164 // interesting as they can indicate indirect calls.
2165 Request.Filter = RefKind::Reference;
2166 // Initially store the ranges in a map keyed by SymbolID of the caller.
2167 // This allows us to group different calls with the same caller
2168 // into the same CallHierarchyIncomingCall.
2169 llvm::DenseMap<SymbolID, std::vector<Range>> CallsIn;
2170 // We can populate the ranges based on a refs request only. As we do so, we
2171 // also accumulate the container IDs into a lookup request.
2172 LookupRequest ContainerLookup;
2173 Index->refs(Request, [&](const Ref &R) {
2174 auto Loc = indexToLSPLocation(R.Location, Item.uri.file());
2175 if (!Loc) {
2176 elog("incomingCalls failed to convert location: {0}", Loc.takeError());
2177 return;
2178 }
2179 auto It = CallsIn.try_emplace(R.Container, std::vector<Range>{}).first;
2180 It->second.push_back(Loc->range);
2181
2182 ContainerLookup.IDs.insert(R.Container);
2183 });
2184 // Perform the lookup request and combine its results with CallsIn to
2185 // get complete CallHierarchyIncomingCall objects.
2186 Index->lookup(ContainerLookup, [&](const Symbol &Caller) {
2187 auto It = CallsIn.find(Caller.ID);
2188 assert(It != CallsIn.end());
2189 if (auto CHI = symbolToCallHierarchyItem(Caller, Item.uri.file()))
2190 Results.push_back(
2191 CallHierarchyIncomingCall{std::move(*CHI), std::move(It->second)});
2192 });
2193 // Sort results by name of container.
2194 llvm::sort(Results, [](const CallHierarchyIncomingCall &A,
2195 const CallHierarchyIncomingCall &B) {
2196 return A.from.name < B.from.name;
2197 });
2198 return Results;
2199 }
2200
getNonLocalDeclRefs(ParsedAST & AST,const FunctionDecl * FD)2201 llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
2202 const FunctionDecl *FD) {
2203 if (!FD->hasBody())
2204 return {};
2205 llvm::DenseSet<const Decl *> DeclRefs;
2206 findExplicitReferences(
2207 FD,
2208 [&](ReferenceLoc Ref) {
2209 for (const Decl *D : Ref.Targets) {
2210 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2211 !Ref.IsDecl)
2212 DeclRefs.insert(D);
2213 }
2214 },
2215 AST.getHeuristicResolver());
2216 return DeclRefs;
2217 }
2218
2219 } // namespace clangd
2220 } // namespace clang
2221