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 "SourceCode.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/Decl.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/AST/DeclarationName.h"
16 #include "clang/AST/NestedNameSpecifier.h"
17 #include "clang/AST/PrettyPrinter.h"
18 #include "clang/AST/TemplateBase.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include "clang/Basic/SourceManager.h"
21 #include "clang/Basic/Specifiers.h"
22 #include "clang/Index/USRGeneration.h"
23 #include "llvm/ADT/Optional.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/ScopedPrinter.h"
26 #include "llvm/Support/raw_ostream.h"
27 
28 namespace clang {
29 namespace clangd {
30 
31 namespace {
32 llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>>
33 getTemplateSpecializationArgLocs(const NamedDecl &ND) {
34   if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) {
35     if (const ASTTemplateArgumentListInfo *Args =
36             Func->getTemplateSpecializationArgsAsWritten())
37       return Args->arguments();
38   } else if (auto *Cls =
39                  llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) {
40     if (auto *Args = Cls->getTemplateArgsAsWritten())
41       return Args->arguments();
42   } else if (auto *Var =
43                  llvm::dyn_cast<VarTemplatePartialSpecializationDecl>(&ND)) {
44     if (auto *Args = Var->getTemplateArgsAsWritten())
45       return Args->arguments();
46   } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND))
47     return Var->getTemplateArgsInfo().arguments();
48   // We return None for ClassTemplateSpecializationDecls because it does not
49   // contain TemplateArgumentLoc information.
50   return llvm::None;
51 }
52 
53 template <class T>
54 bool isTemplateSpecializationKind(const NamedDecl *D,
55                                   TemplateSpecializationKind Kind) {
56   if (const auto *TD = dyn_cast<T>(D))
57     return TD->getTemplateSpecializationKind() == Kind;
58   return false;
59 }
60 
61 bool isTemplateSpecializationKind(const NamedDecl *D,
62                                   TemplateSpecializationKind Kind) {
63   return isTemplateSpecializationKind<FunctionDecl>(D, Kind) ||
64          isTemplateSpecializationKind<CXXRecordDecl>(D, Kind) ||
65          isTemplateSpecializationKind<VarDecl>(D, Kind);
66 }
67 
68 } // namespace
69 
70 bool isImplicitTemplateInstantiation(const NamedDecl *D) {
71   return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation);
72 }
73 
74 bool isExplicitTemplateSpecialization(const NamedDecl *D) {
75   return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization);
76 }
77 
78 bool isImplementationDetail(const Decl *D) {
79   return !isSpelledInSource(D->getLocation(),
80                             D->getASTContext().getSourceManager());
81 }
82 
83 SourceLocation findName(const clang::Decl *D) {
84   return D->getLocation();
85 }
86 
87 std::string printQualifiedName(const NamedDecl &ND) {
88   std::string QName;
89   llvm::raw_string_ostream OS(QName);
90   PrintingPolicy Policy(ND.getASTContext().getLangOpts());
91   // Note that inline namespaces are treated as transparent scopes. This
92   // reflects the way they're most commonly used for lookup. Ideally we'd
93   // include them, but at query time it's hard to find all the inline
94   // namespaces to query: the preamble doesn't have a dedicated list.
95   Policy.SuppressUnwrittenScope = true;
96   ND.printQualifiedName(OS, Policy);
97   OS.flush();
98   assert(!StringRef(QName).startswith("::"));
99   return QName;
100 }
101 
102 static bool isAnonymous(const DeclarationName &N) {
103   return N.isIdentifier() && !N.getAsIdentifierInfo();
104 }
105 
106 NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND) {
107   if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND))
108     return V->getQualifierLoc();
109   if (auto *T = llvm::dyn_cast<TagDecl>(&ND))
110     return T->getQualifierLoc();
111   return NestedNameSpecifierLoc();
112 }
113 
114 std::string printUsingNamespaceName(const ASTContext &Ctx,
115                                     const UsingDirectiveDecl &D) {
116   PrintingPolicy PP(Ctx.getLangOpts());
117   std::string Name;
118   llvm::raw_string_ostream Out(Name);
119 
120   if (auto *Qual = D.getQualifier())
121     Qual->print(Out, PP);
122   D.getNominatedNamespaceAsWritten()->printName(Out);
123   return Out.str();
124 }
125 
126 std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
127   std::string Name;
128   llvm::raw_string_ostream Out(Name);
129   PrintingPolicy PP(Ctx.getLangOpts());
130 
131   // Handle 'using namespace'. They all have the same name - <using-directive>.
132   if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
133     Out << "using namespace ";
134     if (auto *Qual = UD->getQualifier())
135       Qual->print(Out, PP);
136     UD->getNominatedNamespaceAsWritten()->printName(Out);
137     return Out.str();
138   }
139 
140   if (isAnonymous(ND.getDeclName())) {
141     // Come up with a presentation for an anonymous entity.
142     if (isa<NamespaceDecl>(ND))
143       return "(anonymous namespace)";
144     if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
145       return ("(anonymous " + Cls->getKindName() + ")").str();
146     if (isa<EnumDecl>(ND))
147       return "(anonymous enum)";
148     return "(anonymous)";
149   }
150 
151   // Print nested name qualifier if it was written in the source code.
152   if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier())
153     Qualifier->print(Out, PP);
154   // Print the name itself.
155   ND.getDeclName().print(Out, PP);
156   // Print template arguments.
157   Out << printTemplateSpecializationArgs(ND);
158 
159   return Out.str();
160 }
161 
162 std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
163   std::string TemplateArgs;
164   llvm::raw_string_ostream OS(TemplateArgs);
165   PrintingPolicy Policy(ND.getASTContext().getLangOpts());
166   if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
167           getTemplateSpecializationArgLocs(ND)) {
168     printTemplateArgumentList(OS, *Args, Policy);
169   } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
170     if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
171       // ClassTemplateSpecializationDecls do not contain
172       // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
173       // create a new argument location list from TypeSourceInfo.
174       auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
175       llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
176       ArgLocs.reserve(STL.getNumArgs());
177       for (unsigned I = 0; I < STL.getNumArgs(); ++I)
178         ArgLocs.push_back(STL.getArgLoc(I));
179       printTemplateArgumentList(OS, ArgLocs, Policy);
180     } else {
181       // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
182       // e.g. friend decls. Currently we fallback to Template Arguments without
183       // location information.
184       printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
185     }
186   }
187   OS.flush();
188   return TemplateArgs;
189 }
190 
191 std::string printNamespaceScope(const DeclContext &DC) {
192   for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
193     if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
194       if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
195         return printQualifiedName(*NS) + "::";
196   return "";
197 }
198 
199 llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
200   llvm::SmallString<128> USR;
201   if (index::generateUSRForDecl(D, USR))
202     return None;
203   return SymbolID(USR);
204 }
205 
206 llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
207                                      const MacroInfo *MI,
208                                      const SourceManager &SM) {
209   if (MI == nullptr)
210     return None;
211   llvm::SmallString<128> USR;
212   if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
213     return None;
214   return SymbolID(USR);
215 }
216 
217 std::string shortenNamespace(const llvm::StringRef OriginalName,
218                              const llvm::StringRef CurrentNamespace) {
219   llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
220   llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
221   llvm::SmallVector<llvm::StringRef, 8> Result;
222   OriginalName.split(OriginalParts, "::");
223   CurrentNamespace.split(CurrentParts, "::");
224   auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
225 
226   unsigned DifferentAt = 0;
227   while (DifferentAt < MinLength &&
228       CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
229     DifferentAt++;
230   }
231 
232   for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) {
233     Result.push_back(OriginalParts[i]);
234   }
235   return join(Result, "::");
236 }
237 
238 std::string printType(const QualType QT, const DeclContext & Context){
239   PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
240   PP.SuppressUnwrittenScope = 1;
241   PP.SuppressTagKeyword = 1;
242   return shortenNamespace(
243       QT.getAsString(PP),
244       printNamespaceScope(Context) );
245 }
246 
247 
248 } // namespace clangd
249 } // namespace clang
250