21#include "clang-include-cleaner/Analysis.h"
22#include "clang-include-cleaner/Types.h"
30#include "clang/AST/ASTContext.h"
31#include "clang/AST/ASTTypeTraits.h"
32#include "clang/AST/Attr.h"
33#include "clang/AST/Attrs.inc"
34#include "clang/AST/Decl.h"
35#include "clang/AST/DeclCXX.h"
36#include "clang/AST/DeclObjC.h"
37#include "clang/AST/DeclTemplate.h"
38#include "clang/AST/DeclVisitor.h"
39#include "clang/AST/ExprCXX.h"
40#include "clang/AST/RecursiveASTVisitor.h"
41#include "clang/AST/Stmt.h"
42#include "clang/AST/StmtCXX.h"
43#include "clang/AST/StmtVisitor.h"
44#include "clang/AST/Type.h"
45#include "clang/Basic/LLVM.h"
46#include "clang/Basic/LangOptions.h"
47#include "clang/Basic/SourceLocation.h"
48#include "clang/Basic/SourceManager.h"
49#include "clang/Basic/TokenKinds.h"
50#include "clang/Index/IndexDataConsumer.h"
51#include "clang/Index/IndexSymbol.h"
52#include "clang/Index/IndexingAction.h"
53#include "clang/Index/IndexingOptions.h"
54#include "clang/Index/USRGeneration.h"
55#include "clang/Lex/Lexer.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/Path.h"
67#include "llvm/Support/raw_ostream.h"
82const NamedDecl *getDefinition(
const NamedDecl *D) {
85 if (
const auto *TD = dyn_cast<TagDecl>(D))
86 return TD->getDefinition();
87 if (
const auto *VD = dyn_cast<VarDecl>(D))
88 return VD->getDefinition();
89 if (
const auto *FD = dyn_cast<FunctionDecl>(D))
90 return FD->getDefinition();
91 if (
const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
92 if (
const auto *RD = CTD->getTemplatedDecl())
93 return RD->getDefinition();
94 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
95 if (MD->isThisDeclarationADefinition())
98 auto *DeclCtx = cast<Decl>(MD->getDeclContext());
99 if (DeclCtx->isInvalidDecl())
102 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
104 return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
106 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(D))
109 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
110 isa<TemplateTemplateParmDecl>(D))
116void logIfOverflow(
const SymbolLocation &
Loc) {
117 if (
Loc.Start.hasOverflow() ||
Loc.End.hasOverflow())
118 log(
"Possible overflow in symbol location: {0}",
Loc);
125std::optional<Location> toLSPLocation(
const SymbolLocation &
Loc,
126 llvm::StringRef TUPath) {
131 elog(
"Could not parse URI {0}: {1}",
Loc.FileURI, Uri.takeError());
136 elog(
"Could not resolve URI {0}: {1}",
Loc.FileURI, U.takeError());
141 LSPLoc.uri = std::move(*U);
142 LSPLoc.range.start.line =
Loc.Start.line();
143 LSPLoc.range.start.character =
Loc.Start.column();
144 LSPLoc.range.end.line =
Loc.End.line();
145 LSPLoc.range.end.character =
Loc.End.column();
150SymbolLocation toIndexLocation(
const Location &
Loc, std::string &URIStorage) {
151 SymbolLocation SymLoc;
152 URIStorage =
Loc.uri.uri();
153 SymLoc.FileURI = URIStorage.c_str();
154 SymLoc.Start.setLine(
Loc.range.start.line);
155 SymLoc.Start.setColumn(
Loc.range.start.character);
156 SymLoc.End.setLine(
Loc.range.end.line);
157 SymLoc.End.setColumn(
Loc.range.end.character);
162SymbolLocation getPreferredLocation(
const Location &ASTLoc,
163 const SymbolLocation &IdxLoc,
164 std::string &Scratch) {
167 Symbol ASTSym, IdxSym;
168 ASTSym.ID = IdxSym.ID =
SymbolID(
"mock_symbol_id");
169 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
170 IdxSym.CanonicalDeclaration = IdxLoc;
172 return Merged.CanonicalDeclaration;
175std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
176getDeclAtPositionWithRelations(ParsedAST &
AST, SourceLocation
Pos,
177 DeclRelationSet Relations,
178 ASTNodeKind *NodeKind =
nullptr) {
179 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(
Pos).second;
180 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
181 auto ResultFromTree = [&](SelectionTree ST) {
182 if (
const SelectionTree::Node *N = ST.commonAncestor()) {
184 *NodeKind = N->ASTNode.getNodeKind();
189 if (N->ASTNode.get<Attr>() && N->Parent)
192 std::back_inserter(Result),
193 [&](
auto &
Entry) {
return !(
Entry.second & ~Relations); });
195 return !Result.empty();
202std::vector<const NamedDecl *>
203getDeclAtPosition(ParsedAST &
AST, SourceLocation
Pos, DeclRelationSet Relations,
204 ASTNodeKind *NodeKind =
nullptr) {
205 std::vector<const NamedDecl *> Result;
207 getDeclAtPositionWithRelations(
AST,
Pos, Relations, NodeKind))
208 Result.push_back(
Entry.first);
214std::optional<Location> makeLocation(
const ASTContext &
AST, SourceLocation
Loc,
215 llvm::StringRef TUPath) {
216 const auto &SM =
AST.getSourceManager();
217 const auto F = SM.getFileEntryRefForID(SM.getFileID(
Loc));
222 log(
"failed to get path!");
229 auto TokLen = Lexer::MeasureTokenLength(
Loc, SM,
AST.getLangOpts());
231 SM, CharSourceRange::getCharRange(
Loc,
Loc.getLocWithOffset(TokLen)));
236std::optional<LocatedSymbol> locateFileReferent(
const Position &
Pos,
238 llvm::StringRef MainFilePath) {
239 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
240 if (!Inc.Resolved.empty() && Inc.HashLine ==
Pos.line) {
242 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
243 File.PreferredDeclaration = {
245 File.Definition =
File.PreferredDeclaration;
255std::optional<LocatedSymbol>
256locateMacroReferent(
const syntax::Token &TouchedIdentifier, ParsedAST &
AST,
257 llvm::StringRef MainFilePath) {
260 makeLocation(
AST.getASTContext(),
M->NameLoc, MainFilePath)) {
262 Macro.Name = std::string(
M->Name);
285const NamedDecl *getPreferredDecl(
const NamedDecl *D) {
290 D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
293 if (
const auto *
ID = dyn_cast<ObjCInterfaceDecl>(D))
294 if (
const auto *DefinitionID =
ID->getDefinition())
296 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
297 if (
const auto *DefinitionID = PD->getDefinition())
303std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
305 const SymbolIndex *Index,
306 llvm::StringRef MainFilePath) {
307 if (IDs.empty() || !Index)
309 static constexpr trace::Metric FindImplementorsMetric(
313 FindImplementorsMetric.record(1,
"find-base");
316 FindImplementorsMetric.record(1,
"find-override");
320 RelationsRequest Req;
321 Req.Predicate = Predicate;
322 Req.Subjects = std::move(IDs);
323 std::vector<LocatedSymbol>
Results;
324 Index->relations(Req, [&](
const SymbolID &Subject,
const Symbol &
Object) {
328 elog(
"Find overrides: {0}", DeclLoc.takeError());
333 Results.back().PreferredDeclaration = *DeclLoc;
336 elog(
"Failed to convert location: {0}", DefLoc.takeError());
339 Results.back().Definition = *DefLoc;
346void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
347 const SymbolIndex *Index,
348 llvm::StringRef MainFilePath) {
349 LookupRequest QueryRequest;
350 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
351 for (
unsigned I = 0; I < Result.size(); ++I) {
352 if (
auto ID = Result[I].
ID) {
353 ResultIndex.try_emplace(
ID, I);
354 QueryRequest.IDs.insert(
ID);
357 if (!Index || QueryRequest.IDs.empty())
360 Index->lookup(QueryRequest, [&](
const Symbol &Sym) {
361 auto &R = Result[ResultIndex.lookup(Sym.ID)];
366 if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
367 R.PreferredDeclaration = *Loc;
371 if (auto Loc = toLSPLocation(
372 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
376 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
379 if (auto Loc = toLSPLocation(
380 getPreferredLocation(R.PreferredDeclaration,
381 Sym.CanonicalDeclaration, Scratch),
383 R.PreferredDeclaration = *Loc;
392std::vector<LocatedSymbol>
393locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
394 ParsedAST &
AST, llvm::StringRef MainFilePath,
395 const SymbolIndex *Index, ASTNodeKind &NodeKind) {
396 const SourceManager &SM =
AST.getSourceManager();
398 std::vector<LocatedSymbol> Result;
400 static constexpr trace::Metric LocateASTReferentMetric(
402 auto AddResultDecl = [&](
const NamedDecl *D) {
403 D = getPreferredDecl(D);
409 Result.emplace_back();
410 Result.back().Name =
printName(
AST.getASTContext(), *D);
411 Result.back().PreferredDeclaration = *
Loc;
413 if (
const NamedDecl *Def = getDefinition(D))
414 Result.back().Definition = makeLocation(
419 DeclRelationSet Relations =
422 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
423 llvm::DenseSet<SymbolID> VirtualMethods;
424 for (
const auto &
E : Candidates) {
425 const NamedDecl *D =
E.first;
426 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
430 if (CMD->isPureVirtual()) {
431 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
432 TouchedIdentifier->location()) {
434 LocateASTReferentMetric.record(1,
"method-to-override");
438 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
439 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
441 for (
const NamedDecl *ND : CMD->overridden_methods())
454 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
456 D->getBeginLoc(), D->getEndLoc()))
461 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
462 if (TouchedIdentifier &&
463 D->getLocation() == TouchedIdentifier->location()) {
464 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
465 AddResultDecl(CTSD->getSpecializedTemplate());
476 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
477 if (
const auto *
ID = CD->getClassInterface())
478 if (TouchedIdentifier &&
479 (CD->getLocation() == TouchedIdentifier->location() ||
480 ID->getName() == TouchedIdentifier->text(SM))) {
481 LocateASTReferentMetric.record(1,
"objc-category-to-class");
485 LocateASTReferentMetric.record(1,
"regular");
489 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
492 Index, MainFilePath);
493 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
497std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
498 const QualType &
Type,
499 const SymbolIndex *Index) {
500 const auto &SM =
AST.getSourceManager();
501 auto MainFilePath =
AST.tuPath();
505 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
507 AST.getHeuristicResolver());
511 std::vector<LocatedSymbol>
Results;
512 const auto &ASTContext =
AST.getASTContext();
514 for (
const NamedDecl *D : Decls) {
515 D = getPreferredDecl(D);
517 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
525 if (
const NamedDecl *Def = getDefinition(D))
527 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
529 enhanceLocatedSymbolsFromIndex(
Results, Index, MainFilePath);
534bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
535 auto ExpandedTokens = TB.expandedTokens(
536 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
537 return !ExpandedTokens.empty();
540llvm::StringRef sourcePrefix(SourceLocation
Loc,
const SourceManager &SM) {
541 auto D = SM.getDecomposedLoc(
Loc);
543 llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);
544 if (Invalid || D.second > Buf.size())
546 return Buf.substr(0, D.second);
549bool isDependentName(ASTNodeKind NodeKind) {
550 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
552 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
554 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
562 llvm::StringRef MainFilePath,
563 ASTNodeKind NodeKind) {
568 if ((
Word.ExpandedToken && !isDependentName(NodeKind)) ||
569 !
Word.LikelyIdentifier || !Index)
573 if (
Word.PartOfSpelledToken &&
574 isStringLiteral(
Word.PartOfSpelledToken->kind()))
577 const auto &SM =
AST.getSourceManager();
591 bool TooMany =
false;
592 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
593 std::vector<ScoredLocatedSymbol> ScoredResults;
594 Index->fuzzyFind(Req, [&](
const Symbol &Sym) {
604 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
610 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
620 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
627 if (ScoredResults.size() >= 5) {
640 Relevance.
merge(Sym);
643 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
646 ScoredResults.push_back({
Score, std::move(Located)});
650 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
655 llvm::sort(ScoredResults,
656 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
657 return A.first > B.first;
659 std::vector<LocatedSymbol>
Results;
660 for (
auto &Res : std::move(ScoredResults))
661 Results.push_back(std::move(Res.second));
663 vlog(
"No heuristic index definition for {0}",
Word.Text);
665 log(
"Found definition heuristically in index for {0}",
Word.Text);
670 const syntax::TokenBuffer &TB) {
673 if (
Word.ExpandedToken)
677 if (
Word.PartOfSpelledToken &&
678 isStringLiteral(
Word.PartOfSpelledToken->kind()))
681 const SourceManager &SM = TB.sourceManager();
684 auto File = SM.getFileID(
Word.Location);
685 unsigned WordLine = SM.getSpellingLineNumber(
Word.Location);
686 auto Cost = [&](SourceLocation
Loc) ->
unsigned {
687 assert(SM.getFileID(
Loc) ==
File &&
"spelled token in wrong file?");
688 unsigned Line = SM.getSpellingLineNumber(
Loc);
689 return Line >= WordLine ?
Line - WordLine : 2 * (WordLine -
Line);
691 const syntax::Token *BestTok =
nullptr;
692 unsigned BestCost = -1;
696 unsigned MaxDistance =
697 1U << std::min<unsigned>(
Word.Text.size(),
698 std::numeric_limits<unsigned>::digits - 1);
705 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
706 unsigned LineMax = WordLine + 1 + MaxDistance;
707 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
708 assert(LocMin.isValid());
709 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
710 assert(LocMax.isValid());
714 auto Consider = [&](
const syntax::Token &Tok) {
715 if (Tok.location() < LocMin || Tok.location() > LocMax)
717 if (!(Tok.kind() == tok::identifier && Tok.text(SM) ==
Word.Text))
720 if (Tok.location() ==
Word.Location)
723 unsigned TokCost = Cost(Tok.location());
724 if (TokCost >= BestCost)
728 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
735 auto SpelledTokens = TB.spelledTokens(
File);
737 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
738 assert(SM.getFileID(T.location()) == SM.getFileID(
Word.Location));
739 return T.location() <
Word.Location;
742 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
746 for (
const syntax::Token &Tok :
747 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
753 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
754 Word.Text,
Word.Location.printToString(SM),
755 BestTok->location().printToString(SM));
762 const auto &SM =
AST.getSourceManager();
763 auto MainFilePath =
AST.tuPath();
765 if (
auto File = locateFileReferent(
Pos,
AST, MainFilePath))
766 return {std::move(*
File)};
770 elog(
"locateSymbolAt failed to convert position to source location: {0}",
775 const syntax::Token *TouchedIdentifier =
nullptr;
776 auto TokensTouchingCursor =
777 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
778 for (
const syntax::Token &Tok : TokensTouchingCursor) {
779 if (Tok.kind() == tok::identifier) {
780 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
784 return {*std::move(
Macro)};
786 TouchedIdentifier = &Tok;
790 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
794 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
801 ASTNodeKind NodeKind;
802 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
803 MainFilePath, Index, NodeKind);
804 if (!ASTResults.empty())
812 if (
const syntax::Token *NearbyIdent =
814 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
815 log(
"Found macro definition heuristically using nearby identifier {0}",
817 return {*std::move(
Macro)};
819 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
820 MainFilePath, Index, NodeKind);
821 if (!ASTResults.empty()) {
822 log(
"Found definition heuristically using nearby identifier {0}",
823 NearbyIdent->text(SM));
826 vlog(
"No definition found using nearby identifier {0} at {1}",
Word->Text,
827 Word->Location.printToString(SM));
830 auto TextualResults =
832 if (!TextualResults.empty())
833 return TextualResults;
840 const auto &SM =
AST.getSourceManager();
842 std::vector<DocumentLink> Result;
843 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
844 if (Inc.Resolved.empty())
846 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
847 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
848 assert(HashTok &&
"got inclusion at wrong offset");
849 const auto *IncludeTok = std::next(HashTok);
850 const auto *FileTok = std::next(IncludeTok);
855 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
869class ReferenceFinder :
public index::IndexDataConsumer {
876 Range range(
const SourceManager &SM)
const {
881 ReferenceFinder(
const ParsedAST &AST,
882 const llvm::ArrayRef<const NamedDecl *> Targets,
884 : PerToken(PerToken), AST(AST) {
885 for (
const NamedDecl *ND : Targets)
886 TargetDecls.insert(ND->getCanonicalDecl());
889 std::vector<Reference> take() && {
890 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
891 auto LTok = L.SpelledTok.location();
892 auto RTok = R.SpelledTok.location();
893 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
897 [](
const Reference &L,
const Reference &R) {
898 auto LTok = L.SpelledTok.location();
899 auto RTok = R.SpelledTok.location();
900 return std::tie(LTok, L.Role) ==
901 std::tie(RTok, R.Role);
904 return std::move(References);
908 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
909 llvm::ArrayRef<index::SymbolRelation> Relations,
911 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
912 if (!TargetDecls.contains(D->getCanonicalDecl()))
914 const SourceManager &SM = AST.getSourceManager();
917 const auto &TB = AST.getTokens();
919 llvm::SmallVector<SourceLocation, 1> Locs;
923 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
924 OME->getSelectorLocs(Locs);
925 }
else if (
auto *OMD =
926 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
927 OMD->getSelectorLocs(Locs);
931 if (!Locs.empty() && Locs.front() !=
Loc)
939 for (SourceLocation L : Locs) {
940 L = SM.getFileLoc(L);
941 if (
const auto *Tok = TB.spelledTokenContaining(L))
952 const ParsedAST &AST;
953 llvm::DenseSet<const Decl *> TargetDecls;
956std::vector<ReferenceFinder::Reference>
957findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls, ParsedAST &
AST,
959 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
960 index::IndexingOptions IndexOpts;
961 IndexOpts.SystemSymbolFilter =
962 index::IndexingOptions::SystemSymbolFilterKind::All;
963 IndexOpts.IndexFunctionLocals =
true;
964 IndexOpts.IndexParametersInDeclarations =
true;
965 IndexOpts.IndexTemplateParameters =
true;
966 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
967 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
968 return std::move(RefFinder).take();
971const Stmt *getFunctionBody(DynTypedNode N) {
972 if (
const auto *FD = N.get<FunctionDecl>())
973 return FD->getBody();
974 if (
const auto *FD = N.get<BlockDecl>())
975 return FD->getBody();
976 if (
const auto *FD = N.get<LambdaExpr>())
977 return FD->getBody();
978 if (
const auto *FD = N.get<ObjCMethodDecl>())
979 return FD->getBody();
983const Stmt *getLoopBody(DynTypedNode N) {
984 if (
const auto *LS = N.get<ForStmt>())
985 return LS->getBody();
986 if (
const auto *LS = N.get<CXXForRangeStmt>())
987 return LS->getBody();
988 if (
const auto *LS = N.get<WhileStmt>())
989 return LS->getBody();
990 if (
const auto *LS = N.get<DoStmt>())
991 return LS->getBody();
1007 All = Break | Continue | Return | Case | Throw | Goto,
1011 std::vector<SourceLocation> &Result;
1012 const SourceManager &SM;
1016 template <
typename Func>
1017 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1018 auto RestoreIgnore = llvm::make_scope_exit(
1019 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1020 if (getFunctionBody(D))
1022 else if (getLoopBody(D))
1023 Ignore |= Continue | Break;
1024 else if (D.get<SwitchStmt>())
1025 Ignore |= Break | Case;
1027 return (Ignore == All) ? true : Delegate();
1030 void found(Target T, SourceLocation
Loc) {
1033 if (SM.isBeforeInTranslationUnit(
Loc,
Bounds.getBegin()) ||
1034 SM.isBeforeInTranslationUnit(
Bounds.getEnd(),
Loc))
1036 Result.push_back(
Loc);
1040 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1041 const SourceManager &SM)
1046 bool TraverseDecl(
Decl *D) {
1047 return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1048 return RecursiveASTVisitor::TraverseDecl(D);
1051 bool TraverseStmt(Stmt *S) {
1052 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1053 return RecursiveASTVisitor::TraverseStmt(S);
1058 bool VisitReturnStmt(ReturnStmt *R) {
1059 found(Return, R->getReturnLoc());
1062 bool VisitBreakStmt(BreakStmt *B) {
1063 found(Break,
B->getBreakLoc());
1066 bool VisitContinueStmt(ContinueStmt *
C) {
1067 found(Continue,
C->getContinueLoc());
1070 bool VisitSwitchCase(SwitchCase *
C) {
1071 found(Case,
C->getKeywordLoc());
1074 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1075 found(Throw,
T->getThrowLoc());
1078 bool VisitGotoStmt(GotoStmt *G) {
1080 if (
const auto *LD = G->getLabel()) {
1081 if (SM.isBeforeInTranslationUnit(LD->getLocation(),
Bounds.getBegin()) ||
1082 SM.isBeforeInTranslationUnit(
Bounds.getEnd(), LD->getLocation()))
1083 found(Goto, G->getGotoLoc());
1092SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation
Loc,
1093 const SourceManager &SM) {
1096 std::vector<const SwitchCase *> Cases;
1097 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1098 Case = Case->getNextSwitchCase())
1099 Cases.push_back(Case);
1100 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1101 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1105 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *
C) {
1106 return !SM.isBeforeInTranslationUnit(
Loc,
C->getKeywordLoc());
1108 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1109 : (*CaseAfter)->getKeywordLoc();
1112 if (CaseAfter == Cases.begin())
1113 return SourceRange(Switch.getBeginLoc(), End);
1115 auto CaseBefore = std::prev(CaseAfter);
1117 while (CaseBefore != Cases.begin() &&
1118 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1120 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1130std::vector<SourceLocation> relatedControlFlow(
const SelectionTree::Node &N) {
1131 const SourceManager &SM =
1132 N.getDeclContext().getParentASTContext().getSourceManager();
1133 std::vector<SourceLocation> Result;
1136 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1137 if (N.ASTNode.get<BreakStmt>()) {
1138 Cursor = Cur::Break;
1139 }
else if (N.ASTNode.get<ContinueStmt>()) {
1140 Cursor = Cur::Continue;
1141 }
else if (N.ASTNode.get<ReturnStmt>()) {
1142 Cursor = Cur::Return;
1143 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1144 Cursor = Cur::Throw;
1145 }
else if (N.ASTNode.get<SwitchCase>()) {
1147 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1149 Result.push_back(GS->getGotoLoc());
1150 if (
const auto *LD = GS->getLabel())
1151 Result.push_back(LD->getLocation());
1157 const Stmt *
Root =
nullptr;
1160 for (
const auto *P = &N; P; P = P->Parent) {
1162 if (
const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
1163 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1164 Root = FunctionBody;
1169 if (
const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
1170 if (Cursor == Cur::None || Cursor == Cur::Break ||
1171 Cursor == Cur::Continue) {
1175 Result.push_back(P->ASTNode.getSourceRange().getBegin());
1182 if (
const auto *SS = P->ASTNode.get<SwitchStmt>()) {
1183 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1184 Result.push_back(SS->getSwitchLoc());
1185 Root = SS->getBody();
1187 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1192 if (Cursor == Cur::None)
1198 FindControlFlow(
Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(
Root));
1203DocumentHighlight toHighlight(
const ReferenceFinder::Reference &Ref,
1204 const SourceManager &SM) {
1205 DocumentHighlight DH;
1206 DH.range = Ref.range(SM);
1207 if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1209 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1216std::optional<DocumentHighlight> toHighlight(SourceLocation
Loc,
1217 const syntax::TokenBuffer &TB) {
1218 Loc = TB.sourceManager().getFileLoc(
Loc);
1219 if (
const auto *Tok = TB.spelledTokenContaining(
Loc)) {
1220 DocumentHighlight Result;
1223 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1226 return std::nullopt;
1233 const SourceManager &SM =
AST.getSourceManager();
1237 llvm::consumeError(CurLoc.takeError());
1240 std::vector<DocumentHighlight> Result;
1246 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1247 if (!TargetDecls.empty()) {
1250 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1251 Result.push_back(toHighlight(
Ref, SM));
1254 auto ControlFlow = relatedControlFlow(*N);
1255 if (!ControlFlow.empty()) {
1256 for (SourceLocation
Loc : ControlFlow)
1257 if (
auto Highlight = toHighlight(
Loc,
AST.getTokens()))
1258 Result.push_back(std::move(*Highlight));
1266 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1279 const SourceManager &SM =
AST.getSourceManager();
1282 elog(
"Failed to convert position to source location: {0}",
1283 CurLoc.takeError());
1288 llvm::DenseSet<SymbolID> IDs;
1290 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1291 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1292 if (CXXMD->isVirtual()) {
1296 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1301 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1307void getOverriddenMethods(
const CXXMethodDecl *CMD,
1308 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1311 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1313 OverriddenMethods.insert(
ID);
1314 getOverriddenMethods(Base, OverriddenMethods);
1318std::optional<std::string>
1322 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(
Container))
1327std::optional<ReferencesResult>
1328maybeFindIncludeReferences(ParsedAST &
AST, Position
Pos,
1329 URIForFile URIMainFile) {
1330 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1331 auto IncludeOnLine = llvm::find_if(Includes, [&
Pos](
const Inclusion &Inc) {
1332 return Inc.HashLine ==
Pos.line;
1334 if (IncludeOnLine == Includes.end())
1335 return std::nullopt;
1337 const SourceManager &SM =
AST.getSourceManager();
1340 include_cleaner::walkUsed(
1342 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1343 [&](
const include_cleaner::SymbolReference &Ref,
1344 llvm::ArrayRef<include_cleaner::Header> Providers) {
1345 if (Ref.RT != include_cleaner::RefType::Explicit ||
1346 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1349 auto Loc = SM.getFileLoc(Ref.RefLocation);
1352 while (SM.getFileID(Loc) != SM.getMainFileID())
1353 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1355 ReferencesResult::Reference Result;
1356 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1357 assert(Token &&
"references expected token here");
1358 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1359 sourceLocToPosition(SM, Token->endLocation())};
1360 Result.Loc.uri = URIMainFile;
1361 Results.References.push_back(std::move(Result));
1363 if (
Results.References.empty())
1364 return std::nullopt;
1367 ReferencesResult::Reference Result;
1368 Result.Loc.range =
rangeTillEOL(SM.getBufferData(SM.getMainFileID()),
1369 IncludeOnLine->HashOffset);
1370 Result.Loc.uri = URIMainFile;
1371 Results.References.push_back(std::move(Result));
1379 const SourceManager &SM = AST.getSourceManager();
1380 auto MainFilePath = AST.tuPath();
1381 auto URIMainFile = URIForFile::canonicalize(MainFilePath, MainFilePath);
1384 llvm::consumeError(CurLoc.takeError());
1388 const auto IncludeReferences =
1389 maybeFindIncludeReferences(AST,
Pos, URIMainFile);
1390 if (IncludeReferences)
1391 return *IncludeReferences;
1393 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1395 const auto *IdentifierAtCursor =
1396 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1397 std::optional<DefinedMacro>
Macro;
1398 if (IdentifierAtCursor)
1404 const auto &IDToRefs = AST.getMacros().MacroRefs;
1405 auto Refs = IDToRefs.find(MacroSID);
1406 if (Refs != IDToRefs.end()) {
1407 for (
const auto &
Ref : Refs->second) {
1409 Result.Loc.range =
Ref.toRange(SM);
1410 Result.Loc.uri = URIMainFile;
1411 if (
Ref.IsDefinition) {
1412 Result.Attributes |= ReferencesResult::Declaration;
1413 Result.Attributes |= ReferencesResult::Definition;
1415 Results.References.push_back(std::move(Result));
1418 IDsToQuery.insert(MacroSID);
1424 DeclRelation::TemplatePattern | DeclRelation::Alias;
1425 std::vector<const NamedDecl *> Decls =
1426 getDeclAtPosition(AST, *CurLoc, Relations);
1427 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1428 for (
const NamedDecl *D : Decls) {
1432 TargetsInMainFile.push_back(D);
1436 if (D->getParentFunctionOrMethod())
1438 IDsToQuery.insert(
ID);
1444 for (
const NamedDecl *ND : Decls) {
1447 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1448 if (CMD->isVirtual()) {
1451 getOverriddenMethods(CMD, OverriddenMethods);
1458 auto MainFileRefs = findRefs(TargetsInMainFile, AST,
false);
1462 MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
1463 [](
const ReferenceFinder::Reference &L,
1464 const ReferenceFinder::Reference &R) {
1465 return L.SpelledTok.location() ==
1466 R.SpelledTok.location();
1468 MainFileRefs.end());
1469 for (
const auto &
Ref : MainFileRefs) {
1471 Result.Loc.range =
Ref.range(SM);
1472 Result.Loc.uri = URIMainFile;
1474 Result.Loc.containerName =
1476 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1477 Result.Attributes |= ReferencesResult::Declaration;
1479 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1480 Result.Attributes |=
1481 ReferencesResult::Definition | ReferencesResult::Declaration;
1482 Results.References.push_back(std::move(Result));
1490 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1493 if (Limit &&
Results.References.size() >= Limit) {
1494 Results.HasMore = true;
1497 const auto LSPLocDecl =
1498 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1499 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1500 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1502 Result.Loc = {std::move(*LSPLocDecl), std::nullopt};
1504 ReferencesResult::Declaration | ReferencesResult::Override;
1505 RefIndexForContainer.insert({
Object.ID,
Results.References.size()});
1507 Results.References.push_back(std::move(Result));
1511 Result.Loc = {std::move(*LSPLocDef), std::nullopt};
1512 Result.Attributes = ReferencesResult::Declaration |
1513 ReferencesResult::Definition |
1514 ReferencesResult::Override;
1515 RefIndexForContainer.insert({
Object.ID,
Results.References.size()});
1517 Results.References.push_back(std::move(Result));
1521 if (!ContainerLookup.
IDs.empty() && AddContext)
1524 assert(
Ref != RefIndexForContainer.end());
1525 Results.References[
Ref->getSecond()].Loc.containerName =
1531 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1532 bool AllowMainFileSymbols) {
1533 if (IDs.empty() || !Index ||
Results.HasMore)
1536 Req.
IDs = std::move(IDs);
1538 if (Limit <
Results.References.size()) {
1548 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1549 Results.HasMore |= Index->refs(Req, [&](
const Ref &R) {
1550 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1553 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1556 Result.Loc = {std::move(*LSPLoc), std::nullopt};
1557 if (AllowAttributes) {
1558 if ((R.
Kind & RefKind::Declaration) == RefKind::Declaration)
1559 Result.Attributes |= ReferencesResult::Declaration;
1561 if ((R.
Kind & RefKind::Definition) == RefKind::Definition)
1562 Result.Attributes |=
1563 ReferencesResult::Declaration | ReferencesResult::Definition;
1570 Results.References.push_back(std::move(Result));
1573 if (!ContainerLookup.
IDs.empty() && AddContext)
1576 assert(
Ref != RefIndicesForContainer.end());
1578 for (
auto I :
Ref->getSecond()) {
1579 Results.References[I].Loc.containerName = ContainerName;
1583 QueryIndex(std::move(IDsToQuery),
true,
1588 QueryIndex(std::move(OverriddenMethods),
false,
1594 const SourceManager &SM = AST.getSourceManager();
1597 llvm::consumeError(CurLoc.takeError());
1600 auto MainFilePath = AST.tuPath();
1601 std::vector<SymbolDetails>
Results;
1606 DeclRelation::Alias | DeclRelation::Underlying;
1607 for (
const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
1608 D = getPreferredDecl(D);
1614 NewSymbol.
name = std::string(SplitQName.second);
1617 if (
const auto *ParentND =
1618 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1621 llvm::SmallString<32>
USR;
1622 if (!index::generateUSRForDecl(D,
USR)) {
1623 NewSymbol.
USR = std::string(
USR);
1626 if (
const NamedDecl *Def = getDefinition(D))
1628 AST.getASTContext(),
nameLocation(*Def, SM), MainFilePath);
1630 makeLocation(AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1632 Results.push_back(std::move(NewSymbol));
1635 const auto *IdentifierAtCursor =
1636 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1637 if (!IdentifierAtCursor)
1640 if (
auto M =
locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {
1642 NewMacro.
name = std::string(
M->Name);
1643 llvm::SmallString<32>
USR;
1644 if (!index::generateUSRForMacro(NewMacro.
name,
M->Info->getDefinitionLoc(),
1646 NewMacro.
USR = std::string(
USR);
1649 Results.push_back(std::move(NewMacro));
1656 OS << S.Name <<
": " << S.PreferredDeclaration;
1658 OS <<
" def=" << *S.Definition;
1665 if (R.
Attributes & ReferencesResult::Declaration)
1667 if (R.
Attributes & ReferencesResult::Definition)
1669 if (R.
Attributes & ReferencesResult::Override)
1670 OS <<
" [override]";
1674template <
typename HierarchyItem>
1675static std::optional<HierarchyItem>
1677 ASTContext &Ctx = ND.getASTContext();
1678 auto &SM = Ctx.getSourceManager();
1679 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1680 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1681 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1682 const auto DeclRange =
1685 return std::nullopt;
1686 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1688 return std::nullopt;
1691 return std::nullopt;
1695 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1697 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1707 HI.selectionRange =
Range{NameBegin, NameEnd};
1708 if (!HI.range.contains(HI.selectionRange)) {
1711 HI.range = HI.selectionRange;
1714 HI.uri = URIForFile::canonicalize(*FilePath, TUPath);
1719static std::optional<TypeHierarchyItem>
1721 auto Result = declToHierarchyItem<TypeHierarchyItem>(ND, TUPath);
1723 Result->deprecated = ND.isDeprecated();
1733static std::optional<CallHierarchyItem>
1735 auto Result = declToHierarchyItem<CallHierarchyItem>(ND, TUPath);
1738 if (ND.isDeprecated())
1739 Result->tags.push_back(SymbolTag::Deprecated);
1741 Result->data =
ID.str();
1745template <
typename HierarchyItem>
1750 elog(
"Failed to convert symbol to hierarchy item: {0}",
Loc.takeError());
1751 return std::nullopt;
1754 HI.name = std::string(S.Name);
1756 HI.selectionRange =
Loc->range;
1759 HI.range = HI.selectionRange;
1765static std::optional<TypeHierarchyItem>
1767 auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);
1769 Result->deprecated = (S.Flags & Symbol::Deprecated);
1770 Result->data.symbolID = S.ID;
1775static std::optional<CallHierarchyItem>
1777 auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);
1780 Result->data = S.ID.str();
1781 if (S.Flags & Symbol::Deprecated)
1782 Result->tags.push_back(SymbolTag::Deprecated);
1787 std::vector<TypeHierarchyItem> &SubTypes,
1793 if (std::optional<TypeHierarchyItem> ChildSym =
1796 ChildSym->children.emplace();
1799 SubTypes.emplace_back(std::move(*ChildSym));
1817 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
1819 if (!RPSet.insert(Pattern).second) {
1824 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
1825 if (std::optional<TypeHierarchyItem> ParentSym =
1829 Item.
parents->emplace_back(std::move(*ParentSym));
1834 RPSet.erase(Pattern);
1841 std::vector<const CXXRecordDecl *> Records;
1850 AST.getHeuristicResolver());
1851 for (
const NamedDecl *D : Decls) {
1853 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1855 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
1856 Records.push_back(RD);
1860 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
1862 Records.push_back(
Method->getParent());
1870 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
1871 Records.push_back(RD);
1876 const SourceManager &SM = AST.getSourceManager();
1877 std::vector<const CXXRecordDecl *> Result;
1880 llvm::consumeError(
Offset.takeError());
1883 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *
Offset,
1885 Result = RecordFromNode(ST.commonAncestor());
1886 return !Result.empty();
1896 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
1902 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
1903 if (llvm::isa<DeducedType>(TL->getTypePtr()))
1908 if (llvm::isa<TypedefType>(TL->getTypePtr()))
1909 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1910 return TL->getType();
1914 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
1915 if (
const FieldDecl *FD = CCI->getAnyMember())
1916 return FD->getType();
1917 if (
const Type *Base = CCI->getBaseClass())
1918 return QualType(Base, 0);
1922 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
1923 return CBS->getType();
1926 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
1927 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
1929 QualType VisitTypeDecl(
const TypeDecl *D) {
1930 return QualType(D->getTypeForDecl(), 0);
1933 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
1934 return D->getUnderlyingType();
1937 QualType VisitTemplateDecl(
const TemplateDecl *D) {
1938 return Visit(D->getTemplatedDecl());
1944 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
1945 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
1947 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
1950 QualType VisitExpr(
const Expr *S) {
1951 return S->IgnoreImplicitAsWritten()->getType();
1953 QualType VisitMemberExpr(
const MemberExpr *S) {
1955 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
1956 return Expr::findBoundMemberType(S);
1957 return VisitExpr(S);
1960 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
1961 return S->getDestroyedType();
1963 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
1964 return S->getDestroyedType();
1966 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
1967 return S->getSubExpr()->getType();
1969 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
1970 return type(S->getOperand());
1973 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
1975 for (
auto &D : llvm::reverse(S->designators()))
1976 if (D.isFieldDesignator())
1977 if (
const auto *FD = D.getFieldDecl())
1978 return FD->getType();
1983 QualType VisitSwitchStmt(
const SwitchStmt *S) {
1984 return type(S->getCond());
1986 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
1987 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
1988 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
1989 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
1990 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1991 return S->getLoopVariable()->getType();
1993 QualType VisitReturnStmt(
const ReturnStmt *S) {
1994 return type(S->getRetValue());
1996 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
1997 return type(S->getOperand());
1999 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2000 return S->getCaughtType();
2002 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
2003 return type(S->getThrowExpr());
2005 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
2006 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2024 if (
const auto* TDT = T->getAs<TypedefType>())
2025 return Out.push_back(QualType(TDT, 0));
2028 if (
const auto *PT = T->getAs<PointerType>())
2030 if (
const auto *RT = T->getAs<ReferenceType>())
2032 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2036 if (
auto *FT = T->getAs<FunctionType>())
2038 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2039 if (CRD->isLambda())
2040 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2048 if (
const auto* PointeeType = H->getPointeeType(T.getNonReferenceType().getTypePtr())) {
2050 return Out.push_back(T);
2053 return Out.push_back(T);
2059 llvm::SmallVector<QualType> Result;
2066 const SourceManager &SM = AST.getSourceManager();
2068 std::vector<LocatedSymbol> Result;
2070 elog(
"failed to convert position {0} for findTypes: {1}",
Pos,
2075 auto SymbolsFromNode =
2077 std::vector<LocatedSymbol> LocatedSymbols;
2084 llvm::copy(locateSymbolForType(AST,
Type, Index),
2085 std::back_inserter(LocatedSymbols));
2087 return LocatedSymbols;
2089 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *
Offset,
2091 Result = SymbolsFromNode(ST.commonAncestor());
2092 return !Result.empty();
2097std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2098 std::vector<const CXXRecordDecl *> Result;
2102 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2103 if (CTSD->isInvalidDecl())
2104 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2108 if (!CXXRD->hasDefinition())
2111 for (
auto Base : CXXRD->bases()) {
2112 const CXXRecordDecl *ParentDecl =
nullptr;
2114 const Type *
Type = Base.getType().getTypePtr();
2115 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2116 ParentDecl = RT->getAsCXXRecordDecl();
2122 if (
const TemplateSpecializationType *TS =
2123 Type->getAs<TemplateSpecializationType>()) {
2124 TemplateName TN = TS->getTemplateName();
2125 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2126 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2132 Result.push_back(ParentDecl);
2138std::vector<TypeHierarchyItem>
2142 std::vector<TypeHierarchyItem>
Results;
2145 bool WantChildren = Direction == TypeHierarchyDirection::Children ||
2146 Direction == TypeHierarchyDirection::Both;
2156 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2157 CXXRD = CTSD->getTemplateInstantiationPattern();
2160 std::optional<TypeHierarchyItem> Result =
2168 if (WantChildren && ResolveLevels > 0) {
2169 Result->children.emplace();
2173 fillSubTypes(
ID, *Result->children, Index, ResolveLevels, TUPath);
2176 Results.emplace_back(std::move(*Result));
2182std::optional<std::vector<TypeHierarchyItem>>
2184 std::vector<TypeHierarchyItem>
Results;
2186 return std::nullopt;
2190 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2195 Index->lookup(Req, [&Item, &
Results, &IDToData](
const Symbol &S) {
2197 THI->data = *IDToData.lookup(S.ID);
2198 Results.emplace_back(std::move(*THI));
2206 std::vector<TypeHierarchyItem>
Results;
2208 for (
auto &ChildSym :
Results)
2209 ChildSym.data.parents = {Item.
data};
2218 if (!Index || Direction == TypeHierarchyDirection::Parents ||
2227std::vector<CallHierarchyItem>
2229 std::vector<CallHierarchyItem> Result;
2230 const auto &SM = AST.getSourceManager();
2233 elog(
"prepareCallHierarchy failed to convert position to source location: "
2238 for (
const NamedDecl *
Decl : getDeclAtPosition(AST, *
Loc, {})) {
2239 if (!(isa<DeclContext>(
Decl) &&
2240 cast<DeclContext>(
Decl)->isFunctionOrMethod()) &&
2241 Decl->getKind() != Decl::Kind::FunctionTemplate)
2244 Result.emplace_back(std::move(*CHI));
2249std::vector<CallHierarchyIncomingCall>
2251 std::vector<CallHierarchyIncomingCall>
Results;
2252 if (!Index || Item.
data.empty())
2254 auto ID = SymbolID::fromStr(Item.
data);
2256 elog(
"incomingCalls failed to find symbol: {0}",
ID.takeError());
2266 Request.
IDs.insert(*
ID);
2271 Request.
Filter = RefKind::Reference;
2275 llvm::DenseMap<SymbolID, std::vector<Range>> CallsIn;
2279 Index->refs(Request, [&](
const Ref &R) {
2282 elog(
"incomingCalls failed to convert location: {0}",
Loc.takeError());
2285 auto It = CallsIn.try_emplace(R.
Container, std::vector<Range>{}).first;
2286 It->second.push_back(
Loc->range);
2292 Index->lookup(ContainerLookup, [&](
const Symbol &Caller) {
2293 auto It = CallsIn.find(Caller.
ID);
2294 assert(It != CallsIn.end());
2302 return A.from.name < B.from.name;
2308 const FunctionDecl *FD) {
2311 llvm::DenseSet<const Decl *> DeclRefs;
2315 for (
const Decl *D :
Ref.Targets) {
2316 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2321 AST.getHeuristicResolver());
const FunctionDecl * Decl
std::vector< CodeCompletionResult > Results
SignatureQualitySignals Quality
CompiledFragmentImpl & Out
std::optional< float > Score
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
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)
Interface for symbol indexes that can be used for searching or matching symbols among a set of 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< 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.
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.
std::vector< include_cleaner::SymbolReference > collectMacroReferences(ParsedAST &AST)
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)
include_cleaner::Includes convertIncludes(const ParsedAST &AST)
Converts the clangd include representation to include-cleaner include representation.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
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)
std::optional< std::string > getCanonicalPath(const FileEntryRef F, FileManager &FileMgr)
Get the canonical path of F.
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.
clangd::Range rangeTillEOL(llvm::StringRef Code, unsigned HashOffset)
Returns the range starting at offset and spanning the whole line.
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)
@ 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.
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
std::nullopt 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.