19#include <QtCore/qcompilerdetection.h>
22QT_WARNING_DISABLE_MSVC(4267)
24#include "clang/AST/DeclTemplate.h"
25#include "clang/AST/DeclarationName.h"
26#include "clang/AST/GlobalDecl.h"
27#include "clang/AST/Mangle.h"
28#include "clang/Basic/Version.h"
40 bool WithGlobalNsPrefix);
51 const ASTContext &Ctx,
52 const NamespaceDecl *Namesp,
53 bool WithGlobalNsPrefix);
66 const ASTContext &Ctx,
const TypeDecl *TD,
67 bool FullyQualify,
bool WithGlobalNsPrefix);
70 const ASTContext &Ctx,
const Decl *decl,
71 bool FullyQualified,
bool WithGlobalNsPrefix);
74 const ASTContext &Ctx, NestedNameSpecifier *scope,
bool WithGlobalNsPrefix);
78 bool WithGlobalNsPrefix) {
80 NestedNameSpecifier *NNS =
nullptr;
82 TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
85 assert(ArgTDecl !=
nullptr);
86 QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
89 !QTName->hasTemplateKeyword() &&
90 (NNS = QTName->getQualifier())) {
92 Ctx
, NNS
, WithGlobalNsPrefix
);
100 NNS = createNestedNameSpecifierForScopeOf(
101 Ctx, ArgTDecl,
true, WithGlobalNsPrefix);
104 TemplateName UnderlyingTN(ArgTDecl);
105 if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())
106 UnderlyingTN = TemplateName(USD);
108 Ctx.getQualifiedTemplateName(NNS,
109 false, UnderlyingTN);
116 TemplateArgument &Arg,
117 bool WithGlobalNsPrefix) {
118 bool Changed =
false;
123 if (Arg.getKind() == TemplateArgument::Template) {
124 TemplateName TName = Arg.getAsTemplate();
127 Arg = TemplateArgument(TName);
129 }
else if (Arg.getKind() == TemplateArgument::Type) {
130 QualType SubTy = Arg.getAsType();
134 Arg = TemplateArgument(QTFQ);
143 bool WithGlobalNsPrefix) {
147 assert(!isa<DependentTemplateSpecializationType>(TypePtr));
150 if (
const auto *TST = dyn_cast<
const TemplateSpecializationType>(TypePtr)) {
151 bool MightHaveChanged =
false;
152 SmallVector<TemplateArgument, 4> FQArgs;
155 for (TemplateArgument Arg : TST->template_arguments()) {
156 MightHaveChanged |= getFullyQualifiedTemplateArgument(
157 Ctx, Arg, WithGlobalNsPrefix);
158 FQArgs.push_back(Arg);
163 if (MightHaveChanged) {
164#if CLANG_VERSION_MAJOR
>= 21
165 QualType QT = Ctx.getTemplateSpecializationType(
166 TST->getTemplateName(), FQArgs, {},
167 TST->getCanonicalTypeInternal());
169 QualType QT = Ctx.getTemplateSpecializationType(
170 TST->getTemplateName(), FQArgs,
171 TST->getCanonicalTypeInternal());
176 return QT.getTypePtr();
178 }
else if (
const auto *TSTRecord = dyn_cast<
const RecordType>(TypePtr)) {
183 if (
const auto *TSTDecl =
184 dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
185 const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
187 bool MightHaveChanged =
false;
188 SmallVector<TemplateArgument, 4> FQArgs;
189 for (
unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
192 TemplateArgument Arg(TemplateArgs[I]);
194 Ctx
, Arg
, WithGlobalNsPrefix
);
195 FQArgs.push_back(Arg);
200 if (MightHaveChanged) {
201 TemplateName TN(TSTDecl->getSpecializedTemplate());
202#if CLANG_VERSION_MAJOR
>= 21
203 QualType QT = Ctx.getTemplateSpecializationType(
205 TSTRecord->getCanonicalTypeInternal());
207 QualType QT = Ctx.getTemplateSpecializationType(
209 TSTRecord->getCanonicalTypeInternal());
214 return QT.getTypePtr();
221static inline NestedNameSpecifier *
createOuterNNS(
const ASTContext &Ctx,
const Decl *D,
223 bool WithGlobalNsPrefix) {
224 const DeclContext *DC = D->getDeclContext();
225 if (
const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
226 while (NS && NS->isInline()) {
228 NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
230 if (NS && NS->getDeclName()) {
231 return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
234 }
else if (
const auto *TD = dyn_cast<TagDecl>(DC)) {
235 return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
236 }
else if (
const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
237 return createNestedNameSpecifier(
238 Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
239 }
else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
240 return NestedNameSpecifier::GlobalSpecifier(Ctx);
247 const ASTContext &Ctx, NestedNameSpecifier *Scope,
248 bool WithGlobalNsPrefix) {
249 switch (Scope->getKind()) {
250 case NestedNameSpecifier::Global:
253 case NestedNameSpecifier::Namespace:
255 Ctx
, Scope->getAsNamespace()
, WithGlobalNsPrefix
);
256 case NestedNameSpecifier::NamespaceAlias:
263 Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl()
,
265 case NestedNameSpecifier::Identifier:
270 Ctx
, Scope->getPrefix()
, WithGlobalNsPrefix
);
271 case NestedNameSpecifier::Super:
272 case NestedNameSpecifier::TypeSpec:
273#if CLANG_VERSION_MAJOR
< 21
274 case NestedNameSpecifier::TypeSpecWithTemplate:
277 const Type *Type = Scope->getAsType();
279 const TagDecl *TD =
nullptr;
280 if (
const TagType *TagDeclType = Type->getAs<TagType>()) {
281 TD = TagDeclType->getDecl();
283 TD = Type->getAsCXXRecordDecl();
286 return TypeName::createNestedNameSpecifier(Ctx, TD,
289 }
else if (
const auto *TDD = dyn_cast<TypedefType>(Type)) {
290 return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
297 llvm_unreachable(
"bad NNS kind");
303 const ASTContext &Ctx,
const Decl *Decl,
304 bool FullyQualified,
bool WithGlobalNsPrefix) {
307 const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
308 const auto *Outer = dyn_cast<NamedDecl>(DC);
309 const auto *OuterNS = dyn_cast<NamespaceDecl>(DC);
310 if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
312 return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
313 }
else if (
const auto *TD = dyn_cast<TagDecl>(Outer)) {
314 return createNestedNameSpecifier(
315 Ctx, TD, FullyQualified, WithGlobalNsPrefix);
316 }
else if (isa<TranslationUnitDecl>(Outer)) {
325 }
else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
326 return NestedNameSpecifier::GlobalSpecifier(Ctx);
334 const ASTContext &Ctx,
const Type *TypePtr,
335 bool FullyQualified,
bool WithGlobalNsPrefix) {
336 if (!TypePtr)
return nullptr;
338 Decl *Decl =
nullptr;
340 if (
const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
341 Decl = TDT->getDecl();
342 }
else if (
const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
343 Decl = TagDeclType->getDecl();
344 }
else if (
const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
345 Decl = TST->getTemplateName().getAsTemplateDecl();
347 Decl = TypePtr->getAsCXXRecordDecl();
350 if (!Decl)
return nullptr;
353 Ctx
, Decl
, FullyQualified
, WithGlobalNsPrefix
);
357 const NamespaceDecl *Namespace,
358 bool WithGlobalNsPrefix) {
359 while (Namespace && Namespace->isInline()) {
361 Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
363 if (!Namespace)
return nullptr;
365 bool FullyQualified =
true;
366 return NestedNameSpecifier::Create(
368 createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
375 bool WithGlobalNsPrefix) {
376 const Type *TypePtr = TD->getTypeForDecl();
377 if (isa<
const TemplateSpecializationType>(TypePtr) ||
378 isa<
const RecordType>(TypePtr)) {
386 return NestedNameSpecifier::Create(
387 Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
388#if CLANG_VERSION_MAJOR
< 21
397 bool WithGlobalNsPrefix =
false) {
400 if (isa<PointerType>(QT.getTypePtr())) {
402 Qualifiers Quals = QT.getQualifiers();
404 QT = Ctx.getPointerType(QT);
406 QT = Ctx.getQualifiedType(QT, Quals);
410 if (
auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
412 Qualifiers Quals = QT.getQualifiers();
415#if CLANG_VERSION_MAJOR
>= 21
416 QT = Ctx.getMemberPointerType(QT, MPT->getQualifier(), MPT->getMostRecentCXXRecordDecl());
420 QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
423 QT = Ctx.getQualifiedType(QT, Quals);
429 if (isa<ReferenceType>(QT.getTypePtr())) {
431 bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
432 Qualifiers Quals = QT.getQualifiers();
437 QT = Ctx.getLValueReferenceType(QT);
439 QT = Ctx.getRValueReferenceType(QT);
441 QT = Ctx.getQualifiedType(QT, Quals);
449 while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
451 Qualifiers Quals = QT.getQualifiers();
453 QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
456 QT = Ctx.getQualifiedType(QT, Quals);
459 NestedNameSpecifier *Prefix =
nullptr;
463 Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
464 QT = QualType(QT.getTypePtr(), 0);
465#if LIBCLANG_VERSION_MAJOR >= 18
466 constexpr ElaboratedTypeKeyword ETK_None = ElaboratedTypeKeyword::None;
468 ElaboratedTypeKeyword Keyword = ETK_None;
469 if (
const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
470 QT = ETypeInput->getNamedType();
471 assert(!QT.hasLocalQualifiers());
472 Keyword = ETypeInput->getKeyword();
477 if (
const auto *UT = QT->getAs<UsingType>()) {
478 QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers);
489 if (isa<
const TemplateSpecializationType>(QT.getTypePtr()) ||
490 isa<
const RecordType>(QT.getTypePtr())) {
496 Ctx
, QT.getTypePtr()
, WithGlobalNsPrefix
);
497 QT = QualType(TypePtr, 0);
499 if (Prefix || Keyword != ETK_None) {
500 QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
502 QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
507 const ASTContext &Ctx,
508 const PrintingPolicy &Policy,
509 bool WithGlobalNsPrefix =
false) {
511 return FQQT.getAsString(Policy);
static const clang::Decl * get_cursor_declaration(CXCursor cursor)
Returns the underlying Decl that cursor represents.
static QString reconstructQualifiedPathForCursor(CXCursor cur)
Reconstruct the qualified path name of a function that is being overridden.
QString functionName(CXCursor cursor)
Returns the function name from a given cursor representing a function declaration.
static std::string get_default_value_initializer_as_string(const clang::TemplateTemplateParmDecl *parameter)
static QString fromCXString(CXString &&string)
convert a CXString to a QString, and dispose the CXString
static QDebug operator<<(QDebug debug, const std::vector< T > &v)
static QString getSpelling(CXSourceRange range)
static void setOverridesForFunction(FunctionNode *fn, CXCursor cursor)
static QList< QByteArray > includePathsFromHeaders(const std::set< Config::HeaderFilePath > &allHeaders)
static const auto kClangDontDisplayDiagnostics
void getMoreArgs(const std::vector< QByteArray > &include_paths, const std::set< Config::HeaderFilePath > &all_headers, std::vector< const char * > &args)
Load the include paths into moreArgs.
static std::string get_default_value_initializer_as_string(const clang::ParmVarDecl *parameter)
void getDefaultArgs(const QList< QByteArray > &defines, std::vector< const char * > &args)
Load the default arguments and the defines into args.
static std::string get_expression_as_string(const clang::Expr *expression, const clang::ASTContext &declaration_context)
bool visitChildrenLambda(CXCursor cursor, T &&lambda)
Call clang_visitChildren on the given cursor with the lambda as a callback T can be any functor that ...
static std::string get_default_value_initializer_as_string(const clang::NamedDecl *declaration)
static RelaxedTemplateDeclaration get_template_declaration(const clang::TemplateDecl *template_declaration)
static std::string get_default_value_initializer_as_string(const clang::NonTypeTemplateParmDecl *parameter)
static QString fromCache(const QByteArray &cache, unsigned int offset1, unsigned int offset2)
static float getUnpatchedVersion(QString t)
static Location fromCXSourceLocation(CXSourceLocation location)
convert a CXSourceLocation to a qdoc Location
static QString cleanAnonymousTypeName(const QString &typeName)
static Access fromCX_CXXAccessSpecifier(CX_CXXAccessSpecifier spec)
convert a CX_CXXAccessSpecifier to Node::Access
static std::string get_default_value_initializer_as_string(const clang::TemplateTypeParmDecl *parameter)
constexpr const char fnDummyFileName[]
static CXTranslationUnit_Flags flags_
static Node * findNodeForCursor(QDocDatabase *qdb, CXCursor cur)
Find the node from the QDocDatabase qdb that corresponds to the declaration represented by the cursor...
static std::string get_fully_qualified_type_name(clang::QualType type, const clang::ASTContext &declaration_context)
Returns a string representing the name of type as if it was referred to at the end of the translation...
static void printDiagnostics(const CXTranslationUnit &translationUnit)
static const char * defaultArgs_[]
std::optional< PCHFile > buildPCH(QDocDatabase *qdb, QString module_header, const std::set< Config::HeaderFilePath > &all_headers, const std::vector< QByteArray > &include_paths, const QList< QByteArray > &defines, const InclusionPolicy &policy)
Building the PCH must be possible when there are no .cpp files, so it is moved here to its own member...
static QString readFile(CXFile cxFile, unsigned int offset1, unsigned int offset2)
void addChild(Node *child)
Adds the child to this node's child list and sets the child's parent pointer to this Aggregate.
ParsedCppFileIR parse_cpp_file(const QString &filePath)
Get ready to parse the C++ cpp file identified by filePath and add its parsed contents to the databas...
ClangCodeParser(QDocDatabase *qdb, Config &, const std::vector< QByteArray > &include_paths, const QList< QByteArray > &defines, std::optional< std::reference_wrapper< const PCHFile > > pch)
ClangVisitor(QDocDatabase *qdb, const std::set< Config::HeaderFilePath > &allHeaders)
Node * nodeForCommentAtLocation(CXSourceLocation loc, CXSourceLocation nextCommentLoc)
Given a comment at location loc, return a Node for this comment nextCommentLoc is the location of the...
CXChildVisitResult visitChildren(CXCursor cursor)
CXChildVisitResult visitFnArg(CXCursor cursor, Node **fnNode, bool &ignoreSignature)
The ClassNode represents a C++ class.
void addResolvedBaseClass(Access access, ClassNode *node)
Adds the base class node to this class's list of base classes.
static bool isWorthWarningAbout(const Doc &doc)
Test for whether a doc comment warrants warnings.
The Config class contains the configuration variables for controlling how qdoc produces documentation...
const Location & location() const
Returns the starting location of a qdoc comment.
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
void setFlagsType(TypedefNode *typedefNode)
void setAnonymous(bool anonymous)
This node is used to represent any kind of function being documented.
void setVirtualness(Virtualness virtualness)
bool isNonvirtual() const
void setInvokable(bool b)
void setMetaness(Metaness metaness)
Parameters & parameters()
The Location class provides a way to mark a location in a file.
This class represents a C++ namespace.
This class describes one instance of using the Q_PROPERTY macro.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
const QString & leftType() const
Node * clone(Aggregate *parent) override
Clone this node on the heap and make the clone a child of parent.
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
const QString & rightType() const
#define CONFIG_DOCUMENTATIONINHEADERS
bool hasTooManyTopics(const Doc &doc)
Checks if there are too many topic commands in doc.
This namespace holds QDoc-internal utility methods.
static NestedNameSpecifier * createOuterNNS(const ASTContext &Ctx, const Decl *D, bool FullyQualify, bool WithGlobalNsPrefix)
QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, bool WithGlobalNsPrefix)
static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, TemplateName &TName, bool WithGlobalNsPrefix)
static const Type * getFullyQualifiedTemplateType(const ASTContext &Ctx, const Type *TypePtr, bool WithGlobalNsPrefix)
static NestedNameSpecifier * createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Type *TypePtr, bool FullyQualified, bool WithGlobalNsPrefix)
static NestedNameSpecifier * createNestedNameSpecifier(const ASTContext &Ctx, const TypeDecl *TD, bool FullyQualify, bool WithGlobalNsPrefix)
static NestedNameSpecifier * createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *decl, bool FullyQualified, bool WithGlobalNsPrefix)
static NestedNameSpecifier * getFullyQualifiedNestedNameSpecifier(const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix)
Return a fully qualified version of this name specifier.
static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, TemplateArgument &Arg, bool WithGlobalNsPrefix)
std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx, const PrintingPolicy &Policy, bool WithGlobalNsPrefix=false)
static NestedNameSpecifier * createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namesp, bool WithGlobalNsPrefix)
QList< Node * > NodeVector
Returns the spelling in the file for a source range.
std::variant< Node *, FnMatchError > operator()(const Location &location, const QString &fnSignature, const QString &idTag, QStringList context)
Use clang to parse the function signature from a function command.
Encapsulates information about.
The Node class is the base class for all the nodes in QDoc's parse tree.
void setAccess(Access t)
Sets the node's access type to t.
bool isNamespace() const
Returns true if the node type is Namespace.
bool isTypedef() const
Returns true if the node type is Typedef.
bool isEnumType() const
Returns true if the node type is Enum.
bool isVariable() const
Returns true if the node type is Variable.
void setLocation(const Location &t)
Sets the node's declaration location, its definition location, or both, depending on the suffix of th...
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
virtual void setRelatedNonmember(bool b)
Sets a flag in the node indicating whether this node is a related nonmember of something.
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
bool isClass() const
Returns true if the node type is Class.
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
A class for parsing and managing a function parameter list.
Parameter & operator[](int index)
operator CXTranslationUnit()