26#include "clang/AST/ASTContext.h"
27#include "clang/AST/ASTTypeTraits.h"
28#include "clang/AST/Attr.h"
29#include "clang/AST/Attrs.inc"
30#include "clang/AST/Decl.h"
31#include "clang/AST/DeclCXX.h"
32#include "clang/AST/DeclObjC.h"
33#include "clang/AST/DeclTemplate.h"
34#include "clang/AST/DeclVisitor.h"
35#include "clang/AST/ExprCXX.h"
36#include "clang/AST/RecursiveASTVisitor.h"
37#include "clang/AST/Stmt.h"
38#include "clang/AST/StmtCXX.h"
39#include "clang/AST/StmtVisitor.h"
40#include "clang/AST/Type.h"
41#include "clang/Basic/LLVM.h"
42#include "clang/Basic/LangOptions.h"
43#include "clang/Basic/SourceLocation.h"
44#include "clang/Basic/SourceManager.h"
45#include "clang/Basic/TokenKinds.h"
46#include "clang/Index/IndexDataConsumer.h"
47#include "clang/Index/IndexSymbol.h"
48#include "clang/Index/IndexingAction.h"
49#include "clang/Index/IndexingOptions.h"
50#include "clang/Index/USRGeneration.h"
51#include "clang/Tooling/Syntax/Tokens.h"
52#include "llvm/ADT/ArrayRef.h"
53#include "llvm/ADT/DenseMap.h"
54#include "llvm/ADT/STLExtras.h"
55#include "llvm/ADT/ScopeExit.h"
56#include "llvm/ADT/SmallSet.h"
57#include "llvm/ADT/SmallVector.h"
58#include "llvm/ADT/StringRef.h"
59#include "llvm/Support/Casting.h"
60#include "llvm/Support/Error.h"
61#include "llvm/Support/Path.h"
62#include "llvm/Support/raw_ostream.h"
76const NamedDecl *getDefinition(
const NamedDecl *D) {
79 if (
const auto *TD = dyn_cast<TagDecl>(D))
80 return TD->getDefinition();
81 if (
const auto *VD = dyn_cast<VarDecl>(D))
82 return VD->getDefinition();
83 if (
const auto *FD = dyn_cast<FunctionDecl>(D))
84 return FD->getDefinition();
85 if (
const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
86 if (
const auto *RD = CTD->getTemplatedDecl())
87 return RD->getDefinition();
88 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
89 if (MD->isThisDeclarationADefinition())
92 auto *DeclCtx = cast<Decl>(MD->getDeclContext());
93 if (DeclCtx->isInvalidDecl())
96 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
98 return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
100 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(D))
103 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
104 isa<TemplateTemplateParmDecl>(D))
110void logIfOverflow(
const SymbolLocation &
Loc) {
111 if (
Loc.Start.hasOverflow() ||
Loc.End.hasOverflow())
112 log(
"Possible overflow in symbol location: {0}",
Loc);
119std::optional<Location> toLSPLocation(
const SymbolLocation &
Loc,
120 llvm::StringRef TUPath) {
125 elog(
"Could not parse URI {0}: {1}",
Loc.FileURI, Uri.takeError());
130 elog(
"Could not resolve URI {0}: {1}",
Loc.FileURI, U.takeError());
135 LSPLoc.uri = std::move(*U);
136 LSPLoc.range.start.line =
Loc.Start.line();
137 LSPLoc.range.start.character =
Loc.Start.column();
138 LSPLoc.range.end.line =
Loc.End.line();
139 LSPLoc.range.end.character =
Loc.End.column();
144SymbolLocation toIndexLocation(
const Location &
Loc, std::string &URIStorage) {
145 SymbolLocation SymLoc;
146 URIStorage =
Loc.uri.uri();
147 SymLoc.FileURI = URIStorage.c_str();
148 SymLoc.Start.setLine(
Loc.range.start.line);
149 SymLoc.Start.setColumn(
Loc.range.start.character);
150 SymLoc.End.setLine(
Loc.range.end.line);
151 SymLoc.End.setColumn(
Loc.range.end.character);
156SymbolLocation getPreferredLocation(
const Location &ASTLoc,
157 const SymbolLocation &IdxLoc,
158 std::string &Scratch) {
161 Symbol ASTSym, IdxSym;
162 ASTSym.ID = IdxSym.ID =
SymbolID(
"mock_symbol_id");
163 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
164 IdxSym.CanonicalDeclaration = IdxLoc;
166 return Merged.CanonicalDeclaration;
169std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
170getDeclAtPositionWithRelations(ParsedAST &
AST, SourceLocation
Pos,
171 DeclRelationSet Relations,
172 ASTNodeKind *NodeKind =
nullptr) {
173 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(
Pos).second;
174 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
175 auto ResultFromTree = [&](SelectionTree ST) {
176 if (
const SelectionTree::Node *N = ST.commonAncestor()) {
178 *NodeKind = N->ASTNode.getNodeKind();
183 if (N->ASTNode.get<Attr>() && N->Parent)
186 std::back_inserter(Result),
187 [&](
auto &
Entry) {
return !(
Entry.second & ~Relations); });
189 return !Result.empty();
196std::vector<const NamedDecl *>
197getDeclAtPosition(ParsedAST &
AST, SourceLocation
Pos, DeclRelationSet Relations,
198 ASTNodeKind *NodeKind =
nullptr) {
199 std::vector<const NamedDecl *> Result;
201 getDeclAtPositionWithRelations(
AST,
Pos, Relations, NodeKind))
202 Result.push_back(
Entry.first);
208std::optional<Location> makeLocation(
const ASTContext &
AST, SourceLocation
Loc,
209 llvm::StringRef TUPath) {
210 const auto &SM =
AST.getSourceManager();
211 const FileEntry *F = SM.getFileEntryForID(SM.getFileID(
Loc));
216 log(
"failed to get path!");
223 auto TokLen = Lexer::MeasureTokenLength(
Loc, SM,
AST.getLangOpts());
225 SM, CharSourceRange::getCharRange(
Loc,
Loc.getLocWithOffset(TokLen)));
230std::optional<LocatedSymbol> locateFileReferent(
const Position &
Pos,
232 llvm::StringRef MainFilePath) {
233 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
234 if (!Inc.Resolved.empty() && Inc.HashLine ==
Pos.line) {
236 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
237 File.PreferredDeclaration = {
239 File.Definition =
File.PreferredDeclaration;
249std::optional<LocatedSymbol>
250locateMacroReferent(
const syntax::Token &TouchedIdentifier, ParsedAST &
AST,
251 llvm::StringRef MainFilePath) {
254 makeLocation(
AST.getASTContext(),
M->NameLoc, MainFilePath)) {
256 Macro.Name = std::string(
M->Name);
279const NamedDecl *getPreferredDecl(
const NamedDecl *D) {
284 D = llvm::cast<NamedDecl>(
D->getCanonicalDecl());
287 if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
288 if (
const auto *DefinitionID = ID->getDefinition())
290 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
291 if (
const auto *DefinitionID = PD->getDefinition())
297std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
299 const SymbolIndex *Index,
300 llvm::StringRef MainFilePath) {
301 if (IDs.empty() || !Index)
303 static constexpr trace::Metric FindImplementorsMetric(
307 FindImplementorsMetric.record(1,
"find-base");
310 FindImplementorsMetric.record(1,
"find-override");
314 RelationsRequest Req;
315 Req.Predicate = Predicate;
316 Req.Subjects = std::move(IDs);
317 std::vector<LocatedSymbol>
Results;
318 Index->
relations(Req, [&](
const SymbolID &Subject,
const Symbol &
Object) {
322 elog(
"Find overrides: {0}", DeclLoc.takeError());
327 Results.back().PreferredDeclaration = *DeclLoc;
330 elog(
"Failed to convert location: {0}", DefLoc.takeError());
333 Results.back().Definition = *DefLoc;
342std::vector<LocatedSymbol>
343locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
344 ParsedAST &
AST, llvm::StringRef MainFilePath,
345 const SymbolIndex *Index, ASTNodeKind &NodeKind) {
346 const SourceManager &SM =
AST.getSourceManager();
348 std::vector<LocatedSymbol> Result;
350 llvm::DenseMap<SymbolID, size_t> ResultIndex;
352 static constexpr trace::Metric LocateASTReferentMetric(
354 auto AddResultDecl = [&](
const NamedDecl *
D) {
355 D = getPreferredDecl(D);
361 Result.emplace_back();
362 Result.back().Name =
printName(
AST.getASTContext(), *D);
363 Result.back().PreferredDeclaration = *
Loc;
365 if (
const NamedDecl *Def = getDefinition(D))
366 Result.back().Definition = makeLocation(
371 ResultIndex[ID] = Result.size() - 1;
375 DeclRelationSet Relations =
378 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
379 llvm::DenseSet<SymbolID> VirtualMethods;
380 for (
const auto &
E : Candidates) {
381 const NamedDecl *
D =
E.first;
382 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
387 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
388 TouchedIdentifier->location()) {
390 LocateASTReferentMetric.record(1,
"method-to-override");
394 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
395 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
397 for (
const NamedDecl *ND : CMD->overridden_methods())
410 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
412 D->getBeginLoc(),
D->getEndLoc()))
417 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
418 if (TouchedIdentifier &&
419 D->getLocation() == TouchedIdentifier->location()) {
420 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
421 AddResultDecl(CTSD->getSpecializedTemplate());
432 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
433 if (
const auto *ID = CD->getClassInterface())
434 if (TouchedIdentifier &&
435 (CD->getLocation() == TouchedIdentifier->location() ||
436 ID->getName() == TouchedIdentifier->text(SM))) {
437 LocateASTReferentMetric.record(1,
"objc-category-to-class");
441 LocateASTReferentMetric.record(1,
"regular");
447 if (Index && !ResultIndex.empty()) {
448 LookupRequest QueryRequest;
449 for (
auto It : ResultIndex)
450 QueryRequest.IDs.insert(It.first);
452 Index->
lookup(QueryRequest, [&](
const Symbol &Sym) {
453 auto &R = Result[ResultIndex.lookup(Sym.ID)];
458 if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
459 R.PreferredDeclaration = *Loc;
463 if (auto Loc = toLSPLocation(
464 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
468 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
471 if (auto Loc = toLSPLocation(
472 getPreferredLocation(R.PreferredDeclaration,
473 Sym.CanonicalDeclaration, Scratch),
475 R.PreferredDeclaration = *Loc;
481 Index, MainFilePath);
482 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
486std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
487 const QualType &
Type) {
488 const auto &SM =
AST.getSourceManager();
489 auto MainFilePath =
AST.tuPath();
493 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
495 AST.getHeuristicResolver());
499 std::vector<LocatedSymbol>
Results;
500 const auto &ASTContext =
AST.getASTContext();
502 for (
const NamedDecl *D : Decls) {
503 D = getPreferredDecl(D);
505 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
513 if (
const NamedDecl *Def = getDefinition(D))
515 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
521bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
522 auto ExpandedTokens = TB.expandedTokens(
523 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
524 return !ExpandedTokens.empty();
527llvm::StringRef sourcePrefix(SourceLocation
Loc,
const SourceManager &SM) {
528 auto D = SM.getDecomposedLoc(
Loc);
530 llvm::StringRef Buf = SM.getBufferData(
D.first, &Invalid);
531 if (Invalid ||
D.second > Buf.size())
533 return Buf.substr(0,
D.second);
536bool isDependentName(ASTNodeKind NodeKind) {
537 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
539 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
541 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
549 llvm::StringRef MainFilePath,
550 ASTNodeKind NodeKind) {
555 if ((
Word.ExpandedToken && !isDependentName(NodeKind)) ||
556 !
Word.LikelyIdentifier || !Index)
560 if (
Word.PartOfSpelledToken &&
561 isStringLiteral(
Word.PartOfSpelledToken->kind()))
564 const auto &SM =
AST.getSourceManager();
578 bool TooMany =
false;
579 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
580 std::vector<ScoredLocatedSymbol> ScoredResults;
591 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
597 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
607 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
614 if (ScoredResults.size() >= 5) {
627 Relevance.
merge(Sym);
630 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
633 ScoredResults.push_back({
Score, std::move(Located)});
637 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
642 llvm::sort(ScoredResults,
643 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
644 return A.first > B.first;
646 std::vector<LocatedSymbol>
Results;
647 for (
auto &Res : std::move(ScoredResults))
648 Results.push_back(std::move(Res.second));
650 vlog(
"No heuristic index definition for {0}",
Word.Text);
652 log(
"Found definition heuristically in index for {0}",
Word.Text);
657 const syntax::TokenBuffer &TB) {
660 if (
Word.ExpandedToken)
664 if (
Word.PartOfSpelledToken &&
665 isStringLiteral(
Word.PartOfSpelledToken->kind()))
668 const SourceManager &SM = TB.sourceManager();
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);
678 const syntax::Token *BestTok =
nullptr;
679 unsigned BestCost = -1;
683 unsigned MaxDistance =
684 1U << std::min<unsigned>(
Word.Text.size(),
685 std::numeric_limits<unsigned>::digits - 1);
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());
701 auto Consider = [&](
const syntax::Token &Tok) {
702 if (Tok.location() < LocMin || Tok.location() > LocMax)
704 if (!(Tok.kind() == tok::identifier && Tok.text(SM) ==
Word.Text))
707 if (Tok.location() ==
Word.Location)
710 unsigned TokCost = Cost(Tok.location());
711 if (TokCost >= BestCost)
715 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
722 auto SpelledTokens = TB.spelledTokens(
File);
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;
729 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
733 for (
const syntax::Token &Tok :
734 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
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));
749 const auto &SM =
AST.getSourceManager();
750 auto MainFilePath =
AST.tuPath();
752 if (
auto File = locateFileReferent(
Pos,
AST, MainFilePath))
753 return {std::move(*
File)};
757 elog(
"locateSymbolAt failed to convert position to source location: {0}",
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))
771 return {*std::move(
Macro)};
773 TouchedIdentifier = &Tok;
777 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
781 auto LocSym = locateSymbolForType(
AST, *
Deduced);
788 ASTNodeKind NodeKind;
789 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
790 MainFilePath, Index, NodeKind);
791 if (!ASTResults.empty())
799 if (
const syntax::Token *NearbyIdent =
801 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
802 log(
"Found macro definition heuristically using nearby identifier {0}",
804 return {*std::move(
Macro)};
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));
813 vlog(
"No definition found using nearby identifier {0} at {1}",
Word->Text,
814 Word->Location.printToString(SM));
817 auto TextualResults =
819 if (!TextualResults.empty())
820 return TextualResults;
827 const auto &SM =
AST.getSourceManager();
829 std::vector<DocumentLink> Result;
830 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
831 if (Inc.Resolved.empty())
833 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
834 const auto *HashTok =
AST.getTokens().spelledTokenAt(HashLoc);
835 assert(HashTok &&
"got inclusion at wrong offset");
836 const auto *IncludeTok = std::next(HashTok);
837 const auto *FileTok = std::next(IncludeTok);
842 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
856class ReferenceFinder :
public index::IndexDataConsumer {
863 Range range(
const SourceManager &SM)
const {
868 ReferenceFinder(
const ParsedAST &AST,
869 const llvm::ArrayRef<const NamedDecl *> Targets,
871 : PerToken(PerToken), AST(AST) {
872 for (
const NamedDecl *ND : Targets)
873 TargetDecls.insert(ND->getCanonicalDecl());
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);
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);
891 return std::move(References);
895 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
896 llvm::ArrayRef<index::SymbolRelation> Relations,
898 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
899 if (!TargetDecls.contains(
D->getCanonicalDecl()))
901 const SourceManager &SM = AST.getSourceManager();
904 const auto &TB = AST.getTokens();
906 llvm::SmallVector<SourceLocation, 1> Locs;
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);
918 if (!Locs.empty() && Locs.front() !=
Loc)
926 for (SourceLocation L : Locs) {
927 L = SM.getFileLoc(L);
928 if (
const auto *Tok = TB.spelledTokenAt(L))
939 const ParsedAST &AST;
940 llvm::DenseSet<const Decl *> TargetDecls;
943std::vector<ReferenceFinder::Reference>
944findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls, ParsedAST &
AST,
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();
958const 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();
970const 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();
994 All = Break | Continue | Return | Case | Throw | Goto,
998 std::vector<SourceLocation> &Result;
999 const SourceManager &SM;
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))
1009 else if (getLoopBody(D))
1010 Ignore |= Continue | Break;
1011 else if (
D.get<SwitchStmt>())
1012 Ignore |= Break | Case;
1014 return (Ignore == All) ? true : Delegate();
1017 void found(Target T, SourceLocation
Loc) {
1020 if (SM.isBeforeInTranslationUnit(
Loc,
Bounds.getBegin()) ||
1021 SM.isBeforeInTranslationUnit(
Bounds.getEnd(),
Loc))
1023 Result.push_back(
Loc);
1027 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1028 const SourceManager &SM)
1033 bool TraverseDecl(
Decl *D) {
1034 return !
D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1035 return RecursiveASTVisitor::TraverseDecl(D);
1038 bool TraverseStmt(Stmt *S) {
1039 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1040 return RecursiveASTVisitor::TraverseStmt(S);
1045 bool VisitReturnStmt(ReturnStmt *R) {
1046 found(Return, R->getReturnLoc());
1049 bool VisitBreakStmt(BreakStmt *B) {
1050 found(Break,
B->getBreakLoc());
1053 bool VisitContinueStmt(ContinueStmt *
C) {
1054 found(Continue,
C->getContinueLoc());
1057 bool VisitSwitchCase(SwitchCase *
C) {
1058 found(Case,
C->getKeywordLoc());
1061 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1062 found(Throw, T->getThrowLoc());
1065 bool VisitGotoStmt(GotoStmt *G) {
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());
1079SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation
Loc,
1080 const SourceManager &SM) {
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());
1092 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *
C) {
1093 return !SM.isBeforeInTranslationUnit(
Loc,
C->getKeywordLoc());
1095 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1096 : (*CaseAfter)->getKeywordLoc();
1099 if (CaseAfter == Cases.begin())
1100 return SourceRange(Switch.getBeginLoc(), End);
1102 auto CaseBefore = std::prev(CaseAfter);
1104 while (CaseBefore != Cases.begin() &&
1105 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1107 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1117std::vector<SourceLocation> relatedControlFlow(
const SelectionTree::Node &N) {
1118 const SourceManager &SM =
1119 N.getDeclContext().getParentASTContext().getSourceManager();
1120 std::vector<SourceLocation> Result;
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>()) {
1134 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1136 Result.push_back(GS->getGotoLoc());
1137 if (
const auto *LD = GS->getLabel())
1138 Result.push_back(LD->getLocation());
1144 const Stmt *
Root =
nullptr;
1147 for (
const auto *P = &N; P; P = P->Parent) {
1149 if (
const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
1150 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1151 Root = FunctionBody;
1156 if (
const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
1157 if (Cursor == Cur::None || Cursor == Cur::Break ||
1158 Cursor == Cur::Continue) {
1162 Result.push_back(P->ASTNode.getSourceRange().getBegin());
1169 if (
const auto *SS = P->ASTNode.get<SwitchStmt>()) {
1170 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1171 Result.push_back(SS->getSwitchLoc());
1172 Root = SS->getBody();
1174 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1179 if (Cursor == Cur::None)
1185 FindControlFlow(
Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(
Root));
1190DocumentHighlight 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))
1196 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1203std::optional<DocumentHighlight> toHighlight(SourceLocation
Loc,
1204 const syntax::TokenBuffer &TB) {
1205 Loc = TB.sourceManager().getFileLoc(
Loc);
1206 if (
const auto *Tok = TB.spelledTokenAt(
Loc)) {
1207 DocumentHighlight Result;
1210 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1213 return std::nullopt;
1220 const SourceManager &SM =
AST.getSourceManager();
1224 llvm::consumeError(CurLoc.takeError());
1227 std::vector<DocumentHighlight> Result;
1233 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1234 if (!TargetDecls.empty()) {
1237 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1238 Result.push_back(toHighlight(
Ref, SM));
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));
1253 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1266 const SourceManager &SM =
AST.getSourceManager();
1269 elog(
"Failed to convert position to source location: {0}",
1270 CurLoc.takeError());
1275 llvm::DenseSet<SymbolID> IDs;
1277 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1278 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1279 if (CXXMD->isVirtual()) {
1283 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1288 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1294void getOverriddenMethods(
const CXXMethodDecl *CMD,
1295 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1298 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1300 OverriddenMethods.insert(ID);
1301 getOverriddenMethods(Base, OverriddenMethods);
1305std::optional<std::string>
1309 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(
Container))
1318 const SourceManager &SM =
AST.getSourceManager();
1319 auto MainFilePath =
AST.tuPath();
1323 llvm::consumeError(CurLoc.takeError());
1327 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1329 const auto *IdentifierAtCursor =
1330 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1331 std::optional<DefinedMacro>
Macro;
1332 if (IdentifierAtCursor)
1338 const auto &IDToRefs =
AST.getMacros().MacroRefs;
1339 auto Refs = IDToRefs.find(MacroSID);
1340 if (Refs != IDToRefs.end()) {
1341 for (
const auto &
Ref : Refs->second) {
1343 Result.Loc.range =
Ref.Rng;
1344 Result.Loc.uri = URIMainFile;
1345 if (
Ref.IsDefinition) {
1349 Results.References.push_back(std::move(Result));
1352 IDsToQuery.insert(MacroSID);
1359 std::vector<const NamedDecl *> Decls =
1360 getDeclAtPosition(
AST, *CurLoc, Relations);
1361 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1362 for (
const NamedDecl *D : Decls) {
1366 TargetsInMainFile.push_back(D);
1370 if (D->getParentFunctionOrMethod())
1372 IDsToQuery.insert(ID);
1378 for (
const NamedDecl *ND : Decls) {
1381 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1382 if (CMD->isVirtual()) {
1385 getOverriddenMethods(CMD, OverriddenMethods);
1392 auto MainFileRefs = findRefs(TargetsInMainFile,
AST,
false);
1396 MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
1397 [](
const ReferenceFinder::Reference &L,
1398 const ReferenceFinder::Reference &R) {
1399 return L.SpelledTok.location() ==
1400 R.SpelledTok.location();
1402 MainFileRefs.end());
1403 for (
const auto &
Ref : MainFileRefs) {
1405 Result.Loc.range =
Ref.range(SM);
1406 Result.Loc.uri = URIMainFile;
1408 Result.Loc.containerName =
1410 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1413 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1414 Result.Attributes |=
1416 Results.References.push_back(std::move(Result));
1424 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1427 if (Limit &&
Results.References.size() >= Limit) {
1428 Results.HasMore = true;
1431 const auto LSPLocDecl =
1432 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1433 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1434 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1436 Result.Loc = {std::move(*LSPLocDecl), std::nullopt};
1439 RefIndexForContainer.insert({
Object.ID,
Results.References.size()});
1441 Results.References.push_back(std::move(Result));
1445 Result.Loc = {std::move(*LSPLocDef), std::nullopt};
1449 RefIndexForContainer.insert({
Object.ID,
Results.References.size()});
1451 Results.References.push_back(std::move(Result));
1455 if (!ContainerLookup.
IDs.empty() && AddContext)
1458 assert(
Ref != RefIndexForContainer.end());
1459 Results.References[
Ref->getSecond()].Loc.containerName =
1465 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1466 bool AllowMainFileSymbols) {
1467 if (IDs.empty() || !Index ||
Results.HasMore)
1470 Req.
IDs = std::move(IDs);
1472 if (Limit <
Results.References.size()) {
1482 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1484 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1487 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1490 Result.Loc = {std::move(*LSPLoc), std::nullopt};
1491 if (AllowAttributes) {
1496 Result.Attributes |=
1504 Results.References.push_back(std::move(Result));
1507 if (!ContainerLookup.
IDs.empty() && AddContext)
1510 assert(
Ref != RefIndicesForContainer.end());
1512 for (
auto I :
Ref->getSecond()) {
1513 Results.References[I].Loc.containerName = ContainerName;
1517 QueryIndex(std::move(IDsToQuery),
true,
1522 QueryIndex(std::move(OverriddenMethods),
false,
1528 const SourceManager &SM =
AST.getSourceManager();
1531 llvm::consumeError(CurLoc.takeError());
1534 auto MainFilePath =
AST.tuPath();
1535 std::vector<SymbolDetails>
Results;
1541 for (
const NamedDecl *D : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1542 D = getPreferredDecl(D);
1548 NewSymbol.
name = std::string(SplitQName.second);
1551 if (
const auto *ParentND =
1552 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1555 llvm::SmallString<32>
USR;
1556 if (!index::generateUSRForDecl(D,
USR)) {
1557 NewSymbol.
USR = std::string(
USR.str());
1560 if (
const NamedDecl *Def = getDefinition(D))
1564 makeLocation(
AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1566 Results.push_back(std::move(NewSymbol));
1569 const auto *IdentifierAtCursor =
1570 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1571 if (!IdentifierAtCursor)
1576 NewMacro.
name = std::string(
M->Name);
1577 llvm::SmallString<32>
USR;
1578 if (!index::generateUSRForMacro(NewMacro.
name,
M->Info->getDefinitionLoc(),
1580 NewMacro.
USR = std::string(
USR.str());
1583 Results.push_back(std::move(NewMacro));
1604 OS <<
" [override]";
1608template <
typename HierarchyItem>
1609static std::optional<HierarchyItem>
1611 ASTContext &Ctx = ND.getASTContext();
1612 auto &SM = Ctx.getSourceManager();
1613 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1614 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1615 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1616 const auto DeclRange =
1619 return std::nullopt;
1623 return std::nullopt;
1627 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1629 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1639 HI.selectionRange =
Range{NameBegin, NameEnd};
1640 if (!HI.range.contains(HI.selectionRange)) {
1643 HI.range = HI.selectionRange;
1651static std::optional<TypeHierarchyItem>
1653 auto Result = declToHierarchyItem<TypeHierarchyItem>(ND, TUPath);
1655 Result->deprecated = ND.isDeprecated();
1665static std::optional<CallHierarchyItem>
1667 auto Result = declToHierarchyItem<CallHierarchyItem>(ND, TUPath);
1670 if (ND.isDeprecated())
1673 Result->data = ID.str();
1677template <
typename HierarchyItem>
1682 elog(
"Failed to convert symbol to hierarchy item: {0}",
Loc.takeError());
1683 return std::nullopt;
1686 HI.name = std::string(S.
Name);
1688 HI.selectionRange =
Loc->range;
1691 HI.range = HI.selectionRange;
1697static std::optional<TypeHierarchyItem>
1699 auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);
1702 Result->data.symbolID = S.
ID;
1707static std::optional<CallHierarchyItem>
1709 auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);
1712 Result->data = S.
ID.
str();
1719 std::vector<TypeHierarchyItem> &SubTypes,
1725 if (std::optional<TypeHierarchyItem> ChildSym =
1728 ChildSym->children.emplace();
1731 SubTypes.emplace_back(std::move(*ChildSym));
1749 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
1751 if (!RPSet.insert(Pattern).second) {
1756 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
1757 if (std::optional<TypeHierarchyItem> ParentSym =
1761 Item.
parents->emplace_back(std::move(*ParentSym));
1766 RPSet.erase(Pattern);
1773 std::vector<const CXXRecordDecl *> Records;
1782 AST.getHeuristicResolver());
1783 for (
const NamedDecl *D : Decls) {
1785 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1787 Records.push_back(VD->getType().getTypePtr()->getAsCXXRecordDecl());
1791 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
1793 Records.push_back(
Method->getParent());
1801 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
1802 Records.push_back(RD);
1807 const SourceManager &SM =
AST.getSourceManager();
1808 std::vector<const CXXRecordDecl *> Result;
1811 llvm::consumeError(
Offset.takeError());
1816 Result = RecordFromNode(ST.commonAncestor());
1817 return !Result.empty();
1827 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
1833 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
1834 if (llvm::isa<DeducedType>(TL->getTypePtr()))
1839 if (llvm::isa<TypedefType>(TL->getTypePtr()))
1840 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1841 return TL->getType();
1845 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
1846 if (
const FieldDecl *FD = CCI->getAnyMember())
1847 return FD->getType();
1848 if (
const Type *Base = CCI->getBaseClass())
1849 return QualType(Base, 0);
1853 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
1854 return CBS->getType();
1857 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
1858 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
1860 QualType VisitTypeDecl(
const TypeDecl *D) {
1861 return QualType(D->getTypeForDecl(), 0);
1864 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
1865 return D->getUnderlyingType();
1868 QualType VisitTemplateDecl(
const TemplateDecl *D) {
1869 return Visit(D->getTemplatedDecl());
1875 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
1876 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
1878 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
1881 QualType VisitExpr(
const Expr *S) {
1882 return S->IgnoreImplicitAsWritten()->getType();
1884 QualType VisitMemberExpr(
const MemberExpr *S) {
1886 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
1887 return Expr::findBoundMemberType(S);
1888 return VisitExpr(S);
1891 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
1892 return S->getDestroyedType();
1894 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
1895 return S->getDestroyedType();
1897 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
1898 return S->getSubExpr()->getType();
1900 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
1901 return type(S->getOperand());
1904 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
1906 for (
auto &D : llvm::reverse(S->designators()))
1907 if (D.isFieldDesignator())
1908 if (
const auto *FD = D.getField())
1909 return FD->getType();
1914 QualType VisitSwitchStmt(
const SwitchStmt *S) {
1915 return type(S->getCond());
1917 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
1918 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
1919 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
1920 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
1921 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1922 return S->getLoopVariable()->getType();
1924 QualType VisitReturnStmt(
const ReturnStmt *S) {
1925 return type(S->getRetValue());
1927 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
1928 return type(S->getOperand());
1930 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
1931 return S->getCaughtType();
1933 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
1934 return type(S->getThrowExpr());
1936 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
1937 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
1955 if (
const auto* TDT = T->getAs<TypedefType>())
1956 return Out.push_back(QualType(TDT, 0));
1959 if (
const auto *PT = T->getAs<PointerType>())
1961 if (
const auto *RT = T->getAs<ReferenceType>())
1963 if (
const auto *AT = T->getAsArrayTypeUnsafe())
1967 if (
auto *FT = T->getAs<FunctionType>())
1969 if (
auto *CRD = T->getAsCXXRecordDecl()) {
1970 if (CRD->isLambda())
1978 if (
const auto* PointeeType = H->getPointeeType(T.getNonReferenceType().getTypePtr())) {
1980 return Out.push_back(T);
1983 return Out.push_back(T);
1989 llvm::SmallVector<QualType> Result;
1996 const SourceManager &SM =
AST.getSourceManager();
1998 std::vector<LocatedSymbol> Result;
2000 elog(
"failed to convert position {0} for findTypes: {1}",
Pos,
2005 auto SymbolsFromNode =
2007 std::vector<LocatedSymbol> LocatedSymbols;
2014 llvm::copy(locateSymbolForType(
AST,
Type), std::back_inserter(LocatedSymbols));
2016 return LocatedSymbols;
2020 Result = SymbolsFromNode(ST.commonAncestor());
2021 return !Result.empty();
2026std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2027 std::vector<const CXXRecordDecl *> Result;
2031 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2032 if (CTSD->isInvalidDecl())
2033 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2037 if (!CXXRD->hasDefinition())
2040 for (
auto Base : CXXRD->bases()) {
2041 const CXXRecordDecl *ParentDecl =
nullptr;
2043 const Type *
Type = Base.getType().getTypePtr();
2044 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2045 ParentDecl = RT->getAsCXXRecordDecl();
2051 if (
const TemplateSpecializationType *TS =
2052 Type->getAs<TemplateSpecializationType>()) {
2053 TemplateName TN = TS->getTemplateName();
2054 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2055 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2061 Result.push_back(ParentDecl);
2067std::vector<TypeHierarchyItem>
2071 std::vector<TypeHierarchyItem>
Results;
2085 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2086 CXXRD = CTSD->getTemplateInstantiationPattern();
2089 std::optional<TypeHierarchyItem> Result =
2097 if (WantChildren && ResolveLevels > 0) {
2098 Result->children.emplace();
2102 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2105 Results.emplace_back(std::move(*Result));
2111std::optional<std::vector<TypeHierarchyItem>>
2113 std::vector<TypeHierarchyItem>
Results;
2115 return std::nullopt;
2119 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2126 THI->data = *IDToData.lookup(S.ID);
2127 Results.emplace_back(std::move(*THI));
2135 std::vector<TypeHierarchyItem>
Results;
2137 for (
auto &ChildSym :
Results)
2138 ChildSym.data.parents = {Item.
data};
2156std::vector<CallHierarchyItem>
2158 std::vector<CallHierarchyItem> Result;
2159 const auto &SM =
AST.getSourceManager();
2162 elog(
"prepareCallHierarchy failed to convert position to source location: "
2167 for (
const NamedDecl *
Decl : getDeclAtPosition(
AST, *
Loc, {})) {
2168 if (!(isa<DeclContext>(
Decl) &&
2169 cast<DeclContext>(
Decl)->isFunctionOrMethod()) &&
2170 Decl->getKind() != Decl::Kind::FunctionTemplate)
2173 Result.emplace_back(std::move(*CHI));
2178std::vector<CallHierarchyIncomingCall>
2180 std::vector<CallHierarchyIncomingCall>
Results;
2181 if (!Index || Item.
data.empty())
2185 elog(
"incomingCalls failed to find symbol: {0}", ID.takeError());
2195 Request.
IDs.insert(*ID);
2204 llvm::DenseMap<SymbolID, std::vector<Range>> CallsIn;
2208 Index->
refs(Request, [&](
const Ref &R) {
2211 elog(
"incomingCalls failed to convert location: {0}",
Loc.takeError());
2214 auto It = CallsIn.try_emplace(R.
Container, std::vector<Range>{}).first;
2215 It->second.push_back(
Loc->range);
2221 Index->
lookup(ContainerLookup, [&](
const Symbol &Caller) {
2222 auto It = CallsIn.find(Caller.
ID);
2223 assert(It != CallsIn.end());
2231 return A.from.name < B.from.name;
2237 const FunctionDecl *FD) {
2240 llvm::DenseSet<const Decl *> DeclRefs;
2244 for (
const Decl *D :
Ref.Targets) {
2245 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2250 AST.getHeuristicResolver());
const FunctionDecl * Decl
std::vector< CodeCompletionResult > Results
SignatureQualitySignals Quality
CompiledFragmentImpl & Out
std::optional< float > Score
CharSourceRange Range
SourceRange for the file name.
const google::protobuf::Message & M
SymbolCollector::Options CollectorOpts
llvm::raw_string_ostream OS
index::SymbolRoleSet Role
Stores and provides access to parsed AST.
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
static const Decl * getRefContainer(const Decl *Enclosing, const SymbolCollector::Options &Opts)
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
virtual bool fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning.
virtual void relations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (S, P, O) stored in the index such that S is among Req.Subjects and P is Req....
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
virtual void lookup(const LookupRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Looks up symbols with any of the given symbol IDs and applies Callback on each matched symbol.
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
llvm::Expected< Location > indexToLSPLocation(const SymbolLocation &Loc, llvm::StringRef TUPath)
Helper function for deriving an LSP Location from an index SymbolLocation.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos)
Returns symbols for types referenced at Pos.
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
std::optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
static std::optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath)
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
static std::optional< CallHierarchyItem > symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath)
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user.
llvm::SmallVector< std::pair< const NamedDecl *, DeclRelationSet >, 1 > allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver)
Similar to targetDecl(), however instead of applying a filter, all possible decls are returned along ...
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
Find declarations explicitly referenced in the source code defined by N.
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, llvm::StringRef MainFilePath, ASTNodeKind NodeKind)
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
llvm::Expected< Location > symbolToLocation(const Symbol &Sym, llvm::StringRef TUPath)
Helper function for deriving an LSP Location for a Symbol.
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
void vlog(const char *Fmt, Ts &&... Vals)
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
static std::optional< TypeHierarchyItem > declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const DynTypedNode &N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
targetDecl() finds the declaration referred to by an AST node.
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath, TypeHierarchyItem &Item, RecursionProtectionSet &RPSet)
llvm::SmallSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
std::optional< DefinedMacro > locateMacroAt(const syntax::Token &SpelledTok, Preprocessor &PP)
Gets the macro referenced by SpelledTok.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const LangOptions &LangOpts)
Heuristically determine namespaces visible at a point, without parsing Code.
static std::optional< HierarchyItem > declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
static QualType typeForNode(const SelectionTree::Node *N)
static void unwrapFindType(QualType T, const HeuristicResolver *H, llvm::SmallVector< QualType > &Out)
static std::optional< HierarchyItem > symbolToHierarchyItem(const Symbol &S, PathRef TUPath)
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
void log(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind)
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
@ Type
An inlay hint that for a type annotation.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void elog(const char *Fmt, Ts &&... Vals)
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
@ TemplatePattern
This is the pattern the template specialization was instantiated from.
@ Alias
This declaration is an alias that was referred to.
static std::optional< CallHierarchyItem > declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::vector< const CXXRecordDecl * > findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record types referenced at Pos.
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
std::optional< QualType > getDeducedType(ASTContext &ASTCtx, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
std::array< uint8_t, 20 > SymbolID
@ Invalid
Sentinel bit pattern. DO NOT USE!
@ All
Only model a unidirectional implicit conversion and within it only one standard conversion sequence.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents an incoming call, e.g. a caller of a method or constructor.
Represents programming constructs like functions or constructors in the context of call hierarchy.
URIForFile uri
The resource identifier of this item.
std::string data
An optional 'data' field, which can be used to identify a call hierarchy item in an incomingCalls or ...
A range in a text document that links to an internal or external resource, like another text document...
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
std::string Query
A query string for the fuzzy find.
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
bool AnyScope
If set to true, allow symbols from any scope.
std::optional< uint32_t > Limit
The number of top candidates to return.
Location PreferredDeclaration
std::optional< Location > Definition
llvm::DenseSet< SymbolID > IDs
Represents a symbol occurrence in the source file.
SymbolID Container
The ID of the symbol whose definition contains this reference.
SymbolLocation Location
The source location where the symbol is named.
Information about a reference written in the source code, independent of the actual AST node that thi...
bool WantContainer
If set, populates the container of the reference.
llvm::DenseSet< SymbolID > IDs
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
llvm::DenseSet< SymbolID > Subjects
const DeclContext & getDeclContext() const
static std::optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
Represents information about identifier.
std::optional< Location > definitionRange
std::string containerName
std::optional< Location > declarationRange
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol.
Attributes of a symbol that affect how much we like it.
Attributes of a symbol-query pair that affect how much we like it.
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
void merge(const CodeCompletionResult &SemaResult)
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
float evaluateHeuristics() const
The class presents a C++ symbol, e.g.
@ Deprecated
Indicates if the symbol is deprecated.
SymbolLocation Definition
The location of the symbol's definition, if one was found.
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
SymbolID ID
The ID of the symbol.
std::optional< std::vector< ResolveParams > > parents
None means parents aren't resolved and empty is no parents.
URIForFile uri
The resource identifier of this item.
std::optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item.
std::optional< std::vector< TypeHierarchyItem > > parents
This is a clangd exntesion.
ResolveParams data
A data entry field that is preserved between a type hierarchy prepare and supertypes or subtypes requ...
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
llvm::StringRef file() const
Retrieves absolute path to the file.
@ Counter
An aggregate number whose rate of change over time is meaningful.