blob: d04ebcf22a887a36ac125eedbd56fd10d8831f20 [file] [log] [blame]
Haojian Wu5f100262018-03-09 14:00:34 +00001//===--- AST.cpp - Utility AST functions -----------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Haojian Wu5f100262018-03-09 14:00:34 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "AST.h"
10
Sam McCall95738072019-08-06 20:25:59 +000011#include "SourceCode.h"
Haojian Wu5f100262018-03-09 14:00:34 +000012#include "clang/AST/ASTContext.h"
13#include "clang/AST/Decl.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000014#include "clang/AST/DeclTemplate.h"
Ilya Biryukov38fa1a92019-08-14 12:51:04 +000015#include "clang/AST/DeclarationName.h"
16#include "clang/AST/NestedNameSpecifier.h"
17#include "clang/AST/PrettyPrinter.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000018#include "clang/AST/TemplateBase.h"
Eric Liu48597382018-10-18 12:23:05 +000019#include "clang/Basic/SourceLocation.h"
Haojian Wu5f100262018-03-09 14:00:34 +000020#include "clang/Basic/SourceManager.h"
Johan Vikstrom720d19b2019-08-08 07:21:06 +000021#include "clang/Basic/Specifiers.h"
Haojian Wuc6ddb462018-08-07 08:57:52 +000022#include "clang/Index/USRGeneration.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000023#include "llvm/ADT/Optional.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000024#include "llvm/Support/Casting.h"
25#include "llvm/Support/ScopedPrinter.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000026#include "llvm/Support/raw_ostream.h"
Haojian Wu5f100262018-03-09 14:00:34 +000027
28namespace clang {
29namespace clangd {
Haojian Wu5f100262018-03-09 14:00:34 +000030
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000031namespace {
32llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>>
33getTemplateSpecializationArgLocs(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();
Johan Vikstromef0c3dd2019-08-09 07:35:16 +000042 } else if (auto *Var =
43 llvm::dyn_cast<VarTemplatePartialSpecializationDecl>(&ND)) {
44 if (auto *Args = Var->getTemplateArgsAsWritten())
45 return Args->arguments();
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000046 } 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}
Johan Vikstrom720d19b2019-08-08 07:21:06 +000052
53template <class T>
54bool 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
61bool 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
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000068} // namespace
69
Johan Vikstrom720d19b2019-08-08 07:21:06 +000070bool isImplicitTemplateInstantiation(const NamedDecl *D) {
71 return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation);
72}
73
74bool isExplicitTemplateSpecialization(const NamedDecl *D) {
75 return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization);
76}
77
Sam McCall95738072019-08-06 20:25:59 +000078bool isImplementationDetail(const Decl *D) {
79 return !isSpelledInSource(D->getLocation(),
80 D->getASTContext().getSourceManager());
Eric Liu48597382018-10-18 12:23:05 +000081}
82
Sam McCall95738072019-08-06 20:25:59 +000083SourceLocation findName(const clang::Decl *D) {
84 return D->getLocation();
Haojian Wu5f100262018-03-09 14:00:34 +000085}
86
Eric Liu7ad16962018-06-22 10:46:59 +000087std::string printQualifiedName(const NamedDecl &ND) {
88 std::string QName;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000089 llvm::raw_string_ostream OS(QName);
Eric Liu7ad16962018-06-22 10:46:59 +000090 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
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000102static bool isAnonymous(const DeclarationName &N) {
103 return N.isIdentifier() && !N.getAsIdentifierInfo();
104}
105
Haojian Wu65f61c02019-10-18 12:07:19 +0000106NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND) {
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000107 if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND))
Haojian Wu65f61c02019-10-18 12:07:19 +0000108 return V->getQualifierLoc();
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000109 if (auto *T = llvm::dyn_cast<TagDecl>(&ND))
Haojian Wu65f61c02019-10-18 12:07:19 +0000110 return T->getQualifierLoc();
111 return NestedNameSpecifierLoc();
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000112}
113
Utkarsh Saxenab62b4542019-10-16 09:53:59 +0000114std::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
Ilya Biryukov19d75602018-11-23 15:21:19 +0000126std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
127 std::string Name;
128 llvm::raw_string_ostream Out(Name);
129 PrintingPolicy PP(Ctx.getLangOpts());
Sam McCall713c30b2019-11-15 15:08:16 +0100130 // We don't consider a class template's args part of the constructor name.
131 PP.SuppressTemplateArgsInCXXConstructors = true;
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000132
Ilya Biryukov19d75602018-11-23 15:21:19 +0000133 // Handle 'using namespace'. They all have the same name - <using-directive>.
134 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
135 Out << "using namespace ";
136 if (auto *Qual = UD->getQualifier())
137 Qual->print(Out, PP);
138 UD->getNominatedNamespaceAsWritten()->printName(Out);
139 return Out.str();
140 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000141
142 if (isAnonymous(ND.getDeclName())) {
143 // Come up with a presentation for an anonymous entity.
144 if (isa<NamespaceDecl>(ND))
145 return "(anonymous namespace)";
146 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
147 return ("(anonymous " + Cls->getKindName() + ")").str();
148 if (isa<EnumDecl>(ND))
149 return "(anonymous enum)";
150 return "(anonymous)";
Ilya Biryukov19d75602018-11-23 15:21:19 +0000151 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000152
153 // Print nested name qualifier if it was written in the source code.
Haojian Wu65f61c02019-10-18 12:07:19 +0000154 if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier())
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000155 Qualifier->print(Out, PP);
156 // Print the name itself.
157 ND.getDeclName().print(Out, PP);
158 // Print template arguments.
159 Out << printTemplateSpecializationArgs(ND);
160
161 return Out.str();
Ilya Biryukov19d75602018-11-23 15:21:19 +0000162}
163
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000164std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
165 std::string TemplateArgs;
166 llvm::raw_string_ostream OS(TemplateArgs);
167 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
168 if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
169 getTemplateSpecializationArgLocs(ND)) {
170 printTemplateArgumentList(OS, *Args, Policy);
171 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
172 if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
173 // ClassTemplateSpecializationDecls do not contain
174 // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
175 // create a new argument location list from TypeSourceInfo.
176 auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
177 llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
178 ArgLocs.reserve(STL.getNumArgs());
179 for (unsigned I = 0; I < STL.getNumArgs(); ++I)
180 ArgLocs.push_back(STL.getArgLoc(I));
181 printTemplateArgumentList(OS, ArgLocs, Policy);
182 } else {
183 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
184 // e.g. friend decls. Currently we fallback to Template Arguments without
185 // location information.
186 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
187 }
188 }
189 OS.flush();
190 return TemplateArgs;
191}
192
Eric Liu3fac4ef2018-10-17 11:19:02 +0000193std::string printNamespaceScope(const DeclContext &DC) {
194 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
195 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
196 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
197 return printQualifiedName(*NS) + "::";
198 return "";
199}
200
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000201llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
202 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000203 if (index::generateUSRForDecl(D, USR))
204 return None;
205 return SymbolID(USR);
206}
207
Utkarsh Saxena02ec6ff2019-11-11 12:38:17 +0100208llvm::Optional<SymbolID> getSymbolID(const llvm::StringRef MacroName,
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000209 const MacroInfo *MI,
210 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000211 if (MI == nullptr)
212 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000213 llvm::SmallString<128> USR;
Utkarsh Saxena02ec6ff2019-11-11 12:38:17 +0100214 if (index::generateUSRForMacro(MacroName, MI->getDefinitionLoc(), SM, USR))
Eric Liud25f1212018-09-06 09:59:37 +0000215 return None;
216 return SymbolID(USR);
217}
218
Sam McCall94701422019-07-11 16:04:18 +0000219std::string shortenNamespace(const llvm::StringRef OriginalName,
220 const llvm::StringRef CurrentNamespace) {
221 llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
222 llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
223 llvm::SmallVector<llvm::StringRef, 8> Result;
224 OriginalName.split(OriginalParts, "::");
225 CurrentNamespace.split(CurrentParts, "::");
226 auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
227
228 unsigned DifferentAt = 0;
229 while (DifferentAt < MinLength &&
230 CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
231 DifferentAt++;
232 }
233
Paul Robinson2cb5c462019-07-11 23:48:06 +0000234 for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) {
Sam McCall94701422019-07-11 16:04:18 +0000235 Result.push_back(OriginalParts[i]);
236 }
237 return join(Result, "::");
238}
239
240std::string printType(const QualType QT, const DeclContext & Context){
241 PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
Haojian Wuac958c22019-07-18 15:13:45 +0000242 PP.SuppressUnwrittenScope = 1;
Sam McCall94701422019-07-11 16:04:18 +0000243 PP.SuppressTagKeyword = 1;
244 return shortenNamespace(
245 QT.getAsString(PP),
246 printNamespaceScope(Context) );
247}
248
Sam McCall6ec07142019-11-18 21:29:17 +0100249QualType declaredType(const TypeDecl *D) {
250 if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
251 if (const auto *TSI = CTSD->getTypeAsWritten())
252 return TSI->getType();
253 return D->getASTContext().getTypeDeclType(D);
254}
Sam McCall94701422019-07-11 16:04:18 +0000255
Haojian Wu5f100262018-03-09 14:00:34 +0000256} // namespace clangd
257} // namespace clang