1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "XRefs.h"
9 #include "AST.h"
10 #include "CodeCompletionStrings.h"
11 #include "FindSymbols.h"
12 #include "FormattedString.h"
13 #include "Logger.h"
14 #include "Protocol.h"
15 #include "SourceCode.h"
16 #include "URI.h"
17 #include "index/Index.h"
18 #include "index/Merge.h"
19 #include "index/SymbolCollector.h"
20 #include "index/SymbolLocation.h"
21 #include "clang/AST/ASTContext.h"
22 #include "clang/AST/Decl.h"
23 #include "clang/AST/DeclCXX.h"
24 #include "clang/AST/DeclTemplate.h"
25 #include "clang/AST/ExprCXX.h"
26 #include "clang/AST/PrettyPrinter.h"
27 #include "clang/AST/RecursiveASTVisitor.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/USRGeneration.h"
36 #include "llvm/ADT/ArrayRef.h"
37 #include "llvm/ADT/None.h"
38 #include "llvm/ADT/STLExtras.h"
39 #include "llvm/ADT/StringExtras.h"
40 #include "llvm/ADT/StringRef.h"
41 #include "llvm/Support/Casting.h"
42 #include "llvm/Support/FormatVariadic.h"
43 #include "llvm/Support/Path.h"
44 #include "llvm/Support/raw_ostream.h"
45
46 namespace clang {
47 namespace clangd {
48 namespace {
49
50 // Returns the single definition of the entity declared by D, if visible.
51 // In particular:
52 // - for non-redeclarable kinds (e.g. local vars), return D
53 // - for kinds that allow multiple definitions (e.g. namespaces), return nullptr
54 // Kinds of nodes that always return nullptr here will not have definitions
55 // reported by locateSymbolAt().
getDefinition(const Decl * D)56 const Decl *getDefinition(const Decl *D) {
57 assert(D);
58 // Decl has one definition that we can find.
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();
65 // Only a single declaration is allowed.
66 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
67 isa<TemplateTemplateParmDecl>(D)) // except cases above
68 return D;
69 // Multiple definitions are allowed.
70 return nullptr; // except cases above
71 }
72
logIfOverflow(const SymbolLocation & Loc)73 void logIfOverflow(const SymbolLocation &Loc) {
74 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
75 log("Possible overflow in symbol location: {0}", Loc);
76 }
77
78 // Convert a SymbolLocation to LSP's Location.
79 // TUPath is used to resolve the path of URI.
80 // FIXME: figure out a good home for it, and share the implementation with
81 // FindSymbols.
toLSPLocation(const SymbolLocation & Loc,llvm::StringRef TUPath)82 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
83 llvm::StringRef TUPath) {
84 if (!Loc)
85 return None;
86 auto Uri = URI::parse(Loc.FileURI);
87 if (!Uri) {
88 elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
89 return None;
90 }
91 auto U = URIForFile::fromURI(*Uri, TUPath);
92 if (!U) {
93 elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
94 return None;
95 }
96
97 Location LSPLoc;
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();
103 logIfOverflow(Loc);
104 return LSPLoc;
105 }
106
toIndexLocation(const Location & Loc,std::string & URIStorage)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);
115 return SymLoc;
116 }
117
118 // Returns the preferred location between an AST location and an index location.
getPreferredLocation(const Location & ASTLoc,const SymbolLocation & IdxLoc,std::string & Scratch)119 SymbolLocation getPreferredLocation(const Location &ASTLoc,
120 const SymbolLocation &IdxLoc,
121 std::string &Scratch) {
122 // Also use a dummy symbol for the index location so that other fields (e.g.
123 // definition) are not factored into the preferrence.
124 Symbol ASTSym, IdxSym;
125 ASTSym.ID = IdxSym.ID = SymbolID("dummy_id");
126 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
127 IdxSym.CanonicalDeclaration = IdxLoc;
128 auto Merged = mergeSymbol(ASTSym, IdxSym);
129 return Merged.CanonicalDeclaration;
130 }
131
132 /// Finds declarations locations that a given source location refers to.
133 class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
134 std::vector<DefinedMacro> MacroInfos;
135 llvm::DenseSet<const Decl *> Decls;
136 const SourceLocation &SearchedLocation;
137 Preprocessor &PP;
138
139 public:
DeclarationAndMacrosFinder(const SourceLocation & SearchedLocation,Preprocessor & PP)140 DeclarationAndMacrosFinder(const SourceLocation &SearchedLocation,
141 Preprocessor &PP)
142 : SearchedLocation(SearchedLocation), PP(PP) {}
143
144 // The results are sorted by declaration location.
getFoundDecls() const145 std::vector<const Decl *> getFoundDecls() const {
146 std::vector<const Decl *> Result;
147 for (const Decl *D : Decls)
148 Result.push_back(D);
149
150 llvm::sort(Result, [](const Decl *L, const Decl *R) {
151 return L->getBeginLoc() < R->getBeginLoc();
152 });
153 return Result;
154 }
155
takeMacroInfos()156 std::vector<DefinedMacro> takeMacroInfos() {
157 // Don't keep the same Macro info multiple times.
158 llvm::sort(MacroInfos,
159 [](const DefinedMacro &Left, const DefinedMacro &Right) {
160 return Left.Info < Right.Info;
161 });
162
163 auto Last =
164 std::unique(MacroInfos.begin(), MacroInfos.end(),
165 [](const DefinedMacro &Left, const DefinedMacro &Right) {
166 return Left.Info == Right.Info;
167 });
168 MacroInfos.erase(Last, MacroInfos.end());
169 return std::move(MacroInfos);
170 }
171
172 bool
handleDeclOccurence(const Decl * D,index::SymbolRoleSet Roles,llvm::ArrayRef<index::SymbolRelation> Relations,SourceLocation Loc,index::IndexDataConsumer::ASTNodeInfo ASTNode)173 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
174 llvm::ArrayRef<index::SymbolRelation> Relations,
175 SourceLocation Loc,
176 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
177 // Skip non-semantic references.
178 if (Roles & static_cast<unsigned>(index::SymbolRole::NameReference))
179 return true;
180
181 if (Loc == SearchedLocation) {
182 auto IsImplicitExpr = [](const Expr *E) {
183 if (!E)
184 return false;
185 // We assume that a constructor expression is implict (was inserted by
186 // clang) if it has an invalid paren/brace location, since such
187 // experssion is impossible to write down.
188 if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E))
189 return CtorExpr->getParenOrBraceRange().isInvalid();
190 return isa<ImplicitCastExpr>(E);
191 };
192
193 if (IsImplicitExpr(ASTNode.OrigE))
194 return true;
195 // Find and add definition declarations (for GoToDefinition).
196 // We don't use parameter `D`, as Parameter `D` is the canonical
197 // declaration, which is the first declaration of a redeclarable
198 // declaration, and it could be a forward declaration.
199 if (const auto *Def = getDefinition(D)) {
200 Decls.insert(Def);
201 } else {
202 // Couldn't find a definition, fall back to use `D`.
203 Decls.insert(D);
204 }
205 }
206 return true;
207 }
208
209 private:
finish()210 void finish() override {
211 if (auto DefinedMacro = locateMacroAt(SearchedLocation, PP)) {
212 MacroInfos.push_back(*DefinedMacro);
213 assert(Decls.empty());
214 }
215 }
216 };
217
218 struct IdentifiedSymbol {
219 std::vector<const Decl *> Decls;
220 std::vector<DefinedMacro> Macros;
221 };
222
getSymbolAtPosition(ParsedAST & AST,SourceLocation Pos)223 IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) {
224 auto DeclMacrosFinder =
225 DeclarationAndMacrosFinder(Pos, AST.getPreprocessor());
226 index::IndexingOptions IndexOpts;
227 IndexOpts.SystemSymbolFilter =
228 index::IndexingOptions::SystemSymbolFilterKind::All;
229 IndexOpts.IndexFunctionLocals = true;
230 IndexOpts.IndexParametersInDeclarations = true;
231 IndexOpts.IndexTemplateParameters = true;
232 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
233 AST.getLocalTopLevelDecls(), DeclMacrosFinder, IndexOpts);
234
235 return {DeclMacrosFinder.getFoundDecls(), DeclMacrosFinder.takeMacroInfos()};
236 }
237
makeLocation(ASTContext & AST,SourceLocation TokLoc,llvm::StringRef TUPath)238 llvm::Optional<Location> makeLocation(ASTContext &AST, SourceLocation TokLoc,
239 llvm::StringRef TUPath) {
240 const SourceManager &SourceMgr = AST.getSourceManager();
241 const FileEntry *F = SourceMgr.getFileEntryForID(SourceMgr.getFileID(TokLoc));
242 if (!F)
243 return None;
244 auto FilePath = getCanonicalPath(F, SourceMgr);
245 if (!FilePath) {
246 log("failed to get path!");
247 return None;
248 }
249 if (auto Range =
250 getTokenRange(AST.getSourceManager(), AST.getLangOpts(), TokLoc)) {
251 Location L;
252 L.uri = URIForFile::canonicalize(*FilePath, TUPath);
253 L.range = *Range;
254 return L;
255 }
256 return None;
257 }
258
259 } // namespace
260
locateSymbolAt(ParsedAST & AST,Position Pos,const SymbolIndex * Index)261 std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
262 const SymbolIndex *Index) {
263 const auto &SM = AST.getSourceManager();
264 auto MainFilePath =
265 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
266 if (!MainFilePath) {
267 elog("Failed to get a path for the main file, so no references");
268 return {};
269 }
270
271 // Treat #included files as symbols, to enable go-to-definition on them.
272 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
273 if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) {
274 LocatedSymbol File;
275 File.Name = llvm::sys::path::filename(Inc.Resolved);
276 File.PreferredDeclaration = {
277 URIForFile::canonicalize(Inc.Resolved, *MainFilePath), Range{}};
278 File.Definition = File.PreferredDeclaration;
279 // We're not going to find any further symbols on #include lines.
280 return {std::move(File)};
281 }
282 }
283
284 SourceLocation SourceLocationBeg =
285 getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
286 auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
287
288 // Macros are simple: there's no declaration/definition distinction.
289 // As a consequence, there's no need to look them up in the index either.
290 std::vector<LocatedSymbol> Result;
291 for (auto M : Symbols.Macros) {
292 if (auto Loc = makeLocation(AST.getASTContext(), M.Info->getDefinitionLoc(),
293 *MainFilePath)) {
294 LocatedSymbol Macro;
295 Macro.Name = M.Name;
296 Macro.PreferredDeclaration = *Loc;
297 Macro.Definition = Loc;
298 Result.push_back(std::move(Macro));
299 }
300 }
301
302 // Decls are more complicated.
303 // The AST contains at least a declaration, maybe a definition.
304 // These are up-to-date, and so generally preferred over index results.
305 // We perform a single batch index lookup to find additional definitions.
306
307 // Results follow the order of Symbols.Decls.
308 // Keep track of SymbolID -> index mapping, to fill in index data later.
309 llvm::DenseMap<SymbolID, size_t> ResultIndex;
310
311 // Emit all symbol locations (declaration or definition) from AST.
312 for (const Decl *D : Symbols.Decls) {
313 auto Loc = makeLocation(AST.getASTContext(), findNameLoc(D), *MainFilePath);
314 if (!Loc)
315 continue;
316
317 Result.emplace_back();
318 if (auto *ND = dyn_cast<NamedDecl>(D))
319 Result.back().Name = printName(AST.getASTContext(), *ND);
320 Result.back().PreferredDeclaration = *Loc;
321 // DeclInfo.D is always a definition if possible, so this check works.
322 if (getDefinition(D) == D)
323 Result.back().Definition = *Loc;
324
325 // Record SymbolID for index lookup later.
326 if (auto ID = getSymbolID(D))
327 ResultIndex[*ID] = Result.size() - 1;
328 }
329
330 // Now query the index for all Symbol IDs we found in the AST.
331 if (Index && !ResultIndex.empty()) {
332 LookupRequest QueryRequest;
333 for (auto It : ResultIndex)
334 QueryRequest.IDs.insert(It.first);
335 std::string Scratch;
336 Index->lookup(QueryRequest, [&](const Symbol &Sym) {
337 auto &R = Result[ResultIndex.lookup(Sym.ID)];
338
339 if (R.Definition) { // from AST
340 // Special case: if the AST yielded a definition, then it may not be
341 // the right *declaration*. Prefer the one from the index.
342 if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, *MainFilePath))
343 R.PreferredDeclaration = *Loc;
344
345 // We might still prefer the definition from the index, e.g. for
346 // generated symbols.
347 if (auto Loc = toLSPLocation(
348 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
349 *MainFilePath))
350 R.Definition = *Loc;
351 } else {
352 R.Definition = toLSPLocation(Sym.Definition, *MainFilePath);
353
354 // Use merge logic to choose AST or index declaration.
355 if (auto Loc = toLSPLocation(
356 getPreferredLocation(R.PreferredDeclaration,
357 Sym.CanonicalDeclaration, Scratch),
358 *MainFilePath))
359 R.PreferredDeclaration = *Loc;
360 }
361 });
362 }
363
364 return Result;
365 }
366
367 namespace {
368
369 /// Collects references to symbols within the main file.
370 class ReferenceFinder : public index::IndexDataConsumer {
371 public:
372 struct Reference {
373 const Decl *CanonicalTarget;
374 SourceLocation Loc;
375 index::SymbolRoleSet Role;
376 };
377
ReferenceFinder(ASTContext & AST,Preprocessor & PP,const std::vector<const Decl * > & TargetDecls)378 ReferenceFinder(ASTContext &AST, Preprocessor &PP,
379 const std::vector<const Decl *> &TargetDecls)
380 : AST(AST) {
381 for (const Decl *D : TargetDecls)
382 CanonicalTargets.insert(D->getCanonicalDecl());
383 }
384
take()385 std::vector<Reference> take() && {
386 llvm::sort(References, [](const Reference &L, const Reference &R) {
387 return std::tie(L.Loc, L.CanonicalTarget, L.Role) <
388 std::tie(R.Loc, R.CanonicalTarget, R.Role);
389 });
390 // We sometimes see duplicates when parts of the AST get traversed twice.
391 References.erase(
392 std::unique(References.begin(), References.end(),
393 [](const Reference &L, const Reference &R) {
394 return std::tie(L.CanonicalTarget, L.Loc, L.Role) ==
395 std::tie(R.CanonicalTarget, R.Loc, R.Role);
396 }),
397 References.end());
398 return std::move(References);
399 }
400
401 bool
handleDeclOccurence(const Decl * D,index::SymbolRoleSet Roles,llvm::ArrayRef<index::SymbolRelation> Relations,SourceLocation Loc,index::IndexDataConsumer::ASTNodeInfo ASTNode)402 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
403 llvm::ArrayRef<index::SymbolRelation> Relations,
404 SourceLocation Loc,
405 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
406 assert(D->isCanonicalDecl() && "expect D to be a canonical declaration");
407 const SourceManager &SM = AST.getSourceManager();
408 Loc = SM.getFileLoc(Loc);
409 if (isInsideMainFile(Loc, SM) && CanonicalTargets.count(D))
410 References.push_back({D, Loc, Roles});
411 return true;
412 }
413
414 private:
415 llvm::SmallSet<const Decl *, 4> CanonicalTargets;
416 std::vector<Reference> References;
417 const ASTContext &AST;
418 };
419
420 std::vector<ReferenceFinder::Reference>
findRefs(const std::vector<const Decl * > & Decls,ParsedAST & AST)421 findRefs(const std::vector<const Decl *> &Decls, ParsedAST &AST) {
422 ReferenceFinder RefFinder(AST.getASTContext(), AST.getPreprocessor(), Decls);
423 index::IndexingOptions IndexOpts;
424 IndexOpts.SystemSymbolFilter =
425 index::IndexingOptions::SystemSymbolFilterKind::All;
426 IndexOpts.IndexFunctionLocals = true;
427 IndexOpts.IndexParametersInDeclarations = true;
428 IndexOpts.IndexTemplateParameters = true;
429 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
430 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
431 return std::move(RefFinder).take();
432 }
433
434 } // namespace
435
findDocumentHighlights(ParsedAST & AST,Position Pos)436 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
437 Position Pos) {
438 const SourceManager &SM = AST.getSourceManager();
439 auto Symbols = getSymbolAtPosition(
440 AST, getBeginningOfIdentifier(AST, Pos, SM.getMainFileID()));
441 auto References = findRefs(Symbols.Decls, AST);
442
443 std::vector<DocumentHighlight> Result;
444 for (const auto &Ref : References) {
445 if (auto Range =
446 getTokenRange(AST.getASTContext().getSourceManager(),
447 AST.getASTContext().getLangOpts(), Ref.Loc)) {
448 DocumentHighlight DH;
449 DH.range = *Range;
450 if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
451 DH.kind = DocumentHighlightKind::Write;
452 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
453 DH.kind = DocumentHighlightKind::Read;
454 else
455 DH.kind = DocumentHighlightKind::Text;
456 Result.push_back(std::move(DH));
457 }
458 }
459 return Result;
460 }
461
printingPolicyForDecls(PrintingPolicy Base)462 static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
463 PrintingPolicy Policy(Base);
464
465 Policy.AnonymousTagLocations = false;
466 Policy.TerseOutput = true;
467 Policy.PolishForDeclaration = true;
468 Policy.ConstantsAsWritten = true;
469 Policy.SuppressTagKeyword = false;
470
471 return Policy;
472 }
473
474 /// Given a declaration \p D, return a human-readable string representing the
475 /// local scope in which it is declared, i.e. class(es) and method name. Returns
476 /// an empty string if it is not local.
getLocalScope(const Decl * D)477 static std::string getLocalScope(const Decl *D) {
478 std::vector<std::string> Scopes;
479 const DeclContext *DC = D->getDeclContext();
480 auto GetName = [](const Decl *D) {
481 const NamedDecl *ND = dyn_cast<NamedDecl>(D);
482 std::string Name = ND->getNameAsString();
483 if (!Name.empty())
484 return Name;
485 if (auto RD = dyn_cast<RecordDecl>(D))
486 return ("(anonymous " + RD->getKindName() + ")").str();
487 return std::string("");
488 };
489 while (DC) {
490 if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
491 Scopes.push_back(GetName(TD));
492 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
493 Scopes.push_back(FD->getNameAsString());
494 DC = DC->getParent();
495 }
496
497 return llvm::join(llvm::reverse(Scopes), "::");
498 }
499
500 /// Returns the human-readable representation for namespace containing the
501 /// declaration \p D. Returns empty if it is contained global namespace.
getNamespaceScope(const Decl * D)502 static std::string getNamespaceScope(const Decl *D) {
503 const DeclContext *DC = D->getDeclContext();
504
505 if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
506 return getNamespaceScope(TD);
507 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
508 return getNamespaceScope(FD);
509 if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
510 return ND->getQualifiedNameAsString();
511
512 return "";
513 }
514
printDefinition(const Decl * D)515 static std::string printDefinition(const Decl *D) {
516 std::string Definition;
517 llvm::raw_string_ostream OS(Definition);
518 PrintingPolicy Policy =
519 printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
520 Policy.IncludeTagDefinition = false;
521 D->print(OS, Policy);
522 return Definition;
523 }
524
printParams(llvm::raw_ostream & OS,const std::vector<HoverInfo::Param> & Params)525 static void printParams(llvm::raw_ostream &OS,
526 const std::vector<HoverInfo::Param> &Params) {
527 for (size_t I = 0, E = Params.size(); I != E; ++I) {
528 if (I)
529 OS << ", ";
530 OS << Params.at(I);
531 }
532 }
533
534 static std::vector<HoverInfo::Param>
fetchTemplateParameters(const TemplateParameterList * Params,const PrintingPolicy & PP)535 fetchTemplateParameters(const TemplateParameterList *Params,
536 const PrintingPolicy &PP) {
537 assert(Params);
538 std::vector<HoverInfo::Param> TempParameters;
539
540 for (const Decl *Param : *Params) {
541 HoverInfo::Param P;
542 P.Type.emplace();
543 if (const auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
544 P.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
545 if (TTP->isParameterPack())
546 *P.Type += "...";
547
548 if (!TTP->getName().empty())
549 P.Name = TTP->getNameAsString();
550 if (TTP->hasDefaultArgument())
551 P.Default = TTP->getDefaultArgument().getAsString(PP);
552 } else if (const auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
553 if (IdentifierInfo *II = NTTP->getIdentifier())
554 P.Name = II->getName().str();
555
556 llvm::raw_string_ostream Out(*P.Type);
557 NTTP->getType().print(Out, PP);
558 if (NTTP->isParameterPack())
559 Out << "...";
560
561 if (NTTP->hasDefaultArgument()) {
562 P.Default.emplace();
563 llvm::raw_string_ostream Out(*P.Default);
564 NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
565 }
566 } else if (const auto TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
567 llvm::raw_string_ostream OS(*P.Type);
568 OS << "template <";
569 printParams(OS,
570 fetchTemplateParameters(TTPD->getTemplateParameters(), PP));
571 OS << "> class"; // FIXME: TemplateTemplateParameter doesn't store the
572 // info on whether this param was a "typename" or
573 // "class".
574 if (!TTPD->getName().empty())
575 P.Name = TTPD->getNameAsString();
576 if (TTPD->hasDefaultArgument()) {
577 P.Default.emplace();
578 llvm::raw_string_ostream Out(*P.Default);
579 TTPD->getDefaultArgument().getArgument().print(PP, Out);
580 }
581 }
582 TempParameters.push_back(std::move(P));
583 }
584
585 return TempParameters;
586 }
587
getUnderlyingFunction(const Decl * D)588 static const FunctionDecl *getUnderlyingFunction(const Decl *D) {
589 // Extract lambda from variables.
590 if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
591 auto QT = VD->getType();
592 if (!QT.isNull()) {
593 while (!QT->getPointeeType().isNull())
594 QT = QT->getPointeeType();
595
596 if (const auto *CD = QT->getAsCXXRecordDecl())
597 return CD->getLambdaCallOperator();
598 }
599 }
600
601 // Non-lambda functions.
602 return D->getAsFunction();
603 }
604
605 // Look up information about D from the index, and add it to Hover.
enhanceFromIndex(HoverInfo & Hover,const Decl * D,const SymbolIndex * Index)606 static void enhanceFromIndex(HoverInfo &Hover, const Decl *D,
607 const SymbolIndex *Index) {
608 if (!Index || !llvm::isa<NamedDecl>(D))
609 return;
610 const NamedDecl &ND = *cast<NamedDecl>(D);
611 // We only add documentation, so don't bother if we already have some.
612 if (!Hover.Documentation.empty())
613 return;
614 // Skip querying for non-indexable symbols, there's no point.
615 // We're searching for symbols that might be indexed outside this main file.
616 if (!SymbolCollector::shouldCollectSymbol(ND, ND.getASTContext(),
617 SymbolCollector::Options(),
618 /*IsMainFileOnly=*/false))
619 return;
620 auto ID = getSymbolID(&ND);
621 if (!ID)
622 return;
623 LookupRequest Req;
624 Req.IDs.insert(*ID);
625 Index->lookup(
626 Req, [&](const Symbol &S) { Hover.Documentation = S.Documentation; });
627 }
628
629 /// Generate a \p Hover object given the declaration \p D.
getHoverContents(const Decl * D,const SymbolIndex * Index)630 static HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) {
631 HoverInfo HI;
632 const ASTContext &Ctx = D->getASTContext();
633
634 HI.NamespaceScope = getNamespaceScope(D);
635 if (!HI.NamespaceScope->empty())
636 HI.NamespaceScope->append("::");
637 HI.LocalScope = getLocalScope(D);
638 if (!HI.LocalScope.empty())
639 HI.LocalScope.append("::");
640
641 PrintingPolicy Policy = printingPolicyForDecls(Ctx.getPrintingPolicy());
642 if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
643 HI.Documentation = getDeclComment(Ctx, *ND);
644 HI.Name = printName(Ctx, *ND);
645 }
646
647 HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(D).Kind);
648
649 // Fill in template params.
650 if (const TemplateDecl *TD = D->getDescribedTemplate()) {
651 HI.TemplateParameters =
652 fetchTemplateParameters(TD->getTemplateParameters(), Policy);
653 D = TD;
654 } else if (const FunctionDecl *FD = D->getAsFunction()) {
655 if (const auto FTD = FD->getDescribedTemplate()) {
656 HI.TemplateParameters =
657 fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
658 D = FTD;
659 }
660 }
661
662 // Fill in types and params.
663 if (const FunctionDecl *FD = getUnderlyingFunction(D)) {
664 HI.ReturnType.emplace();
665 {
666 llvm::raw_string_ostream OS(*HI.ReturnType);
667 FD->getReturnType().print(OS, Policy);
668 }
669
670 HI.Parameters.emplace();
671 for (const ParmVarDecl *PVD : FD->parameters()) {
672 HI.Parameters->emplace_back();
673 auto &P = HI.Parameters->back();
674 if (!PVD->getType().isNull()) {
675 P.Type.emplace();
676 llvm::raw_string_ostream OS(*P.Type);
677 PVD->getType().print(OS, Policy);
678 } else {
679 std::string Param;
680 llvm::raw_string_ostream OS(Param);
681 PVD->dump(OS);
682 OS.flush();
683 elog("Got param with null type: {0}", Param);
684 }
685 if (!PVD->getName().empty())
686 P.Name = PVD->getNameAsString();
687 if (PVD->hasDefaultArg()) {
688 P.Default.emplace();
689 llvm::raw_string_ostream Out(*P.Default);
690 PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
691 }
692 }
693
694 HI.Type.emplace();
695 llvm::raw_string_ostream TypeOS(*HI.Type);
696 // Lambdas
697 if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
698 VD->getType().getDesugaredType(D->getASTContext()).print(TypeOS, Policy);
699 // Functions
700 else
701 FD->getType().print(TypeOS, Policy);
702 // FIXME: handle variadics.
703 } else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
704 HI.Type.emplace();
705 llvm::raw_string_ostream OS(*HI.Type);
706 VD->getType().print(OS, Policy);
707 }
708
709 // Fill in value with evaluated initializer if possible.
710 // FIXME(kadircet): Also set Value field for expressions like "sizeof" and
711 // function calls.
712 if (const auto *Var = dyn_cast<VarDecl>(D)) {
713 if (const Expr *Init = Var->getInit()) {
714 Expr::EvalResult Result;
715 if (!Init->isValueDependent() && Init->EvaluateAsRValue(Result, Ctx)) {
716 HI.Value.emplace();
717 llvm::raw_string_ostream ValueOS(*HI.Value);
718 Result.Val.printPretty(ValueOS, const_cast<ASTContext &>(Ctx),
719 Init->getType());
720 }
721 }
722 }
723
724 HI.Definition = printDefinition(D);
725 enhanceFromIndex(HI, D, Index);
726 return HI;
727 }
728
729 /// Generate a \p Hover object given the type \p T.
getHoverContents(QualType T,const Decl * D,ASTContext & ASTCtx,const SymbolIndex * Index)730 static HoverInfo getHoverContents(QualType T, const Decl *D, ASTContext &ASTCtx,
731 const SymbolIndex *Index) {
732 HoverInfo HI;
733 llvm::raw_string_ostream OS(HI.Name);
734 PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
735 T.print(OS, Policy);
736
737 if (D) {
738 HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(D).Kind);
739 enhanceFromIndex(HI, D, Index);
740 }
741 return HI;
742 }
743
744 /// Generate a \p Hover object given the macro \p MacroDecl.
getHoverContents(const DefinedMacro & Macro,ParsedAST & AST)745 static HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
746 HoverInfo HI;
747 SourceManager &SM = AST.getSourceManager();
748 HI.Name = Macro.Name;
749 HI.Kind = indexSymbolKindToSymbolKind(
750 index::getSymbolInfoForMacro(*Macro.Info).Kind);
751 // FIXME: Populate documentation
752 // FIXME: Pupulate parameters
753
754 // Try to get the full definition, not just the name
755 SourceLocation StartLoc = Macro.Info->getDefinitionLoc();
756 SourceLocation EndLoc = Macro.Info->getDefinitionEndLoc();
757 if (EndLoc.isValid()) {
758 EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM,
759 AST.getASTContext().getLangOpts());
760 bool Invalid;
761 StringRef Buffer = SM.getBufferData(SM.getFileID(StartLoc), &Invalid);
762 if (!Invalid) {
763 unsigned StartOffset = SM.getFileOffset(StartLoc);
764 unsigned EndOffset = SM.getFileOffset(EndLoc);
765 if (EndOffset <= Buffer.size() && StartOffset < EndOffset)
766 HI.Definition =
767 ("#define " + Buffer.substr(StartOffset, EndOffset - StartOffset))
768 .str();
769 }
770 }
771 return HI;
772 }
773
774 namespace {
775 /// Computes the deduced type at a given location by visiting the relevant
776 /// nodes. We use this to display the actual type when hovering over an "auto"
777 /// keyword or "decltype()" expression.
778 /// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
779 /// seems that the AutoTypeLocs that can be visited along with their AutoType do
780 /// not have the deduced type set. Instead, we have to go to the appropriate
781 /// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
782 /// a deduced type set. The AST should be improved to simplify this scenario.
783 class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
784 SourceLocation SearchedLocation;
785
786 public:
DeducedTypeVisitor(SourceLocation SearchedLocation)787 DeducedTypeVisitor(SourceLocation SearchedLocation)
788 : SearchedLocation(SearchedLocation) {}
789
790 // Handle auto initializers:
791 //- auto i = 1;
792 //- decltype(auto) i = 1;
793 //- auto& i = 1;
794 //- auto* i = &a;
VisitDeclaratorDecl(DeclaratorDecl * D)795 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
796 if (!D->getTypeSourceInfo() ||
797 D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
798 return true;
799
800 if (auto *AT = D->getType()->getContainedAutoType()) {
801 if (!AT->getDeducedType().isNull()) {
802 DeducedType = AT->getDeducedType();
803 this->D = D;
804 }
805 }
806 return true;
807 }
808
809 // Handle auto return types:
810 //- auto foo() {}
811 //- auto& foo() {}
812 //- auto foo() -> int {}
813 //- auto foo() -> decltype(1+1) {}
814 //- operator auto() const { return 10; }
VisitFunctionDecl(FunctionDecl * D)815 bool VisitFunctionDecl(FunctionDecl *D) {
816 if (!D->getTypeSourceInfo())
817 return true;
818 // Loc of auto in return type (c++14).
819 auto CurLoc = D->getReturnTypeSourceRange().getBegin();
820 // Loc of "auto" in operator auto()
821 if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
822 CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
823 // Loc of "auto" in function with traling return type (c++11).
824 if (CurLoc.isInvalid())
825 CurLoc = D->getSourceRange().getBegin();
826 if (CurLoc != SearchedLocation)
827 return true;
828
829 const AutoType *AT = D->getReturnType()->getContainedAutoType();
830 if (AT && !AT->getDeducedType().isNull()) {
831 DeducedType = AT->getDeducedType();
832 this->D = D;
833 } else if (auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
834 // auto in a trailing return type just points to a DecltypeType and
835 // getContainedAutoType does not unwrap it.
836 if (!DT->getUnderlyingType().isNull()) {
837 DeducedType = DT->getUnderlyingType();
838 this->D = D;
839 }
840 } else if (!D->getReturnType().isNull()) {
841 DeducedType = D->getReturnType();
842 this->D = D;
843 }
844 return true;
845 }
846
847 // Handle non-auto decltype, e.g.:
848 // - auto foo() -> decltype(expr) {}
849 // - decltype(expr);
VisitDecltypeTypeLoc(DecltypeTypeLoc TL)850 bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
851 if (TL.getBeginLoc() != SearchedLocation)
852 return true;
853
854 // A DecltypeType's underlying type can be another DecltypeType! E.g.
855 // int I = 0;
856 // decltype(I) J = I;
857 // decltype(J) K = J;
858 const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
859 while (DT && !DT->getUnderlyingType().isNull()) {
860 DeducedType = DT->getUnderlyingType();
861 D = DT->getAsTagDecl();
862 DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
863 }
864 return true;
865 }
866
867 QualType DeducedType;
868 const Decl *D = nullptr;
869 };
870 } // namespace
871
872 /// Retrieves the deduced type at a given location (auto, decltype).
873 /// SourceLocationBeg must point to the first character of the token
getDeducedType(ParsedAST & AST,SourceLocation SourceLocationBeg)874 llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
875 SourceLocation SourceLocationBeg) {
876 Token Tok;
877 auto &ASTCtx = AST.getASTContext();
878 // Only try to find a deduced type if the token is auto or decltype.
879 if (!SourceLocationBeg.isValid() ||
880 Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
881 ASTCtx.getLangOpts(), false) ||
882 !Tok.is(tok::raw_identifier)) {
883 return {};
884 }
885 AST.getPreprocessor().LookUpIdentifierInfo(Tok);
886 if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
887 return {};
888
889 DeducedTypeVisitor V(SourceLocationBeg);
890 V.TraverseAST(AST.getASTContext());
891 return V.DeducedType;
892 }
893
894 /// Retrieves the deduced type at a given location (auto, decltype).
hasDeducedType(ParsedAST & AST,SourceLocation SourceLocationBeg)895 bool hasDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg) {
896 return (bool)getDeducedType(AST, SourceLocationBeg);
897 }
898
getHover(ParsedAST & AST,Position Pos,format::FormatStyle Style,const SymbolIndex * Index)899 llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
900 format::FormatStyle Style,
901 const SymbolIndex *Index) {
902 llvm::Optional<HoverInfo> HI;
903 SourceLocation SourceLocationBeg = getBeginningOfIdentifier(
904 AST, Pos, AST.getSourceManager().getMainFileID());
905 // Identified symbols at a specific position.
906 auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
907
908 if (!Symbols.Macros.empty())
909 HI = getHoverContents(Symbols.Macros[0], AST);
910 else if (!Symbols.Decls.empty())
911 HI = getHoverContents(Symbols.Decls[0], Index);
912 else {
913 if (!hasDeducedType(AST, SourceLocationBeg))
914 return None;
915
916 DeducedTypeVisitor V(SourceLocationBeg);
917 V.TraverseAST(AST.getASTContext());
918 if (V.DeducedType.isNull())
919 return None;
920 HI = getHoverContents(V.DeducedType, V.D, AST.getASTContext(), Index);
921 }
922
923 auto Replacements = format::reformat(
924 Style, HI->Definition, tooling::Range(0, HI->Definition.size()));
925 if (auto Formatted =
926 tooling::applyAllReplacements(HI->Definition, Replacements))
927 HI->Definition = *Formatted;
928
929 HI->SymRange =
930 getTokenRange(AST.getASTContext().getSourceManager(),
931 AST.getASTContext().getLangOpts(), SourceLocationBeg);
932 return HI;
933 }
934
findReferences(ParsedAST & AST,Position Pos,uint32_t Limit,const SymbolIndex * Index)935 std::vector<Location> findReferences(ParsedAST &AST, Position Pos,
936 uint32_t Limit, const SymbolIndex *Index) {
937 if (!Limit)
938 Limit = std::numeric_limits<uint32_t>::max();
939 std::vector<Location> Results;
940 const SourceManager &SM = AST.getSourceManager();
941 auto MainFilePath =
942 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
943 if (!MainFilePath) {
944 elog("Failed to get a path for the main file, so no references");
945 return Results;
946 }
947 auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
948 auto Symbols = getSymbolAtPosition(AST, Loc);
949
950 // We traverse the AST to find references in the main file.
951 // TODO: should we handle macros, too?
952 auto MainFileRefs = findRefs(Symbols.Decls, AST);
953 for (const auto &Ref : MainFileRefs) {
954 if (auto Range =
955 getTokenRange(AST.getASTContext().getSourceManager(),
956 AST.getASTContext().getLangOpts(), Ref.Loc)) {
957 Location Result;
958 Result.range = *Range;
959 Result.uri = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
960 Results.push_back(std::move(Result));
961 }
962 }
963
964 // Now query the index for references from other files.
965 if (Index && Results.size() < Limit) {
966 RefsRequest Req;
967 Req.Limit = Limit;
968
969 for (const Decl *D : Symbols.Decls) {
970 // Not all symbols can be referenced from outside (e.g. function-locals).
971 // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
972 // we know this file isn't a header. The details might be tricky.
973 if (D->getParentFunctionOrMethod())
974 continue;
975 if (auto ID = getSymbolID(D))
976 Req.IDs.insert(*ID);
977 }
978 if (Req.IDs.empty())
979 return Results;
980 Index->refs(Req, [&](const Ref &R) {
981 auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
982 // Avoid indexed results for the main file - the AST is authoritative.
983 if (LSPLoc && LSPLoc->uri.file() != *MainFilePath)
984 Results.push_back(std::move(*LSPLoc));
985 });
986 }
987 if (Results.size() > Limit)
988 Results.resize(Limit);
989 return Results;
990 }
991
getSymbolInfo(ParsedAST & AST,Position Pos)992 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
993 const SourceManager &SM = AST.getSourceManager();
994
995 auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
996 auto Symbols = getSymbolAtPosition(AST, Loc);
997
998 std::vector<SymbolDetails> Results;
999
1000 for (const Decl *D : Symbols.Decls) {
1001 SymbolDetails NewSymbol;
1002 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
1003 std::string QName = printQualifiedName(*ND);
1004 std::tie(NewSymbol.containerName, NewSymbol.name) =
1005 splitQualifiedName(QName);
1006
1007 if (NewSymbol.containerName.empty()) {
1008 if (const auto *ParentND =
1009 dyn_cast_or_null<NamedDecl>(ND->getDeclContext()))
1010 NewSymbol.containerName = printQualifiedName(*ParentND);
1011 }
1012 }
1013 llvm::SmallString<32> USR;
1014 if (!index::generateUSRForDecl(D, USR)) {
1015 NewSymbol.USR = USR.str();
1016 NewSymbol.ID = SymbolID(NewSymbol.USR);
1017 }
1018 Results.push_back(std::move(NewSymbol));
1019 }
1020
1021 for (const auto &Macro : Symbols.Macros) {
1022 SymbolDetails NewMacro;
1023 NewMacro.name = Macro.Name;
1024 llvm::SmallString<32> USR;
1025 if (!index::generateUSRForMacro(NewMacro.name,
1026 Macro.Info->getDefinitionLoc(), SM, USR)) {
1027 NewMacro.USR = USR.str();
1028 NewMacro.ID = SymbolID(NewMacro.USR);
1029 }
1030 Results.push_back(std::move(NewMacro));
1031 }
1032
1033 return Results;
1034 }
1035
operator <<(llvm::raw_ostream & OS,const LocatedSymbol & S)1036 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {
1037 OS << S.Name << ": " << S.PreferredDeclaration;
1038 if (S.Definition)
1039 OS << " def=" << *S.Definition;
1040 return OS;
1041 }
1042
1043 // FIXME(nridge): Reduce duplication between this function and declToSym().
1044 static llvm::Optional<TypeHierarchyItem>
declToTypeHierarchyItem(ASTContext & Ctx,const NamedDecl & ND)1045 declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND) {
1046 auto &SM = Ctx.getSourceManager();
1047
1048 SourceLocation NameLoc = findNameLoc(&ND);
1049 // getFileLoc is a good choice for us, but we also need to make sure
1050 // sourceLocToPosition won't switch files, so we call getSpellingLoc on top of
1051 // that to make sure it does not switch files.
1052 // FIXME: sourceLocToPosition should not switch files!
1053 SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc()));
1054 SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc()));
1055 if (NameLoc.isInvalid() || BeginLoc.isInvalid() || EndLoc.isInvalid())
1056 return llvm::None;
1057
1058 Position NameBegin = sourceLocToPosition(SM, NameLoc);
1059 Position NameEnd = sourceLocToPosition(
1060 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1061
1062 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1063 // FIXME: this is not classifying constructors, destructors and operators
1064 // correctly (they're all "methods").
1065 SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
1066
1067 TypeHierarchyItem THI;
1068 THI.name = printName(Ctx, ND);
1069 THI.kind = SK;
1070 THI.deprecated = ND.isDeprecated();
1071 THI.range =
1072 Range{sourceLocToPosition(SM, BeginLoc), sourceLocToPosition(SM, EndLoc)};
1073 THI.selectionRange = Range{NameBegin, NameEnd};
1074 if (!THI.range.contains(THI.selectionRange)) {
1075 // 'selectionRange' must be contained in 'range', so in cases where clang
1076 // reports unrelated ranges we need to reconcile somehow.
1077 THI.range = THI.selectionRange;
1078 }
1079
1080 auto FilePath =
1081 getCanonicalPath(SM.getFileEntryForID(SM.getFileID(BeginLoc)), SM);
1082 auto TUPath = getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
1083 if (!FilePath || !TUPath)
1084 return llvm::None; // Not useful without a uri.
1085 THI.uri = URIForFile::canonicalize(*FilePath, *TUPath);
1086
1087 return THI;
1088 }
1089
1090 static Optional<TypeHierarchyItem>
symbolToTypeHierarchyItem(const Symbol & S,const SymbolIndex * Index,PathRef TUPath)1091 symbolToTypeHierarchyItem(const Symbol &S, const SymbolIndex *Index,
1092 PathRef TUPath) {
1093 auto Loc = symbolToLocation(S, TUPath);
1094 if (!Loc) {
1095 log("Type hierarchy: {0}", Loc.takeError());
1096 return llvm::None;
1097 }
1098 TypeHierarchyItem THI;
1099 THI.name = S.Name;
1100 THI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
1101 THI.deprecated = (S.Flags & Symbol::Deprecated);
1102 THI.selectionRange = Loc->range;
1103 // FIXME: Populate 'range' correctly
1104 // (https://github.com/clangd/clangd/issues/59).
1105 THI.range = THI.selectionRange;
1106 THI.uri = Loc->uri;
1107 // Store the SymbolID in the 'data' field. The client will
1108 // send this back in typeHierarchy/resolve, allowing us to
1109 // continue resolving additional levels of the type hierarchy.
1110 THI.data = S.ID.str();
1111
1112 return std::move(THI);
1113 }
1114
fillSubTypes(const SymbolID & ID,std::vector<TypeHierarchyItem> & SubTypes,const SymbolIndex * Index,int Levels,PathRef TUPath)1115 static void fillSubTypes(const SymbolID &ID,
1116 std::vector<TypeHierarchyItem> &SubTypes,
1117 const SymbolIndex *Index, int Levels, PathRef TUPath) {
1118 RelationsRequest Req;
1119 Req.Subjects.insert(ID);
1120 Req.Predicate = index::SymbolRole::RelationBaseOf;
1121 Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
1122 if (Optional<TypeHierarchyItem> ChildSym =
1123 symbolToTypeHierarchyItem(Object, Index, TUPath)) {
1124 if (Levels > 1) {
1125 ChildSym->children.emplace();
1126 fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);
1127 }
1128 SubTypes.emplace_back(std::move(*ChildSym));
1129 }
1130 });
1131 }
1132
1133 using RecursionProtectionSet = llvm::SmallSet<const CXXRecordDecl *, 4>;
1134
fillSuperTypes(const CXXRecordDecl & CXXRD,ASTContext & ASTCtx,std::vector<TypeHierarchyItem> & SuperTypes,RecursionProtectionSet & RPSet)1135 static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx,
1136 std::vector<TypeHierarchyItem> &SuperTypes,
1137 RecursionProtectionSet &RPSet) {
1138 // typeParents() will replace dependent template specializations
1139 // with their class template, so to avoid infinite recursion for
1140 // certain types of hierarchies, keep the templates encountered
1141 // along the parent chain in a set, and stop the recursion if one
1142 // starts to repeat.
1143 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;
1144 if (Pattern) {
1145 if (!RPSet.insert(Pattern).second) {
1146 return;
1147 }
1148 }
1149
1150 for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {
1151 if (Optional<TypeHierarchyItem> ParentSym =
1152 declToTypeHierarchyItem(ASTCtx, *ParentDecl)) {
1153 ParentSym->parents.emplace();
1154 fillSuperTypes(*ParentDecl, ASTCtx, *ParentSym->parents, RPSet);
1155 SuperTypes.emplace_back(std::move(*ParentSym));
1156 }
1157 }
1158
1159 if (Pattern) {
1160 RPSet.erase(Pattern);
1161 }
1162 }
1163
findRecordTypeAt(ParsedAST & AST,Position Pos)1164 const CXXRecordDecl *findRecordTypeAt(ParsedAST &AST, Position Pos) {
1165 SourceLocation SourceLocationBeg = getBeginningOfIdentifier(
1166 AST, Pos, AST.getSourceManager().getMainFileID());
1167 IdentifiedSymbol Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
1168 if (Symbols.Decls.empty())
1169 return nullptr;
1170
1171 const Decl *D = Symbols.Decls[0];
1172
1173 if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1174 // If this is a variable, use the type of the variable.
1175 return VD->getType().getTypePtr()->getAsCXXRecordDecl();
1176 }
1177
1178 if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
1179 // If this is a method, use the type of the class.
1180 return Method->getParent();
1181 }
1182
1183 // We don't handle FieldDecl because it's not clear what behaviour
1184 // the user would expect: the enclosing class type (as with a
1185 // method), or the field's type (as with a variable).
1186
1187 return dyn_cast<CXXRecordDecl>(D);
1188 }
1189
typeParents(const CXXRecordDecl * CXXRD)1190 std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {
1191 std::vector<const CXXRecordDecl *> Result;
1192
1193 for (auto Base : CXXRD->bases()) {
1194 const CXXRecordDecl *ParentDecl = nullptr;
1195
1196 const Type *Type = Base.getType().getTypePtr();
1197 if (const RecordType *RT = Type->getAs<RecordType>()) {
1198 ParentDecl = RT->getAsCXXRecordDecl();
1199 }
1200
1201 if (!ParentDecl) {
1202 // Handle a dependent base such as "Base<T>" by using the primary
1203 // template.
1204 if (const TemplateSpecializationType *TS =
1205 Type->getAs<TemplateSpecializationType>()) {
1206 TemplateName TN = TS->getTemplateName();
1207 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
1208 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
1209 }
1210 }
1211 }
1212
1213 if (ParentDecl)
1214 Result.push_back(ParentDecl);
1215 }
1216
1217 return Result;
1218 }
1219
1220 llvm::Optional<TypeHierarchyItem>
getTypeHierarchy(ParsedAST & AST,Position Pos,int ResolveLevels,TypeHierarchyDirection Direction,const SymbolIndex * Index,PathRef TUPath)1221 getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
1222 TypeHierarchyDirection Direction, const SymbolIndex *Index,
1223 PathRef TUPath) {
1224 const CXXRecordDecl *CXXRD = findRecordTypeAt(AST, Pos);
1225 if (!CXXRD)
1226 return llvm::None;
1227
1228 Optional<TypeHierarchyItem> Result =
1229 declToTypeHierarchyItem(AST.getASTContext(), *CXXRD);
1230 if (!Result)
1231 return Result;
1232
1233 if (Direction == TypeHierarchyDirection::Parents ||
1234 Direction == TypeHierarchyDirection::Both) {
1235 Result->parents.emplace();
1236
1237 RecursionProtectionSet RPSet;
1238 fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet);
1239 }
1240
1241 if ((Direction == TypeHierarchyDirection::Children ||
1242 Direction == TypeHierarchyDirection::Both) &&
1243 ResolveLevels > 0) {
1244 Result->children.emplace();
1245
1246 if (Index) {
1247 if (Optional<SymbolID> ID = getSymbolID(CXXRD))
1248 fillSubTypes(*ID, *Result->children, Index, ResolveLevels, TUPath);
1249 }
1250 }
1251
1252 return Result;
1253 }
1254
resolveTypeHierarchy(TypeHierarchyItem & Item,int ResolveLevels,TypeHierarchyDirection Direction,const SymbolIndex * Index)1255 void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
1256 TypeHierarchyDirection Direction,
1257 const SymbolIndex *Index) {
1258 // We only support typeHierarchy/resolve for children, because for parents
1259 // we ignore ResolveLevels and return all levels of parents eagerly.
1260 if (Direction == TypeHierarchyDirection::Parents || ResolveLevels == 0)
1261 return;
1262
1263 Item.children.emplace();
1264
1265 if (Index && Item.data) {
1266 // We store the item's SymbolID in the 'data' field, and the client
1267 // passes it back to us in typeHierarchy/resolve.
1268 if (Expected<SymbolID> ID = SymbolID::fromStr(*Item.data)) {
1269 fillSubTypes(*ID, *Item.children, Index, ResolveLevels, Item.uri.file());
1270 }
1271 }
1272 }
1273
present() const1274 FormattedString HoverInfo::present() const {
1275 FormattedString Output;
1276 if (NamespaceScope) {
1277 Output.appendText("Declared in");
1278 // Drop trailing "::".
1279 if (!LocalScope.empty())
1280 Output.appendInlineCode(llvm::StringRef(LocalScope).drop_back(2));
1281 else if (NamespaceScope->empty())
1282 Output.appendInlineCode("global namespace");
1283 else
1284 Output.appendInlineCode(llvm::StringRef(*NamespaceScope).drop_back(2));
1285 }
1286
1287 if (!Definition.empty()) {
1288 Output.appendCodeBlock(Definition);
1289 } else {
1290 // Builtin types
1291 Output.appendCodeBlock(Name);
1292 }
1293
1294 if (!Documentation.empty())
1295 Output.appendText(Documentation);
1296 return Output;
1297 }
1298
operator <<(llvm::raw_ostream & OS,const HoverInfo::Param & P)1299 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
1300 const HoverInfo::Param &P) {
1301 std::vector<llvm::StringRef> Output;
1302 if (P.Type)
1303 Output.push_back(*P.Type);
1304 if (P.Name)
1305 Output.push_back(*P.Name);
1306 OS << llvm::join(Output, " ");
1307 if (P.Default)
1308 OS << " = " << *P.Default;
1309 return OS;
1310 }
1311
1312 } // namespace clangd
1313 } // namespace clang
1314