blob: ce1254f6693cbccd35990bc02e58bfb83551df83 [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
Kadir Cetinkayab2eaac32019-12-18 11:23:47 +010011#include "FindTarget.h"
Sam McCall95738072019-08-06 20:25:59 +000012#include "SourceCode.h"
Haojian Wu5f100262018-03-09 14:00:34 +000013#include "clang/AST/ASTContext.h"
Kadir Cetinkayab2eaac32019-12-18 11:23:47 +010014#include "clang/AST/ASTTypeTraits.h"
Haojian Wu5f100262018-03-09 14:00:34 +000015#include "clang/AST/Decl.h"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010016#include "clang/AST/DeclBase.h"
Kadir Cetinkaya9ab15f32019-12-16 14:22:48 +010017#include "clang/AST/DeclCXX.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000018#include "clang/AST/DeclTemplate.h"
Ilya Biryukov38fa1a92019-08-14 12:51:04 +000019#include "clang/AST/DeclarationName.h"
20#include "clang/AST/NestedNameSpecifier.h"
21#include "clang/AST/PrettyPrinter.h"
Sam McCall765b1252019-11-16 17:00:19 +010022#include "clang/AST/RecursiveASTVisitor.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000023#include "clang/AST/TemplateBase.h"
Eric Liu48597382018-10-18 12:23:05 +000024#include "clang/Basic/SourceLocation.h"
Haojian Wu5f100262018-03-09 14:00:34 +000025#include "clang/Basic/SourceManager.h"
Johan Vikstrom720d19b2019-08-08 07:21:06 +000026#include "clang/Basic/Specifiers.h"
Haojian Wuc6ddb462018-08-07 08:57:52 +000027#include "clang/Index/USRGeneration.h"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010028#include "llvm/ADT/ArrayRef.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000029#include "llvm/ADT/Optional.h"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010030#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/StringRef.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000032#include "llvm/Support/Casting.h"
33#include "llvm/Support/ScopedPrinter.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000034#include "llvm/Support/raw_ostream.h"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010035#include <string>
36#include <vector>
Haojian Wu5f100262018-03-09 14:00:34 +000037
38namespace clang {
39namespace clangd {
Haojian Wu5f100262018-03-09 14:00:34 +000040
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000041namespace {
42llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>>
43getTemplateSpecializationArgLocs(const NamedDecl &ND) {
44 if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) {
45 if (const ASTTemplateArgumentListInfo *Args =
46 Func->getTemplateSpecializationArgsAsWritten())
47 return Args->arguments();
48 } else if (auto *Cls =
49 llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) {
50 if (auto *Args = Cls->getTemplateArgsAsWritten())
51 return Args->arguments();
Johan Vikstromef0c3dd2019-08-09 07:35:16 +000052 } else if (auto *Var =
53 llvm::dyn_cast<VarTemplatePartialSpecializationDecl>(&ND)) {
54 if (auto *Args = Var->getTemplateArgsAsWritten())
55 return Args->arguments();
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000056 } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND))
57 return Var->getTemplateArgsInfo().arguments();
58 // We return None for ClassTemplateSpecializationDecls because it does not
59 // contain TemplateArgumentLoc information.
60 return llvm::None;
61}
Johan Vikstrom720d19b2019-08-08 07:21:06 +000062
63template <class T>
64bool isTemplateSpecializationKind(const NamedDecl *D,
65 TemplateSpecializationKind Kind) {
66 if (const auto *TD = dyn_cast<T>(D))
67 return TD->getTemplateSpecializationKind() == Kind;
68 return false;
69}
70
71bool isTemplateSpecializationKind(const NamedDecl *D,
72 TemplateSpecializationKind Kind) {
73 return isTemplateSpecializationKind<FunctionDecl>(D, Kind) ||
74 isTemplateSpecializationKind<CXXRecordDecl>(D, Kind) ||
75 isTemplateSpecializationKind<VarDecl>(D, Kind);
76}
77
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010078// Store all UsingDirectiveDecls in parent contexts of DestContext, that were
79// introduced before InsertionPoint.
80llvm::DenseSet<const NamespaceDecl *>
81getUsingNamespaceDirectives(const DeclContext *DestContext,
82 SourceLocation Until) {
83 const auto &SM = DestContext->getParentASTContext().getSourceManager();
84 llvm::DenseSet<const NamespaceDecl *> VisibleNamespaceDecls;
85 for (const auto *DC = DestContext; DC; DC = DC->getLookupParent()) {
86 for (const auto *D : DC->decls()) {
87 if (!SM.isWrittenInSameFile(D->getLocation(), Until) ||
88 !SM.isBeforeInTranslationUnit(D->getLocation(), Until))
89 continue;
90 if (auto *UDD = llvm::dyn_cast<UsingDirectiveDecl>(D))
91 VisibleNamespaceDecls.insert(
92 UDD->getNominatedNamespace()->getCanonicalDecl());
93 }
94 }
95 return VisibleNamespaceDecls;
96}
97
Kazuaki Ishizakidd5571d2020-04-05 15:28:11 +090098// Goes over all parents of SourceContext until we find a common ancestor for
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010099// DestContext and SourceContext. Any qualifier including and above common
100// ancestor is redundant, therefore we stop at lowest common ancestor.
101// In addition to that stops early whenever IsVisible returns true. This can be
102// used to implement support for "using namespace" decls.
103std::string
104getQualification(ASTContext &Context, const DeclContext *DestContext,
105 const DeclContext *SourceContext,
106 llvm::function_ref<bool(NestedNameSpecifier *)> IsVisible) {
107 std::vector<const NestedNameSpecifier *> Parents;
108 bool ReachedNS = false;
109 for (const DeclContext *CurContext = SourceContext; CurContext;
110 CurContext = CurContext->getLookupParent()) {
111 // Stop once we reach a common ancestor.
112 if (CurContext->Encloses(DestContext))
113 break;
114
115 NestedNameSpecifier *NNS = nullptr;
116 if (auto *TD = llvm::dyn_cast<TagDecl>(CurContext)) {
117 // There can't be any more tag parents after hitting a namespace.
118 assert(!ReachedNS);
119 NNS = NestedNameSpecifier::Create(Context, nullptr, false,
120 TD->getTypeForDecl());
121 } else {
122 ReachedNS = true;
123 auto *NSD = llvm::cast<NamespaceDecl>(CurContext);
124 NNS = NestedNameSpecifier::Create(Context, nullptr, NSD);
125 // Anonymous and inline namespace names are not spelled while qualifying a
126 // name, so skip those.
127 if (NSD->isAnonymousNamespace() || NSD->isInlineNamespace())
128 continue;
129 }
130 // Stop if this namespace is already visible at DestContext.
131 if (IsVisible(NNS))
132 break;
133
134 Parents.push_back(NNS);
135 }
136
137 // Go over name-specifiers in reverse order to create necessary qualification,
138 // since we stored inner-most parent first.
139 std::string Result;
140 llvm::raw_string_ostream OS(Result);
141 for (const auto *Parent : llvm::reverse(Parents))
142 Parent->print(OS, Context.getPrintingPolicy());
143 return OS.str();
144}
145
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000146} // namespace
147
Johan Vikstrom720d19b2019-08-08 07:21:06 +0000148bool isImplicitTemplateInstantiation(const NamedDecl *D) {
149 return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation);
150}
151
152bool isExplicitTemplateSpecialization(const NamedDecl *D) {
153 return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization);
154}
155
Sam McCall95738072019-08-06 20:25:59 +0000156bool isImplementationDetail(const Decl *D) {
157 return !isSpelledInSource(D->getLocation(),
158 D->getASTContext().getSourceManager());
Eric Liu48597382018-10-18 12:23:05 +0000159}
160
Ilya Biryukovb63c35e2019-12-10 10:08:39 +0100161SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM) {
162 auto L = D.getLocation();
163 if (isSpelledInSource(L, SM))
164 return SM.getSpellingLoc(L);
165 return SM.getExpansionLoc(L);
166}
Haojian Wu5f100262018-03-09 14:00:34 +0000167
Eric Liu7ad16962018-06-22 10:46:59 +0000168std::string printQualifiedName(const NamedDecl &ND) {
169 std::string QName;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000170 llvm::raw_string_ostream OS(QName);
Eric Liu7ad16962018-06-22 10:46:59 +0000171 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
172 // Note that inline namespaces are treated as transparent scopes. This
173 // reflects the way they're most commonly used for lookup. Ideally we'd
174 // include them, but at query time it's hard to find all the inline
175 // namespaces to query: the preamble doesn't have a dedicated list.
176 Policy.SuppressUnwrittenScope = true;
177 ND.printQualifiedName(OS, Policy);
178 OS.flush();
179 assert(!StringRef(QName).startswith("::"));
180 return QName;
181}
182
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000183static bool isAnonymous(const DeclarationName &N) {
184 return N.isIdentifier() && !N.getAsIdentifierInfo();
185}
186
Haojian Wu65f61c02019-10-18 12:07:19 +0000187NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND) {
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000188 if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND))
Haojian Wu65f61c02019-10-18 12:07:19 +0000189 return V->getQualifierLoc();
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000190 if (auto *T = llvm::dyn_cast<TagDecl>(&ND))
Haojian Wu65f61c02019-10-18 12:07:19 +0000191 return T->getQualifierLoc();
192 return NestedNameSpecifierLoc();
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000193}
194
Utkarsh Saxenab62b4542019-10-16 09:53:59 +0000195std::string printUsingNamespaceName(const ASTContext &Ctx,
196 const UsingDirectiveDecl &D) {
197 PrintingPolicy PP(Ctx.getLangOpts());
198 std::string Name;
199 llvm::raw_string_ostream Out(Name);
200
201 if (auto *Qual = D.getQualifier())
202 Qual->print(Out, PP);
203 D.getNominatedNamespaceAsWritten()->printName(Out);
204 return Out.str();
205}
206
Ilya Biryukov19d75602018-11-23 15:21:19 +0000207std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
208 std::string Name;
209 llvm::raw_string_ostream Out(Name);
210 PrintingPolicy PP(Ctx.getLangOpts());
Sam McCall713c30b2019-11-15 15:08:16 +0100211 // We don't consider a class template's args part of the constructor name.
212 PP.SuppressTemplateArgsInCXXConstructors = true;
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000213
Ilya Biryukov19d75602018-11-23 15:21:19 +0000214 // Handle 'using namespace'. They all have the same name - <using-directive>.
215 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
216 Out << "using namespace ";
217 if (auto *Qual = UD->getQualifier())
218 Qual->print(Out, PP);
219 UD->getNominatedNamespaceAsWritten()->printName(Out);
220 return Out.str();
221 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000222
223 if (isAnonymous(ND.getDeclName())) {
224 // Come up with a presentation for an anonymous entity.
225 if (isa<NamespaceDecl>(ND))
226 return "(anonymous namespace)";
Kadir Cetinkaya9ab15f32019-12-16 14:22:48 +0100227 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND)) {
228 if (Cls->isLambda())
229 return "(lambda)";
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000230 return ("(anonymous " + Cls->getKindName() + ")").str();
Kadir Cetinkaya9ab15f32019-12-16 14:22:48 +0100231 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000232 if (isa<EnumDecl>(ND))
233 return "(anonymous enum)";
234 return "(anonymous)";
Ilya Biryukov19d75602018-11-23 15:21:19 +0000235 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000236
237 // Print nested name qualifier if it was written in the source code.
Haojian Wu65f61c02019-10-18 12:07:19 +0000238 if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier())
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000239 Qualifier->print(Out, PP);
240 // Print the name itself.
241 ND.getDeclName().print(Out, PP);
242 // Print template arguments.
243 Out << printTemplateSpecializationArgs(ND);
244
245 return Out.str();
Ilya Biryukov19d75602018-11-23 15:21:19 +0000246}
247
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000248std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
249 std::string TemplateArgs;
250 llvm::raw_string_ostream OS(TemplateArgs);
251 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
252 if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
253 getTemplateSpecializationArgLocs(ND)) {
254 printTemplateArgumentList(OS, *Args, Policy);
255 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
256 if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
257 // ClassTemplateSpecializationDecls do not contain
258 // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
259 // create a new argument location list from TypeSourceInfo.
260 auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
261 llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
262 ArgLocs.reserve(STL.getNumArgs());
263 for (unsigned I = 0; I < STL.getNumArgs(); ++I)
264 ArgLocs.push_back(STL.getArgLoc(I));
265 printTemplateArgumentList(OS, ArgLocs, Policy);
266 } else {
267 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
268 // e.g. friend decls. Currently we fallback to Template Arguments without
269 // location information.
270 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
271 }
272 }
273 OS.flush();
274 return TemplateArgs;
275}
276
Eric Liu3fac4ef2018-10-17 11:19:02 +0000277std::string printNamespaceScope(const DeclContext &DC) {
278 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
279 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
280 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
281 return printQualifiedName(*NS) + "::";
282 return "";
283}
284
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000285llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
286 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000287 if (index::generateUSRForDecl(D, USR))
288 return None;
289 return SymbolID(USR);
290}
291
Utkarsh Saxena02ec6ff2019-11-11 12:38:17 +0100292llvm::Optional<SymbolID> getSymbolID(const llvm::StringRef MacroName,
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000293 const MacroInfo *MI,
294 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000295 if (MI == nullptr)
296 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000297 llvm::SmallString<128> USR;
Utkarsh Saxena02ec6ff2019-11-11 12:38:17 +0100298 if (index::generateUSRForMacro(MacroName, MI->getDefinitionLoc(), SM, USR))
Eric Liud25f1212018-09-06 09:59:37 +0000299 return None;
300 return SymbolID(USR);
301}
302
Kadir Cetinkayab2eaac32019-12-18 11:23:47 +0100303// FIXME: This should be handled while printing underlying decls instead.
304std::string printType(const QualType QT, const DeclContext &CurContext) {
305 std::string Result;
306 llvm::raw_string_ostream OS(Result);
307 auto Decls = explicitReferenceTargets(
308 ast_type_traits::DynTypedNode::create(QT), DeclRelation::Alias);
309 if (!Decls.empty())
310 OS << getQualification(CurContext.getParentASTContext(), &CurContext,
311 Decls.front(),
312 /*VisibleNamespaces=*/llvm::ArrayRef<std::string>{});
313 PrintingPolicy PP(CurContext.getParentASTContext().getPrintingPolicy());
314 PP.SuppressScope = true;
315 PP.SuppressTagKeyword = true;
316 QT.print(OS, PP);
317 return OS.str();
Sam McCall94701422019-07-11 16:04:18 +0000318}
319
Sam McCall6ec07142019-11-18 21:29:17 +0100320QualType declaredType(const TypeDecl *D) {
321 if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
322 if (const auto *TSI = CTSD->getTypeAsWritten())
323 return TSI->getType();
324 return D->getASTContext().getTypeDeclType(D);
325}
Sam McCall94701422019-07-11 16:04:18 +0000326
Sam McCall765b1252019-11-16 17:00:19 +0100327namespace {
328/// Computes the deduced type at a given location by visiting the relevant
329/// nodes. We use this to display the actual type when hovering over an "auto"
330/// keyword or "decltype()" expression.
331/// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
332/// seems that the AutoTypeLocs that can be visited along with their AutoType do
333/// not have the deduced type set. Instead, we have to go to the appropriate
334/// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
335/// a deduced type set. The AST should be improved to simplify this scenario.
336class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
337 SourceLocation SearchedLocation;
338
339public:
340 DeducedTypeVisitor(SourceLocation SearchedLocation)
341 : SearchedLocation(SearchedLocation) {}
342
343 // Handle auto initializers:
344 //- auto i = 1;
345 //- decltype(auto) i = 1;
346 //- auto& i = 1;
347 //- auto* i = &a;
348 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
349 if (!D->getTypeSourceInfo() ||
350 D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
351 return true;
352
353 if (auto *AT = D->getType()->getContainedAutoType()) {
354 if (!AT->getDeducedType().isNull())
355 DeducedType = AT->getDeducedType();
356 }
357 return true;
358 }
359
360 // Handle auto return types:
361 //- auto foo() {}
362 //- auto& foo() {}
363 //- auto foo() -> int {}
364 //- auto foo() -> decltype(1+1) {}
365 //- operator auto() const { return 10; }
366 bool VisitFunctionDecl(FunctionDecl *D) {
367 if (!D->getTypeSourceInfo())
368 return true;
369 // Loc of auto in return type (c++14).
370 auto CurLoc = D->getReturnTypeSourceRange().getBegin();
371 // Loc of "auto" in operator auto()
372 if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
373 CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
Kirill Bobyrev3b9715c2019-12-16 10:33:56 +0100374 // Loc of "auto" in function with trailing return type (c++11).
Sam McCall765b1252019-11-16 17:00:19 +0100375 if (CurLoc.isInvalid())
376 CurLoc = D->getSourceRange().getBegin();
377 if (CurLoc != SearchedLocation)
378 return true;
379
380 const AutoType *AT = D->getReturnType()->getContainedAutoType();
381 if (AT && !AT->getDeducedType().isNull()) {
382 DeducedType = AT->getDeducedType();
383 } else if (auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
384 // auto in a trailing return type just points to a DecltypeType and
385 // getContainedAutoType does not unwrap it.
386 if (!DT->getUnderlyingType().isNull())
387 DeducedType = DT->getUnderlyingType();
388 } else if (!D->getReturnType().isNull()) {
389 DeducedType = D->getReturnType();
390 }
391 return true;
392 }
393
394 // Handle non-auto decltype, e.g.:
395 // - auto foo() -> decltype(expr) {}
396 // - decltype(expr);
397 bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
398 if (TL.getBeginLoc() != SearchedLocation)
399 return true;
400
401 // A DecltypeType's underlying type can be another DecltypeType! E.g.
402 // int I = 0;
403 // decltype(I) J = I;
404 // decltype(J) K = J;
405 const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
406 while (DT && !DT->getUnderlyingType().isNull()) {
407 DeducedType = DT->getUnderlyingType();
408 DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
409 }
410 return true;
411 }
412
413 QualType DeducedType;
414};
415} // namespace
416
417llvm::Optional<QualType> getDeducedType(ASTContext &ASTCtx,
418 SourceLocation Loc) {
Kadir Cetinkayaf31fc102020-02-26 18:22:27 +0100419 if (!Loc.isValid())
Sam McCall765b1252019-11-16 17:00:19 +0100420 return {};
Sam McCall765b1252019-11-16 17:00:19 +0100421 DeducedTypeVisitor V(Loc);
422 V.TraverseAST(ASTCtx);
423 if (V.DeducedType.isNull())
424 return llvm::None;
425 return V.DeducedType;
426}
427
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100428std::string getQualification(ASTContext &Context,
429 const DeclContext *DestContext,
430 SourceLocation InsertionPoint,
431 const NamedDecl *ND) {
432 auto VisibleNamespaceDecls =
433 getUsingNamespaceDirectives(DestContext, InsertionPoint);
434 return getQualification(
435 Context, DestContext, ND->getDeclContext(),
436 [&](NestedNameSpecifier *NNS) {
437 if (NNS->getKind() != NestedNameSpecifier::Namespace)
438 return false;
439 const auto *CanonNSD = NNS->getAsNamespace()->getCanonicalDecl();
440 return llvm::any_of(VisibleNamespaceDecls,
441 [CanonNSD](const NamespaceDecl *NSD) {
442 return NSD->getCanonicalDecl() == CanonNSD;
443 });
444 });
445}
446
447std::string getQualification(ASTContext &Context,
448 const DeclContext *DestContext,
Kadir Cetinkayab2eaac32019-12-18 11:23:47 +0100449 const NamedDecl *ND,
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100450 llvm::ArrayRef<std::string> VisibleNamespaces) {
Eric Christophere8075692019-11-25 15:27:30 -0800451 for (llvm::StringRef NS : VisibleNamespaces) {
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100452 assert(NS.endswith("::"));
Eric Christophere8075692019-11-25 15:27:30 -0800453 (void)NS;
454 }
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100455 return getQualification(
456 Context, DestContext, ND->getDeclContext(),
457 [&](NestedNameSpecifier *NNS) {
458 return llvm::any_of(VisibleNamespaces, [&](llvm::StringRef Namespace) {
459 std::string NS;
460 llvm::raw_string_ostream OS(NS);
461 NNS->print(OS, Context.getPrintingPolicy());
462 return OS.str() == Namespace;
463 });
464 });
465}
466
Sam McCall26290352020-02-04 14:42:06 +0100467bool hasUnstableLinkage(const Decl *D) {
468 // Linkage of a ValueDecl depends on the type.
469 // If that's not deduced yet, deducing it may change the linkage.
470 auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D);
471 return VD && !VD->getType().isNull() && VD->getType()->isUndeducedType();
472}
473
Haojian Wu5f100262018-03-09 14:00:34 +0000474} // namespace clangd
475} // namespace clang