clang-tools 22.0.0git
AST.cpp
Go to the documentation of this file.
1//===--- AST.cpp - Utility AST functions -----------------------*- C++ -*-===//
2//
3// 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
6//
7//===----------------------------------------------------------------------===//
8
9#include "AST.h"
10
11#include "SourceCode.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/AST/ASTTypeTraits.h"
14#include "clang/AST/Decl.h"
15#include "clang/AST/DeclBase.h"
16#include "clang/AST/DeclCXX.h"
17#include "clang/AST/DeclObjC.h"
18#include "clang/AST/DeclTemplate.h"
19#include "clang/AST/DeclarationName.h"
20#include "clang/AST/ExprCXX.h"
21#include "clang/AST/NestedNameSpecifier.h"
22#include "clang/AST/PrettyPrinter.h"
23#include "clang/AST/RecursiveASTVisitor.h"
24#include "clang/AST/Stmt.h"
25#include "clang/AST/TemplateBase.h"
26#include "clang/AST/TypeLoc.h"
27#include "clang/Basic/Builtins.h"
28#include "clang/Basic/SourceLocation.h"
29#include "clang/Basic/SourceManager.h"
30#include "clang/Basic/Specifiers.h"
31#include "clang/Index/USRGeneration.h"
32#include "clang/Sema/HeuristicResolver.h"
33#include "llvm/ADT/ArrayRef.h"
34#include "llvm/ADT/STLExtras.h"
35#include "llvm/ADT/SmallSet.h"
36#include "llvm/ADT/StringRef.h"
37#include "llvm/Support/Casting.h"
38#include "llvm/Support/raw_ostream.h"
39#include <iterator>
40#include <optional>
41#include <string>
42#include <vector>
43
44namespace clang {
45namespace clangd {
46
47namespace {
48std::optional<llvm::ArrayRef<TemplateArgumentLoc>>
49getTemplateSpecializationArgLocs(const NamedDecl &ND) {
50 if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) {
51 if (const ASTTemplateArgumentListInfo *Args =
52 Func->getTemplateSpecializationArgsAsWritten())
53 return Args->arguments();
54 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
55 if (auto *Args = Cls->getTemplateArgsAsWritten())
56 return Args->arguments();
57 } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND)) {
58 if (auto *Args = Var->getTemplateArgsAsWritten())
59 return Args->arguments();
60 }
61 // We return std::nullopt for ClassTemplateSpecializationDecls because it does
62 // not contain TemplateArgumentLoc information.
63 return std::nullopt;
64}
65
66template <class T>
67bool isTemplateSpecializationKind(const NamedDecl *D,
68 TemplateSpecializationKind Kind) {
69 if (const auto *TD = dyn_cast<T>(D))
70 return TD->getTemplateSpecializationKind() == Kind;
71 return false;
72}
73
74bool isTemplateSpecializationKind(const NamedDecl *D,
75 TemplateSpecializationKind Kind) {
76 return isTemplateSpecializationKind<FunctionDecl>(D, Kind) ||
77 isTemplateSpecializationKind<CXXRecordDecl>(D, Kind) ||
78 isTemplateSpecializationKind<VarDecl>(D, Kind);
79}
80
81// Store all UsingDirectiveDecls in parent contexts of DestContext, that were
82// introduced before InsertionPoint.
83llvm::DenseSet<const NamespaceDecl *>
84getUsingNamespaceDirectives(const DeclContext *DestContext,
85 SourceLocation Until) {
86 const auto &SM = DestContext->getParentASTContext().getSourceManager();
87 llvm::DenseSet<const NamespaceDecl *> VisibleNamespaceDecls;
88 for (const auto *DC = DestContext; DC; DC = DC->getLookupParent()) {
89 for (const auto *D : DC->decls()) {
90 if (!SM.isWrittenInSameFile(D->getLocation(), Until) ||
91 !SM.isBeforeInTranslationUnit(D->getLocation(), Until))
92 continue;
93 if (auto *UDD = llvm::dyn_cast<UsingDirectiveDecl>(D))
94 VisibleNamespaceDecls.insert(
95 UDD->getNominatedNamespace()->getCanonicalDecl());
96 }
97 }
98 return VisibleNamespaceDecls;
99}
100
101// Goes over all parents of SourceContext until we find a common ancestor for
102// DestContext and SourceContext. Any qualifier including and above common
103// ancestor is redundant, therefore we stop at lowest common ancestor.
104// In addition to that stops early whenever IsVisible returns true. This can be
105// used to implement support for "using namespace" decls.
106std::string getQualification(ASTContext &Context,
107 const DeclContext *DestContext,
108 const DeclContext *SourceContext,
109 llvm::function_ref<bool(const Decl *)> IsVisible) {
110 std::vector<const Decl *> Parents;
111 [[maybe_unused]] bool ReachedNS = false;
112 for (const DeclContext *CurContext = SourceContext; CurContext;
113 CurContext = CurContext->getLookupParent()) {
114 // Stop once we reach a common ancestor.
115 if (CurContext->Encloses(DestContext))
116 break;
117
118 const Decl *CurD;
119 if (auto *TD = llvm::dyn_cast<TagDecl>(CurContext)) {
120 // There can't be any more tag parents after hitting a namespace.
121 assert(!ReachedNS);
122 CurD = TD;
123 } else if (auto *NSD = llvm::dyn_cast<NamespaceDecl>(CurContext)) {
124 ReachedNS = true;
125 // Anonymous and inline namespace names are not spelled while qualifying
126 // a name, so skip those.
127 if (NSD->isAnonymousNamespace() || NSD->isInlineNamespace())
128 continue;
129 CurD = NSD;
130 } else {
131 // Other types of contexts cannot be spelled in code, just skip over
132 // them.
133 continue;
134 }
135 // Stop if this namespace is already visible at DestContext.
136 if (IsVisible(CurD))
137 break;
138
139 Parents.push_back(CurD);
140 }
141
142 // Go over the declarations in reverse order, since we stored inner-most
143 // parent first.
144 NestedNameSpecifier Qualifier = std::nullopt;
145 bool IsFirst = true;
146 for (const auto *CurD : llvm::reverse(Parents)) {
147 if (auto *TD = llvm::dyn_cast<TagDecl>(CurD)) {
148 QualType T;
149 if (const auto *RD = dyn_cast<CXXRecordDecl>(TD);
150 ClassTemplateDecl *CTD =
151 RD ? RD->getDescribedClassTemplate() : nullptr) {
152 ArrayRef<TemplateArgument> Args;
153 if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
154 Args = SD->getTemplateArgs().asArray();
155 else
156 Args = CTD->getTemplateParameters()->getInjectedTemplateArgs(Context);
157 T = Context.getTemplateSpecializationType(
158 ElaboratedTypeKeyword::None,
159 Context.getQualifiedTemplateName(
160 Qualifier, /*TemplateKeyword=*/!IsFirst, TemplateName(CTD)),
161 Args, /*CanonicalArgs=*/{}, Context.getCanonicalTagType(RD));
162 } else {
163 T = Context.getTagType(ElaboratedTypeKeyword::None, Qualifier, TD,
164 /*OwnsTag=*/false);
165 }
166 Qualifier = NestedNameSpecifier(T.getTypePtr());
167 } else {
168 Qualifier =
169 NestedNameSpecifier(Context, cast<NamespaceDecl>(CurD), Qualifier);
170 }
171 IsFirst = false;
172 }
173 if (!Qualifier)
174 return "";
175
176 std::string Result;
177 llvm::raw_string_ostream OS(Result);
178 Qualifier.print(OS, Context.getPrintingPolicy());
179 return OS.str();
180}
181
182} // namespace
183
184bool isImplicitTemplateInstantiation(const NamedDecl *D) {
185 return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation);
186}
187
188bool isExplicitTemplateSpecialization(const NamedDecl *D) {
189 return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization);
190}
191
192bool isImplementationDetail(const Decl *D) {
193 return !isSpelledInSource(D->getLocation(),
194 D->getASTContext().getSourceManager());
195}
196
197SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM) {
198 auto L = D.getLocation();
199 // For `- (void)foo` we want `foo` not the `-`.
200 if (const auto *MD = dyn_cast<ObjCMethodDecl>(&D))
201 L = MD->getSelectorStartLoc();
202 if (isSpelledInSource(L, SM))
203 return SM.getSpellingLoc(L);
204 return SM.getExpansionLoc(L);
205}
206
207std::string printQualifiedName(const NamedDecl &ND) {
208 std::string QName;
209 llvm::raw_string_ostream OS(QName);
210 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
211 // Note that inline namespaces are treated as transparent scopes. This
212 // reflects the way they're most commonly used for lookup. Ideally we'd
213 // include them, but at query time it's hard to find all the inline
214 // namespaces to query: the preamble doesn't have a dedicated list.
215 Policy.SuppressUnwrittenScope = true;
216 Policy.SuppressScope = true;
217 // (unnamed struct), not (unnamed struct at /path/to/foo.cc:42:1).
218 // In clangd, context is usually available and paths are mostly noise.
219 Policy.AnonymousTagLocations = false;
220 ND.printQualifiedName(OS, Policy);
221 assert(!StringRef(QName).starts_with("::"));
222 return QName;
223}
224
225static bool isAnonymous(const DeclarationName &N) {
226 return N.isIdentifier() && !N.getAsIdentifierInfo();
227}
228
229NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND) {
230 if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND))
231 return V->getQualifierLoc();
232 if (auto *T = llvm::dyn_cast<TagDecl>(&ND))
233 return T->getQualifierLoc();
234 return NestedNameSpecifierLoc();
235}
236
237std::string printUsingNamespaceName(const ASTContext &Ctx,
238 const UsingDirectiveDecl &D) {
239 PrintingPolicy PP(Ctx.getLangOpts());
240 std::string Name;
241 llvm::raw_string_ostream Out(Name);
242
243 D.getQualifier().print(Out, PP);
244 D.getNominatedNamespaceAsWritten()->printName(Out);
245 return Out.str();
246}
247
248std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
249 std::string Name;
250 llvm::raw_string_ostream Out(Name);
251 PrintingPolicy PP(Ctx.getLangOpts());
252 // We don't consider a class template's args part of the constructor name.
253 PP.SuppressTemplateArgsInCXXConstructors = true;
254
255 // Handle 'using namespace'. They all have the same name - <using-directive>.
256 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
257 Out << "using namespace ";
258 UD->getQualifier().print(Out, PP);
259 UD->getNominatedNamespaceAsWritten()->printName(Out);
260 return Out.str();
261 }
262
263 if (isAnonymous(ND.getDeclName())) {
264 // Come up with a presentation for an anonymous entity.
265 if (isa<NamespaceDecl>(ND))
266 return "(anonymous namespace)";
267 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND)) {
268 if (Cls->isLambda())
269 return "(lambda)";
270 return ("(anonymous " + Cls->getKindName() + ")").str();
271 }
272 if (isa<EnumDecl>(ND))
273 return "(anonymous enum)";
274 return "(anonymous)";
275 }
276
277 // Print nested name qualifier if it was written in the source code.
278 getQualifierLoc(ND).getNestedNameSpecifier().print(Out, PP);
279 // Print the name itself.
280 ND.getDeclName().print(Out, PP);
281 // Print template arguments.
283
284 return Out.str();
285}
286
287std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
288 std::string TemplateArgs;
289 llvm::raw_string_ostream OS(TemplateArgs);
290 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
291 if (std::optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
292 getTemplateSpecializationArgLocs(ND)) {
293 printTemplateArgumentList(OS, *Args, Policy);
294 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
295 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
296 // e.g. friend decls. Currently we fallback to Template Arguments without
297 // location information.
298 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
299 }
300 return TemplateArgs;
301}
302
303std::string printNamespaceScope(const DeclContext &DC) {
304 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
305 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
306 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
307 return printQualifiedName(*NS) + "::";
308 return "";
309}
310
311static llvm::StringRef
312getNameOrErrForObjCInterface(const ObjCInterfaceDecl *ID) {
313 return ID ? ID->getName() : "<<error-type>>";
314}
315
316std::string printObjCMethod(const ObjCMethodDecl &Method) {
317 std::string Name;
318 llvm::raw_string_ostream OS(Name);
319
320 OS << (Method.isInstanceMethod() ? '-' : '+') << '[';
321
322 // Should always be true.
323 if (const ObjCContainerDecl *C =
324 dyn_cast<ObjCContainerDecl>(Method.getDeclContext()))
325 OS << printObjCContainer(*C);
326
327 Method.getSelector().print(OS << ' ');
328 if (Method.isVariadic())
329 OS << ", ...";
330
331 OS << ']';
332 return Name;
333}
334
335std::string printObjCContainer(const ObjCContainerDecl &C) {
336 if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(&C)) {
337 std::string Name;
338 llvm::raw_string_ostream OS(Name);
339 const ObjCInterfaceDecl *Class = Category->getClassInterface();
340 OS << getNameOrErrForObjCInterface(Class) << '(' << Category->getName()
341 << ')';
342 return Name;
343 }
344 if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(&C)) {
345 std::string Name;
346 llvm::raw_string_ostream OS(Name);
347 const ObjCInterfaceDecl *Class = CID->getClassInterface();
348 OS << getNameOrErrForObjCInterface(Class) << '(' << CID->getName() << ')';
349 return Name;
350 }
351 return C.getNameAsString();
352}
353
354SymbolID getSymbolID(const Decl *D) {
355 llvm::SmallString<128> USR;
356 if (index::generateUSRForDecl(D, USR))
357 return {};
358 return SymbolID(USR);
359}
360
361SymbolID getSymbolID(const llvm::StringRef MacroName, const MacroInfo *MI,
362 const SourceManager &SM) {
363 if (MI == nullptr)
364 return {};
365 llvm::SmallString<128> USR;
366 if (index::generateUSRForMacro(MacroName, MI->getDefinitionLoc(), SM, USR))
367 return {};
368 return SymbolID(USR);
369}
370
371const ObjCImplDecl *getCorrespondingObjCImpl(const ObjCContainerDecl *D) {
372 if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
373 return ID->getImplementation();
374 if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D)) {
375 if (CD->IsClassExtension()) {
376 if (const auto *ID = CD->getClassInterface())
377 return ID->getImplementation();
378 return nullptr;
379 }
380 return CD->getImplementation();
381 }
382 return nullptr;
383}
384
386preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts,
387 ArrayRef<Inclusion> MainFileIncludes,
388 ArrayRef<const Decl *> TopLevelDecls) {
389 // Always prefer #include for non-ObjC code.
390 if (!LangOpts.ObjC)
392 // If this is not a header file and has ObjC set as the language, prefer
393 // #import.
394 if (!isHeaderFile(FileName, LangOpts))
396
397 // Headers lack proper compile flags most of the time, so we might treat a
398 // header as ObjC accidentally. Perform some extra checks to make sure this
399 // works.
400
401 // Any file with a #import, should keep #import-ing.
402 for (auto &Inc : MainFileIncludes)
403 if (Inc.Directive == tok::pp_import)
405
406 // Any file declaring an ObjC decl should also be #import-ing.
407 // No need to look over the references, as the file doesn't have any #imports,
408 // it must be declaring interesting ObjC-like decls.
409 for (const Decl *D : TopLevelDecls)
410 if (isa<ObjCContainerDecl, ObjCIvarDecl, ObjCMethodDecl, ObjCPropertyDecl>(
411 D))
413
415}
416
417std::string printType(const QualType QT, const DeclContext &CurContext,
418 const llvm::StringRef Placeholder, bool FullyQualify) {
419 std::string Result;
420 llvm::raw_string_ostream OS(Result);
421 PrintingPolicy PP(CurContext.getParentASTContext().getPrintingPolicy());
422 PP.SuppressTagKeyword = true;
423 PP.SuppressUnwrittenScope = true;
424 PP.FullyQualifiedName = FullyQualify;
425
426 class PrintCB : public PrintingCallbacks {
427 public:
428 PrintCB(const DeclContext *CurContext) : CurContext(CurContext) {}
429 virtual ~PrintCB() {}
430 bool isScopeVisible(const DeclContext *DC) const override {
431 return DC->Encloses(CurContext);
432 }
433
434 private:
435 const DeclContext *CurContext;
436 };
437 PrintCB PCB(&CurContext);
438 PP.Callbacks = &PCB;
439
440 QT.print(OS, PP, Placeholder);
441 return OS.str();
442}
443
444bool hasReservedName(const Decl &D) {
445 if (const auto *ND = llvm::dyn_cast<NamedDecl>(&D))
446 if (const auto *II = ND->getIdentifier())
447 return isReservedName(II->getName());
448 return false;
449}
450
451bool hasReservedScope(const DeclContext &DC) {
452 for (const DeclContext *D = &DC; D; D = D->getParent()) {
453 if (D->isTransparentContext() || D->isInlineNamespace())
454 continue;
455 if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
456 if (hasReservedName(*ND))
457 return true;
458 }
459 return false;
460}
461
462QualType declaredType(const TypeDecl *D) {
463 ASTContext &Context = D->getASTContext();
464 if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
465 if (const auto *Args = CTSD->getTemplateArgsAsWritten())
466 return Context.getTemplateSpecializationType(
467 ElaboratedTypeKeyword::None,
468 TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(),
469 /*CanonicalArgs=*/{});
470 return Context.getTypeDeclType(D);
471}
472
473namespace {
474/// Computes the deduced type at a given location by visiting the relevant
475/// nodes. We use this to display the actual type when hovering over an "auto"
476/// keyword or "decltype()" expression.
477/// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
478/// seems that the AutoTypeLocs that can be visited along with their AutoType do
479/// not have the deduced type set. Instead, we have to go to the appropriate
480/// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
481/// a deduced type set. The AST should be improved to simplify this scenario.
482class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
483 SourceLocation SearchedLocation;
484 const HeuristicResolver *Resolver;
485
486public:
487 DeducedTypeVisitor(SourceLocation SearchedLocation,
488 const HeuristicResolver *Resolver)
489 : SearchedLocation(SearchedLocation), Resolver(Resolver) {}
490
491 // Handle auto initializers:
492 //- auto i = 1;
493 //- decltype(auto) i = 1;
494 //- auto& i = 1;
495 //- auto* i = &a;
496 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
497 if (!D->getTypeSourceInfo() ||
498 !D->getTypeSourceInfo()->getTypeLoc().getContainedAutoTypeLoc() ||
499 D->getTypeSourceInfo()
500 ->getTypeLoc()
501 .getContainedAutoTypeLoc()
502 .getNameLoc() != SearchedLocation)
503 return true;
504
505 if (auto *AT = D->getType()->getContainedAutoType()) {
506 if (AT->isUndeducedAutoType()) {
507 if (const auto *VD = dyn_cast<VarDecl>(D)) {
508 if (Resolver && VD->hasInit()) {
509 DeducedType = Resolver->resolveExprToType(VD->getInit());
510 return true;
511 }
512 }
513 }
514 DeducedType = AT->desugar();
515 }
516 return true;
517 }
518
519 // Handle auto return types:
520 //- auto foo() {}
521 //- auto& foo() {}
522 //- auto foo() -> int {}
523 //- auto foo() -> decltype(1+1) {}
524 //- operator auto() const { return 10; }
525 bool VisitFunctionDecl(FunctionDecl *D) {
526 if (!D->getTypeSourceInfo())
527 return true;
528 // Loc of auto in return type (c++14).
529 auto CurLoc = D->getReturnTypeSourceRange().getBegin();
530 // Loc of "auto" in operator auto()
531 if (CurLoc.isInvalid() && isa<CXXConversionDecl>(D))
532 CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
533 // Loc of "auto" in function with trailing return type (c++11).
534 if (CurLoc.isInvalid())
535 CurLoc = D->getSourceRange().getBegin();
536 if (CurLoc != SearchedLocation)
537 return true;
538
539 const AutoType *AT = D->getReturnType()->getContainedAutoType();
540 if (AT && !AT->getDeducedType().isNull()) {
541 DeducedType = AT->getDeducedType();
542 } else if (auto *DT = dyn_cast<DecltypeType>(D->getReturnType())) {
543 // auto in a trailing return type just points to a DecltypeType and
544 // getContainedAutoType does not unwrap it.
545 if (!DT->getUnderlyingType().isNull())
546 DeducedType = DT->getUnderlyingType();
547 } else if (!D->getReturnType().isNull()) {
548 DeducedType = D->getReturnType();
549 }
550 return true;
551 }
552
553 // Handle non-auto decltype, e.g.:
554 // - auto foo() -> decltype(expr) {}
555 // - decltype(expr);
556 bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
557 if (TL.getBeginLoc() != SearchedLocation)
558 return true;
559
560 // A DecltypeType's underlying type can be another DecltypeType! E.g.
561 // int I = 0;
562 // decltype(I) J = I;
563 // decltype(J) K = J;
564 const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
565 while (DT && !DT->getUnderlyingType().isNull()) {
566 DeducedType = DT->getUnderlyingType();
567 DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
568 }
569 return true;
570 }
571
572 // Handle functions/lambdas with `auto` typed parameters.
573 // We deduce the type if there's exactly one instantiation visible.
574 bool VisitParmVarDecl(ParmVarDecl *PVD) {
575 if (!PVD->getType()->isDependentType())
576 return true;
577 // 'auto' here does not name an AutoType, but an implicit template param.
578 TemplateTypeParmTypeLoc Auto =
579 getContainedAutoParamType(PVD->getTypeSourceInfo()->getTypeLoc());
580 if (Auto.isNull() || Auto.getNameLoc() != SearchedLocation)
581 return true;
582
583 // We expect the TTP to be attached to this function template.
584 // Find the template and the param index.
585 auto *Templated = llvm::dyn_cast<FunctionDecl>(PVD->getDeclContext());
586 if (!Templated)
587 return true;
588 auto *FTD = Templated->getDescribedFunctionTemplate();
589 if (!FTD)
590 return true;
591 int ParamIndex = paramIndex(*FTD, *Auto.getDecl());
592 if (ParamIndex < 0) {
593 assert(false && "auto TTP is not from enclosing function?");
594 return true;
595 }
596
597 // Now find the instantiation and the deduced template type arg.
598 auto *Instantiation =
599 llvm::dyn_cast_or_null<FunctionDecl>(getOnlyInstantiation(Templated));
600 if (!Instantiation)
601 return true;
602 const auto *Args = Instantiation->getTemplateSpecializationArgs();
603 if (Args->size() != FTD->getTemplateParameters()->size())
604 return true; // no weird variadic stuff
605 DeducedType = Args->get(ParamIndex).getAsType();
606 return true;
607 }
608
609 static int paramIndex(const TemplateDecl &TD, NamedDecl &Param) {
610 unsigned I = 0;
611 for (auto *ND : *TD.getTemplateParameters()) {
612 if (&Param == ND)
613 return I;
614 ++I;
615 }
616 return -1;
617 }
618
619 QualType DeducedType;
620};
621} // namespace
622
623std::optional<QualType> getDeducedType(ASTContext &ASTCtx,
624 const HeuristicResolver *Resolver,
625 SourceLocation Loc) {
626 if (!Loc.isValid())
627 return {};
628 DeducedTypeVisitor V(Loc, Resolver);
629 V.TraverseAST(ASTCtx);
630 if (V.DeducedType.isNull())
631 return std::nullopt;
632 return V.DeducedType;
633}
634
635TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL) {
636 if (auto QTL = TL.getAs<QualifiedTypeLoc>())
637 return getContainedAutoParamType(QTL.getUnqualifiedLoc());
638 if (llvm::isa<PointerType, ReferenceType, ParenType>(TL.getTypePtr()))
639 return getContainedAutoParamType(TL.getNextTypeLoc());
640 if (auto FTL = TL.getAs<FunctionTypeLoc>())
641 return getContainedAutoParamType(FTL.getReturnLoc());
642 if (auto TTPTL = TL.getAs<TemplateTypeParmTypeLoc>()) {
643 if (TTPTL.getTypePtr()->getDecl()->isImplicit())
644 return TTPTL;
645 }
646 return {};
647}
648
649template <typename TemplateDeclTy>
650static NamedDecl *getOnlyInstantiationImpl(TemplateDeclTy *TD) {
651 NamedDecl *Only = nullptr;
652 for (auto *Spec : TD->specializations()) {
653 if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
654 continue;
655 if (Only != nullptr)
656 return nullptr;
657 Only = Spec;
658 }
659 return Only;
660}
661
662NamedDecl *getOnlyInstantiation(NamedDecl *TemplatedDecl) {
663 if (TemplateDecl *TD = TemplatedDecl->getDescribedTemplate()) {
664 if (auto *CTD = llvm::dyn_cast<ClassTemplateDecl>(TD))
665 return getOnlyInstantiationImpl(CTD);
666 if (auto *FTD = llvm::dyn_cast<FunctionTemplateDecl>(TD))
667 return getOnlyInstantiationImpl(FTD);
668 if (auto *VTD = llvm::dyn_cast<VarTemplateDecl>(TD))
669 return getOnlyInstantiationImpl(VTD);
670 }
671 return nullptr;
672}
673
674std::vector<const Attr *> getAttributes(const DynTypedNode &N) {
675 std::vector<const Attr *> Result;
676 if (const auto *TL = N.get<TypeLoc>()) {
677 for (AttributedTypeLoc ATL = TL->getAs<AttributedTypeLoc>(); !ATL.isNull();
678 ATL = ATL.getModifiedLoc().getAs<AttributedTypeLoc>()) {
679 if (const Attr *A = ATL.getAttr())
680 Result.push_back(A);
681 assert(!ATL.getModifiedLoc().isNull());
682 }
683 }
684 if (const auto *S = N.get<AttributedStmt>()) {
685 for (; S != nullptr; S = dyn_cast<AttributedStmt>(S->getSubStmt()))
686 for (const Attr *A : S->getAttrs())
687 if (A)
688 Result.push_back(A);
689 }
690 if (const auto *D = N.get<Decl>()) {
691 for (const Attr *A : D->attrs())
692 if (A)
693 Result.push_back(A);
694 }
695 return Result;
696}
697
698std::string getQualification(ASTContext &Context,
699 const DeclContext *DestContext,
700 SourceLocation InsertionPoint,
701 const NamedDecl *ND) {
702 auto VisibleNamespaceDecls =
703 getUsingNamespaceDirectives(DestContext, InsertionPoint);
704 return getQualification(
705 Context, DestContext, ND->getDeclContext(), [&](const Decl *D) {
706 if (D->getKind() != Decl::Namespace)
707 return false;
708 const auto *NS = cast<NamespaceDecl>(D)->getCanonicalDecl();
709 return llvm::any_of(VisibleNamespaceDecls,
710 [NS](const NamespaceDecl *NSD) {
711 return NSD->getCanonicalDecl() == NS;
712 });
713 });
714}
715
716std::string getQualification(ASTContext &Context,
717 const DeclContext *DestContext,
718 const NamedDecl *ND,
719 llvm::ArrayRef<std::string> VisibleNamespaces) {
720 for (llvm::StringRef NS : VisibleNamespaces) {
721 assert(NS.ends_with("::"));
722 (void)NS;
723 }
724 return getQualification(
725 Context, DestContext, ND->getDeclContext(), [&](const Decl *D) {
726 return llvm::any_of(VisibleNamespaces, [&](llvm::StringRef Namespace) {
727 std::string NS;
728 llvm::raw_string_ostream OS(NS);
729 D->print(OS, Context.getPrintingPolicy());
730 return OS.str() == Namespace;
731 });
732 });
733}
734
735bool hasUnstableLinkage(const Decl *D) {
736 // Linkage of a ValueDecl depends on the type.
737 // If that's not deduced yet, deducing it may change the linkage.
738 auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D);
739 return VD && !VD->getType().isNull() && VD->getType()->isUndeducedType();
740}
741
742bool isDeeplyNested(const Decl *D, unsigned MaxDepth) {
743 size_t ContextDepth = 0;
744 for (auto *Ctx = D->getDeclContext(); Ctx && !Ctx->isTranslationUnit();
745 Ctx = Ctx->getParent()) {
746 if (++ContextDepth == MaxDepth)
747 return true;
748 }
749 return false;
750}
751
752namespace {
753
754// returns true for `X` in `template <typename... X> void foo()`
755bool isTemplateTypeParameterPack(NamedDecl *D) {
756 if (const auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D)) {
757 return TTPD->isParameterPack();
758 }
759 return false;
760}
761
762// Returns the template parameter pack type from an instantiated function
763// template, if it exists, nullptr otherwise.
764const TemplateTypeParmType *getFunctionPackType(const FunctionDecl *Callee) {
765 if (const auto *TemplateDecl = Callee->getPrimaryTemplate()) {
766 auto TemplateParams = TemplateDecl->getTemplateParameters()->asArray();
767 // find the template parameter pack from the back
768 const auto It = std::find_if(TemplateParams.rbegin(), TemplateParams.rend(),
769 isTemplateTypeParameterPack);
770 if (It != TemplateParams.rend()) {
771 const auto *TTPD = dyn_cast<TemplateTypeParmDecl>(*It);
772 return TTPD->getTypeForDecl()->castAs<TemplateTypeParmType>();
773 }
774 }
775 return nullptr;
776}
777
778// Returns the template parameter pack type that this parameter was expanded
779// from (if in the Args... or Args&... or Args&&... form), if this is the case,
780// nullptr otherwise.
781const TemplateTypeParmType *getUnderlyingPackType(const ParmVarDecl *Param) {
782 const auto *PlainType = Param->getType().getTypePtr();
783 if (auto *RT = dyn_cast<ReferenceType>(PlainType))
784 PlainType = RT->getPointeeTypeAsWritten().getTypePtr();
785 if (const auto *SubstType = dyn_cast<SubstTemplateTypeParmType>(PlainType)) {
786 const auto *ReplacedParameter = SubstType->getReplacedParameter();
787 if (ReplacedParameter->isParameterPack()) {
788 return ReplacedParameter->getTypeForDecl()
789 ->castAs<TemplateTypeParmType>();
790 }
791 }
792 return nullptr;
793}
794
795// This visitor walks over the body of an instantiated function template.
796// The template accepts a parameter pack and the visitor records whether
797// the pack parameters were forwarded to another call. For example, given:
798//
799// template <typename T, typename... Args>
800// auto make_unique(Args... args) {
801// return unique_ptr<T>(new T(args...));
802// }
803//
804// When called as `make_unique<std::string>(2, 'x')` this yields a function
805// `make_unique<std::string, int, char>` with two parameters.
806// The visitor records that those two parameters are forwarded to the
807// `constructor std::string(int, char);`.
808//
809// This information is recorded in the `ForwardingInfo` split into fully
810// resolved parameters (passed as argument to a parameter that is not an
811// expanded template type parameter pack) and forwarding parameters (passed to a
812// parameter that is an expanded template type parameter pack).
813class ForwardingCallVisitor
814 : public RecursiveASTVisitor<ForwardingCallVisitor> {
815public:
816 ForwardingCallVisitor(ArrayRef<const ParmVarDecl *> Parameters)
817 : Parameters{Parameters},
818 PackType{getUnderlyingPackType(Parameters.front())} {}
819
820 bool VisitCallExpr(CallExpr *E) {
821 auto *Callee = getCalleeDeclOrUniqueOverload(E);
822 if (Callee) {
823 handleCall(Callee, E->arguments());
824 }
825 return !Info.has_value();
826 }
827
828 bool VisitCXXConstructExpr(CXXConstructExpr *E) {
829 auto *Callee = E->getConstructor();
830 if (Callee) {
831 handleCall(Callee, E->arguments());
832 }
833 return !Info.has_value();
834 }
835
836 // The expanded parameter pack to be resolved
837 ArrayRef<const ParmVarDecl *> Parameters;
838 // The type of the parameter pack
839 const TemplateTypeParmType *PackType;
840
841 struct ForwardingInfo {
842 // If the parameters were resolved to another FunctionDecl, these are its
843 // first non-variadic parameters (i.e. the first entries of the parameter
844 // pack that are passed as arguments bound to a non-pack parameter.)
845 ArrayRef<const ParmVarDecl *> Head;
846 // If the parameters were resolved to another FunctionDecl, these are its
847 // variadic parameters (i.e. the entries of the parameter pack that are
848 // passed as arguments bound to a pack parameter.)
849 ArrayRef<const ParmVarDecl *> Pack;
850 // If the parameters were resolved to another FunctionDecl, these are its
851 // last non-variadic parameters (i.e. the last entries of the parameter pack
852 // that are passed as arguments bound to a non-pack parameter.)
853 ArrayRef<const ParmVarDecl *> Tail;
854 // If the parameters were resolved to another forwarding FunctionDecl, this
855 // is it.
856 std::optional<FunctionDecl *> PackTarget;
857 };
858
859 // The output of this visitor
860 std::optional<ForwardingInfo> Info;
861
862private:
863 // inspects the given callee with the given args to check whether it
864 // contains Parameters, and sets Info accordingly.
865 void handleCall(FunctionDecl *Callee, typename CallExpr::arg_range Args) {
866 // Skip functions with less parameters, they can't be the target.
867 if (Callee->parameters().size() < Parameters.size())
868 return;
869 if (llvm::any_of(Args,
870 [](const Expr *E) { return isa<PackExpansionExpr>(E); })) {
871 return;
872 }
873 auto PackLocation = findPack(Args);
874 if (!PackLocation)
875 return;
876 ArrayRef<ParmVarDecl *> MatchingParams =
877 Callee->parameters().slice(*PackLocation, Parameters.size());
878 // Check whether the function has a parameter pack as the last template
879 // parameter
880 if (const auto *TTPT = getFunctionPackType(Callee)) {
881 // In this case: Separate the parameters into head, pack and tail
882 auto IsExpandedPack = [&](const ParmVarDecl *P) {
883 return getUnderlyingPackType(P) == TTPT;
884 };
885 ForwardingInfo FI;
886 FI.Head = MatchingParams.take_until(IsExpandedPack);
887 FI.Pack =
888 MatchingParams.drop_front(FI.Head.size()).take_while(IsExpandedPack);
889 FI.Tail = MatchingParams.drop_front(FI.Head.size() + FI.Pack.size());
890 FI.PackTarget = Callee;
891 Info = FI;
892 return;
893 }
894 // Default case: assume all parameters were fully resolved
895 ForwardingInfo FI;
896 FI.Head = MatchingParams;
897 Info = FI;
898 }
899
900 // Returns the beginning of the expanded pack represented by Parameters
901 // in the given arguments, if it is there.
902 std::optional<size_t> findPack(typename CallExpr::arg_range Args) {
903 // find the argument directly referring to the first parameter
904 assert(Parameters.size() <= static_cast<size_t>(llvm::size(Args)));
905 for (auto Begin = Args.begin(), End = Args.end() - Parameters.size() + 1;
906 Begin != End; ++Begin) {
907 if (const auto *RefArg = unwrapForward(*Begin)) {
908 if (Parameters.front() != RefArg->getDecl())
909 continue;
910 // Check that this expands all the way until the last parameter.
911 // It's enough to look at the last parameter, because it isn't possible
912 // to expand without expanding all of them.
913 auto ParamEnd = Begin + Parameters.size() - 1;
914 RefArg = unwrapForward(*ParamEnd);
915 if (!RefArg || Parameters.back() != RefArg->getDecl())
916 continue;
917 return std::distance(Args.begin(), Begin);
918 }
919 }
920 return std::nullopt;
921 }
922
923 static FunctionDecl *getCalleeDeclOrUniqueOverload(CallExpr *E) {
924 Decl *CalleeDecl = E->getCalleeDecl();
925 auto *Callee = dyn_cast_or_null<FunctionDecl>(CalleeDecl);
926 if (!Callee) {
927 if (auto *Lookup = dyn_cast<UnresolvedLookupExpr>(E->getCallee())) {
928 Callee = resolveOverload(Lookup, E);
929 }
930 }
931 // Ignore the callee if the number of arguments is wrong (deal with va_args)
932 if (Callee && Callee->getNumParams() == E->getNumArgs())
933 return Callee;
934 return nullptr;
935 }
936
937 static FunctionDecl *resolveOverload(UnresolvedLookupExpr *Lookup,
938 CallExpr *E) {
939 FunctionDecl *MatchingDecl = nullptr;
940 if (!Lookup->requiresADL()) {
941 // Check whether there is a single overload with this number of
942 // parameters
943 for (auto *Candidate : Lookup->decls()) {
944 if (auto *FuncCandidate = dyn_cast_or_null<FunctionDecl>(Candidate)) {
945 if (FuncCandidate->getNumParams() == E->getNumArgs()) {
946 if (MatchingDecl) {
947 // there are multiple candidates - abort
948 return nullptr;
949 }
950 MatchingDecl = FuncCandidate;
951 }
952 }
953 }
954 }
955 return MatchingDecl;
956 }
957
958 // Tries to get to the underlying argument by unwrapping implicit nodes and
959 // std::forward.
960 static const DeclRefExpr *unwrapForward(const Expr *E) {
961 E = E->IgnoreImplicitAsWritten();
962 // There might be an implicit copy/move constructor call on top of the
963 // forwarded arg.
964 // FIXME: Maybe mark implicit calls in the AST to properly filter here.
965 if (const auto *Const = dyn_cast<CXXConstructExpr>(E))
966 if (Const->getConstructor()->isCopyOrMoveConstructor())
967 E = Const->getArg(0)->IgnoreImplicitAsWritten();
968 if (const auto *Call = dyn_cast<CallExpr>(E)) {
969 const auto Callee = Call->getBuiltinCallee();
970 if (Callee == Builtin::BIforward) {
971 return dyn_cast<DeclRefExpr>(
972 Call->getArg(0)->IgnoreImplicitAsWritten());
973 }
974 }
975 return dyn_cast<DeclRefExpr>(E);
976 }
977};
978
979} // namespace
980
981SmallVector<const ParmVarDecl *>
982resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth) {
983 auto Parameters = D->parameters();
984 // If the function has a template parameter pack
985 if (const auto *TTPT = getFunctionPackType(D)) {
986 // Split the parameters into head, pack and tail
987 auto IsExpandedPack = [TTPT](const ParmVarDecl *P) {
988 return getUnderlyingPackType(P) == TTPT;
989 };
990 ArrayRef<const ParmVarDecl *> Head = Parameters.take_until(IsExpandedPack);
991 ArrayRef<const ParmVarDecl *> Pack =
992 Parameters.drop_front(Head.size()).take_while(IsExpandedPack);
993 ArrayRef<const ParmVarDecl *> Tail =
994 Parameters.drop_front(Head.size() + Pack.size());
995 SmallVector<const ParmVarDecl *> Result(Parameters.size());
996 // Fill in non-pack parameters
997 auto *HeadIt = std::copy(Head.begin(), Head.end(), Result.begin());
998 auto TailIt = std::copy(Tail.rbegin(), Tail.rend(), Result.rbegin());
999 // Recurse on pack parameters
1000 size_t Depth = 0;
1001 const FunctionDecl *CurrentFunction = D;
1002 llvm::SmallPtrSet<const FunctionTemplateDecl *, 4> SeenTemplates;
1003 if (const auto *Template = D->getPrimaryTemplate()) {
1004 SeenTemplates.insert(Template);
1005 }
1006 while (!Pack.empty() && CurrentFunction && Depth < MaxDepth) {
1007 // Find call expressions involving the pack
1008 ForwardingCallVisitor V{Pack};
1009 V.TraverseStmt(CurrentFunction->getBody());
1010 if (!V.Info) {
1011 break;
1012 }
1013 // If we found something: Fill in non-pack parameters
1014 auto Info = *V.Info;
1015 HeadIt = std::copy(Info.Head.begin(), Info.Head.end(), HeadIt);
1016 TailIt = std::copy(Info.Tail.rbegin(), Info.Tail.rend(), TailIt);
1017 // Prepare next recursion level
1018 Pack = Info.Pack;
1019 CurrentFunction = Info.PackTarget.value_or(nullptr);
1020 Depth++;
1021 // If we are recursing into a previously encountered function: Abort
1022 if (CurrentFunction) {
1023 if (const auto *Template = CurrentFunction->getPrimaryTemplate()) {
1024 bool NewFunction = SeenTemplates.insert(Template).second;
1025 if (!NewFunction) {
1026 return {Parameters.begin(), Parameters.end()};
1027 }
1028 }
1029 }
1030 }
1031 // Fill in the remaining unresolved pack parameters
1032 HeadIt = std::copy(Pack.begin(), Pack.end(), HeadIt);
1033 assert(TailIt.base() == HeadIt);
1034 return Result;
1035 }
1036 return {Parameters.begin(), Parameters.end()};
1037}
1038
1039bool isExpandedFromParameterPack(const ParmVarDecl *D) {
1040 return getUnderlyingPackType(D) != nullptr;
1041}
1042
1043} // namespace clangd
1044} // namespace clang
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition Context.h:69
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
SmallVector< const ParmVarDecl * > resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth)
Recursively resolves the parameters of a FunctionDecl that forwards its parameters to another functio...
Definition AST.cpp:982
static llvm::StringRef getNameOrErrForObjCInterface(const ObjCInterfaceDecl *ID)
Definition AST.cpp:312
std::string printTemplateSpecializationArgs(const NamedDecl &ND)
Prints template arguments of a decl as written in the source code, including enclosing '<' and '>',...
Definition AST.cpp:287
std::string printObjCMethod(const ObjCMethodDecl &Method)
Print the Objective-C method name, including the full container name, e.g.
Definition AST.cpp:316
@ Info
An information message.
Definition Protocol.h:738
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
Definition AST.cpp:354
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user.
Definition AST.cpp:248
std::string printObjCContainer(const ObjCContainerDecl &C)
Print the Objective-C container name including categories, e.g. MyClass,.
Definition AST.cpp:335
std::string printType(const QualType QT, const DeclContext &CurContext, const llvm::StringRef Placeholder, bool FullyQualify)
Returns a QualType as string.
Definition AST.cpp:417
std::string getQualification(ASTContext &Context, const DeclContext *DestContext, SourceLocation InsertionPoint, const NamedDecl *ND)
Gets the nested name specifier necessary for spelling ND in DestContext, at InsertionPoint.
Definition AST.cpp:698
bool isReservedName(llvm::StringRef Name)
Returns true if Name is reserved, like _Foo or __Vector_base.
Definition SourceCode.h:334
bool isExplicitTemplateSpecialization(const NamedDecl *D)
Indicates if D is an explicit template specialization, e.g.
Definition AST.cpp:188
NamedDecl * getOnlyInstantiation(NamedDecl *TemplatedDecl)
Definition AST.cpp:662
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
Definition AST.cpp:197
NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND)
Returns a nested name specifier loc of ND if it was present in the source, e.g.
Definition AST.cpp:229
std::optional< QualType > getDeducedType(ASTContext &ASTCtx, const HeuristicResolver *Resolver, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
Definition AST.cpp:623
static NamedDecl * getOnlyInstantiationImpl(TemplateDeclTy *TD)
Definition AST.cpp:650
Symbol::IncludeDirective preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts, ArrayRef< Inclusion > MainFileIncludes, ArrayRef< const Decl * > TopLevelDecls)
Infer the include directive to use for the given FileName.
Definition AST.cpp:386
bool isExpandedFromParameterPack(const ParmVarDecl *D)
Checks whether D is instantiated from a function parameter pack whose type is a bare type parameter p...
Definition AST.cpp:1039
bool hasUnstableLinkage(const Decl *D)
Whether we must avoid computing linkage for D during code completion.
Definition AST.cpp:735
std::string printUsingNamespaceName(const ASTContext &Ctx, const UsingDirectiveDecl &D)
Returns the name of the namespace inside the 'using namespace' directive, as written in the code.
Definition AST.cpp:237
bool hasReservedName(const Decl &D)
Returns true if this is a NamedDecl with a reserved name.
Definition AST.cpp:444
std::vector< const Attr * > getAttributes(const DynTypedNode &N)
Return attributes attached directly to a node.
Definition AST.cpp:674
static bool isAnonymous(const DeclarationName &N)
Definition AST.cpp:225
@ Auto
Diagnostics must not be generated for this snapshot.
Definition TUScheduler.h:56
QualType declaredType(const TypeDecl *D)
Definition AST.cpp:462
bool isImplementationDetail(const Decl *D)
Returns true if the declaration is considered implementation detail based on heuristics.
Definition AST.cpp:192
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
Definition AST.cpp:371
bool isImplicitTemplateInstantiation(const NamedDecl *D)
Indicates if D is a template instantiation implicitly generated by the compiler, e....
Definition AST.cpp:184
bool hasReservedScope(const DeclContext &DC)
Returns true if this scope would be written with a reserved name.
Definition AST.cpp:451
bool isSpelledInSource(SourceLocation Loc, const SourceManager &SM)
Returns true if the token at Loc is spelled in the source code.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition AST.cpp:207
TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL)
Definition AST.cpp:635
bool isDeeplyNested(const Decl *D, unsigned MaxDepth)
Checks whether D is more than MaxDepth away from translation unit scope.
Definition AST.cpp:742
bool isHeaderFile(llvm::StringRef FileName, std::optional< LangOptions > LangOpts)
Infers whether this is a header from the FileName and LangOpts (if presents).
std::string printNamespaceScope(const DeclContext &DC)
Returns the first enclosing namespace scope starting from DC.
Definition AST.cpp:303
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccess P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
@ Include
#include "header.h"
Definition Symbol.h:93
@ Import
#import "header.h"
Definition Symbol.h:95