blob: 1a9be178b3af69dd0c3f680f0e87b5bcb0678861 [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"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000015#include "clang/AST/TemplateBase.h"
Eric Liu48597382018-10-18 12:23:05 +000016#include "clang/Basic/SourceLocation.h"
Haojian Wu5f100262018-03-09 14:00:34 +000017#include "clang/Basic/SourceManager.h"
Johan Vikstrom720d19b2019-08-08 07:21:06 +000018#include "clang/Basic/Specifiers.h"
Haojian Wuc6ddb462018-08-07 08:57:52 +000019#include "clang/Index/USRGeneration.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000020#include "llvm/ADT/Optional.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000021#include "llvm/Support/Casting.h"
22#include "llvm/Support/ScopedPrinter.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000023#include "llvm/Support/raw_ostream.h"
Haojian Wu5f100262018-03-09 14:00:34 +000024
25namespace clang {
26namespace clangd {
Haojian Wu5f100262018-03-09 14:00:34 +000027
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000028namespace {
29llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>>
30getTemplateSpecializationArgLocs(const NamedDecl &ND) {
31 if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) {
32 if (const ASTTemplateArgumentListInfo *Args =
33 Func->getTemplateSpecializationArgsAsWritten())
34 return Args->arguments();
35 } else if (auto *Cls =
36 llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) {
37 if (auto *Args = Cls->getTemplateArgsAsWritten())
38 return Args->arguments();
Johan Vikstromef0c3dd2019-08-09 07:35:16 +000039 } else if (auto *Var =
40 llvm::dyn_cast<VarTemplatePartialSpecializationDecl>(&ND)) {
41 if (auto *Args = Var->getTemplateArgsAsWritten())
42 return Args->arguments();
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000043 } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND))
44 return Var->getTemplateArgsInfo().arguments();
45 // We return None for ClassTemplateSpecializationDecls because it does not
46 // contain TemplateArgumentLoc information.
47 return llvm::None;
48}
Johan Vikstrom720d19b2019-08-08 07:21:06 +000049
50template <class T>
51bool isTemplateSpecializationKind(const NamedDecl *D,
52 TemplateSpecializationKind Kind) {
53 if (const auto *TD = dyn_cast<T>(D))
54 return TD->getTemplateSpecializationKind() == Kind;
55 return false;
56}
57
58bool isTemplateSpecializationKind(const NamedDecl *D,
59 TemplateSpecializationKind Kind) {
60 return isTemplateSpecializationKind<FunctionDecl>(D, Kind) ||
61 isTemplateSpecializationKind<CXXRecordDecl>(D, Kind) ||
62 isTemplateSpecializationKind<VarDecl>(D, Kind);
63}
64
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000065} // namespace
66
Johan Vikstrom720d19b2019-08-08 07:21:06 +000067bool isImplicitTemplateInstantiation(const NamedDecl *D) {
68 return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation);
69}
70
71bool isExplicitTemplateSpecialization(const NamedDecl *D) {
72 return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization);
73}
74
Sam McCall95738072019-08-06 20:25:59 +000075bool isImplementationDetail(const Decl *D) {
76 return !isSpelledInSource(D->getLocation(),
77 D->getASTContext().getSourceManager());
Eric Liu48597382018-10-18 12:23:05 +000078}
79
Sam McCall95738072019-08-06 20:25:59 +000080SourceLocation findName(const clang::Decl *D) {
81 return D->getLocation();
Haojian Wu5f100262018-03-09 14:00:34 +000082}
83
Eric Liu7ad16962018-06-22 10:46:59 +000084std::string printQualifiedName(const NamedDecl &ND) {
85 std::string QName;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000086 llvm::raw_string_ostream OS(QName);
Eric Liu7ad16962018-06-22 10:46:59 +000087 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
88 // Note that inline namespaces are treated as transparent scopes. This
89 // reflects the way they're most commonly used for lookup. Ideally we'd
90 // include them, but at query time it's hard to find all the inline
91 // namespaces to query: the preamble doesn't have a dedicated list.
92 Policy.SuppressUnwrittenScope = true;
93 ND.printQualifiedName(OS, Policy);
94 OS.flush();
95 assert(!StringRef(QName).startswith("::"));
96 return QName;
97}
98
Ilya Biryukov19d75602018-11-23 15:21:19 +000099std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
100 std::string Name;
101 llvm::raw_string_ostream Out(Name);
102 PrintingPolicy PP(Ctx.getLangOpts());
103 // Handle 'using namespace'. They all have the same name - <using-directive>.
104 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
105 Out << "using namespace ";
106 if (auto *Qual = UD->getQualifier())
107 Qual->print(Out, PP);
108 UD->getNominatedNamespaceAsWritten()->printName(Out);
109 return Out.str();
110 }
111 ND.getDeclName().print(Out, PP);
112 if (!Out.str().empty()) {
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000113 Out << printTemplateSpecializationArgs(ND);
Ilya Biryukov19d75602018-11-23 15:21:19 +0000114 return Out.str();
115 }
116 // The name was empty, so present an anonymous entity.
Henry Wong1a1fbdc2018-11-27 04:27:00 +0000117 if (isa<NamespaceDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000118 return "(anonymous namespace)";
119 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
120 return ("(anonymous " + Cls->getKindName() + ")").str();
Henry Wong1a1fbdc2018-11-27 04:27:00 +0000121 if (isa<EnumDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000122 return "(anonymous enum)";
123 return "(anonymous)";
124}
125
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000126std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
127 std::string TemplateArgs;
128 llvm::raw_string_ostream OS(TemplateArgs);
129 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
130 if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
131 getTemplateSpecializationArgLocs(ND)) {
132 printTemplateArgumentList(OS, *Args, Policy);
133 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
134 if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
135 // ClassTemplateSpecializationDecls do not contain
136 // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
137 // create a new argument location list from TypeSourceInfo.
138 auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
139 llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
140 ArgLocs.reserve(STL.getNumArgs());
141 for (unsigned I = 0; I < STL.getNumArgs(); ++I)
142 ArgLocs.push_back(STL.getArgLoc(I));
143 printTemplateArgumentList(OS, ArgLocs, Policy);
144 } else {
145 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
146 // e.g. friend decls. Currently we fallback to Template Arguments without
147 // location information.
148 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
149 }
150 }
151 OS.flush();
152 return TemplateArgs;
153}
154
Eric Liu3fac4ef2018-10-17 11:19:02 +0000155std::string printNamespaceScope(const DeclContext &DC) {
156 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
157 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
158 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
159 return printQualifiedName(*NS) + "::";
160 return "";
161}
162
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000163llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
164 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000165 if (index::generateUSRForDecl(D, USR))
166 return None;
167 return SymbolID(USR);
168}
169
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000170llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
171 const MacroInfo *MI,
172 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000173 if (MI == nullptr)
174 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000175 llvm::SmallString<128> USR;
Eric Liud25f1212018-09-06 09:59:37 +0000176 if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
177 return None;
178 return SymbolID(USR);
179}
180
Sam McCall94701422019-07-11 16:04:18 +0000181std::string shortenNamespace(const llvm::StringRef OriginalName,
182 const llvm::StringRef CurrentNamespace) {
183 llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
184 llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
185 llvm::SmallVector<llvm::StringRef, 8> Result;
186 OriginalName.split(OriginalParts, "::");
187 CurrentNamespace.split(CurrentParts, "::");
188 auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
189
190 unsigned DifferentAt = 0;
191 while (DifferentAt < MinLength &&
192 CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
193 DifferentAt++;
194 }
195
Paul Robinson2cb5c462019-07-11 23:48:06 +0000196 for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) {
Sam McCall94701422019-07-11 16:04:18 +0000197 Result.push_back(OriginalParts[i]);
198 }
199 return join(Result, "::");
200}
201
202std::string printType(const QualType QT, const DeclContext & Context){
203 PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
Haojian Wuac958c22019-07-18 15:13:45 +0000204 PP.SuppressUnwrittenScope = 1;
Sam McCall94701422019-07-11 16:04:18 +0000205 PP.SuppressTagKeyword = 1;
206 return shortenNamespace(
207 QT.getAsString(PP),
208 printNamespaceScope(Context) );
209}
210
211
Haojian Wu5f100262018-03-09 14:00:34 +0000212} // namespace clangd
213} // namespace clang