// Makes sure there is a "virtual" keyword on virtual methods. // // Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a // trick to get around that. If a class has member variables whose types are // in the "testing" namespace (which is how gmock works behind the scenes), // there's a really high chance we won't care about these errors void FindBadConstructsConsumer::CheckVirtualMethods( SourceLocation record_location, CXXRecordDecl* record, bool warn_on_inline_bodies) { for (CXXRecordDecl::field_iterator it = record->field_begin(); it != record->field_end(); ++it) { CXXRecordDecl* record_type = it->getTypeSourceInfo() ->getTypeLoc() .getTypePtr() ->getAsCXXRecordDecl(); if (record_type) { if (InTestingNamespace(record_type)) { return; } } } for (CXXRecordDecl::method_iterator it = record->method_begin(); it != record->method_end(); ++it) { if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) { // Ignore constructors and assignment operators. } else if (isa<CXXDestructorDecl>(*it) && !record->hasUserDeclaredDestructor()) { // Ignore non-user-declared destructors. } else { CheckVirtualMethod(*it, warn_on_inline_bodies); CheckOverriddenMethod(*it); } } }
static bool canGenerateCXXConstructor(const CXXConstructorDecl *D, ASTContext &Context) { const CXXRecordDecl *RD = D->getParent(); // The class has base classes - we don't support that right now. if (RD->getNumBases() > 0) return false; for (CXXRecordDecl::field_iterator I = RD->field_begin(Context), E = RD->field_end(Context); I != E; ++I) { // We don't support ctors for fields that aren't POD. if (!I->getType()->isPODType()) return false; } return true; }
/// Try to emit a base destructor as an alias to its primary /// base-class destructor. bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { if (!getCodeGenOpts().CXXCtorDtorAliases) return true; // Producing an alias to a base class ctor/dtor can degrade debug quality // as the debugger cannot tell them apart. if (getCodeGenOpts().OptimizationLevel == 0) return true; // If the destructor doesn't have a trivial body, we have to emit it // separately. if (!D->hasTrivialBody()) return true; const CXXRecordDecl *Class = D->getParent(); // If we need to manipulate a VTT parameter, give up. if (Class->getNumVBases()) { // Extra Credit: passing extra parameters is perfectly safe // in many calling conventions, so only bail out if the ctor's // calling convention is nonstandard. return true; } // If any field has a non-trivial destructor, we have to emit the // destructor separately. for (CXXRecordDecl::field_iterator I = Class->field_begin(), E = Class->field_end(); I != E; ++I) if (I->getType().isDestructedType()) return true; // Try to find a unique base class with a non-trivial destructor. const CXXRecordDecl *UniqueBase = 0; for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), E = Class->bases_end(); I != E; ++I) { // We're in the base destructor, so skip virtual bases. if (I->isVirtual()) continue; // Skip base classes with trivial destructors. const CXXRecordDecl *Base = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); if (Base->hasTrivialDestructor()) continue; // If we've already found a base class with a non-trivial // destructor, give up. if (UniqueBase) return true; UniqueBase = Base; } // If we didn't find any bases with a non-trivial destructor, then // the base destructor is actually effectively trivial, which can // happen if it was needlessly user-defined or if there are virtual // bases with non-trivial destructors. if (!UniqueBase) return true; // If the base is at a non-zero offset, give up. const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class); if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero()) return true; const CXXDestructorDecl *BaseD = UniqueBase->getDestructor(); return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base), GlobalDecl(BaseD, Dtor_Base), false); }