bool BlinkGCPluginConsumer::DeclaresVirtualMethods(CXXRecordDecl* decl) { CXXRecordDecl::method_iterator it = decl->method_begin(); for (; it != decl->method_end(); ++it) if (it->isVirtual() && !it->isPure()) return true; return false; }
// 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); } } }
CXXMethodDecl* RecordInfo::DeclaresNewOperator() { for (CXXRecordDecl::method_iterator it = record_->method_begin(); it != record_->method_end(); ++it) { if (it->getNameAsString() == kNewOperatorName && it->getNumParams() == 1) return *it; } return 0; }
// A (non-virtual) class is considered abstract in Blink if it has // no public constructors and no create methods. bool RecordInfo::IsConsideredAbstract() { for (CXXRecordDecl::ctor_iterator it = record_->ctor_begin(); it != record_->ctor_end(); ++it) { if (!it->isCopyOrMoveConstructor() && it->getAccess() == AS_public) return false; } for (CXXRecordDecl::method_iterator it = record_->method_begin(); it != record_->method_end(); ++it) { if (it->getNameAsString() == kCreateName) return false; } return true; }
void RecordInfo::DetermineTracingMethods() { if (determined_trace_methods_) return; determined_trace_methods_ = true; if (Config::IsGCBase(name_)) return; CXXMethodDecl* trace = 0; CXXMethodDecl* traceAfterDispatch = 0; bool isTraceAfterDispatch; for (CXXRecordDecl::method_iterator it = record_->method_begin(); it != record_->method_end(); ++it) { if (Config::IsTraceMethod(*it, &isTraceAfterDispatch)) { if (isTraceAfterDispatch) { traceAfterDispatch = *it; } else { trace = *it; } } else if (it->getNameAsString() == kFinalizeName) { finalize_dispatch_method_ = *it; } } if (traceAfterDispatch) { trace_method_ = traceAfterDispatch; trace_dispatch_method_ = trace; } else { // TODO: Can we never have a dispatch method called trace without the same // class defining a traceAfterDispatch method? trace_method_ = trace; trace_dispatch_method_ = 0; } if (trace_dispatch_method_ && finalize_dispatch_method_) return; // If this class does not define dispatching methods inherit them. for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { // TODO: Does it make sense to inherit multiple dispatch methods? if (CXXMethodDecl* dispatch = it->second.info()->GetTraceDispatchMethod()) { assert(!trace_dispatch_method_ && "Multiple trace dispatching methods"); trace_dispatch_method_ = dispatch; } if (CXXMethodDecl* dispatch = it->second.info()->GetFinalizeDispatchMethod()) { assert(!finalize_dispatch_method_ && "Multiple finalize dispatching methods"); finalize_dispatch_method_ = dispatch; } } }
bool RecordInfo::IsNonNewable() { if (is_non_newable_ == kNotComputed) { bool deleted = false; bool all_deleted = true; for (CXXRecordDecl::method_iterator it = record_->method_begin(); it != record_->method_end(); ++it) { if (it->getNameAsString() == kNewOperatorName) { deleted = it->isDeleted(); all_deleted = all_deleted && deleted; } } is_non_newable_ = (deleted && all_deleted) ? kTrue : kFalse; } return is_non_newable_; }
bool RecordInfo::IsStackAllocated() { if (is_stack_allocated_ == kNotComputed) { is_stack_allocated_ = kFalse; for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { if (it->second.info()->IsStackAllocated()) { is_stack_allocated_ = kTrue; return is_stack_allocated_; } } for (CXXRecordDecl::method_iterator it = record_->method_begin(); it != record_->method_end(); ++it) { if (it->getNameAsString() == kNewOperatorName && it->isDeleted() && Config::IsStackAnnotated(*it)) { is_stack_allocated_ = kTrue; return is_stack_allocated_; } } } return is_stack_allocated_; }
bool RecordInfo::IsOnlyPlacementNewable() { if (is_only_placement_newable_ == kNotComputed) { bool placement = false; bool new_deleted = false; for (CXXRecordDecl::method_iterator it = record_->method_begin(); it != record_->method_end(); ++it) { if (it->getNameAsString() == kNewOperatorName) { if (it->getNumParams() == 1) { new_deleted = it->isDeleted(); } else if (it->getNumParams() == 2) { placement = !it->isDeleted(); } } } is_only_placement_newable_ = (placement && new_deleted) ? kTrue : kFalse; } return is_only_placement_newable_; }
void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, bool VirtualBase, const CXXRecordDecl *InVirtualSubobject, CXXFinalOverriderMap &Overriders) { unsigned SubobjectNumber = 0; if (!VirtualBase) SubobjectNumber = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())]; for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); if (!BaseDecl->isPolymorphic()) continue; if (Overriders.empty() && !Base->isVirtual()) { // There are no other overriders of virtual member functions, // so let the base class fill in our overriders for us. Collect(BaseDecl, false, InVirtualSubobject, Overriders); continue; } // Collect all of the overridders from the base class subobject // and merge them into the set of overridders for this class. // For virtual base classes, populate or use the cached virtual // overrides so that we do not walk the virtual base class (and // its base classes) more than once. CXXFinalOverriderMap ComputedBaseOverriders; CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders; if (Base->isVirtual()) { CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl]; BaseOverriders = MyVirtualOverriders; if (!MyVirtualOverriders) { MyVirtualOverriders = new CXXFinalOverriderMap; // Collect may cause VirtualOverriders to reallocate, invalidating the // MyVirtualOverriders reference. Set BaseOverriders to the right // value now. BaseOverriders = MyVirtualOverriders; Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders); } } else Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders); // Merge the overriders from this base class into our own set of // overriders. for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(), OMEnd = BaseOverriders->end(); OM != OMEnd; ++OM) { const CXXMethodDecl *CanonOM = cast<CXXMethodDecl>(OM->first->getCanonicalDecl()); Overriders[CanonOM].add(OM->second); } } } for (CXXRecordDecl::method_iterator M = RD->method_begin(), MEnd = RD->method_end(); M != MEnd; ++M) { // We only care about virtual methods. if (!M->isVirtual()) continue; CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl()); if (CanonM->begin_overridden_methods() == CanonM->end_overridden_methods()) { // This is a new virtual function that does not override any // other virtual function. Add it to the map of virtual // functions for which we are tracking overridders. // C++ [class.virtual]p2: // For convenience we say that any virtual function overrides itself. Overriders[CanonM].add(SubobjectNumber, UniqueVirtualMethod(CanonM, SubobjectNumber, InVirtualSubobject)); continue; } // This virtual method overrides other virtual methods, so it does // not add any new slots into the set of overriders. Instead, we // replace entries in the set of overriders with the new // overrider. To do so, we dig down to the original virtual // functions using data recursion and update all of the methods it // overrides. typedef std::pair<CXXMethodDecl::method_iterator, CXXMethodDecl::method_iterator> OverriddenMethods; SmallVector<OverriddenMethods, 4> Stack; Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(), CanonM->end_overridden_methods())); while (!Stack.empty()) { OverriddenMethods OverMethods = Stack.back(); Stack.pop_back(); for (; OverMethods.first != OverMethods.second; ++OverMethods.first) { const CXXMethodDecl *CanonOM = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl()); // C++ [class.virtual]p2: // A virtual member function C::vf of a class object S is // a final overrider unless the most derived class (1.8) // of which S is a base class subobject (if any) declares // or inherits another member function that overrides vf. // // Treating this object like the most derived class, we // replace any overrides from base classes with this // overriding virtual function. Overriders[CanonOM].replaceAll( UniqueVirtualMethod(CanonM, SubobjectNumber, InVirtualSubobject)); if (CanonOM->begin_overridden_methods() == CanonOM->end_overridden_methods()) continue; // Continue recursion to the methods that this virtual method // overrides. Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(), CanonOM->end_overridden_methods())); } } // C++ [class.virtual]p2: // For convenience we say that any virtual function overrides itself. Overriders[CanonM].add(SubobjectNumber, UniqueVirtualMethod(CanonM, SubobjectNumber, InVirtualSubobject)); } }