FindBadConstructs.cpp revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file defines a bunch of recurring problems in the Chromium C++ code. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks that are implemented: 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Constructors/Destructors should not be inlined if they are of a complex 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// class type. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Missing "virtual" keywords on methods that should be virtual. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Non-annotated overriding virtual methods. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Virtual methods with nonempty implementations in their headers. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Classes that derive from base::RefCounted / base::RefCountedThreadSafe 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// should have protected or private destructors. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Frontend/FrontendPluginRegistry.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/ASTConsumer.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/AST.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/CXXInheritance.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/TypeLoc.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Basic/SourceManager.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Frontend/CompilerInstance.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/raw_ostream.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ChromeClassTester.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypeHasNonTrivialDtor(const Type* type) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (const CXXRecordDecl* cxx_r = type->getPointeeCXXRecordDecl()) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cxx_r->hasTrivialDestructor(); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the underlying Type for |type| by expanding typedefs and removing 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// any namespace qualifiers. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const Type* UnwrapType(const Type* type) { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return UnwrapType(elaborated->getNamedType().getTypePtr()); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return UnwrapType(typedefed->desugar().getTypePtr()); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return type; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Searches for constructs that we know we don't want in the Chromium code base. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FindBadConstructsConsumer : public ChromeClassTester { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindBadConstructsConsumer(CompilerInstance& instance, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool check_refcounted_dtors, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool check_virtuals_in_implementations) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : ChromeClassTester(instance), 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) check_refcounted_dtors_(check_refcounted_dtors), 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) check_virtuals_in_implementations_(check_virtuals_in_implementations) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void CheckChromeClass(SourceLocation record_location, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool implementation_file = InImplementationFile(record_location); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!implementation_file) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only check for "heavy" constructors/destructors in header files; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // within implementation files, there is no performance cost. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckCtorDtorWeight(record_location, record); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!implementation_file || check_virtuals_in_implementations_) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool warn_on_inline_bodies = !implementation_file; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check that all virtual methods are marked accordingly with both 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // virtual and OVERRIDE. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckVirtualMethods(record_location, record, warn_on_inline_bodies); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (check_refcounted_dtors_) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckRefCountedDtors(record_location, record); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool check_refcounted_dtors_; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool check_virtuals_in_implementations_; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if |base| specifies one of the Chromium reference counted 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // classes (base::RefCounted / base::RefCountedThreadSafe). |user_data| is 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ignored. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool IsRefCountedCallback(const CXXBaseSpecifier* base, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXBasePath& path, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* user_data) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindBadConstructsConsumer* self = 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<FindBadConstructsConsumer*>(user_data); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TemplateSpecializationType* base_type = 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dyn_cast<TemplateSpecializationType>( 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnwrapType(base->getType().getTypePtr())); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base_type) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Base-most definition is not a template, so this cannot derive from 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // base::RefCounted. However, it may still be possible to use with a 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // scoped_refptr<> and support ref-counting, so this is not a perfect 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // guarantee of safety. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TemplateName name = base_type->getTemplateName(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (TemplateDecl* decl = name.getAsTemplateDecl()) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string base_name = decl->getNameAsString(); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check for both base::RefCounted and base::RefCountedThreadSafe. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base_name.compare(0, 10, "RefCounted") == 0 && 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self->GetNamespace(decl) == "base") { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prints errors if the destructor of a RefCounted class is public. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckRefCountedDtors(SourceLocation record_location, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip anonymous structs. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (record->getIdentifier() == NULL) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXBasePaths paths; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!record->lookupInBases( 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &FindBadConstructsConsumer::IsRefCountedCallback, this, paths)) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Class does not derive from a ref-counted base class. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!record->hasUserDeclaredDestructor()) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning( 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) record_location, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Classes that are ref-counted should have explicit " 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "destructors that are protected or private."); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (CXXDestructorDecl* dtor = record->getDestructor()) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dtor->getAccess() == AS_public) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning( 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dtor->getInnerLocStart(), 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Classes that are ref-counted should not have " 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "public destructors."); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prints errors if the constructor/destructor weight is too heavy. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckCtorDtorWeight(SourceLocation record_location, 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't handle anonymous structs. If this record doesn't have a 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // name, it's of the form: 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // struct { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ... 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // } name_; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (record->getIdentifier() == NULL) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Count the number of templated base classes as a feature of whether the 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destructor can be inlined. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int templated_base_classes = 0; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::base_class_const_iterator it = record->bases_begin(); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->bases_end(); ++it) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->getTypeSourceInfo()->getTypeLoc().getTypeLocClass() == 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeLoc::TemplateSpecialization) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++templated_base_classes; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Count the number of trivial and non-trivial member variables. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int trivial_member = 0; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int non_trivial_member = 0; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int templated_non_trivial_member = 0; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (RecordDecl::field_iterator it = record->field_begin(); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->field_end(); ++it) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountType(it->getType().getTypePtr(), 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &trivial_member, 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &non_trivial_member, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &templated_non_trivial_member); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if we need to ban inlined/synthesized constructors. Note 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that the cutoffs here are kind of arbitrary. Scores over 10 break. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int dtor_score = 0; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Deriving from a templated base class shouldn't be enough to trigger 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the ctor warning, but if you do *anything* else, it should. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(erg): This is motivated by templated base classes that don't have 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // any data members. Somehow detect when templated base classes have data 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // members and treat them differently. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dtor_score += templated_base_classes * 9; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Instantiating a template is an insta-hit. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dtor_score += templated_non_trivial_member * 10; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The fourth normal class member should trigger the warning. 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dtor_score += non_trivial_member * 3; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ctor_score = dtor_score; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // You should be able to have 9 ints before we warn you. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctor_score += trivial_member; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctor_score >= 10) { 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!record->hasUserDeclaredConstructor()) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(record_location, 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex class/struct needs an explicit out-of-line " 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "constructor."); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate across all the constructors in this file and yell if we 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // find one that tries to be inline. 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::ctor_iterator it = record->ctor_begin(); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->ctor_end(); ++it) { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->hasInlineBody()) { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->isCopyConstructor() && 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !record->hasUserDeclaredCopyConstructor()) { 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(record_location, 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex class/struct needs an explicit out-of-line " 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "copy constructor."); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(it->getInnerLocStart(), 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex constructor has an inlined body."); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The destructor side is equivalent except that we don't check for 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trivial members; 20 ints don't need a destructor. 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dtor_score >= 10 && !record->hasTrivialDestructor()) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!record->hasUserDeclaredDestructor()) { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning( 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) record_location, 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex class/struct needs an explicit out-of-line " 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "destructor."); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (CXXDestructorDecl* dtor = record->getDestructor()) { 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dtor->hasInlineBody()) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(dtor->getInnerLocStart(), 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex destructor has an inline body."); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckVirtualMethod(const CXXMethodDecl* method, 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool warn_on_inline_bodies) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!method->isVirtual()) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!method->isVirtualAsWritten()) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SourceLocation loc = method->getTypeSpecStartLoc(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isa<CXXDestructorDecl>(method)) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loc = method->getInnerLocStart(); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(loc, "Overriding method must have \"virtual\" keyword."); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Virtual methods should not have inline definitions beyond "{}". This 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only matters for header files. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (warn_on_inline_bodies && method->hasBody() && 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) method->hasInlineBody()) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cs->size()) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning( 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cs->getLBracLoc(), 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "virtual methods with non-empty bodies shouldn't be " 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "declared inline."); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool InTestingNamespace(const Decl* record) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetNamespace(record).find("testing") != std::string::npos; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsMethodInBannedNamespace(const CXXMethodDecl* method) { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InBannedNamespace(method)) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods(); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != method->end_overridden_methods(); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++i) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CXXMethodDecl* overridden = *i; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsMethodInBannedNamespace(overridden)) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckOverriddenMethod(const CXXMethodDecl* method) { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!method->size_overridden_methods() || method->getAttr<OverrideAttr>()) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isa<CXXDestructorDecl>(method) || method->isPure()) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsMethodInBannedNamespace(method)) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SourceLocation loc = method->getTypeSpecStartLoc(); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(loc, "Overriding method must be marked with OVERRIDE."); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Makes sure there is a "virtual" keyword on virtual methods. 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trick to get around that. If a class has member variables whose types are 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in the "testing" namespace (which is how gmock works behind the scenes), 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there's a really high chance we won't care about these errors 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckVirtualMethods(SourceLocation record_location, 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record, 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool warn_on_inline_bodies) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::field_iterator it = record->field_begin(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->field_end(); ++it) { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record_type = 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->getTypeSourceInfo()->getTypeLoc().getTypePtr()-> 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getAsCXXRecordDecl(); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (record_type) { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InTestingNamespace(record_type)) { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::method_iterator it = record->method_begin(); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->method_end(); ++it) { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore constructors and assignment operators. 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (isa<CXXDestructorDecl>(*it) && 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !record->hasUserDeclaredDestructor()) { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore non-user-declared destructors. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckVirtualMethod(*it, warn_on_inline_bodies); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckOverriddenMethod(*it); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CountType(const Type* type, 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* trivial_member, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* non_trivial_member, 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* templated_non_trivial_member) { 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type->getTypeClass()) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::Record: { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Simplifying; the whole class isn't trivial if the dtor is, but 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we use this as a signal about complexity. 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (TypeHasNonTrivialDtor(type)) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*trivial_member)++; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*non_trivial_member)++; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::TemplateSpecialization: { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TemplateName name = 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dyn_cast<TemplateSpecializationType>(type)->getTemplateName(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool whitelisted_template = false; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HACK: I'm at a loss about how to get the syntax checker to get 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whether a template is exterened or not. For the first pass here, 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just do retarded string comparisons. 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (TemplateDecl* decl = name.getAsTemplateDecl()) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string base_name = decl->getNameAsString(); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base_name == "basic_string") 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) whitelisted_template = true; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (whitelisted_template) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*non_trivial_member)++; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*templated_non_trivial_member)++; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::Elaborated: { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountType( 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dyn_cast<ElaboratedType>(type)->getNamedType().getTypePtr(), 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trivial_member, non_trivial_member, templated_non_trivial_member); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::Typedef: { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (const TypedefType* TT = dyn_cast<TypedefType>(type)) { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = TT->getDecl()->getUnderlyingType().getTypePtr(); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountType(type, trivial_member, non_trivial_member, 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) templated_non_trivial_member); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stupid assumption: anything we see that isn't the above is one of 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the 20 integer types. 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*trivial_member)++; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FindBadConstructsAction : public PluginASTAction { 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindBadConstructsAction() 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : check_refcounted_dtors_(true), 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) check_virtuals_in_implementations_(true) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from PluginASTAction: 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance, 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::StringRef ref) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new FindBadConstructsConsumer( 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instance, check_refcounted_dtors_, check_virtuals_in_implementations_); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool ParseArgs(const CompilerInstance& instance, 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& args) { 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool parsed = true; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < args.size() && parsed; ++i) { 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (args[i] == "skip-refcounted-dtors") { 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) check_refcounted_dtors_ = false; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (args[i] == "skip-virtuals-in-implementations") { 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) check_virtuals_in_implementations_ = false; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parsed = false; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return parsed; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool check_refcounted_dtors_; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool check_virtuals_in_implementations_; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static FrontendPluginRegistry::Add<FindBadConstructsAction> 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)X("find-bad-constructs", "Finds bad C++ constructs"); 436