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