172 const NestedNameSpecifier
177 const IgnoreNamespace ignoreNamespace)
181#if not IS_CLANG_NEWER_THAN(22)
182 if(
const auto* prefix = stmt->getPrefix()) {
186 switch(stmt->getKind()) {
187 case NestedNameSpecifier::Identifier: fullNamespace.append(stmt->getAsIdentifier()->getName());
break;
189 case NestedNameSpecifier::Namespace:
190 RETURN_IF((IgnoreNamespace::Yes == ignoreNamespace) or (stmt->getAsNamespace()->isAnonymousNamespace()));
192 fullNamespace.append(stmt->getAsNamespace()->getName());
195 case NestedNameSpecifier::NamespaceAlias: fullNamespace.append(stmt->getAsNamespaceAlias()->getName());
break;
196#if IS_CLANG_NEWER_THAN(20)
198 case NestedNameSpecifier::TypeSpecWithTemplate:
199 if(
auto* dependentSpecType = stmt->getAsType()->getAs<DependentTemplateSpecializationType>()) {
205 case NestedNameSpecifier::TypeSpec:
208 switch(stmt.getKind()) {
209 case NestedNameSpecifier::Kind::Namespace: {
210 const auto [ns, prefix] = stmt.getAsNamespaceAndPrefix();
214 RETURN_IF((IgnoreNamespace::Yes == ignoreNamespace) or
215 (isa<NamespaceDecl>(ns) and cast<NamespaceDecl>(ns)->isAnonymousNamespace()));
217 fullNamespace.append(ns->getName());
220 case NestedNameSpecifier::Kind::Type:
229 fullNamespace.append(
"::"sv);
362std::string
GetDeclContext(
const DeclContext* ctx, WithTemplateParameters withTemplateParameters)
365 SmallVector<const DeclContext*, 8> contexts{};
368 if(isa<NamedDecl>(ctx)) {
369 contexts.push_back(ctx);
371 ctx = ctx->getParent();
374 for(
const auto* declContext : llvm::reverse(contexts)) {
375 if(
const auto* classTmplSpec = dyn_cast<ClassTemplateSpecializationDecl>(declContext)) {
376 mOutputFormatHelper.
Append(classTmplSpec->getName());
381 }
else if(
const auto* nd = dyn_cast<NamespaceDecl>(declContext)) {
382 if(nd->isAnonymousNamespace() or nd->isInline()) {
386 mOutputFormatHelper.Append(nd->getName());
388 }
else if(
const auto* rd = dyn_cast<RecordDecl>(declContext)) {
389 if(not rd->getIdentifier()) {
393 mOutputFormatHelper.Append(rd->getName());
397 if(WithTemplateParameters::Yes == withTemplateParameters ) {
398 if(
const auto* cxxRecordDecl = dyn_cast_or_null<CXXRecordDecl>(rd)) {
399 if(
const auto* classTmpl = cxxRecordDecl->getDescribedClassTemplate()) {
402 CodeGenerator::TemplateParamsOnly::Yes);
407 }
else if(dyn_cast<FunctionDecl>(declContext)) {
410 }
else if(
const auto* ed = dyn_cast<EnumDecl>(declContext)) {
411 if(not ed->isScoped()) {
415 mOutputFormatHelper.Append(ed->getName());
418 mOutputFormatHelper.Append(cast<NamedDecl>(declContext)->getName());
421 mOutputFormatHelper.Append(
"::"sv);
424 return mOutputFormatHelper.GetString();
483 const QualType& mType;
486 std::string mDataAfter{};
487 bool mHasData{
false};
488 bool mSkipSpace{
false};
489 bool mScanningArrayDimension{};
490 std::string mScope{};
492 bool mTmplParamTypeRes{};
494 bool HandleType(
const TemplateTypeParmType* type)
496 if(
const TemplateTypeParmDecl* decl = type->getDecl();
497 (
nullptr == type->getIdentifier()) or
498 (decl and decl->isImplicit()) ) {
504 }
else if(
nullptr != type->getIdentifier()) {
505 mData.Append(type->getIdentifier()->getName());
508 return mTmplParamTypeRes;
511 bool HandleType(
const LValueReferenceType* type)
513 mDataAfter +=
" &"sv;
515 return HandleType(type->getPointeeType().getTypePtrOrNull());
518 bool HandleType(
const RValueReferenceType* type)
520 mDataAfter +=
" &&"sv;
522 return HandleType(type->getPointeeType().getTypePtrOrNull());
525 bool HandleType(
const PointerType* type)
527 const bool ret = HandleType(type->getPointeeType().getTypePtrOrNull());
529 if(not mData.empty() and (mData.GetString().back() !=
' ') and not isa<ParenType>(type->getPointeeType())) {
535 HandleTypeAfter(type);
540 bool HandleType(
const InjectedClassNameType* type)
543#if IS_CLANG_NEWER_THAN(22)
544 HandleType(type->getDecl()->getCanonicalTemplateSpecializationType(
GetGlobalAST()).getTypePtr());
546 HandleType(type->getInjectedTST());
550 bool HandleType(
const RecordType* type)
555 if(
const auto* tt = dyn_cast_or_null<ClassTemplateSpecializationDecl>(type->getDecl())) {
561 if(
const auto* identifierName = mType.getBaseTypeIdentifier()) {
562 const auto& scope =
GetScope(type->getDecl()->getDeclContext());
566 mData.Append(mScope);
571 mData.Append(identifierName->getName());
577 if(
const auto* cxxRecordDecl = type->getAsCXXRecordDecl()) {
579 if(type->isDependentType()) {
580 std::string context{
GetDeclContext(type->getDecl()->getDeclContext())};
582 if(not context.empty()) {
583 mData.Append(std::move(context), cxxRecordDecl->getName());
589 if(cxxRecordDecl->isLambda()) {
603#if IS_CLANG_NEWER_THAN(22)
605 if(not type->getQualifier()) {
606 if(
const auto scope =
GetScope(cxxRecordDecl->getDeclContext(), RemoveCurrentScope::No);
607 cxxRecordDecl->getDeclContext()->isNamespace() and not scope.empty()) {
608 mData.Append(ScopeHandler::RemoveCurrentScope(scope + std::string{cxxRecordDecl->getName()}));
614 std::string memberPath{cxxRecordDecl->getName().str()};
615 const CXXRecordDecl* ctx = dyn_cast_or_null<CXXRecordDecl>(cxxRecordDecl->getDeclContext());
617 while(ctx and not isa<ClassTemplateSpecializationDecl>(ctx)) {
618 memberPath.insert(0, ctx->getName().str() +
"::");
619 ctx = dyn_cast_or_null<CXXRecordDecl>(ctx->getDeclContext());
623 mData.Append(ScopeHandler::RemoveCurrentScope(
624 QualType{
GetGlobalAST().getCanonicalTagType(ctx)}.getAsString(mPrintingPolicy) +
631 if(
const auto qualifier = type->getQualifier(); qualifier) {
636 mData.Append(
GetName(*cxxRecordDecl));
642 bool HandleType(
const AutoType* type) {
return HandleType(type->getDeducedType().getTypePtrOrNull()); }
644 bool HandleType(
const SubstTemplateTypeParmType* type)
646 return HandleType(type->getReplacementType().getTypePtrOrNull());
649#if not IS_CLANG_NEWER_THAN(22)
650 bool HandleType(
const ElaboratedType* type)
653 ? IgnoreNamespace::No
654 : IgnoreNamespace::Yes;
656 mScope =
GetNestedName(type->getQualifier(), ignoreNamespace);
658 const bool ret = HandleType(type->getNamedType().getTypePtrOrNull());
665 bool HandleType(
const DependentTemplateSpecializationType* type)
668 GetNestedName(type->getDependentTemplateName().getQualifier()),
670 GetName(type->getDependentTemplateName()));
679 bool HandleType(
const DeducedTemplateSpecializationType* type)
681 return HandleType(type->getDeducedType().getTypePtrOrNull());
684 bool HandleType(
const TemplateSpecializationType* type)
686 if(type->getAsRecordDecl()) {
687#if IS_CLANG_NEWER_THAN(22)
689 const IgnoreNamespace ignoreNamespace =
691 : IgnoreNamespace::Yes;
698 GetGlobalAST().getCanonicalTagType(type->getAsRecordDecl()).getTypePtr()
700 type->getAsRecordDecl()->getTypeForDecl()
703 HandleType(type->getPointeeType().getTypePtrOrNull());
711 bool HandleType(
const MemberPointerType* type)
713 const auto* pointeeType{type->getPointeeType().getTypePtrOrNull()};
716 (not type->isMemberFunctionPointer() and (isa<TemplateTypeParmType>(pointeeType) or
717 isa<SubstTemplateTypeParmType>(pointeeType)))};
718 HandleType(pointeeType);
722 if(not type->isMemberFunctionPointer() and
723 (isa<TemplateTypeParmType>(pointeeType) or isa<SubstTemplateTypeParmType>(pointeeType))) {
728#if IS_CLANG_NEWER_THAN(20)
735 HandleType(type->getClass());
737 mData.Append(
"::*)"sv);
740 HandleTypeAfter(pointeeType);
745 bool HandleType(
const FunctionProtoType* type)
749 const bool ret = HandleType(type->getReturnType().getTypePtrOrNull());
750 mData.Append(
" ("sv);
755 bool HandleType(
const ParenType* type)
757 const bool ret = HandleType(type->getInnerType().getTypePtrOrNull());
758 if(not isa<FunctionType>(type->getInnerType())) {
765 void HandleTypeAfter(
const PointerType* type) { HandleTypeAfter(type->getPointeeType().getTypePtrOrNull()); }
767 void HandleTypeAfter(
const ParenType* type)
769 if(not isa<FunctionType>(type->getInnerType())) {
773 HandleTypeAfter(type->getInnerType().getTypePtrOrNull());
776 void HandleTypeAfter(
const FunctionProtoType* type)
781 mData.Append(
")("sv);
783 for(
OnceFalse needsComma{};
const auto& t : type->getParamTypes()) {
785 mData.Append(
", "sv);
788 HandleType(t.getTypePtrOrNull());
793 if(not type->getMethodQuals().empty()) {
794 mData.Append(
" "sv, type->getMethodQuals().getAsString());
801 bool HandleType(
const BuiltinType* type)
803 mData.Append(type->getName(mPrintingPolicy));
812#if IS_CLANG_NEWER_THAN(22)
813 bool HandleType(
const PredefinedSugarType* type)
816 mData.Append(type->desugar().getCanonicalType().getAsString(mPrintingPolicy));
822 bool HandleType(
const TypedefType* type)
824#if IS_CLANG_NEWER_THAN(22)
827 if(
const auto* tt = dyn_cast_or_null<ClassTemplateSpecializationDecl>(type->getDecl()->getDeclContext());
828 tt and not mPrintingPolicy.PrintAsCanonical and
829 (NestedNameSpecifier::Kind::Type == type->getQualifier().getKind()) and
830 llvm::any_of(tt->getTemplateArgs().asArray(),
831 [](
const auto& arg) { return TemplateArgument::Integral == arg.getKind(); })) {
837 mData.GetString().clear();
838 mData.Append(
GetScope(tt->getDeclContext(), RemoveCurrentScope::No),
842 type->getDecl()->getName());
848 if(
const auto* decl = type->getDecl()) {
849 return HandleType(decl->getUnderlyingType().getTypePtrOrNull());
852 return HandleType(type->getPointeeType().getTypePtrOrNull());
855#if IS_CLANG_NEWER_THAN(22)
856 bool HandleType(
const UsingType* type)
858 const auto* target = type->getDecl()->getTargetDecl();
861 if(
const auto nestedName =
GetNestedName(type->getQualifier()); not nestedName.empty()) {
862 mData.Append(nestedName, target->getName());
867 mData.Append(
GetScope(target->getDeclContext()), target->getName());
873 bool HandleType(
const ConstantArrayType* type)
876 bool scanningArrayDimension =
false;
877 if(not mScanningArrayDimension) {
878 mScanningArrayDimension =
true;
879 scanningArrayDimension =
true;
882 const bool ret = HandleType(type->getElementType().getTypePtrOrNull());
885 if(scanningArrayDimension) {
887 mData.Append(
"["sv,
GetSize(type),
"]"sv);
888 }
while((type = dyn_cast_or_null<ConstantArrayType>(type->getElementType().getTypePtrOrNull())));
890 mScanningArrayDimension =
false;
896 bool HandleType(
const PackExpansionType* type)
898 const bool ret = HandleType(type->getPattern().getTypePtrOrNull());
907 bool HandleType(
const DecltypeType* type)
911 if(not isa_and_nonnull<DecltypeType>(type->desugar().getTypePtrOrNull())) {
914 HandleType(type->desugar().getTypePtrOrNull());
921 if(not isa_and_nonnull<DeclRefExpr>(type->getUnderlyingExpr())) {
924 return not visitor.TraverseStmt(type->getUnderlyingExpr());
930 bool HandleType(
const Type* type)
932#define HANDLE_TYPE(t) \
934 return HandleType(dyn_cast_or_null<t>(type)); \
937 if(
nullptr == type) {
950#if not IS_CLANG_NEWER_THAN(22)
957#if IS_CLANG_NEWER_THAN(22)
961#if IS_CLANG_NEWER_THAN(22)
966#if not IS_CLANG_NEWER_THAN(22)
976 void HandleTypeAfter(
const Type* type)
978#define HANDLE_TYPE(t) \
980 HandleTypeAfter(dyn_cast_or_null<t>(type)); \
983 if(
nullptr != type) {
990 void AddCVQualifiers(
const Qualifiers& quals)
993 mData.Append(quals.getAsString());
995 if(not mData.empty() and not mSkipSpace) {
1004 , mPrintingPolicy{printingPolicy}
1012 if(
const SplitQualType splitted{mType.split()}; splitted.Quals.empty()) {
1013 const auto& canonicalType = mType.getCanonicalType();
1015 if(canonicalType->getPointeeType().getLocalFastQualifiers()) {
1016 AddCVQualifiers(canonicalType->getPointeeType().getLocalQualifiers());
1017 }
else if(canonicalType.getLocalFastQualifiers()) {
1018 AddCVQualifiers(canonicalType.getLocalQualifiers());
1021 AddCVQualifiers(splitted.Quals);
1024 const auto* typePtr = mType.getTypePtrOrNull();
1025 mHasData = HandleType(typePtr);
1026 mData.Append(mDataAfter);
1029 if(mType.getQualifiers().hasFastQualifiers()) {
1030 const QualType fastQualifierType{typePtr, mType.getQualifiers().getFastQualifiers()};
1033 AddCVQualifiers(fastQualifierType.getCanonicalType()->getPointeeType().getLocalQualifiers());
1103 if(not fd->param_empty()) {
1106 for(
const auto& param : fd->parameters()) {
1107 QualType t = param->getType();
1108 QualType plainType = t.getNonReferenceType();
1109 plainType.removeLocalConst();
1110 plainType.removeLocalVolatile();
1114 while(plainType->isPointerType()) {
1116 plainType = plainType->getPointeeType();
1118 auto quals = plainType.getQualifiers();
1119 auto lquals = plainType.getLocalQualifiers();
1121 if(quals.hasConst() or lquals.hasConst()) {
1125 plainType.removeLocalConst();
1128 if(t.isCanonical()) {
1129 t = t.getCanonicalType();
1132 if(plainType->isBuiltinType() and plainType->hasUnsignedIntegerRepresentation()) {
1133 std::string tmp{
GetName(plainType)};
1142 auto quals = t.getQualifiers();
1143 auto lquals = t.getLocalQualifiers();
1145 if(t->isPointerType()) {
1149 if(quals.hasConst() or lquals.hasConst()) {
1153 if(t->isLValueReferenceType()) {
1157 if(t->isRValueReferenceType()) {
1162 }
else if(
const auto* md = dyn_cast_or_null<CXXMethodDecl>(fd);
1164 name =
GetName(*md->getParent());
1449 const bool isFunctionPointer =
1450 HasTypeWithSubType<ReferenceType, FunctionProtoType>(t.getCanonicalType()) or
1451 HasTypeWithSubType<ReferenceType, PointerType, FunctionProtoType>(t.getCanonicalType());
1452 const bool isArrayRef = HasTypeWithSubType<ReferenceType, ArrayType>(t);
1454 const bool isAutoType = (
nullptr != dyn_cast_or_null<AutoType>(t.getTypePtrOrNull()));
1455 const auto pointerToArrayBaseType = isAutoType ? t->getContainedAutoType()->getDeducedType() : t;
1456 const bool isPointerToArray = HasTypeWithSubType<PointerType, ArrayType>(pointerToArrayBaseType);
1458 const bool isRawArrayType = t->isArrayType() and not(isa<TypedefType>(t)
1460 or isa<ElaboratedType>(t)
1462 or isa<UsingType>(t));
1468 auto getSpaceOrEmpty = [&](
const std::string_view& needle) -> std::string_view {
1469 if(not
Contains(typeName, needle)) {
1476 if(isRawArrayType and not t->isLValueReferenceType()) {
1477 const auto space = getSpaceOrEmpty(
" ["sv);
1480 }
else if(isArrayRef) {
1481 const bool isRValueRef{HasTypeWithSubType<RValueReferenceType, ArrayType>(t)};
1482 const std::string_view contains{isRValueRef ?
"(&&" :
"(&"};
1487 const std::string_view insertBefore{isRValueRef ?
"&&[" :
"&["};
1499 }
else if(isFunctionPointer) {
1500 const bool isRValueRef{HasTypeWithSubType<RValueReferenceType, FunctionProtoType>(t)};
1501 const auto contains{[&]() {
1506 else if(HasTypeWithSubType<LValueReferenceType, PointerType, FunctionProtoType>(t)) {
1516 typeName +=
StrCat(
" "sv, varName);
1519 }
else if(isa<MemberPointerType>(t)) {
1522 }
else if(isPointerToArray) {
1525 }
else if(
Contains(typeName,
"*"sv)) {
1529 }
else if(t->isFunctionPointerType()) {
1533 typeName +=
StrCat(
" "sv, varName);
1535 }
else if(HasTypePath<PointerType, ParenType>(t)) {
1538 }
else if(not isRawArrayType and not varName.empty()) {
1539 typeName +=
StrCat(
" "sv, varName);