================ @@ -64,39 +64,117 @@ static bool hasOptionalClassName(const CXXRecordDecl &RD) { return false; } +static const CXXRecordDecl *getOptionalBaseClass(const CXXRecordDecl *RD) { + if (RD == nullptr) + return nullptr; + if (hasOptionalClassName(*RD)) + return RD; + + if (!RD->hasDefinition()) + return nullptr; + + for (const CXXBaseSpecifier &Base : RD->bases()) + if (const CXXRecordDecl *BaseClass = + getOptionalBaseClass(Base.getType()->getAsCXXRecordDecl())) + return BaseClass; + + return nullptr; +} + namespace { using namespace ::clang::ast_matchers; using LatticeTransferState = TransferState<NoopLattice>; -AST_MATCHER(CXXRecordDecl, hasOptionalClassNameMatcher) { - return hasOptionalClassName(Node); +AST_MATCHER(CXXRecordDecl, optionalClass) { return hasOptionalClassName(Node); } + +AST_MATCHER(CXXRecordDecl, optionalOrDerivedClass) { + return getOptionalBaseClass(&Node) != nullptr; } -DeclarationMatcher optionalClass() { - return classTemplateSpecializationDecl( - hasOptionalClassNameMatcher(), - hasTemplateArgument(0, refersToType(type().bind("T")))); +auto desugarsToOptionalType() { + return hasUnqualifiedDesugaredType( + recordType(hasDeclaration(cxxRecordDecl(optionalClass())))); } -auto optionalOrAliasType() { +auto desugarsToOptionalOrDerivedType() { return hasUnqualifiedDesugaredType( - recordType(hasDeclaration(optionalClass()))); + recordType(hasDeclaration(cxxRecordDecl(optionalOrDerivedClass())))); } -/// Matches any of the spellings of the optional types and sugar, aliases, etc. -auto hasOptionalType() { return hasType(optionalOrAliasType()); } +auto hasOptionalType() { return hasType(desugarsToOptionalType()); } + +/// Matches any of the spellings of the optional types and sugar, aliases, +/// derived classes, etc. +auto hasOptionalOrDerivedType() { + return hasType(desugarsToOptionalOrDerivedType()); +} + +QualType getPublicType(const Expr *E) { + auto *Cast = dyn_cast<ImplicitCastExpr>(E->IgnoreParens()); + if (Cast == nullptr || Cast->getCastKind() != CK_UncheckedDerivedToBase) { + QualType Ty = E->getType(); + if (Ty->isPointerType()) + return Ty->getPointeeType(); + return Ty; + } + + QualType Ty = getPublicType(Cast->getSubExpr()); + + // Is `Ty` the type of `*this`? In this special case, we can upcast to the + // base class even if the base is non-public. + bool TyIsThisType = isa<CXXThisExpr>(Cast->getSubExpr()); + + for (const CXXBaseSpecifier *Base : Cast->path()) { + if (Base->getAccessSpecifier() != AS_public && !TyIsThisType) + break; + Ty = Base->getType(); + TyIsThisType = false; + } ---------------- ymand wrote:
Yes, very clear now. Thanks! https://github.com/llvm/llvm-project/pull/84138 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits