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