23 #include "clang/AST/ASTContext.h" 24 #include "clang/AST/Decl.h" 25 #include "clang/AST/DeclCXX.h" 26 #include "clang/AST/DeclTemplate.h" 27 #include "clang/AST/ExprCXX.h" 28 #include "clang/AST/Type.h" 29 #include "clang/Basic/LLVM.h" 30 #include "clang/Basic/SourceLocation.h" 31 #include "clang/Basic/SourceManager.h" 32 #include "clang/Index/IndexDataConsumer.h" 33 #include "clang/Index/IndexSymbol.h" 34 #include "clang/Index/IndexingAction.h" 35 #include "clang/Index/IndexingOptions.h" 36 #include "clang/Index/USRGeneration.h" 37 #include "llvm/ADT/ArrayRef.h" 38 #include "llvm/ADT/None.h" 39 #include "llvm/ADT/STLExtras.h" 40 #include "llvm/ADT/StringExtras.h" 41 #include "llvm/ADT/StringRef.h" 42 #include "llvm/Support/Casting.h" 43 #include "llvm/Support/Path.h" 44 #include "llvm/Support/raw_ostream.h" 56 const NamedDecl *getDefinition(
const NamedDecl *D) {
59 if (
const auto *TD = dyn_cast<TagDecl>(D))
60 return TD->getDefinition();
61 if (
const auto *VD = dyn_cast<VarDecl>(D))
62 return VD->getDefinition();
63 if (
const auto *FD = dyn_cast<FunctionDecl>(D))
64 return FD->getDefinition();
66 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
67 isa<TemplateTemplateParmDecl>(D))
73 void logIfOverflow(
const SymbolLocation &
Loc) {
74 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
75 log(
"Possible overflow in symbol location: {0}", Loc);
82 llvm::Optional<Location> toLSPLocation(
const SymbolLocation &Loc,
83 llvm::StringRef TUPath) {
88 elog(
"Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
93 elog(
"Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
98 LSPLoc.uri = std::move(*U);
99 LSPLoc.range.start.line = Loc.Start.line();
100 LSPLoc.range.start.character = Loc.Start.column();
101 LSPLoc.range.end.line = Loc.End.line();
102 LSPLoc.range.end.character = Loc.End.column();
107 SymbolLocation toIndexLocation(
const Location &Loc, std::string &URIStorage) {
108 SymbolLocation SymLoc;
109 URIStorage = Loc.uri.uri();
110 SymLoc.FileURI = URIStorage.c_str();
111 SymLoc.Start.setLine(Loc.range.start.line);
112 SymLoc.Start.setColumn(Loc.range.start.character);
113 SymLoc.End.setLine(Loc.range.end.line);
114 SymLoc.End.setColumn(Loc.range.end.character);
119 SymbolLocation getPreferredLocation(
const Location &ASTLoc,
120 const SymbolLocation &IdxLoc,
121 std::string &Scratch) {
124 Symbol ASTSym, IdxSym;
125 ASTSym.ID = IdxSym.ID =
SymbolID(
"dummy_id");
126 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
127 IdxSym.CanonicalDeclaration = IdxLoc;
129 return Merged.CanonicalDeclaration;
132 std::vector<const NamedDecl *> getDeclAtPosition(ParsedAST &AST,
134 DeclRelationSet Relations) {
137 std::tie(FID, Offset) = AST.getSourceManager().getDecomposedSpellingLoc(Pos);
138 SelectionTree Selection(AST.getASTContext(), AST.getTokens(),
Offset);
139 std::vector<const NamedDecl *> Result;
140 if (
const SelectionTree::Node *N = Selection.commonAncestor()) {
147 llvm::Optional<Location> makeLocation(ASTContext &AST, SourceLocation TokLoc,
148 llvm::StringRef TUPath) {
149 const SourceManager &SourceMgr = AST.getSourceManager();
150 const FileEntry *F = SourceMgr.getFileEntryForID(SourceMgr.getFileID(TokLoc));
155 log(
"failed to get path!");
159 getTokenRange(AST.getSourceManager(), AST.getLangOpts(), TokLoc)) {
175 elog(
"Failed to get a path for the main file, so no links");
179 std::vector<DocumentLink> Result;
181 if (!Inc.Resolved.empty()) {
196 elog(
"Failed to get a path for the main file, so no references");
202 if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.
line) {
204 File.
Name = llvm::sys::path::filename(Inc.Resolved);
209 return {std::move(File)};
215 SourceLocation IdentStartLoc = SM.getMacroArgExpandedLocation(
217 std::vector<LocatedSymbol> Result;
220 M->Info->getDefinitionLoc(), *MainFilePath)) {
222 Macro.
Name = M->Name;
225 Result.push_back(std::move(Macro));
241 llvm::DenseMap<SymbolID, size_t> ResultIndex;
243 SourceLocation SourceLoc;
247 elog(
"locateSymbolAt failed to convert position to source location: {0}",
255 for (
const NamedDecl *D : getDeclAtPosition(AST, SourceLoc, Relations)) {
256 const NamedDecl *Def = getDefinition(D);
257 const NamedDecl *Preferred = Def ? Def : D;
261 if (SM.getMacroArgExpandedLocation(Preferred->getLocation()) ==
263 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Preferred)) {
264 D = CTSD->getSpecializedTemplate();
265 Def = getDefinition(D);
266 Preferred = Def ? Def : D;
275 Result.emplace_back();
277 Result.back().PreferredDeclaration = *
Loc;
279 if (Def == Preferred)
280 Result.back().Definition = *
Loc;
284 ResultIndex[*ID] = Result.size() - 1;
288 if (Index && !ResultIndex.empty()) {
290 for (
auto It : ResultIndex)
291 QueryRequest.
IDs.insert(It.first);
294 auto &R = Result[ResultIndex.lookup(Sym.
ID)];
300 R.PreferredDeclaration = *
Loc;
304 if (
auto Loc = toLSPLocation(
305 getPreferredLocation(*R.Definition, Sym.
Definition, Scratch),
309 R.Definition = toLSPLocation(Sym.
Definition, *MainFilePath);
312 if (
auto Loc = toLSPLocation(
313 getPreferredLocation(R.PreferredDeclaration,
316 R.PreferredDeclaration = *
Loc;
327 class ReferenceFinder :
public index::IndexDataConsumer {
334 ReferenceFinder(ASTContext &AST, Preprocessor &
PP,
335 const std::vector<const NamedDecl *> &TargetDecls)
337 for (
const NamedDecl *D : TargetDecls)
338 CanonicalTargets.insert(D->getCanonicalDecl());
341 std::vector<Reference> take() && {
343 return std::tie(L.Loc, L.Role) < std::tie(R.Loc, R.Role);
348 return std::tie(L.Loc, L.Role) ==
349 std::tie(R.Loc, R.Role);
356 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
357 llvm::ArrayRef<index::SymbolRelation> Relations,
359 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
360 assert(D->isCanonicalDecl() &&
"expect D to be a canonical declaration");
361 const SourceManager &SM = AST.getSourceManager();
362 Loc = SM.getFileLoc(Loc);
369 llvm::SmallSet<const Decl *, 4> CanonicalTargets;
371 const ASTContext &
AST;
374 std::vector<ReferenceFinder::Reference>
375 findRefs(
const std::vector<const NamedDecl *> &
Decls, ParsedAST &AST) {
376 ReferenceFinder RefFinder(AST.getASTContext(), AST.getPreprocessor(),
Decls);
377 index::IndexingOptions IndexOpts;
378 IndexOpts.SystemSymbolFilter =
379 index::IndexingOptions::SystemSymbolFilterKind::All;
380 IndexOpts.IndexFunctionLocals =
true;
381 IndexOpts.IndexParametersInDeclarations =
true;
382 IndexOpts.IndexTemplateParameters =
true;
383 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
384 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
385 return std::move(RefFinder).take();
397 getDeclAtPosition(AST,
405 std::vector<DocumentHighlight> Result;
411 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
413 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
417 Result.push_back(std::move(DH));
426 Limit = std::numeric_limits<uint32_t>::max();
432 elog(
"Failed to get a path for the main file, so no references");
436 auto Loc = SM.getMacroArgExpandedLocation(
445 auto Refs = IDToRefs.find(*MacroSID);
446 if (
Refs != IDToRefs.end()) {
447 for (
const auto Ref :
Refs->second) {
450 Result.
uri = URIMainFile;
451 Results.
References.push_back(std::move(Result));
454 Req.
IDs.insert(*MacroSID);
463 auto Decls = getDeclAtPosition(AST, Loc, Relations);
466 auto MainFileRefs = findRefs(
Decls, AST);
470 MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
473 return L.Loc == R.Loc;
476 for (
const auto &
Ref : MainFileRefs) {
480 Result.
uri = URIMainFile;
481 Results.
References.push_back(std::move(Result));
490 if (D->getParentFunctionOrMethod())
504 auto LSPLoc = toLSPLocation(R.
Location, *MainFilePath);
506 if (!LSPLoc || LSPLoc->uri.file() == *MainFilePath)
509 Results.
References.push_back(std::move(*LSPLoc));
521 auto Loc = SM.getMacroArgExpandedLocation(
524 std::vector<SymbolDetails>
Results;
530 for (
const NamedDecl *D : getDeclAtPosition(AST, Loc, Relations)) {
537 if (
const auto *ParentND =
538 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
541 llvm::SmallString<32> USR;
542 if (!index::generateUSRForDecl(D, USR)) {
543 NewSymbol.
USR = USR.str();
546 Results.push_back(std::move(NewSymbol));
551 NewMacro.
name = M->Name;
552 llvm::SmallString<32> USR;
553 if (!index::generateUSRForMacro(NewMacro.
name, M->Info->getDefinitionLoc(),
555 NewMacro.
USR = USR.str();
558 Results.push_back(std::move(NewMacro));
572 static llvm::Optional<TypeHierarchyItem>
574 auto &SM = Ctx.getSourceManager();
576 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
581 SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc()));
582 SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc()));
583 if (NameLoc.isInvalid() || BeginLoc.isInvalid() || EndLoc.isInvalid())
588 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
610 auto TUPath =
getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
611 if (!FilePath || !TUPath)
618 static Optional<TypeHierarchyItem>
623 log(
"Type hierarchy: {0}", Loc.takeError());
640 return std::move(THI);
644 std::vector<TypeHierarchyItem> &SubTypes,
650 if (Optional<TypeHierarchyItem> ChildSym =
653 ChildSym->children.emplace();
654 fillSubTypes(Object.
ID, *ChildSym->children, Index, Levels - 1, TUPath);
656 SubTypes.emplace_back(std::move(*ChildSym));
664 std::vector<TypeHierarchyItem> &SuperTypes,
671 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
673 if (!RPSet.insert(Pattern).second) {
678 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
679 if (Optional<TypeHierarchyItem> ParentSym =
681 ParentSym->parents.emplace();
683 SuperTypes.emplace_back(std::move(*ParentSym));
688 RPSet.erase(Pattern);
694 SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation(
711 const NamedDecl *D =
Decls[0];
713 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
715 return VD->getType().getTypePtr()->getAsCXXRecordDecl();
718 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
720 return Method->getParent();
727 return dyn_cast<CXXRecordDecl>(D);
730 std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
731 std::vector<const CXXRecordDecl *> Result;
735 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
736 if (CTSD->isInvalidDecl())
737 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
740 for (
auto Base : CXXRD->bases()) {
741 const CXXRecordDecl *ParentDecl =
nullptr;
744 if (
const RecordType *RT = Type->getAs<RecordType>()) {
745 ParentDecl = RT->getAsCXXRecordDecl();
751 if (
const TemplateSpecializationType *TS =
752 Type->getAs<TemplateSpecializationType>()) {
753 TemplateName TN = TS->getTemplateName();
754 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
755 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
761 Result.push_back(ParentDecl);
767 llvm::Optional<TypeHierarchyItem>
775 Optional<TypeHierarchyItem> Result =
782 Result->parents.emplace();
791 Result->children.emplace();
796 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
797 CXXRD = CTSD->getTemplateInstantiationPattern();
800 fillSubTypes(*ID, *Result->children, Index, ResolveLevels, TUPath);
817 if (Index && Item.
data) {
827 const FunctionDecl *FD) {
830 llvm::DenseSet<const Decl *> DeclRefs;
833 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
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...
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol...
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user. ...
static llvm::Optional< TypeHierarchyItem > declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND)
llvm::Optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item...
static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx, std::vector< TypeHierarchyItem > &SuperTypes, RecursionProtectionSet &RPSet)
const FunctionDecl * Decl
llvm::DenseSet< SymbolID > IDs
static Optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, const SymbolIndex *Index, PathRef TUPath)
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
const LangOptions & getLangOpts() const
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Range range
The range this highlight applies to.
Preprocessor & getPreprocessor()
Information about a reference written in the source code, independent of the actual AST node that thi...
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
llvm::SmallSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
This is the pattern the template specialization was instantiated from.
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
llvm::DenseSet< SymbolID > IDs
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
Represents a symbol occurrence in the source file.
llvm::Optional< Location > Definition
SourceLocation getBeginningOfIdentifier(const Position &Pos, const SourceManager &SM, const LangOptions &LangOpts)
Get the beginning SourceLocation at a specified Pos in the main file.
llvm::Optional< std::string > data
An optional 'data' filed, which can be used to identify a type hierarchy item in a resolve request...
URIForFile uri
The text document's URI.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
std::vector< CodeCompletionResult > Results
std::string name
The human readable name of the hierarchy item.
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index)
Returns references of the symbol at a specified Pos.
Documents should not be synced at all.
Range selectionRange
The range that should be selected and revealed when this type hierarchy item is being picked...
void elog(const char *Fmt, Ts &&... Vals)
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
This declaration is an alias that was referred to.
const syntax::TokenBuffer & getTokens() const
Tokens recorded while parsing the main file.
Range range
The range enclosing this type hierarchy item not including leading/trailing whitespace but everything...
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
SymbolID ID
The ID of the symbol.
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
A document highlight is a range inside a text document which deserves special attention.
llvm::DenseMap< SymbolID, std::vector< Range > > MacroRefs
SymbolLocation Definition
The location of the symbol's definition, if one was found.
llvm::Optional< SymbolID > ID
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
const IncludeStructure & getIncludeStructure() const
clang::find_all_symbols::SymbolInfo SymbolInfo
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask)
SymbolLocation Location
The source location where the symbol is named.
void log(const char *Fmt, Ts &&... Vals)
index::SymbolRoleSet Role
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
std::string containerName
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
Location PreferredDeclaration
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
llvm::SmallVector< const NamedDecl *, 1 > Targets
A list of targets referenced by this name.
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
llvm::DenseSet< SymbolID > Subjects
llvm::Expected< Location > symbolToLocation(const Symbol &Sym, llvm::StringRef HintPath)
Helper function for deriving an LSP Location for a Symbol.
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const ast_type_traits::DynTypedNode &N, DeclRelationSet Mask)
targetDecl() finds the declaration referred to by an AST node.
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Stores and provides access to parsed AST.
SourceManager & getSourceManager()
int line
Line position in a document (zero-based).
const MainFileMacros & getMacros() const
Gets all macro references (definition, expansions) present in the main file, including those in the p...
bool contains(Position Pos) const
The class presents a C++ symbol, e.g.
std::vector< Inclusion > MainFileIncludes
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const CXXRecordDecl * findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record type references at Pos.
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out)
Recursively traverse S and report all references explicitly written in the code.
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
This is the underlying declaration for an alias, decltype etc.
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
CharSourceRange Range
SourceRange for the file name.
DocumentHighlightKind kind
The highlight kind, default is DocumentHighlightKind.Text.
llvm::Optional< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
llvm::SmallDenseMap< const NamedDecl *, RelSet > Decls
SymbolKind kind
The kind of the hierarchy item. For instance, class or interface.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Indicates if the symbol is deprecated.
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
A range in a text document that links to an internal or external resource, like another text document...
std::unique_ptr< GlobalCompilationDatabase > Base
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
URIForFile uri
The URI of the text document where this type hierarchy item belongs to.
std::array< uint8_t, 20 > SymbolID
llvm::Optional< DefinedMacro > locateMacroAt(SourceLocation Loc, Preprocessor &PP)
Gets the macro at a specified Loc.
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...
bool deprecated
true if the hierarchy item is deprecated. Otherwise, false.
Represents information about identifier.
std::vector< Location > References
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
llvm::StringRef file() const
Retrieves absolute path to the file.
const SymbolIndex * Index