clang-tools  9.0.0
AST.cpp
Go to the documentation of this file.
1 //===--- AST.cpp - Utility AST functions -----------------------*- 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 
9 #include "AST.h"
10 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/Decl.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "clang/AST/TemplateBase.h"
15 #include "clang/Basic/SourceLocation.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Index/USRGeneration.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/Support/Casting.h"
20 #include "llvm/Support/ScopedPrinter.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 namespace clang {
24 namespace clangd {
25 
26 namespace {
27 llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>>
28 getTemplateSpecializationArgLocs(const NamedDecl &ND) {
29  if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) {
30  if (const ASTTemplateArgumentListInfo *Args =
31  Func->getTemplateSpecializationArgsAsWritten())
32  return Args->arguments();
33  } else if (auto *Cls =
34  llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) {
35  if (auto *Args = Cls->getTemplateArgsAsWritten())
36  return Args->arguments();
37  } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND))
38  return Var->getTemplateArgsInfo().arguments();
39  // We return None for ClassTemplateSpecializationDecls because it does not
40  // contain TemplateArgumentLoc information.
41  return llvm::None;
42 }
43 } // namespace
44 
45 // Returns true if the complete name of decl \p D is spelled in the source code.
46 // This is not the case for:
47 // * symbols formed via macro concatenation, the spelling location will
48 // be "<scratch space>"
49 // * symbols controlled and defined by a compile command-line option
50 // `-DName=foo`, the spelling location will be "<command line>".
51 bool isSpelledInSourceCode(const Decl *D) {
52  const auto &SM = D->getASTContext().getSourceManager();
53  auto Loc = D->getLocation();
54  // FIXME: Revisit the strategy, the heuristic is limitted when handling
55  // macros, we should use the location where the whole definition occurs.
56  if (Loc.isMacroID()) {
57  std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM);
58  if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
59  llvm::StringRef(PrintLoc).startswith("<command line>"))
60  return false;
61  }
62  return true;
63 }
64 
65 bool isImplementationDetail(const Decl *D) { return !isSpelledInSourceCode(D); }
66 
67 SourceLocation findNameLoc(const clang::Decl *D) {
68  const auto &SM = D->getASTContext().getSourceManager();
69  if (!isSpelledInSourceCode(D))
70  // Use the expansion location as spelling location is not interesting.
71  return SM.getExpansionRange(D->getLocation()).getBegin();
72  return SM.getSpellingLoc(D->getLocation());
73 }
74 
75 std::string printQualifiedName(const NamedDecl &ND) {
76  std::string QName;
77  llvm::raw_string_ostream OS(QName);
78  PrintingPolicy Policy(ND.getASTContext().getLangOpts());
79  // Note that inline namespaces are treated as transparent scopes. This
80  // reflects the way they're most commonly used for lookup. Ideally we'd
81  // include them, but at query time it's hard to find all the inline
82  // namespaces to query: the preamble doesn't have a dedicated list.
83  Policy.SuppressUnwrittenScope = true;
84  ND.printQualifiedName(OS, Policy);
85  OS.flush();
86  assert(!StringRef(QName).startswith("::"));
87  return QName;
88 }
89 
90 std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
91  std::string Name;
92  llvm::raw_string_ostream Out(Name);
93  PrintingPolicy PP(Ctx.getLangOpts());
94  // Handle 'using namespace'. They all have the same name - <using-directive>.
95  if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
96  Out << "using namespace ";
97  if (auto *Qual = UD->getQualifier())
98  Qual->print(Out, PP);
99  UD->getNominatedNamespaceAsWritten()->printName(Out);
100  return Out.str();
101  }
102  ND.getDeclName().print(Out, PP);
103  if (!Out.str().empty()) {
105  return Out.str();
106  }
107  // The name was empty, so present an anonymous entity.
108  if (isa<NamespaceDecl>(ND))
109  return "(anonymous namespace)";
110  if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
111  return ("(anonymous " + Cls->getKindName() + ")").str();
112  if (isa<EnumDecl>(ND))
113  return "(anonymous enum)";
114  return "(anonymous)";
115 }
116 
117 std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
118  std::string TemplateArgs;
119  llvm::raw_string_ostream OS(TemplateArgs);
120  PrintingPolicy Policy(ND.getASTContext().getLangOpts());
121  if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
122  getTemplateSpecializationArgLocs(ND)) {
123  printTemplateArgumentList(OS, *Args, Policy);
124  } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
125  if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
126  // ClassTemplateSpecializationDecls do not contain
127  // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
128  // create a new argument location list from TypeSourceInfo.
129  auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
130  llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
131  ArgLocs.reserve(STL.getNumArgs());
132  for (unsigned I = 0; I < STL.getNumArgs(); ++I)
133  ArgLocs.push_back(STL.getArgLoc(I));
134  printTemplateArgumentList(OS, ArgLocs, Policy);
135  } else {
136  // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
137  // e.g. friend decls. Currently we fallback to Template Arguments without
138  // location information.
139  printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
140  }
141  }
142  OS.flush();
143  return TemplateArgs;
144 }
145 
146 std::string printNamespaceScope(const DeclContext &DC) {
147  for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
148  if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
149  if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
150  return printQualifiedName(*NS) + "::";
151  return "";
152 }
153 
154 llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
155  llvm::SmallString<128> USR;
156  if (index::generateUSRForDecl(D, USR))
157  return None;
158  return SymbolID(USR);
159 }
160 
161 llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
162  const MacroInfo *MI,
163  const SourceManager &SM) {
164  if (MI == nullptr)
165  return None;
166  llvm::SmallString<128> USR;
167  if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
168  return None;
169  return SymbolID(USR);
170 }
171 
172 std::string shortenNamespace(const llvm::StringRef OriginalName,
173  const llvm::StringRef CurrentNamespace) {
174  llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
175  llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
176  llvm::SmallVector<llvm::StringRef, 8> Result;
177  OriginalName.split(OriginalParts, "::");
178  CurrentNamespace.split(CurrentParts, "::");
179  auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
180 
181  unsigned DifferentAt = 0;
182  while (DifferentAt < MinLength &&
183  CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
184  DifferentAt++;
185  }
186 
187  for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) {
188  Result.push_back(OriginalParts[i]);
189  }
190  return join(Result, "::");
191 }
192 
193 std::string printType(const QualType QT, const DeclContext & Context){
194  PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
195  PP.SuppressTagKeyword = 1;
196  return shortenNamespace(
197  QT.getAsString(PP),
198  printNamespaceScope(Context) );
199 }
200 
201 
202 } // namespace clangd
203 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user. ...
Definition: AST.cpp:90
std::string printType(const QualType QT, const DeclContext &Context)
Returns a QualType as string.
Definition: AST.cpp:193
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:75
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Definition: AST.cpp:154
std::string printNamespaceScope(const DeclContext &DC)
Returns the first enclosing namespace scope starting from DC.
Definition: AST.cpp:146
SourceLocation findNameLoc(const clang::Decl *D)
Find the identifier source location of the given D.
Definition: AST.cpp:67
Documents should not be synced at all.
std::string printTemplateSpecializationArgs(const NamedDecl &ND)
Prints template arguments of a decl as written in the source code, including enclosing &#39;<&#39; and &#39;>&#39;...
Definition: AST.cpp:117
bool isSpelledInSourceCode(const Decl *D)
Definition: AST.cpp:51
Context Ctx
std::string QName
static constexpr llvm::StringLiteral Name
const Decl * D
Definition: XRefs.cpp:868
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:69
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: Rename.cpp:36
bool isImplementationDetail(const Decl *D)
Returns true if the declaration is considered implementation detail based on heuristics.
Definition: AST.cpp:65
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
std::string shortenNamespace(const llvm::StringRef OriginalName, const llvm::StringRef CurrentNamespace)
Try to shorten the OriginalName by removing namespaces from the left of the string that are redundant...
Definition: AST.cpp:172
std::array< uint8_t, 20 > SymbolID