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"
39#if CLANG_VERSION_MAJOR
>= 22
184static inline const Type *
461 if (
const auto *
TST =
528 bool WithGlobalNsPrefix);
539 const ASTContext &Ctx,
540 const NamespaceDecl *Namesp,
541 bool WithGlobalNsPrefix);
554 const ASTContext &Ctx,
const TypeDecl *TD,
555 bool FullyQualify,
bool WithGlobalNsPrefix);
558 const ASTContext &Ctx,
const Decl *decl,
559 bool FullyQualified,
bool WithGlobalNsPrefix);
562 const ASTContext &Ctx, NestedNameSpecifier *scope,
bool WithGlobalNsPrefix);
566 bool WithGlobalNsPrefix) {
567 bool Changed =
false;
568 NestedNameSpecifier *NNS =
nullptr;
570 TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
573 assert(ArgTDecl !=
nullptr);
574 QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
577 !QTName->hasTemplateKeyword() &&
578 (NNS = QTName->getQualifier())) {
580 Ctx
, NNS
, WithGlobalNsPrefix
);
588 NNS = createNestedNameSpecifierForScopeOf(
589 Ctx, ArgTDecl,
true, WithGlobalNsPrefix);
592 TemplateName UnderlyingTN(ArgTDecl);
593 if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())
594 UnderlyingTN = TemplateName(USD);
596 Ctx.getQualifiedTemplateName(NNS,
597 false, UnderlyingTN);
604 TemplateArgument &Arg,
605 bool WithGlobalNsPrefix) {
606 bool Changed =
false;
611 if (Arg.getKind() == TemplateArgument::Template) {
612 TemplateName TName = Arg.getAsTemplate();
615 Arg = TemplateArgument(TName);
617 }
else if (Arg.getKind() == TemplateArgument::Type) {
618 QualType SubTy = Arg.getAsType();
622 Arg = TemplateArgument(QTFQ);
631 bool WithGlobalNsPrefix) {
635 assert(!isa<DependentTemplateSpecializationType>(TypePtr));
638 if (
const auto *TST = dyn_cast<
const TemplateSpecializationType>(TypePtr)) {
639 bool MightHaveChanged =
false;
640 SmallVector<TemplateArgument, 4> FQArgs;
643 for (TemplateArgument Arg : TST->template_arguments()) {
644 MightHaveChanged |= getFullyQualifiedTemplateArgument(
645 Ctx, Arg, WithGlobalNsPrefix);
646 FQArgs.push_back(Arg);
651 if (MightHaveChanged) {
652#if CLANG_VERSION_MAJOR
>= 21
653 QualType QT = Ctx.getTemplateSpecializationType(
654 TST->getTemplateName(), FQArgs, {},
655 TST->getCanonicalTypeInternal());
657 QualType QT = Ctx.getTemplateSpecializationType(
658 TST->getTemplateName(), FQArgs,
659 TST->getCanonicalTypeInternal());
664 return QT.getTypePtr();
666 }
else if (
const auto *TSTRecord = dyn_cast<
const RecordType>(TypePtr)) {
671 if (
const auto *TSTDecl =
672 dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
673 const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
675 bool MightHaveChanged =
false;
676 SmallVector<TemplateArgument, 4> FQArgs;
677 for (
unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
680 TemplateArgument Arg(TemplateArgs[I]);
682 Ctx
, Arg
, WithGlobalNsPrefix
);
683 FQArgs.push_back(Arg);
688 if (MightHaveChanged) {
689 TemplateName TN(TSTDecl->getSpecializedTemplate());
690#if CLANG_VERSION_MAJOR
>= 21
691 QualType QT = Ctx.getTemplateSpecializationType(
693 TSTRecord->getCanonicalTypeInternal());
695 QualType QT = Ctx.getTemplateSpecializationType(
697 TSTRecord->getCanonicalTypeInternal());
702 return QT.getTypePtr();
709static inline NestedNameSpecifier *
createOuterNNS(
const ASTContext &Ctx,
const Decl *D,
711 bool WithGlobalNsPrefix) {
712 const DeclContext *DC = D->getDeclContext();
713 if (
const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
714 while (NS && NS->isInline()) {
716 NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
718 if (NS && NS->getDeclName()) {
719 return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
722 }
else if (
const auto *TD = dyn_cast<TagDecl>(DC)) {
723 return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
724 }
else if (
const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
725 return createNestedNameSpecifier(
726 Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
727 }
else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
728 return NestedNameSpecifier::GlobalSpecifier(Ctx);
735 const ASTContext &Ctx, NestedNameSpecifier *Scope,
736 bool WithGlobalNsPrefix) {
737 switch (Scope->getKind()) {
738 case NestedNameSpecifier::Global:
741 case NestedNameSpecifier::Namespace:
743 Ctx
, Scope->getAsNamespace()
, WithGlobalNsPrefix
);
744 case NestedNameSpecifier::NamespaceAlias:
751 Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl()
,
753 case NestedNameSpecifier::Identifier:
758 Ctx
, Scope->getPrefix()
, WithGlobalNsPrefix
);
759 case NestedNameSpecifier::Super:
760 case NestedNameSpecifier::TypeSpec:
761#if CLANG_VERSION_MAJOR
< 21
762 case NestedNameSpecifier::TypeSpecWithTemplate:
765 const Type *Type = Scope->getAsType();
767 const TagDecl *TD =
nullptr;
768 if (
const TagType *TagDeclType = Type->getAs<TagType>()) {
769 TD = TagDeclType->getDecl();
771 TD = Type->getAsCXXRecordDecl();
774 return TypeName::createNestedNameSpecifier(Ctx, TD,
777 }
else if (
const auto *TDD = dyn_cast<TypedefType>(Type)) {
778 return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
785 llvm_unreachable(
"bad NNS kind");
791 const ASTContext &Ctx,
const Decl *Decl,
792 bool FullyQualified,
bool WithGlobalNsPrefix) {
795 const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
796 const auto *Outer = dyn_cast<NamedDecl>(DC);
797 const auto *OuterNS = dyn_cast<NamespaceDecl>(DC);
798 if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
800 return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
801 }
else if (
const auto *TD = dyn_cast<TagDecl>(Outer)) {
802 return createNestedNameSpecifier(
803 Ctx, TD, FullyQualified, WithGlobalNsPrefix);
804 }
else if (isa<TranslationUnitDecl>(Outer)) {
813 }
else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
814 return NestedNameSpecifier::GlobalSpecifier(Ctx);
822 const ASTContext &Ctx,
const Type *TypePtr,
823 bool FullyQualified,
bool WithGlobalNsPrefix) {
824 if (!TypePtr)
return nullptr;
826 Decl *Decl =
nullptr;
828 if (
const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
829 Decl = TDT->getDecl();
830 }
else if (
const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
831 Decl = TagDeclType->getDecl();
832 }
else if (
const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
833 Decl = TST->getTemplateName().getAsTemplateDecl();
835 Decl = TypePtr->getAsCXXRecordDecl();
838 if (!Decl)
return nullptr;
841 Ctx
, Decl
, FullyQualified
, WithGlobalNsPrefix
);
845 const NamespaceDecl *Namespace,
846 bool WithGlobalNsPrefix) {
847 while (Namespace && Namespace->isInline()) {
849 Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
851 if (!Namespace)
return nullptr;
853 bool FullyQualified =
true;
854 return NestedNameSpecifier::Create(
856 createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
863 bool WithGlobalNsPrefix) {
864 const Type *TypePtr = TD->getTypeForDecl();
865 if (isa<
const TemplateSpecializationType>(TypePtr) ||
866 isa<
const RecordType>(TypePtr)) {
874 return NestedNameSpecifier::Create(
875 Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
876#if CLANG_VERSION_MAJOR
< 21
885 bool WithGlobalNsPrefix =
false) {
888 if (isa<PointerType>(QT.getTypePtr())) {
890 Qualifiers Quals = QT.getQualifiers();
892 QT = Ctx.getPointerType(QT);
894 QT = Ctx.getQualifiedType(QT, Quals);
898 if (
auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
900 Qualifiers Quals = QT.getQualifiers();
903#if CLANG_VERSION_MAJOR
>= 21
904 QT = Ctx.getMemberPointerType(QT, MPT->getQualifier(), MPT->getMostRecentCXXRecordDecl());
906 QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
908 QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
911 QT = Ctx.getQualifiedType(QT, Quals);
917 if (isa<ReferenceType>(QT.getTypePtr())) {
919 bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
920 Qualifiers Quals = QT.getQualifiers();
925 QT = Ctx.getLValueReferenceType(QT);
927 QT = Ctx.getRValueReferenceType(QT);
929 QT = Ctx.getQualifiedType(QT, Quals);
937 while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
939 Qualifiers Quals = QT.getQualifiers();
941 QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
944 QT = Ctx.getQualifiedType(QT, Quals);
947 NestedNameSpecifier *Prefix =
nullptr;
951 Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
952 QT = QualType(QT.getTypePtr(), 0);
953#if LIBCLANG_VERSION_MAJOR >= 18
954 constexpr ElaboratedTypeKeyword ETK_None = ElaboratedTypeKeyword::None;
956 ElaboratedTypeKeyword Keyword = ETK_None;
957 if (
const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
958 QT = ETypeInput->getNamedType();
959 assert(!QT.hasLocalQualifiers());
960 Keyword = ETypeInput->getKeyword();
965 if (
const auto *UT = QT->getAs<UsingType>()) {
966 QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers);
977 if (isa<
const TemplateSpecializationType>(QT.getTypePtr()) ||
978 isa<
const RecordType>(QT.getTypePtr())) {
984 Ctx
, QT.getTypePtr()
, WithGlobalNsPrefix
);
985 QT = QualType(TypePtr, 0);
987 if (Prefix || Keyword != ETK_None) {
988 QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
990 QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
997 const ASTContext &Ctx,
998 const PrintingPolicy &Policy,
999 bool WithGlobalNsPrefix =
false) {
1001 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.
static std::optional< QString > classNameFromParameterType(clang::QualType param_type)
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
static const clang::TemplateSpecializationType * find_template_specialization_through_sugar(const clang::Type *type)
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::optional< SfinaeConstraint > detect_sfinae_constraint(const clang::NonTypeTemplateParmDecl *param)
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 bool is_enable_if_name(const std::string &qualified_name)
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 void autoGenerateSmfDoc(FunctionNode *fn, const QString &className)
static std::string get_fully_qualified_type_name(clang::QualType type, const clang::ASTContext &declaration_context)
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)
static std::string ensureAnonymousTagKeyword(std::string typeName, clang::QualType type)
Returns a string representing the name of type as if it was referred to at the end of the translation...
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)
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)
ClangVisitor(QDocDatabase *qdb, const std::set< Config::HeaderFilePath > &allHeaders, const Config::InternalFilePatterns &internalFilePatterns)
CXChildVisitResult visitFnArg(CXCursor cursor, Node **fnNode, bool &ignoreSignature)
The ClassNode represents a C++ class.
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.
void markAutoGenerated()
Marks this documentation as auto-generated by QDoc.
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
This node is used to represent any kind of function being documented.
void markDeletedAsWritten()
void setVirtualness(Virtualness virtualness)
bool isNonvirtual() const
void setInvokable(bool b)
bool isSpecialMemberFunction() const
bool isDeletedAsWritten() const
void markExplicitlyDefaulted()
void setMetaness(Metaness metaness)
bool isExplicitlyDefaulted() const
Parameters & parameters()
void setHiddenFriend(bool b)
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.
Status
Specifies the status of the QQmlIncubator.
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.
Combined button and popup list for selecting options.
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 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.
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
void setDoc(const Doc &doc, bool replace=false)
Sets this Node's Doc to doc.
bool isClass() const
Returns true if the node type is Class.
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
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)
Holds the source-level alias with its template arguments for a SFINAE constraint detected in a non-ty...
operator CXTranslationUnit()