clang-tools  8.0.0
SymbolCollector.cpp
Go to the documentation of this file.
1 //===--- SymbolCollector.cpp -------------------------------------*- C++-*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "SymbolCollector.h"
11 #include "AST.h"
12 #include "CanonicalIncludes.h"
13 #include "CodeComplete.h"
14 #include "CodeCompletionStrings.h"
15 #include "Logger.h"
16 #include "SourceCode.h"
17 #include "URI.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclBase.h"
20 #include "clang/AST/DeclCXX.h"
21 #include "clang/AST/DeclTemplate.h"
22 #include "clang/Basic/SourceLocation.h"
23 #include "clang/Basic/SourceManager.h"
24 #include "clang/Basic/Specifiers.h"
25 #include "clang/Index/IndexSymbol.h"
26 #include "clang/Index/USRGeneration.h"
27 #include "llvm/Support/Casting.h"
28 #include "llvm/Support/FileSystem.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/Path.h"
31 
32 namespace clang {
33 namespace clangd {
34 namespace {
35 
36 /// If \p ND is a template specialization, returns the described template.
37 /// Otherwise, returns \p ND.
38 const NamedDecl &getTemplateOrThis(const NamedDecl &ND) {
39  if (auto T = ND.getDescribedTemplate())
40  return *T;
41  return ND;
42 }
43 
44 // Returns a URI of \p Path. Firstly, this makes the \p Path absolute using the
45 // current working directory of the given SourceManager if the Path is not an
46 // absolute path. If failed, this resolves relative paths against \p FallbackDir
47 // to get an absolute path. Then, this tries creating an URI for the absolute
48 // path with schemes specified in \p Opts. This returns an URI with the first
49 // working scheme, if there is any; otherwise, this returns None.
50 //
51 // The Path can be a path relative to the build directory, or retrieved from
52 // the SourceManager.
53 std::string toURI(const SourceManager &SM, llvm::StringRef Path,
54  const SymbolCollector::Options &Opts) {
55  llvm::SmallString<128> AbsolutePath(Path);
56  if (auto CanonPath =
57  getCanonicalPath(SM.getFileManager().getFile(Path), SM)) {
58  AbsolutePath = *CanonPath;
59  }
60  // We don't perform is_absolute check in an else branch because makeAbsolute
61  // might return a relative path on some InMemoryFileSystems.
62  if (!llvm::sys::path::is_absolute(AbsolutePath) && !Opts.FallbackDir.empty())
63  llvm::sys::fs::make_absolute(Opts.FallbackDir, AbsolutePath);
64  llvm::sys::path::remove_dots(AbsolutePath, /*remove_dot_dot=*/true);
65  return URI::create(AbsolutePath).toString();
66 }
67 
68 // All proto generated headers should start with this line.
69 static const char *PROTO_HEADER_COMMENT =
70  "// Generated by the protocol buffer compiler. DO NOT EDIT!";
71 
72 // Checks whether the decl is a private symbol in a header generated by
73 // protobuf compiler.
74 // To identify whether a proto header is actually generated by proto compiler,
75 // we check whether it starts with PROTO_HEADER_COMMENT.
76 // FIXME: make filtering extensible when there are more use cases for symbol
77 // filters.
78 bool isPrivateProtoDecl(const NamedDecl &ND) {
79  const auto &SM = ND.getASTContext().getSourceManager();
80  auto Loc = findNameLoc(&ND);
81  auto FileName = SM.getFilename(Loc);
82  if (!FileName.endswith(".proto.h") && !FileName.endswith(".pb.h"))
83  return false;
84  auto FID = SM.getFileID(Loc);
85  // Double check that this is an actual protobuf header.
86  if (!SM.getBufferData(FID).startswith(PROTO_HEADER_COMMENT))
87  return false;
88 
89  // ND without identifier can be operators.
90  if (ND.getIdentifier() == nullptr)
91  return false;
92  auto Name = ND.getIdentifier()->getName();
93  if (!Name.contains('_'))
94  return false;
95  // Nested proto entities (e.g. Message::Nested) have top-level decls
96  // that shouldn't be used (Message_Nested). Ignore them completely.
97  // The nested entities are dangling type aliases, we may want to reconsider
98  // including them in the future.
99  // For enum constants, SOME_ENUM_CONSTANT is not private and should be
100  // indexed. Outer_INNER is private. This heuristic relies on naming style, it
101  // will include OUTER_INNER and exclude some_enum_constant.
102  // FIXME: the heuristic relies on naming style (i.e. no underscore in
103  // user-defined names) and can be improved.
104  return (ND.getKind() != Decl::EnumConstant) || llvm::any_of(Name, islower);
105 }
106 
107 // We only collect #include paths for symbols that are suitable for global code
108 // completion, except for namespaces since #include path for a namespace is hard
109 // to define.
110 bool shouldCollectIncludePath(index::SymbolKind Kind) {
111  using SK = index::SymbolKind;
112  switch (Kind) {
113  case SK::Macro:
114  case SK::Enum:
115  case SK::Struct:
116  case SK::Class:
117  case SK::Union:
118  case SK::TypeAlias:
119  case SK::Using:
120  case SK::Function:
121  case SK::Variable:
122  case SK::EnumConstant:
123  return true;
124  default:
125  return false;
126  }
127 }
128 
129 /// Gets a canonical include (URI of the header or <header> or "header") for
130 /// header of \p Loc.
131 /// Returns None if fails to get include header for \p Loc.
132 llvm::Optional<std::string>
133 getIncludeHeader(llvm::StringRef QName, const SourceManager &SM,
134  SourceLocation Loc, const SymbolCollector::Options &Opts) {
135  std::vector<std::string> Headers;
136  // Collect the #include stack.
137  while (true) {
138  if (!Loc.isValid())
139  break;
140  auto FilePath = SM.getFilename(Loc);
141  if (FilePath.empty())
142  break;
143  Headers.push_back(FilePath);
144  if (SM.isInMainFile(Loc))
145  break;
146  Loc = SM.getIncludeLoc(SM.getFileID(Loc));
147  }
148  if (Headers.empty())
149  return None;
150  llvm::StringRef Header = Headers[0];
151  if (Opts.Includes) {
152  Header = Opts.Includes->mapHeader(Headers, QName);
153  if (Header.startswith("<") || Header.startswith("\""))
154  return Header.str();
155  }
156  return toURI(SM, Header, Opts);
157 }
158 
159 // Return the symbol range of the token at \p TokLoc.
160 std::pair<SymbolLocation::Position, SymbolLocation::Position>
161 getTokenRange(SourceLocation TokLoc, const SourceManager &SM,
162  const LangOptions &LangOpts) {
163  auto CreatePosition = [&SM](SourceLocation Loc) {
164  auto LSPLoc = sourceLocToPosition(SM, Loc);
165  SymbolLocation::Position Pos;
166  Pos.setLine(LSPLoc.line);
167  Pos.setColumn(LSPLoc.character);
168  return Pos;
169  };
170 
171  auto TokenLength = clang::Lexer::MeasureTokenLength(TokLoc, SM, LangOpts);
172  return {CreatePosition(TokLoc),
173  CreatePosition(TokLoc.getLocWithOffset(TokenLength))};
174 }
175 
176 bool shouldIndexFile(const SourceManager &SM, FileID FID,
177  const SymbolCollector::Options &Opts,
178  llvm::DenseMap<FileID, bool> *FilesToIndexCache) {
179  if (!Opts.FileFilter)
180  return true;
181  auto I = FilesToIndexCache->try_emplace(FID);
182  if (I.second)
183  I.first->second = Opts.FileFilter(SM, FID);
184  return I.first->second;
185 }
186 
187 // Return the symbol location of the token at \p TokLoc.
188 llvm::Optional<SymbolLocation>
189 getTokenLocation(SourceLocation TokLoc, const SourceManager &SM,
190  const SymbolCollector::Options &Opts,
191  const clang::LangOptions &LangOpts,
192  std::string &FileURIStorage) {
193  auto Path = SM.getFilename(TokLoc);
194  if (Path.empty())
195  return None;
196  FileURIStorage = toURI(SM, Path, Opts);
197  SymbolLocation Result;
198  Result.FileURI = FileURIStorage.c_str();
199  auto Range = getTokenRange(TokLoc, SM, LangOpts);
200  Result.Start = Range.first;
201  Result.End = Range.second;
202 
203  return Result;
204 }
205 
206 // Checks whether \p ND is a definition of a TagDecl (class/struct/enum/union)
207 // in a header file, in which case clangd would prefer to use ND as a canonical
208 // declaration.
209 // FIXME: handle symbol types that are not TagDecl (e.g. functions), if using
210 // the first seen declaration as canonical declaration is not a good enough
211 // heuristic.
212 bool isPreferredDeclaration(const NamedDecl &ND, index::SymbolRoleSet Roles) {
213  const auto& SM = ND.getASTContext().getSourceManager();
214  return (Roles & static_cast<unsigned>(index::SymbolRole::Definition)) &&
215  isa<TagDecl>(&ND) &&
216  !SM.isWrittenInMainFile(SM.getExpansionLoc(ND.getLocation()));
217 }
218 
219 RefKind toRefKind(index::SymbolRoleSet Roles) {
220  return static_cast<RefKind>(static_cast<unsigned>(RefKind::All) & Roles);
221 }
222 
223 template <class T> bool explicitTemplateSpecialization(const NamedDecl &ND) {
224  if (const auto *TD = dyn_cast<T>(&ND))
225  if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
226  return true;
227  return false;
228 }
229 
230 } // namespace
231 
232 SymbolCollector::SymbolCollector(Options Opts) : Opts(std::move(Opts)) {}
233 
234 void SymbolCollector::initialize(ASTContext &Ctx) {
235  ASTCtx = &Ctx;
236  CompletionAllocator = std::make_shared<GlobalCodeCompletionAllocator>();
237  CompletionTUInfo =
238  llvm::make_unique<CodeCompletionTUInfo>(CompletionAllocator);
239 }
240 
241 bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND,
242  const ASTContext &ASTCtx,
243  const Options &Opts,
244  bool IsMainFileOnly) {
245  if (ND.isImplicit())
246  return false;
247  // Skip anonymous declarations, e.g (anonymous enum/class/struct).
248  if (ND.getDeclName().isEmpty())
249  return false;
250 
251  // Skip main-file symbols if we are not collecting them.
252  if (IsMainFileOnly && !Opts.CollectMainFileSymbols)
253  return false;
254 
255  // Skip symbols in anonymous namespaces in header files.
256  if (!IsMainFileOnly && ND.isInAnonymousNamespace())
257  return false;
258 
259  // We want most things but not "local" symbols such as symbols inside
260  // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl.
261  // FIXME: Need a matcher for ExportDecl in order to include symbols declared
262  // within an export.
263  const auto *DeclCtx = ND.getDeclContext();
264  switch (DeclCtx->getDeclKind()) {
265  case Decl::TranslationUnit:
266  case Decl::Namespace:
267  case Decl::LinkageSpec:
268  case Decl::Enum:
269  case Decl::ObjCProtocol:
270  case Decl::ObjCInterface:
271  case Decl::ObjCCategory:
272  case Decl::ObjCCategoryImpl:
273  case Decl::ObjCImplementation:
274  break;
275  default:
276  // Record has a few derivations (e.g. CXXRecord, Class specialization), it's
277  // easier to cast.
278  if (!isa<RecordDecl>(DeclCtx))
279  return false;
280  }
281  if (explicitTemplateSpecialization<FunctionDecl>(ND) ||
282  explicitTemplateSpecialization<CXXRecordDecl>(ND) ||
283  explicitTemplateSpecialization<VarDecl>(ND))
284  return false;
285 
286  // Avoid indexing internal symbols in protobuf generated headers.
287  if (isPrivateProtoDecl(ND))
288  return false;
289  return true;
290 }
291 
292 // Always return true to continue indexing.
294  const Decl *D, index::SymbolRoleSet Roles,
295  llvm::ArrayRef<index::SymbolRelation> Relations, SourceLocation Loc,
296  index::IndexDataConsumer::ASTNodeInfo ASTNode) {
297  assert(ASTCtx && PP.get() && "ASTContext and Preprocessor must be set.");
298  assert(CompletionAllocator && CompletionTUInfo);
299  assert(ASTNode.OrigD);
300  // If OrigD is an declaration associated with a friend declaration and it's
301  // not a definition, skip it. Note that OrigD is the occurrence that the
302  // collector is currently visiting.
303  if ((ASTNode.OrigD->getFriendObjectKind() !=
304  Decl::FriendObjectKind::FOK_None) &&
305  !(Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
306  return true;
307  // A declaration created for a friend declaration should not be used as the
308  // canonical declaration in the index. Use OrigD instead, unless we've already
309  // picked a replacement for D
310  if (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None)
311  D = CanonicalDecls.try_emplace(D, ASTNode.OrigD).first->second;
312  const NamedDecl *ND = dyn_cast<NamedDecl>(D);
313  if (!ND)
314  return true;
315 
316  // Mark D as referenced if this is a reference coming from the main file.
317  // D may not be an interesting symbol, but it's cheaper to check at the end.
318  auto &SM = ASTCtx->getSourceManager();
319  auto SpellingLoc = SM.getSpellingLoc(Loc);
320  if (Opts.CountReferences &&
321  (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
322  SM.getFileID(SpellingLoc) == SM.getMainFileID())
323  ReferencedDecls.insert(ND);
324 
325  bool CollectRef = static_cast<unsigned>(Opts.RefFilter) & Roles;
326  bool IsOnlyRef =
327  !(Roles & (static_cast<unsigned>(index::SymbolRole::Declaration) |
328  static_cast<unsigned>(index::SymbolRole::Definition)));
329 
330  if (IsOnlyRef && !CollectRef)
331  return true;
332 
333  // ND is the canonical (i.e. first) declaration. If it's in the main file,
334  // then no public declaration was visible, so assume it's main-file only.
335  bool IsMainFileOnly = SM.isWrittenInMainFile(SM.getExpansionLoc(
336  ND->getBeginLoc()));
337  if (!shouldCollectSymbol(*ND, *ASTCtx, Opts, IsMainFileOnly))
338  return true;
339  // Do not store references to main-file symbols.
340  if (CollectRef && !IsMainFileOnly && !isa<NamespaceDecl>(ND) &&
341  (Opts.RefsInHeaders || SM.getFileID(SpellingLoc) == SM.getMainFileID()))
342  DeclRefs[ND].emplace_back(SpellingLoc, Roles);
343  // Don't continue indexing if this is a mere reference.
344  if (IsOnlyRef)
345  return true;
346 
347  auto ID = getSymbolID(ND);
348  if (!ID)
349  return true;
350 
351  const NamedDecl &OriginalDecl = *cast<NamedDecl>(ASTNode.OrigD);
352  const Symbol *BasicSymbol = Symbols.find(*ID);
353  if (!BasicSymbol) // Regardless of role, ND is the canonical declaration.
354  BasicSymbol = addDeclaration(*ND, std::move(*ID), IsMainFileOnly);
355  else if (isPreferredDeclaration(OriginalDecl, Roles))
356  // If OriginalDecl is preferred, replace the existing canonical
357  // declaration (e.g. a class forward declaration). There should be at most
358  // one duplicate as we expect to see only one preferred declaration per
359  // TU, because in practice they are definitions.
360  BasicSymbol = addDeclaration(OriginalDecl, std::move(*ID), IsMainFileOnly);
361 
362  if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
363  addDefinition(OriginalDecl, *BasicSymbol);
364  return true;
365 }
366 
367 bool SymbolCollector::handleMacroOccurence(const IdentifierInfo *Name,
368  const MacroInfo *MI,
369  index::SymbolRoleSet Roles,
370  SourceLocation Loc) {
371  if (!Opts.CollectMacro)
372  return true;
373  assert(PP.get());
374 
375  const auto &SM = PP->getSourceManager();
376  auto DefLoc = MI->getDefinitionLoc();
377  if (SM.isInMainFile(SM.getExpansionLoc(DefLoc)))
378  return true;
379  // Header guards are not interesting in index. Builtin macros don't have
380  // useful locations and are not needed for code completions.
381  if (MI->isUsedForHeaderGuard() || MI->isBuiltinMacro())
382  return true;
383 
384  // Mark the macro as referenced if this is a reference coming from the main
385  // file. The macro may not be an interesting symbol, but it's cheaper to check
386  // at the end.
387  if (Opts.CountReferences &&
388  (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
389  SM.getFileID(SM.getSpellingLoc(Loc)) == SM.getMainFileID())
390  ReferencedMacros.insert(Name);
391  // Don't continue indexing if this is a mere reference.
392  // FIXME: remove macro with ID if it is undefined.
393  if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
394  Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
395  return true;
396 
397  auto ID = getSymbolID(*Name, MI, SM);
398  if (!ID)
399  return true;
400 
401  // Only collect one instance in case there are multiple.
402  if (Symbols.find(*ID) != nullptr)
403  return true;
404 
405  Symbol S;
406  S.ID = std::move(*ID);
407  S.Name = Name->getName();
409  S.SymInfo = index::getSymbolInfoForMacro(*MI);
410  std::string FileURI;
411  // FIXME: use the result to filter out symbols.
412  shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache);
413  if (auto DeclLoc =
414  getTokenLocation(DefLoc, SM, Opts, PP->getLangOpts(), FileURI))
415  S.CanonicalDeclaration = *DeclLoc;
416 
417  CodeCompletionResult SymbolCompletion(Name);
418  const auto *CCS = SymbolCompletion.CreateCodeCompletionStringForMacro(
419  *PP, *CompletionAllocator, *CompletionTUInfo);
420  std::string Signature;
421  std::string SnippetSuffix;
422  getSignature(*CCS, &Signature, &SnippetSuffix);
423 
424  std::string Include;
425  if (Opts.CollectIncludePath && shouldCollectIncludePath(S.SymInfo.Kind)) {
426  if (auto Header = getIncludeHeader(Name->getName(), SM,
427  SM.getExpansionLoc(DefLoc), Opts))
428  Include = std::move(*Header);
429  }
430  S.Signature = Signature;
432  if (!Include.empty())
433  S.IncludeHeaders.emplace_back(Include, 1);
434 
435  Symbols.insert(S);
436  return true;
437 }
438 
440  // At the end of the TU, add 1 to the refcount of all referenced symbols.
441  auto IncRef = [this](const SymbolID &ID) {
442  if (const auto *S = Symbols.find(ID)) {
443  Symbol Inc = *S;
444  ++Inc.References;
445  Symbols.insert(Inc);
446  }
447  };
448  for (const NamedDecl *ND : ReferencedDecls) {
449  if (auto ID = getSymbolID(ND)) {
450  IncRef(*ID);
451  }
452  }
453  if (Opts.CollectMacro) {
454  assert(PP);
455  for (const IdentifierInfo *II : ReferencedMacros) {
456  if (const auto *MI = PP->getMacroDefinition(II).getMacroInfo())
457  if (auto ID = getSymbolID(*II, MI, PP->getSourceManager()))
458  IncRef(*ID);
459  }
460  }
461 
462  const auto &SM = ASTCtx->getSourceManager();
463  llvm::DenseMap<FileID, std::string> URICache;
464  auto GetURI = [&](FileID FID) -> llvm::Optional<std::string> {
465  auto Found = URICache.find(FID);
466  if (Found == URICache.end()) {
467  if (auto *FileEntry = SM.getFileEntryForID(FID)) {
468  auto FileURI = toURI(SM, FileEntry->getName(), Opts);
469  Found = URICache.insert({FID, FileURI}).first;
470  } else {
471  // Ignore cases where we can not find a corresponding file entry
472  // for the loc, thoses are not interesting, e.g. symbols formed
473  // via macro concatenation.
474  return None;
475  }
476  }
477  return Found->second;
478  };
479 
480  if (auto MainFileURI = GetURI(SM.getMainFileID())) {
481  for (const auto &It : DeclRefs) {
482  if (auto ID = getSymbolID(It.first)) {
483  for (const auto &LocAndRole : It.second) {
484  auto FileID = SM.getFileID(LocAndRole.first);
485  // FIXME: use the result to filter out references.
486  shouldIndexFile(SM, FileID, Opts, &FilesToIndexCache);
487  if (auto FileURI = GetURI(FileID)) {
488  auto Range =
489  getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts());
490  Ref R;
491  R.Location.Start = Range.first;
492  R.Location.End = Range.second;
493  R.Location.FileURI = FileURI->c_str();
494  R.Kind = toRefKind(LocAndRole.second);
495  Refs.insert(*ID, R);
496  }
497  }
498  }
499  }
500  }
501 
502  ReferencedDecls.clear();
503  ReferencedMacros.clear();
504  DeclRefs.clear();
505  FilesToIndexCache.clear();
506 }
507 
508 const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND,
509  SymbolID ID,
510  bool IsMainFileOnly) {
511  auto &Ctx = ND.getASTContext();
512  auto &SM = Ctx.getSourceManager();
513 
514  Symbol S;
515  S.ID = std::move(ID);
516  std::string QName = printQualifiedName(ND);
517  std::tie(S.Scope, S.Name) = splitQualifiedName(QName);
518  // FIXME: this returns foo:bar: for objective-C methods, we prefer only foo:
519  // for consistency with CodeCompletionString and a clean name/signature split.
520 
521  // We collect main-file symbols, but do not use them for code completion.
522  if (!IsMainFileOnly && isIndexedForCodeCompletion(ND, Ctx))
524  if (isImplementationDetail(&ND))
526  if (!IsMainFileOnly)
528  S.SymInfo = index::getSymbolInfo(&ND);
529  std::string FileURI;
530  auto Loc = findNameLoc(&ND);
531  // FIXME: use the result to filter out symbols.
532  shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache);
533  if (auto DeclLoc =
534  getTokenLocation(Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI))
535  S.CanonicalDeclaration = *DeclLoc;
536 
537  S.Origin = Opts.Origin;
538  if (ND.getAvailability() == AR_Deprecated)
540 
541  // Add completion info.
542  // FIXME: we may want to choose a different redecl, or combine from several.
543  assert(ASTCtx && PP.get() && "ASTContext and Preprocessor must be set.");
544  // We use the primary template, as clang does during code completion.
545  CodeCompletionResult SymbolCompletion(&getTemplateOrThis(ND), 0);
546  const auto *CCS = SymbolCompletion.CreateCodeCompletionString(
547  *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator,
548  *CompletionTUInfo,
549  /*IncludeBriefComments*/ false);
550  std::string Documentation =
551  formatDocumentation(*CCS, getDocComment(Ctx, SymbolCompletion,
552  /*CommentsFromHeaders=*/true));
553  // For symbols not indexed for completion (class members), we also store their
554  // docs in the index, because Sema doesn't load the docs from the preamble, we
555  // rely on the index to get the docs.
556  // FIXME: this can be optimized by only storing the docs in dynamic index --
557  // dynamic index should index these symbols when Sema completes a member
558  // completion.
559  S.Documentation = Documentation;
561  Symbols.insert(S);
562  return Symbols.find(S.ID);
563  }
564 
565  std::string Signature;
566  std::string SnippetSuffix;
567  getSignature(*CCS, &Signature, &SnippetSuffix);
568  S.Signature = Signature;
570  std::string ReturnType = getReturnType(*CCS);
572 
573  std::string Include;
574  if (Opts.CollectIncludePath && shouldCollectIncludePath(S.SymInfo.Kind)) {
575  // Use the expansion location to get the #include header since this is
576  // where the symbol is exposed.
577  if (auto Header = getIncludeHeader(
578  QName, SM, SM.getExpansionLoc(ND.getLocation()), Opts))
579  Include = std::move(*Header);
580  }
581  if (!Include.empty())
582  S.IncludeHeaders.emplace_back(Include, 1);
583 
584  llvm::Optional<OpaqueType> TypeStorage;
586  TypeStorage = OpaqueType::fromCompletionResult(*ASTCtx, SymbolCompletion);
587  if (TypeStorage)
588  S.Type = TypeStorage->raw();
589  }
590 
591  Symbols.insert(S);
592  return Symbols.find(S.ID);
593 }
594 
595 void SymbolCollector::addDefinition(const NamedDecl &ND,
596  const Symbol &DeclSym) {
597  if (DeclSym.Definition)
598  return;
599  // If we saw some forward declaration, we end up copying the symbol.
600  // This is not ideal, but avoids duplicating the "is this a definition" check
601  // in clang::index. We should only see one definition.
602  Symbol S = DeclSym;
603  std::string FileURI;
604  auto Loc = findNameLoc(&ND);
605  const auto &SM = ND.getASTContext().getSourceManager();
606  // FIXME: use the result to filter out symbols.
607  shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache);
608  if (auto DefLoc =
609  getTokenLocation(Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI))
610  S.Definition = *DefLoc;
611  Symbols.insert(S);
612 }
613 
614 } // namespace clangd
615 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI, index::SymbolRoleSet Roles, SourceLocation Loc) override
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:54
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Definition: AST.cpp:117
const Symbol * find(const SymbolID &ID)
Definition: Index.h:323
clang::find_all_symbols::SymbolInfo::SymbolKind SymbolKind
Definition: SymbolInfo.cpp:22
SourceLocation findNameLoc(const clang::Decl *D)
Find the identifier source location of the given D.
Definition: AST.cpp:46
void insert(const Symbol &S)
Definition: Index.cpp:91
def make_absolute(f, directory)
llvm::StringRef Scope
Definition: Index.h:168
std::string getDocComment(const ASTContext &Ctx, const CodeCompletionResult &Result, bool CommentsFromHeaders)
Gets a minimally formatted documentation comment of Result, with comment markers stripped.
Documents should not be synced at all.
void initialize(ASTContext &Ctx) override
unsigned References
Definition: Index.h:183
index::SymbolInfo SymInfo
Definition: Index.h:164
std::string getReturnType(const CodeCompletionString &CCS)
Gets detail to be used as the detail field in an LSP completion item.
BindArgumentKind Kind
SymbolLocation Definition
Definition: Index.h:171
Context Ctx
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:765
Whether or not this symbol is meant to be used for the code completion.
Definition: Index.h:239
bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles, ArrayRef< index::SymbolRelation > Relations, SourceLocation Loc, index::IndexDataConsumer::ASTNodeInfo ASTNode) override
bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx)
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be incuded via different headers.
Definition: Index.h:231
SymbolFlag Flags
Definition: Index.h:248
llvm::StringRef Signature
A brief description of the symbol that can be appended in the completion candidate list...
Definition: Index.h:189
SymbolLocation Location
Definition: Index.h:375
std::string Signature
llvm::StringRef Documentation
Documentation including comment for the symbol declaration.
Definition: Index.h:196
std::string Path
A typedef to represent a file path.
Definition: Path.h:21
static constexpr llvm::StringLiteral Name
SymbolLocation CanonicalDeclaration
Definition: Index.h:180
const Decl * D
Definition: XRefs.cpp:79
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
PathRef FileName
std::string formatDocumentation(const CodeCompletionString &CCS, llvm::StringRef DocComment)
Assembles formatted documentation for a completion result.
std::string ReturnType
std::string SnippetSuffix
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:128
bool CollectMainFileSymbols
Collect symbols local to main-files, such as static functions and symbols inside an anonymous namespa...
Position Pos
static bool shouldCollectSymbol(const NamedDecl &ND, const ASTContext &ASTCtx, const Options &Opts, bool IsMainFileSymbol)
Returns true is ND should be collected.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
Definition: URI.cpp:188
void getSignature(const CodeCompletionString &CCS, std::string *Signature, std::string *Snippet, std::string *RequiredQualifiers)
Formats the signature for an item, as a display string and snippet.
Position Start
The symbol range, using half-open range [Start, End).
Definition: Index.h:61
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::StringRef Name
Definition: Index.h:166
CharSourceRange Range
SourceRange for the file name.
std::pair< llvm::StringRef, llvm::StringRef > splitQualifiedName(llvm::StringRef QName)
From "a::b::c", return {"a::b::", "c"}.
Definition: SourceCode.cpp:164
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:187
void insert(const SymbolID &ID, const Ref &S)
Definition: Index.cpp:135
bool isImplementationDetail(const Decl *D)
Returns true if the declaration is considered implementation detail based on heuristics.
Definition: AST.cpp:44
llvm::StringRef CompletionSnippetSuffix
What to insert when completing this symbol, after the symbol name.
Definition: Index.h:194
Indicates if the symbol is deprecated.
Definition: Index.h:241
llvm::StringRef Type
Raw representation of the OpaqueType of the symbol, used for scoring purposes.
Definition: Index.h:205
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
Definition: Index.h:185
llvm::StringRef ReturnType
Type when this symbol is used in an expression.
Definition: Index.h:200
static llvm::Optional< OpaqueType > fromCompletionResult(ASTContext &Ctx, const CodeCompletionResult &R)
Create a type from a code completion result.