blob: 6aa02a7454dc1addfb10b2a9d23ddeeab798c826 [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"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010014#include "clang/AST/DeclBase.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000015#include "clang/AST/DeclTemplate.h"
Ilya Biryukov38fa1a92019-08-14 12:51:04 +000016#include "clang/AST/DeclarationName.h"
17#include "clang/AST/NestedNameSpecifier.h"
18#include "clang/AST/PrettyPrinter.h"
Sam McCall765b1252019-11-16 17:00:19 +010019#include "clang/AST/RecursiveASTVisitor.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000020#include "clang/AST/TemplateBase.h"
Eric Liu48597382018-10-18 12:23:05 +000021#include "clang/Basic/SourceLocation.h"
Haojian Wu5f100262018-03-09 14:00:34 +000022#include "clang/Basic/SourceManager.h"
Johan Vikstrom720d19b2019-08-08 07:21:06 +000023#include "clang/Basic/Specifiers.h"
Haojian Wuc6ddb462018-08-07 08:57:52 +000024#include "clang/Index/USRGeneration.h"
Sam McCall765b1252019-11-16 17:00:19 +010025#include "clang/Lex/Lexer.h"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010026#include "llvm/ADT/ArrayRef.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000027#include "llvm/ADT/Optional.h"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010028#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/StringRef.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000030#include "llvm/Support/Casting.h"
31#include "llvm/Support/ScopedPrinter.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000032#include "llvm/Support/raw_ostream.h"
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010033#include <string>
34#include <vector>
Haojian Wu5f100262018-03-09 14:00:34 +000035
36namespace clang {
37namespace clangd {
Haojian Wu5f100262018-03-09 14:00:34 +000038
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000039namespace {
40llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>>
41getTemplateSpecializationArgLocs(const NamedDecl &ND) {
42 if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) {
43 if (const ASTTemplateArgumentListInfo *Args =
44 Func->getTemplateSpecializationArgsAsWritten())
45 return Args->arguments();
46 } else if (auto *Cls =
47 llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) {
48 if (auto *Args = Cls->getTemplateArgsAsWritten())
49 return Args->arguments();
Johan Vikstromef0c3dd2019-08-09 07:35:16 +000050 } else if (auto *Var =
51 llvm::dyn_cast<VarTemplatePartialSpecializationDecl>(&ND)) {
52 if (auto *Args = Var->getTemplateArgsAsWritten())
53 return Args->arguments();
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000054 } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND))
55 return Var->getTemplateArgsInfo().arguments();
56 // We return None for ClassTemplateSpecializationDecls because it does not
57 // contain TemplateArgumentLoc information.
58 return llvm::None;
59}
Johan Vikstrom720d19b2019-08-08 07:21:06 +000060
61template <class T>
62bool isTemplateSpecializationKind(const NamedDecl *D,
63 TemplateSpecializationKind Kind) {
64 if (const auto *TD = dyn_cast<T>(D))
65 return TD->getTemplateSpecializationKind() == Kind;
66 return false;
67}
68
69bool isTemplateSpecializationKind(const NamedDecl *D,
70 TemplateSpecializationKind Kind) {
71 return isTemplateSpecializationKind<FunctionDecl>(D, Kind) ||
72 isTemplateSpecializationKind<CXXRecordDecl>(D, Kind) ||
73 isTemplateSpecializationKind<VarDecl>(D, Kind);
74}
75
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +010076// Store all UsingDirectiveDecls in parent contexts of DestContext, that were
77// introduced before InsertionPoint.
78llvm::DenseSet<const NamespaceDecl *>
79getUsingNamespaceDirectives(const DeclContext *DestContext,
80 SourceLocation Until) {
81 const auto &SM = DestContext->getParentASTContext().getSourceManager();
82 llvm::DenseSet<const NamespaceDecl *> VisibleNamespaceDecls;
83 for (const auto *DC = DestContext; DC; DC = DC->getLookupParent()) {
84 for (const auto *D : DC->decls()) {
85 if (!SM.isWrittenInSameFile(D->getLocation(), Until) ||
86 !SM.isBeforeInTranslationUnit(D->getLocation(), Until))
87 continue;
88 if (auto *UDD = llvm::dyn_cast<UsingDirectiveDecl>(D))
89 VisibleNamespaceDecls.insert(
90 UDD->getNominatedNamespace()->getCanonicalDecl());
91 }
92 }
93 return VisibleNamespaceDecls;
94}
95
96// Goes over all parents of SourceContext until we find a comman ancestor for
97// DestContext and SourceContext. Any qualifier including and above common
98// ancestor is redundant, therefore we stop at lowest common ancestor.
99// In addition to that stops early whenever IsVisible returns true. This can be
100// used to implement support for "using namespace" decls.
101std::string
102getQualification(ASTContext &Context, const DeclContext *DestContext,
103 const DeclContext *SourceContext,
104 llvm::function_ref<bool(NestedNameSpecifier *)> IsVisible) {
105 std::vector<const NestedNameSpecifier *> Parents;
106 bool ReachedNS = false;
107 for (const DeclContext *CurContext = SourceContext; CurContext;
108 CurContext = CurContext->getLookupParent()) {
109 // Stop once we reach a common ancestor.
110 if (CurContext->Encloses(DestContext))
111 break;
112
113 NestedNameSpecifier *NNS = nullptr;
114 if (auto *TD = llvm::dyn_cast<TagDecl>(CurContext)) {
115 // There can't be any more tag parents after hitting a namespace.
116 assert(!ReachedNS);
117 NNS = NestedNameSpecifier::Create(Context, nullptr, false,
118 TD->getTypeForDecl());
119 } else {
120 ReachedNS = true;
121 auto *NSD = llvm::cast<NamespaceDecl>(CurContext);
122 NNS = NestedNameSpecifier::Create(Context, nullptr, NSD);
123 // Anonymous and inline namespace names are not spelled while qualifying a
124 // name, so skip those.
125 if (NSD->isAnonymousNamespace() || NSD->isInlineNamespace())
126 continue;
127 }
128 // Stop if this namespace is already visible at DestContext.
129 if (IsVisible(NNS))
130 break;
131
132 Parents.push_back(NNS);
133 }
134
135 // Go over name-specifiers in reverse order to create necessary qualification,
136 // since we stored inner-most parent first.
137 std::string Result;
138 llvm::raw_string_ostream OS(Result);
139 for (const auto *Parent : llvm::reverse(Parents))
140 Parent->print(OS, Context.getPrintingPolicy());
141 return OS.str();
142}
143
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000144} // namespace
145
Johan Vikstrom720d19b2019-08-08 07:21:06 +0000146bool isImplicitTemplateInstantiation(const NamedDecl *D) {
147 return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation);
148}
149
150bool isExplicitTemplateSpecialization(const NamedDecl *D) {
151 return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization);
152}
153
Sam McCall95738072019-08-06 20:25:59 +0000154bool isImplementationDetail(const Decl *D) {
155 return !isSpelledInSource(D->getLocation(),
156 D->getASTContext().getSourceManager());
Eric Liu48597382018-10-18 12:23:05 +0000157}
158
Ilya Biryukovb63c35e2019-12-10 10:08:39 +0100159SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM) {
160 auto L = D.getLocation();
161 if (isSpelledInSource(L, SM))
162 return SM.getSpellingLoc(L);
163 return SM.getExpansionLoc(L);
164}
Haojian Wu5f100262018-03-09 14:00:34 +0000165
Eric Liu7ad16962018-06-22 10:46:59 +0000166std::string printQualifiedName(const NamedDecl &ND) {
167 std::string QName;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000168 llvm::raw_string_ostream OS(QName);
Eric Liu7ad16962018-06-22 10:46:59 +0000169 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
170 // Note that inline namespaces are treated as transparent scopes. This
171 // reflects the way they're most commonly used for lookup. Ideally we'd
172 // include them, but at query time it's hard to find all the inline
173 // namespaces to query: the preamble doesn't have a dedicated list.
174 Policy.SuppressUnwrittenScope = true;
175 ND.printQualifiedName(OS, Policy);
176 OS.flush();
177 assert(!StringRef(QName).startswith("::"));
178 return QName;
179}
180
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000181static bool isAnonymous(const DeclarationName &N) {
182 return N.isIdentifier() && !N.getAsIdentifierInfo();
183}
184
Haojian Wu65f61c02019-10-18 12:07:19 +0000185NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND) {
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000186 if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND))
Haojian Wu65f61c02019-10-18 12:07:19 +0000187 return V->getQualifierLoc();
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000188 if (auto *T = llvm::dyn_cast<TagDecl>(&ND))
Haojian Wu65f61c02019-10-18 12:07:19 +0000189 return T->getQualifierLoc();
190 return NestedNameSpecifierLoc();
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000191}
192
Utkarsh Saxenab62b4542019-10-16 09:53:59 +0000193std::string printUsingNamespaceName(const ASTContext &Ctx,
194 const UsingDirectiveDecl &D) {
195 PrintingPolicy PP(Ctx.getLangOpts());
196 std::string Name;
197 llvm::raw_string_ostream Out(Name);
198
199 if (auto *Qual = D.getQualifier())
200 Qual->print(Out, PP);
201 D.getNominatedNamespaceAsWritten()->printName(Out);
202 return Out.str();
203}
204
Ilya Biryukov19d75602018-11-23 15:21:19 +0000205std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
206 std::string Name;
207 llvm::raw_string_ostream Out(Name);
208 PrintingPolicy PP(Ctx.getLangOpts());
Sam McCall713c30b2019-11-15 15:08:16 +0100209 // We don't consider a class template's args part of the constructor name.
210 PP.SuppressTemplateArgsInCXXConstructors = true;
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000211
Ilya Biryukov19d75602018-11-23 15:21:19 +0000212 // Handle 'using namespace'. They all have the same name - <using-directive>.
213 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
214 Out << "using namespace ";
215 if (auto *Qual = UD->getQualifier())
216 Qual->print(Out, PP);
217 UD->getNominatedNamespaceAsWritten()->printName(Out);
218 return Out.str();
219 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000220
221 if (isAnonymous(ND.getDeclName())) {
222 // Come up with a presentation for an anonymous entity.
223 if (isa<NamespaceDecl>(ND))
224 return "(anonymous namespace)";
225 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
226 return ("(anonymous " + Cls->getKindName() + ")").str();
227 if (isa<EnumDecl>(ND))
228 return "(anonymous enum)";
229 return "(anonymous)";
Ilya Biryukov19d75602018-11-23 15:21:19 +0000230 }
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000231
232 // Print nested name qualifier if it was written in the source code.
Haojian Wu65f61c02019-10-18 12:07:19 +0000233 if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier())
Ilya Biryukov38fa1a92019-08-14 12:51:04 +0000234 Qualifier->print(Out, PP);
235 // Print the name itself.
236 ND.getDeclName().print(Out, PP);
237 // Print template arguments.
238 Out << printTemplateSpecializationArgs(ND);
239
240 return Out.str();
Ilya Biryukov19d75602018-11-23 15:21:19 +0000241}
242
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000243std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
244 std::string TemplateArgs;
245 llvm::raw_string_ostream OS(TemplateArgs);
246 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
247 if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
248 getTemplateSpecializationArgLocs(ND)) {
249 printTemplateArgumentList(OS, *Args, Policy);
250 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
251 if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
252 // ClassTemplateSpecializationDecls do not contain
253 // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
254 // create a new argument location list from TypeSourceInfo.
255 auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
256 llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
257 ArgLocs.reserve(STL.getNumArgs());
258 for (unsigned I = 0; I < STL.getNumArgs(); ++I)
259 ArgLocs.push_back(STL.getArgLoc(I));
260 printTemplateArgumentList(OS, ArgLocs, Policy);
261 } else {
262 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
263 // e.g. friend decls. Currently we fallback to Template Arguments without
264 // location information.
265 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
266 }
267 }
268 OS.flush();
269 return TemplateArgs;
270}
271
Eric Liu3fac4ef2018-10-17 11:19:02 +0000272std::string printNamespaceScope(const DeclContext &DC) {
273 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
274 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
275 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
276 return printQualifiedName(*NS) + "::";
277 return "";
278}
279
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000280llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
281 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000282 if (index::generateUSRForDecl(D, USR))
283 return None;
284 return SymbolID(USR);
285}
286
Utkarsh Saxena02ec6ff2019-11-11 12:38:17 +0100287llvm::Optional<SymbolID> getSymbolID(const llvm::StringRef MacroName,
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000288 const MacroInfo *MI,
289 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000290 if (MI == nullptr)
291 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000292 llvm::SmallString<128> USR;
Utkarsh Saxena02ec6ff2019-11-11 12:38:17 +0100293 if (index::generateUSRForMacro(MacroName, MI->getDefinitionLoc(), SM, USR))
Eric Liud25f1212018-09-06 09:59:37 +0000294 return None;
295 return SymbolID(USR);
296}
297
Sam McCall94701422019-07-11 16:04:18 +0000298std::string shortenNamespace(const llvm::StringRef OriginalName,
299 const llvm::StringRef CurrentNamespace) {
300 llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
301 llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
302 llvm::SmallVector<llvm::StringRef, 8> Result;
303 OriginalName.split(OriginalParts, "::");
304 CurrentNamespace.split(CurrentParts, "::");
305 auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
306
307 unsigned DifferentAt = 0;
308 while (DifferentAt < MinLength &&
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100309 CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
Sam McCall94701422019-07-11 16:04:18 +0000310 DifferentAt++;
311 }
312
Paul Robinson2cb5c462019-07-11 23:48:06 +0000313 for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) {
Sam McCall94701422019-07-11 16:04:18 +0000314 Result.push_back(OriginalParts[i]);
315 }
316 return join(Result, "::");
317}
318
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100319std::string printType(const QualType QT, const DeclContext &Context) {
Sam McCall94701422019-07-11 16:04:18 +0000320 PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
Haojian Wuac958c22019-07-18 15:13:45 +0000321 PP.SuppressUnwrittenScope = 1;
Sam McCall94701422019-07-11 16:04:18 +0000322 PP.SuppressTagKeyword = 1;
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100323 return shortenNamespace(QT.getAsString(PP), printNamespaceScope(Context));
Sam McCall94701422019-07-11 16:04:18 +0000324}
325
Sam McCall6ec07142019-11-18 21:29:17 +0100326QualType declaredType(const TypeDecl *D) {
327 if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
328 if (const auto *TSI = CTSD->getTypeAsWritten())
329 return TSI->getType();
330 return D->getASTContext().getTypeDeclType(D);
331}
Sam McCall94701422019-07-11 16:04:18 +0000332
Sam McCall765b1252019-11-16 17:00:19 +0100333namespace {
334/// Computes the deduced type at a given location by visiting the relevant
335/// nodes. We use this to display the actual type when hovering over an "auto"
336/// keyword or "decltype()" expression.
337/// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
338/// seems that the AutoTypeLocs that can be visited along with their AutoType do
339/// not have the deduced type set. Instead, we have to go to the appropriate
340/// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
341/// a deduced type set. The AST should be improved to simplify this scenario.
342class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
343 SourceLocation SearchedLocation;
344
345public:
346 DeducedTypeVisitor(SourceLocation SearchedLocation)
347 : SearchedLocation(SearchedLocation) {}
348
349 // Handle auto initializers:
350 //- auto i = 1;
351 //- decltype(auto) i = 1;
352 //- auto& i = 1;
353 //- auto* i = &a;
354 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
355 if (!D->getTypeSourceInfo() ||
356 D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
357 return true;
358
359 if (auto *AT = D->getType()->getContainedAutoType()) {
360 if (!AT->getDeducedType().isNull())
361 DeducedType = AT->getDeducedType();
362 }
363 return true;
364 }
365
366 // Handle auto return types:
367 //- auto foo() {}
368 //- auto& foo() {}
369 //- auto foo() -> int {}
370 //- auto foo() -> decltype(1+1) {}
371 //- operator auto() const { return 10; }
372 bool VisitFunctionDecl(FunctionDecl *D) {
373 if (!D->getTypeSourceInfo())
374 return true;
375 // Loc of auto in return type (c++14).
376 auto CurLoc = D->getReturnTypeSourceRange().getBegin();
377 // Loc of "auto" in operator auto()
378 if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
379 CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
Kirill Bobyrev3b9715c2019-12-16 10:33:56 +0100380 // Loc of "auto" in function with trailing return type (c++11).
Sam McCall765b1252019-11-16 17:00:19 +0100381 if (CurLoc.isInvalid())
382 CurLoc = D->getSourceRange().getBegin();
383 if (CurLoc != SearchedLocation)
384 return true;
385
386 const AutoType *AT = D->getReturnType()->getContainedAutoType();
387 if (AT && !AT->getDeducedType().isNull()) {
388 DeducedType = AT->getDeducedType();
389 } else if (auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
390 // auto in a trailing return type just points to a DecltypeType and
391 // getContainedAutoType does not unwrap it.
392 if (!DT->getUnderlyingType().isNull())
393 DeducedType = DT->getUnderlyingType();
394 } else if (!D->getReturnType().isNull()) {
395 DeducedType = D->getReturnType();
396 }
397 return true;
398 }
399
400 // Handle non-auto decltype, e.g.:
401 // - auto foo() -> decltype(expr) {}
402 // - decltype(expr);
403 bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
404 if (TL.getBeginLoc() != SearchedLocation)
405 return true;
406
407 // A DecltypeType's underlying type can be another DecltypeType! E.g.
408 // int I = 0;
409 // decltype(I) J = I;
410 // decltype(J) K = J;
411 const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
412 while (DT && !DT->getUnderlyingType().isNull()) {
413 DeducedType = DT->getUnderlyingType();
414 DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
415 }
416 return true;
417 }
418
419 QualType DeducedType;
420};
421} // namespace
422
423llvm::Optional<QualType> getDeducedType(ASTContext &ASTCtx,
424 SourceLocation Loc) {
425 Token Tok;
426 // Only try to find a deduced type if the token is auto or decltype.
427 if (!Loc.isValid() ||
428 Lexer::getRawToken(Loc, Tok, ASTCtx.getSourceManager(),
429 ASTCtx.getLangOpts(), false) ||
430 !Tok.is(tok::raw_identifier) ||
431 !(Tok.getRawIdentifier() == "auto" ||
432 Tok.getRawIdentifier() == "decltype")) {
433 return {};
434 }
435 DeducedTypeVisitor V(Loc);
436 V.TraverseAST(ASTCtx);
437 if (V.DeducedType.isNull())
438 return llvm::None;
439 return V.DeducedType;
440}
441
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100442std::string getQualification(ASTContext &Context,
443 const DeclContext *DestContext,
444 SourceLocation InsertionPoint,
445 const NamedDecl *ND) {
446 auto VisibleNamespaceDecls =
447 getUsingNamespaceDirectives(DestContext, InsertionPoint);
448 return getQualification(
449 Context, DestContext, ND->getDeclContext(),
450 [&](NestedNameSpecifier *NNS) {
451 if (NNS->getKind() != NestedNameSpecifier::Namespace)
452 return false;
453 const auto *CanonNSD = NNS->getAsNamespace()->getCanonicalDecl();
454 return llvm::any_of(VisibleNamespaceDecls,
455 [CanonNSD](const NamespaceDecl *NSD) {
456 return NSD->getCanonicalDecl() == CanonNSD;
457 });
458 });
459}
460
461std::string getQualification(ASTContext &Context,
462 const DeclContext *DestContext,
463 SourceLocation InsertionPoint, const NamedDecl *ND,
464 llvm::ArrayRef<std::string> VisibleNamespaces) {
Eric Christophere8075692019-11-25 15:27:30 -0800465 for (llvm::StringRef NS : VisibleNamespaces) {
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100466 assert(NS.endswith("::"));
Eric Christophere8075692019-11-25 15:27:30 -0800467 (void)NS;
468 }
Kadir Cetinkaya97d6e8e2019-10-30 09:04:10 +0100469 return getQualification(
470 Context, DestContext, ND->getDeclContext(),
471 [&](NestedNameSpecifier *NNS) {
472 return llvm::any_of(VisibleNamespaces, [&](llvm::StringRef Namespace) {
473 std::string NS;
474 llvm::raw_string_ostream OS(NS);
475 NNS->print(OS, Context.getPrintingPolicy());
476 return OS.str() == Namespace;
477 });
478 });
479}
480
Haojian Wu5f100262018-03-09 14:00:34 +0000481} // namespace clangd
482} // namespace clang