bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, const ASTContext &Context) { const auto *ClassDecl = dyn_cast<CXXRecordDecl>(&RecordDecl); // Non-C++ records are always trivially constructible. if (!ClassDecl) return true; // A class with a user-provided default constructor is not trivially // constructible. if (ClassDecl->hasUserProvidedDefaultConstructor()) return false; // A class is trivially constructible if it has a trivial default constructor. if (ClassDecl->hasTrivialDefaultConstructor()) return true; // If all its fields are trivially constructible. for (const FieldDecl *Field : ClassDecl->fields()) { if (!isTriviallyDefaultConstructible(Field->getType(), Context)) return false; } // If all its direct bases are trivially constructible. for (const CXXBaseSpecifier &Base : ClassDecl->bases()) { if (!isTriviallyDefaultConstructible(Base.getType(), Context)) return false; } return true; }
// Based on QualType::isTrivial. bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { if (Type.isNull()) return false; if (Type->isArrayType()) return isTriviallyDefaultConstructible(Context.getBaseElementType(Type), Context); // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if (Type->isIncompleteType()) return false; if (Context.getLangOpts().ObjCAutoRefCount) { switch (Type.getObjCLifetime()) { case Qualifiers::OCL_ExplicitNone: return true; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return false; case Qualifiers::OCL_None: if (Type->isObjCLifetimeType()) return false; break; } } QualType CanonicalType = Type.getCanonicalType(); if (CanonicalType->isDependentType()) return false; // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs<RecordType>()) { return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context); } // No other types can match. return false; }
void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) { auto Construct = cxxConstructExpr( hasDeclaration(cxxConstructorDecl(hasParent( cxxRecordDecl(unless(isTriviallyDefaultConstructible())))))) .bind("construct"); Finder->addMatcher( cxxConstructorDecl( unless(isDelegatingConstructor()), ofClass(unless( anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))), forEachConstructorInitializer( cxxCtorInitializer(isWritten(), withInitializer(ignoringImplicit(Construct)), unless(forField(hasType(isConstQualified())))) .bind("init"))), this); }