16d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
26d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
36d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// found in the LICENSE file.
46d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
56d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "FindBadConstructsConsumer.h"
66d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
76d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "clang/Frontend/CompilerInstance.h"
86d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "clang/Lex/Lexer.h"
96d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "llvm/Support/raw_ostream.h"
106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)using namespace clang;
126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)namespace chrome_checker {
146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)namespace {
166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kMethodRequiresOverride[] =
186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] Overriding method must be marked with OVERRIDE.";
196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kMethodRequiresVirtual[] =
206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] Overriding method must have \"virtual\" keyword.";
216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kNoExplicitDtor[] =
226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] Classes that are ref-counted should have explicit "
236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "destructors that are declared protected or private.";
246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kPublicDtor[] =
256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] Classes that are ref-counted should have "
266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "destructors that are declared protected or private.";
276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kProtectedNonVirtualDtor[] =
286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] Classes that are ref-counted and have non-private "
296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "destructors should declare their destructor virtual.";
306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kWeakPtrFactoryOrder[] =
316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] WeakPtrFactory members which refer to their outer class "
326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "must be the last member in the outer class definition.";
336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kBadLastEnumValue[] =
346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] _LAST/Last constants of enum types must have the maximal "
356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "value for any constant of that type.";
366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kNoteInheritance[] = "[chromium-style] %0 inherits from %1 here";
376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kNoteImplicitDtor[] =
386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] No explicit destructor for %0 defined";
396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kNotePublicDtor[] =
406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] Public destructor declared here";
416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kNoteProtectedNonVirtualDtor[] =
426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    "[chromium-style] Protected non-virtual destructor declared here";
436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool TypeHasNonTrivialDtor(const Type* type) {
456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (const CXXRecordDecl* cxx_r = type->getPointeeCXXRecordDecl())
466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return !cxx_r->hasTrivialDestructor();
476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return false;
496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Returns the underlying Type for |type| by expanding typedefs and removing
526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// any namespace qualifiers. This is similar to desugaring, except that for
536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// ElaboratedTypes, desugar will unwrap too much.
546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const Type* UnwrapType(const Type* type) {
556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type))
566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return UnwrapType(elaborated->getNamedType().getTypePtr());
576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (const TypedefType* typedefed = dyn_cast<TypedefType>(type))
586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return UnwrapType(typedefed->desugar().getTypePtr());
596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return type;
606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}  // namespace
636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)FindBadConstructsConsumer::FindBadConstructsConsumer(CompilerInstance& instance,
656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                     const Options& options)
666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    : ChromeClassTester(instance), options_(options) {
676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Register warning/error messages.
686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_method_requires_override_ =
696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresOverride);
706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_method_requires_virtual_ =
716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresVirtual);
726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_no_explicit_dtor_ =
736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(getErrorLevel(), kNoExplicitDtor);
746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_public_dtor_ =
756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(getErrorLevel(), kPublicDtor);
766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_protected_non_virtual_dtor_ =
776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(getErrorLevel(), kProtectedNonVirtualDtor);
786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_weak_ptr_factory_order_ =
796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(getErrorLevel(), kWeakPtrFactoryOrder);
806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_bad_enum_last_value_ =
816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(getErrorLevel(), kBadLastEnumValue);
826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Registers notes to make it easier to interpret warnings.
846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_note_inheritance_ =
856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNoteInheritance);
866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_note_implicit_dtor_ =
876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNoteImplicitDtor);
886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_note_public_dtor_ =
896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNotePublicDtor);
906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID(
916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor);
926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckChromeClass(SourceLocation record_location,
956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                 CXXRecordDecl* record) {
966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  bool implementation_file = InImplementationFile(record_location);
976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!implementation_file) {
996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // Only check for "heavy" constructors/destructors in header files;
1006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // within implementation files, there is no performance cost.
1016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CheckCtorDtorWeight(record_location, record);
1026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool warn_on_inline_bodies = !implementation_file;
1056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Check that all virtual methods are marked accordingly with both
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // virtual and OVERRIDE.
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CheckVirtualMethods(record_location, record, warn_on_inline_bodies);
1096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  CheckRefCountedDtors(record_location, record);
1116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (options_.check_weak_ptr_factory_order)
1136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CheckWeakPtrFactoryMembers(record_location, record);
1146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckChromeEnum(SourceLocation enum_location,
1176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                EnumDecl* enum_decl) {
1186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!options_.check_enum_last_value)
1196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
1206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  bool got_one = false;
1226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  bool is_signed = false;
1236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  llvm::APSInt max_so_far;
1246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  EnumDecl::enumerator_iterator iter;
1256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (iter = enum_decl->enumerator_begin();
1266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       iter != enum_decl->enumerator_end();
1276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++iter) {
1286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    llvm::APSInt current_value = iter->getInitVal();
1296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (!got_one) {
1306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      max_so_far = current_value;
1316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      is_signed = current_value.isSigned();
1326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      got_one = true;
1336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    } else {
1346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (is_signed != current_value.isSigned()) {
1356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        // This only happens in some cases when compiling C (not C++) files,
1366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        // so it is OK to bail out here.
1376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        return;
1386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
1396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (current_value > max_so_far)
1406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        max_so_far = current_value;
1416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
1426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (iter = enum_decl->enumerator_begin();
1446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       iter != enum_decl->enumerator_end();
1456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++iter) {
1466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    std::string name = iter->getNameAsString();
1476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (((name.size() > 4 && name.compare(name.size() - 4, 4, "Last") == 0) ||
1486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)         (name.size() > 5 && name.compare(name.size() - 5, 5, "_LAST") == 0)) &&
1496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        iter->getInitVal() < max_so_far) {
1506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().Report(iter->getLocation(), diag_bad_enum_last_value_);
1516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
1526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckCtorDtorWeight(
1566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation record_location,
1576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CXXRecordDecl* record) {
1586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // We don't handle anonymous structs. If this record doesn't have a
1596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // name, it's of the form:
1606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //
1616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // struct {
1626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //   ...
1636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // } name_;
1646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (record->getIdentifier() == NULL)
1656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
1666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Count the number of templated base classes as a feature of whether the
1686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // destructor can be inlined.
1696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int templated_base_classes = 0;
1706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (CXXRecordDecl::base_class_const_iterator it = record->bases_begin();
1716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       it != record->bases_end();
1726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++it) {
1736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (it->getTypeSourceInfo()->getTypeLoc().getTypeLocClass() ==
1746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        TypeLoc::TemplateSpecialization) {
1756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      ++templated_base_classes;
1766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
1776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Count the number of trivial and non-trivial member variables.
1806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int trivial_member = 0;
1816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int non_trivial_member = 0;
1826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int templated_non_trivial_member = 0;
1836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (RecordDecl::field_iterator it = record->field_begin();
1846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       it != record->field_end();
1856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++it) {
1866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CountType(it->getType().getTypePtr(),
1876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)              &trivial_member,
1886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)              &non_trivial_member,
1896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)              &templated_non_trivial_member);
1906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Check to see if we need to ban inlined/synthesized constructors. Note
1936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // that the cutoffs here are kind of arbitrary. Scores over 10 break.
1946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int dtor_score = 0;
1956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Deriving from a templated base class shouldn't be enough to trigger
1966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // the ctor warning, but if you do *anything* else, it should.
1976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //
1986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // TODO(erg): This is motivated by templated base classes that don't have
1996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // any data members. Somehow detect when templated base classes have data
2006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // members and treat them differently.
2016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  dtor_score += templated_base_classes * 9;
2026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Instantiating a template is an insta-hit.
2036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  dtor_score += templated_non_trivial_member * 10;
2046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // The fourth normal class member should trigger the warning.
2056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  dtor_score += non_trivial_member * 3;
2066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int ctor_score = dtor_score;
2086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // You should be able to have 9 ints before we warn you.
2096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ctor_score += trivial_member;
2106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (ctor_score >= 10) {
2126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (!record->hasUserDeclaredConstructor()) {
2136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      emitWarning(record_location,
2146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                  "Complex class/struct needs an explicit out-of-line "
2156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                  "constructor.");
2166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    } else {
2176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // Iterate across all the constructors in this file and yell if we
2186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // find one that tries to be inline.
2196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      for (CXXRecordDecl::ctor_iterator it = record->ctor_begin();
2206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)           it != record->ctor_end();
2216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)           ++it) {
2226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        if (it->hasInlineBody()) {
2236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          if (it->isCopyConstructor() &&
2246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)              !record->hasUserDeclaredCopyConstructor()) {
2256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)            emitWarning(record_location,
2266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                        "Complex class/struct needs an explicit out-of-line "
2276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                        "copy constructor.");
2286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          } else {
2296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)            emitWarning(it->getInnerLocStart(),
2306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                        "Complex constructor has an inlined body.");
2316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          }
2326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        }
2336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
2346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
2356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
2366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // The destructor side is equivalent except that we don't check for
2386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // trivial members; 20 ints don't need a destructor.
2396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (dtor_score >= 10 && !record->hasTrivialDestructor()) {
2406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (!record->hasUserDeclaredDestructor()) {
2416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      emitWarning(record_location,
2426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                  "Complex class/struct needs an explicit out-of-line "
2436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                  "destructor.");
2446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    } else if (CXXDestructorDecl* dtor = record->getDestructor()) {
2456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (dtor->hasInlineBody()) {
2466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        emitWarning(dtor->getInnerLocStart(),
2476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                    "Complex destructor has an inline body.");
2486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
2496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
2506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
2516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
2526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckVirtualMethod(const CXXMethodDecl* method,
2546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                   bool warn_on_inline_bodies) {
2556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!method->isVirtual())
2566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
2576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!method->isVirtualAsWritten()) {
2596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation loc = method->getTypeSpecStartLoc();
2606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (isa<CXXDestructorDecl>(method))
2616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      loc = method->getInnerLocStart();
2626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceManager& manager = instance().getSourceManager();
2636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    FullSourceLoc full_loc(loc, manager);
2646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation spelling_loc = manager.getSpellingLoc(loc);
2656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    diagnostic().Report(full_loc, diag_method_requires_virtual_)
2666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        << FixItHint::CreateInsertion(spelling_loc, "virtual ");
2676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
2686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Virtual methods should not have inline definitions beyond "{}". This
2706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // only matters for header files.
2716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (warn_on_inline_bodies && method->hasBody() && method->hasInlineBody()) {
2726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) {
2736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (cs->size()) {
2746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        emitWarning(cs->getLBracLoc(),
2756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                    "virtual methods with non-empty bodies shouldn't be "
2766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                    "declared inline.");
2776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
2786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
2796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
2806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
2816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool FindBadConstructsConsumer::InTestingNamespace(const Decl* record) {
2836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return GetNamespace(record).find("testing") != std::string::npos;
2846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
2856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool FindBadConstructsConsumer::IsMethodInBannedOrTestingNamespace(
2876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const CXXMethodDecl* method) {
2886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (InBannedNamespace(method))
2896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return true;
2906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods();
2916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       i != method->end_overridden_methods();
2926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++i) {
2936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const CXXMethodDecl* overridden = *i;
2946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (IsMethodInBannedOrTestingNamespace(overridden) ||
2956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        InTestingNamespace(overridden)) {
2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return true;
2976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
2986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
2996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return false;
3016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
3026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckOverriddenMethod(
3046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const CXXMethodDecl* method) {
3056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!method->size_overridden_methods() || method->getAttr<OverrideAttr>())
3066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
3076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (isa<CXXDestructorDecl>(method) || method->isPure())
3096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
3106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (IsMethodInBannedOrTestingNamespace(method))
3126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
3136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SourceManager& manager = instance().getSourceManager();
3156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SourceRange type_info_range =
3166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      method->getTypeSourceInfo()->getTypeLoc().getSourceRange();
3176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  FullSourceLoc loc(type_info_range.getBegin(), manager);
3186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Build the FixIt insertion point after the end of the method definition,
3206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // including any const-qualifiers and attributes, and before the opening
3216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // of the l-curly-brace (if inline) or the semi-color (if a declaration).
3226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SourceLocation spelling_end =
3236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      manager.getSpellingLoc(type_info_range.getEnd());
3246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (spelling_end.isValid()) {
3256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation token_end =
3266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        Lexer::getLocForEndOfToken(spelling_end, 0, manager, LangOptions());
3276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    diagnostic().Report(token_end, diag_method_requires_override_)
3286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        << FixItHint::CreateInsertion(token_end, " OVERRIDE");
3296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  } else {
3306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    diagnostic().Report(loc, diag_method_requires_override_);
3316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
3326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
3336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Makes sure there is a "virtual" keyword on virtual methods.
3356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)//
3366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a
3376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// trick to get around that. If a class has member variables whose types are
3386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// in the "testing" namespace (which is how gmock works behind the scenes),
3396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// there's a really high chance we won't care about these errors
3406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckVirtualMethods(
3416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation record_location,
3426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CXXRecordDecl* record,
3436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    bool warn_on_inline_bodies) {
3446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (CXXRecordDecl::field_iterator it = record->field_begin();
3456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       it != record->field_end();
3466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++it) {
3476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CXXRecordDecl* record_type = it->getTypeSourceInfo()
3486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                     ->getTypeLoc()
3496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                     .getTypePtr()
3506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                     ->getAsCXXRecordDecl();
3516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (record_type) {
3526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (InTestingNamespace(record_type)) {
3536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        return;
3546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
3556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
3566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
3576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (CXXRecordDecl::method_iterator it = record->method_begin();
3596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       it != record->method_end();
3606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++it) {
3616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) {
3626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // Ignore constructors and assignment operators.
3636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    } else if (isa<CXXDestructorDecl>(*it) &&
3646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)               !record->hasUserDeclaredDestructor()) {
3656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // Ignore non-user-declared destructors.
3666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    } else {
3676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      CheckVirtualMethod(*it, warn_on_inline_bodies);
3686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      CheckOverriddenMethod(*it);
3696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
3706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
3716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
3726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CountType(const Type* type,
3746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                          int* trivial_member,
3756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                          int* non_trivial_member,
3766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                          int* templated_non_trivial_member) {
3776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  switch (type->getTypeClass()) {
3786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    case Type::Record: {
3796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // Simplifying; the whole class isn't trivial if the dtor is, but
3806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // we use this as a signal about complexity.
3816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (TypeHasNonTrivialDtor(type))
3826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        (*trivial_member)++;
3836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      else
3846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        (*non_trivial_member)++;
3856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      break;
3866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
3876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    case Type::TemplateSpecialization: {
3886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      TemplateName name =
3896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          dyn_cast<TemplateSpecializationType>(type)->getTemplateName();
3906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      bool whitelisted_template = false;
3916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // HACK: I'm at a loss about how to get the syntax checker to get
3936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // whether a template is exterened or not. For the first pass here,
3946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // just do retarded string comparisons.
3956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (TemplateDecl* decl = name.getAsTemplateDecl()) {
3966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        std::string base_name = decl->getNameAsString();
3976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        if (base_name == "basic_string")
3986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          whitelisted_template = true;
3996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
4006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (whitelisted_template)
4026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        (*non_trivial_member)++;
4036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      else
4046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        (*templated_non_trivial_member)++;
4056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      break;
4066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
4076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    case Type::Elaborated: {
4086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      CountType(dyn_cast<ElaboratedType>(type)->getNamedType().getTypePtr(),
4096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                trivial_member,
4106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                non_trivial_member,
4116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                templated_non_trivial_member);
4126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      break;
4136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
4146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    case Type::Typedef: {
4156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      while (const TypedefType* TT = dyn_cast<TypedefType>(type)) {
4166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        type = TT->getDecl()->getUnderlyingType().getTypePtr();
4176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
4186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      CountType(type,
4196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                trivial_member,
4206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                non_trivial_member,
4216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                templated_non_trivial_member);
4226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      break;
4236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
4246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    default: {
4256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // Stupid assumption: anything we see that isn't the above is one of
4266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // the 20 integer types.
4276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      (*trivial_member)++;
4286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      break;
4296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
4306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
4316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
4326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Check |record| for issues that are problematic for ref-counted types.
4346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Note that |record| may not be a ref-counted type, but a base class for
4356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// a type that is.
4366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// If there are issues, update |loc| with the SourceLocation of the issue
4376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// and returns appropriately, or returns None if there are no issues.
4386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)FindBadConstructsConsumer::RefcountIssue
4396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)FindBadConstructsConsumer::CheckRecordForRefcountIssue(
4406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const CXXRecordDecl* record,
4416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation& loc) {
4426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!record->hasUserDeclaredDestructor()) {
4436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    loc = record->getLocation();
4446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return ImplicitDestructor;
4456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
4466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (CXXDestructorDecl* dtor = record->getDestructor()) {
4486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (dtor->getAccess() == AS_public) {
4496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      loc = dtor->getInnerLocStart();
4506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return PublicDestructor;
4516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
4526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
4536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return None;
4556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
4566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Adds either a warning or error, based on the current handling of
4586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// -Werror.
4596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)DiagnosticsEngine::Level FindBadConstructsConsumer::getErrorLevel() {
4606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error
4616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                            : DiagnosticsEngine::Warning;
4626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
4636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Returns true if |base| specifies one of the Chromium reference counted
4656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// classes (base::RefCounted / base::RefCountedThreadSafe).
4666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool FindBadConstructsConsumer::IsRefCountedCallback(
4676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const CXXBaseSpecifier* base,
4686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CXXBasePath& path,
4696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    void* user_data) {
4706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  FindBadConstructsConsumer* self =
4716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      static_cast<FindBadConstructsConsumer*>(user_data);
4726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const TemplateSpecializationType* base_type =
4746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      dyn_cast<TemplateSpecializationType>(
4756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          UnwrapType(base->getType().getTypePtr()));
4766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!base_type) {
4776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // Base-most definition is not a template, so this cannot derive from
4786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // base::RefCounted. However, it may still be possible to use with a
4796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // scoped_refptr<> and support ref-counting, so this is not a perfect
4806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // guarantee of safety.
4816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
4826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
4836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  TemplateName name = base_type->getTemplateName();
4856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (TemplateDecl* decl = name.getAsTemplateDecl()) {
4866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    std::string base_name = decl->getNameAsString();
4876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // Check for both base::RefCounted and base::RefCountedThreadSafe.
4896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (base_name.compare(0, 10, "RefCounted") == 0 &&
4906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        self->GetNamespace(decl) == "base") {
4916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return true;
4926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
4936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
4946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return false;
4966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
4976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Returns true if |base| specifies a class that has a public destructor,
4996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// either explicitly or implicitly.
5006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool FindBadConstructsConsumer::HasPublicDtorCallback(
5016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const CXXBaseSpecifier* base,
5026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CXXBasePath& path,
5036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    void* user_data) {
5046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Only examine paths that have public inheritance, as they are the
5056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // only ones which will result in the destructor potentially being
5066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // exposed. This check is largely redundant, as Chromium code should be
5076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // exclusively using public inheritance.
5086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (path.Access != AS_public)
5096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
5106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  CXXRecordDecl* record =
5126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      dyn_cast<CXXRecordDecl>(base->getType()->getAs<RecordType>()->getDecl());
5136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SourceLocation unused;
5146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return None != CheckRecordForRefcountIssue(record, unused);
5156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
5166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Outputs a C++ inheritance chain as a diagnostic aid.
5186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::PrintInheritanceChain(const CXXBasePath& path) {
5196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (CXXBasePath::const_iterator it = path.begin(); it != path.end(); ++it) {
5206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    diagnostic().Report(it->Base->getLocStart(), diag_note_inheritance_)
5216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        << it->Class << it->Base->getType();
5226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
5236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
5246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)unsigned FindBadConstructsConsumer::DiagnosticForIssue(RefcountIssue issue) {
5266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  switch (issue) {
5276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    case ImplicitDestructor:
5286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return diag_no_explicit_dtor_;
5296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    case PublicDestructor:
5306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return diag_public_dtor_;
5316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    case None:
5326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      assert(false && "Do not call DiagnosticForIssue with issue None");
5336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return 0;
5346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
5356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  assert(false);
5366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return 0;
5376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
5386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Check |record| to determine if it has any problematic refcounting
5406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// issues and, if so, print them as warnings/errors based on the current
5416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// value of getErrorLevel().
5426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)//
5436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// If |record| is a C++ class, and if it inherits from one of the Chromium
5446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// ref-counting classes (base::RefCounted / base::RefCountedThreadSafe),
5456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// ensure that there are no public destructors in the class hierarchy. This
5466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// is to guard against accidentally stack-allocating a RefCounted class or
5476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// sticking it in a non-ref-counted container (like scoped_ptr<>).
5486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckRefCountedDtors(
5496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation record_location,
5506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CXXRecordDecl* record) {
5516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Skip anonymous structs.
5526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (record->getIdentifier() == NULL)
5536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
5546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Determine if the current type is even ref-counted.
5566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  CXXBasePaths refcounted_path;
5576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!record->lookupInBases(&FindBadConstructsConsumer::IsRefCountedCallback,
5586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                             this,
5596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                             refcounted_path)) {
5606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;  // Class does not derive from a ref-counted base class.
5616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
5626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Easy check: Check to see if the current type is problematic.
5646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SourceLocation loc;
5656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  RefcountIssue issue = CheckRecordForRefcountIssue(record, loc);
5666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (issue != None) {
5676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    diagnostic().Report(loc, DiagnosticForIssue(issue));
5686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    PrintInheritanceChain(refcounted_path.front());
5696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
5706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
5716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (CXXDestructorDecl* dtor =
5726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          refcounted_path.begin()->back().Class->getDestructor()) {
5736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (dtor->getAccess() == AS_protected && !dtor->isVirtual()) {
5746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      loc = dtor->getInnerLocStart();
5756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().Report(loc, diag_protected_non_virtual_dtor_);
5766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return;
5776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
5786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
5796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Long check: Check all possible base classes for problematic
5816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // destructors. This checks for situations involving multiple
5826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // inheritance, where the ref-counted class may be implementing an
5836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // interface that has a public or implicit destructor.
5846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //
5856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // struct SomeInterface {
5866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //   virtual void DoFoo();
5876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // };
5886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //
5896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // struct RefCountedInterface
5906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //    : public base::RefCounted<RefCountedInterface>,
5916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //      public SomeInterface {
5926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //  private:
5936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //   friend class base::Refcounted<RefCountedInterface>;
5946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //   virtual ~RefCountedInterface() {}
5956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // };
5966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //
5976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // While RefCountedInterface is "safe", in that its destructor is
5986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // private, it's possible to do the following "unsafe" code:
5996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //   scoped_refptr<RefCountedInterface> some_class(
6006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //       new RefCountedInterface);
6016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //   // Calls SomeInterface::~SomeInterface(), which is unsafe.
6026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  //   delete static_cast<SomeInterface*>(some_class.get());
6036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!options_.check_base_classes)
6046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
6056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Find all public destructors. This will record the class hierarchy
6076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // that leads to the public destructor in |dtor_paths|.
6086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  CXXBasePaths dtor_paths;
6096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!record->lookupInBases(&FindBadConstructsConsumer::HasPublicDtorCallback,
6106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                             this,
6116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                             dtor_paths)) {
6126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
6136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
6146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (CXXBasePaths::const_paths_iterator it = dtor_paths.begin();
6166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       it != dtor_paths.end();
6176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++it) {
6186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // The record with the problem will always be the last record
6196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // in the path, since it is the record that stopped the search.
6206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const CXXRecordDecl* problem_record = dyn_cast<CXXRecordDecl>(
6216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        it->back().Base->getType()->getAs<RecordType>()->getDecl());
6226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    issue = CheckRecordForRefcountIssue(problem_record, loc);
6246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (issue == ImplicitDestructor) {
6266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().Report(record_location, diag_no_explicit_dtor_);
6276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      PrintInheritanceChain(refcounted_path.front());
6286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().Report(loc, diag_note_implicit_dtor_) << problem_record;
6296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      PrintInheritanceChain(*it);
6306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    } else if (issue == PublicDestructor) {
6316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().Report(record_location, diag_public_dtor_);
6326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      PrintInheritanceChain(refcounted_path.front());
6336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().Report(loc, diag_note_public_dtor_);
6346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      PrintInheritanceChain(*it);
6356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
6366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
6376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
6386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Check for any problems with WeakPtrFactory class members. This currently
6406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// only checks that any WeakPtrFactory<T> member of T appears as the last
6416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// data member in T. We could consider checking for bad uses of
6426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// WeakPtrFactory to refer to other data members, but that would require
6436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// looking at the initializer list in constructors to see what the factory
6446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// points to.
6456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Note, if we later add other unrelated checks of data members, we should
6466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// consider collapsing them in to one loop to avoid iterating over the data
6476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// members more than once.
6486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void FindBadConstructsConsumer::CheckWeakPtrFactoryMembers(
6496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SourceLocation record_location,
6506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CXXRecordDecl* record) {
6516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Skip anonymous structs.
6526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (record->getIdentifier() == NULL)
6536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
6546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Iterate through members of the class.
6566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  RecordDecl::field_iterator iter(record->field_begin()),
6576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      the_end(record->field_end());
6586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SourceLocation weak_ptr_factory_location;  // Invalid initially.
6596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (; iter != the_end; ++iter) {
6606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // If we enter the loop but have already seen a matching WeakPtrFactory,
6616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // it means there is at least one member after the factory.
6626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (weak_ptr_factory_location.isValid()) {
6636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      diagnostic().Report(weak_ptr_factory_location,
6646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                          diag_weak_ptr_factory_order_);
6656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
6666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const TemplateSpecializationType* template_spec_type =
6676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        iter->getType().getTypePtr()->getAs<TemplateSpecializationType>();
6686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (template_spec_type) {
6696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      const TemplateDecl* template_decl =
6706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          template_spec_type->getTemplateName().getAsTemplateDecl();
6716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (template_decl && template_spec_type->getNumArgs() >= 1) {
6726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        if (template_decl->getNameAsString().compare("WeakPtrFactory") == 0 &&
6736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)            GetNamespace(template_decl) == "base") {
6746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          const TemplateArgument& arg = template_spec_type->getArg(0);
6756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          if (arg.getAsType().getTypePtr()->getAsCXXRecordDecl() ==
6766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)              record->getTypeForDecl()->getAsCXXRecordDecl()) {
6776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)            weak_ptr_factory_location = iter->getLocation();
6786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          }
6796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        }
6806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      }
6816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
6826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
6836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
6846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}  // namespace chrome_checker
686