blob: a4ea7b0c1f133db3e8ab5caa6df001f0755692f8 [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
106/// Returns a nested name specifier of \p ND if it was present in the source,
107/// e.g.
108/// void ns::something::foo() -> returns 'ns::something'
109/// void foo() -> returns null
110static NestedNameSpecifier *getQualifier(const NamedDecl &ND) {
111 if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND))
112 return V->getQualifier();
113 if (auto *T = llvm::dyn_cast<TagDecl>(&ND))
114 return T->getQualifier();
115 return nullptr;
116}
117
Ilya Biryukov19d75602018-11-23 15:21:19 +0000118std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
119 std::string Name;
120 llvm::raw_string_ostream Out(Name);
121 PrintingPolicy PP(Ctx.getLangOpts());
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000122
Ilya Biryukov19d75602018-11-23 15:21:19 +0000123 // Handle 'using namespace'. They all have the same name - <using-directive>.
124 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
125 Out << "using namespace ";
126 if (auto *Qual = UD->getQualifier())
127 Qual->print(Out, PP);
128 UD->getNominatedNamespaceAsWritten()->printName(Out);
129 return Out.str();
130 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000131
132 if (isAnonymous(ND.getDeclName())) {
133 // Come up with a presentation for an anonymous entity.
134 if (isa<NamespaceDecl>(ND))
135 return "(anonymous namespace)";
136 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
137 return ("(anonymous " + Cls->getKindName() + ")").str();
138 if (isa<EnumDecl>(ND))
139 return "(anonymous enum)";
140 return "(anonymous)";
Ilya Biryukov19d75602018-11-23 15:21:19 +0000141 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000142
143 // Print nested name qualifier if it was written in the source code.
144 if (auto *Qualifier = getQualifier(ND))
145 Qualifier->print(Out, PP);
146 // Print the name itself.
147 ND.getDeclName().print(Out, PP);
148 // Print template arguments.
149 Out << printTemplateSpecializationArgs(ND);
150
151 return Out.str();
Ilya Biryukov19d75602018-11-23 15:21:19 +0000152}
153
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000154std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
155 std::string TemplateArgs;
156 llvm::raw_string_ostream OS(TemplateArgs);
157 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
158 if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
159 getTemplateSpecializationArgLocs(ND)) {
160 printTemplateArgumentList(OS, *Args, Policy);
161 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
162 if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
163 // ClassTemplateSpecializationDecls do not contain
164 // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
165 // create a new argument location list from TypeSourceInfo.
166 auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
167 llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
168 ArgLocs.reserve(STL.getNumArgs());
169 for (unsigned I = 0; I < STL.getNumArgs(); ++I)
170 ArgLocs.push_back(STL.getArgLoc(I));
171 printTemplateArgumentList(OS, ArgLocs, Policy);
172 } else {
173 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
174 // e.g. friend decls. Currently we fallback to Template Arguments without
175 // location information.
176 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
177 }
178 }
179 OS.flush();
180 return TemplateArgs;
181}
182
Eric Liu3fac4ef2018-10-17 11:19:02 +0000183std::string printNamespaceScope(const DeclContext &DC) {
184 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
185 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
186 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
187 return printQualifiedName(*NS) + "::";
188 return "";
189}
190
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000191llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
192 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000193 if (index::generateUSRForDecl(D, USR))
194 return None;
195 return SymbolID(USR);
196}
197
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000198llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
199 const MacroInfo *MI,
200 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000201 if (MI == nullptr)
202 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000203 llvm::SmallString<128> USR;
Eric Liud25f1212018-09-06 09:59:37 +0000204 if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
205 return None;
206 return SymbolID(USR);
207}
208
Sam McCall94701422019-07-11 16:04:18 +0000209std::string shortenNamespace(const llvm::StringRef OriginalName,
210 const llvm::StringRef CurrentNamespace) {
211 llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
212 llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
213 llvm::SmallVector<llvm::StringRef, 8> Result;
214 OriginalName.split(OriginalParts, "::");
215 CurrentNamespace.split(CurrentParts, "::");
216 auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
217
218 unsigned DifferentAt = 0;
219 while (DifferentAt < MinLength &&
220 CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
221 DifferentAt++;
222 }
223
Paul Robinson2cb5c462019-07-11 23:48:06 +0000224 for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) {
Sam McCall94701422019-07-11 16:04:18 +0000225 Result.push_back(OriginalParts[i]);
226 }
227 return join(Result, "::");
228}
229
230std::string printType(const QualType QT, const DeclContext & Context){
231 PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
Haojian Wuac958c22019-07-18 15:13:45 +0000232 PP.SuppressUnwrittenScope = 1;
Sam McCall94701422019-07-11 16:04:18 +0000233 PP.SuppressTagKeyword = 1;
234 return shortenNamespace(
235 QT.getAsString(PP),
236 printNamespaceScope(Context) );
237}
238
239
Haojian Wu5f100262018-03-09 14:00:34 +0000240} // namespace clangd
241} // namespace clang