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. 154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// - WeakPtrFactory members that refer to their outer class should be the last 164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// member. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/ASTConsumer.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/AST.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/AST/Attr.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/CXXInheritance.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/TypeLoc.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Basic/SourceManager.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Frontend/CompilerInstance.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/Frontend/FrontendPluginRegistry.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/Lex/Lexer.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/raw_ostream.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ChromeClassTester.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kMethodRequiresOverride[] = 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] Overriding method must be marked with OVERRIDE."; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kMethodRequiresVirtual[] = 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] Overriding method must have \"virtual\" keyword."; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNoExplicitDtor[] = 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] Classes that are ref-counted should have explicit " 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "destructors that are declared protected or private."; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kPublicDtor[] = 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] Classes that are ref-counted should have " 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "destructors that are declared protected or private."; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kProtectedNonVirtualDtor[] = 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] Classes that are ref-counted and have non-private " 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "destructors should declare their destructor virtual."; 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kWeakPtrFactoryOrder[] = 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) "[chromium-style] WeakPtrFactory members which refer to their outer class " 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) "must be the last member in the outer class definition."; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNoteInheritance[] = 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] %0 inherits from %1 here"; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNoteImplicitDtor[] = 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] No explicit destructor for %0 defined"; 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNotePublicDtor[] = 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] Public destructor declared here"; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNoteProtectedNonVirtualDtor[] = 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "[chromium-style] Protected non-virtual destructor declared here"; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypeHasNonTrivialDtor(const Type* type) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (const CXXRecordDecl* cxx_r = type->getPointeeCXXRecordDecl()) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cxx_r->hasTrivialDestructor(); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the underlying Type for |type| by expanding typedefs and removing 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// any namespace qualifiers. This is similar to desugaring, except that for 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ElaboratedTypes, desugar will unwrap too much. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const Type* UnwrapType(const Type* type) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return UnwrapType(elaborated->getNamedType().getTypePtr()); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return UnwrapType(typedefed->desugar().getTypePtr()); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return type; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)struct FindBadConstructsOptions { 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FindBadConstructsOptions() : check_base_classes(false), 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) check_virtuals_in_implementations(true), 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) check_url_directory(false), 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) check_weak_ptr_factory_order(false) { 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool check_base_classes; 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool check_virtuals_in_implementations; 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool check_url_directory; 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool check_weak_ptr_factory_order; 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Searches for constructs that we know we don't want in the Chromium code base. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FindBadConstructsConsumer : public ChromeClassTester { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindBadConstructsConsumer(CompilerInstance& instance, 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const FindBadConstructsOptions& options) 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : ChromeClassTester(instance, options.check_url_directory), 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) options_(options) { 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Register warning/error messages. 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_method_requires_override_ = diagnostic().getCustomDiagID( 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getErrorLevel(), kMethodRequiresOverride); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_method_requires_virtual_ = diagnostic().getCustomDiagID( 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getErrorLevel(), kMethodRequiresVirtual); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_no_explicit_dtor_ = diagnostic().getCustomDiagID( 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getErrorLevel(), kNoExplicitDtor); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_public_dtor_ = diagnostic().getCustomDiagID( 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getErrorLevel(), kPublicDtor); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getErrorLevel(), kProtectedNonVirtualDtor); 1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID( 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) getErrorLevel(), kWeakPtrFactoryOrder); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Registers notes to make it easier to interpret warnings. 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_note_inheritance_ = diagnostic().getCustomDiagID( 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiagnosticsEngine::Note, kNoteInheritance); 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_note_implicit_dtor_ = diagnostic().getCustomDiagID( 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiagnosticsEngine::Note, kNoteImplicitDtor); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_note_public_dtor_ = diagnostic().getCustomDiagID( 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiagnosticsEngine::Note, kNotePublicDtor); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void CheckChromeClass(SourceLocation record_location, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool implementation_file = InImplementationFile(record_location); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!implementation_file) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only check for "heavy" constructors/destructors in header files; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // within implementation files, there is no performance cost. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckCtorDtorWeight(record_location, record); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!implementation_file || options_.check_virtuals_in_implementations) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool warn_on_inline_bodies = !implementation_file; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check that all virtual methods are marked accordingly with both 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // virtual and OVERRIDE. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckVirtualMethods(record_location, record, warn_on_inline_bodies); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CheckRefCountedDtors(record_location, record); 1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (options_.check_weak_ptr_factory_order) 1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CheckWeakPtrFactoryMembers(record_location, record); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The type of problematic ref-counting pattern that was encountered. 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enum RefcountIssue { 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) None, 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ImplicitDestructor, 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PublicDestructor 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FindBadConstructsOptions options_; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_method_requires_override_; 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_method_requires_virtual_; 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_no_explicit_dtor_; 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_public_dtor_; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_protected_non_virtual_dtor_; 1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) unsigned diag_weak_ptr_factory_order_; 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_note_inheritance_; 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_note_implicit_dtor_; 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_note_public_dtor_; 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned diag_note_protected_non_virtual_dtor_; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prints errors if the constructor/destructor weight is too heavy. 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckCtorDtorWeight(SourceLocation record_location, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't handle anonymous structs. If this record doesn't have a 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // name, it's of the form: 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // struct { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ... 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // } name_; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (record->getIdentifier() == NULL) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Count the number of templated base classes as a feature of whether the 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destructor can be inlined. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int templated_base_classes = 0; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::base_class_const_iterator it = record->bases_begin(); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->bases_end(); ++it) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->getTypeSourceInfo()->getTypeLoc().getTypeLocClass() == 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeLoc::TemplateSpecialization) { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++templated_base_classes; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Count the number of trivial and non-trivial member variables. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int trivial_member = 0; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int non_trivial_member = 0; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int templated_non_trivial_member = 0; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (RecordDecl::field_iterator it = record->field_begin(); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->field_end(); ++it) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountType(it->getType().getTypePtr(), 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &trivial_member, 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &non_trivial_member, 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &templated_non_trivial_member); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if we need to ban inlined/synthesized constructors. Note 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that the cutoffs here are kind of arbitrary. Scores over 10 break. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int dtor_score = 0; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Deriving from a templated base class shouldn't be enough to trigger 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the ctor warning, but if you do *anything* else, it should. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(erg): This is motivated by templated base classes that don't have 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // any data members. Somehow detect when templated base classes have data 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // members and treat them differently. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dtor_score += templated_base_classes * 9; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Instantiating a template is an insta-hit. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dtor_score += templated_non_trivial_member * 10; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The fourth normal class member should trigger the warning. 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dtor_score += non_trivial_member * 3; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ctor_score = dtor_score; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // You should be able to have 9 ints before we warn you. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctor_score += trivial_member; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctor_score >= 10) { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!record->hasUserDeclaredConstructor()) { 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(record_location, 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex class/struct needs an explicit out-of-line " 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "constructor."); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate across all the constructors in this file and yell if we 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // find one that tries to be inline. 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::ctor_iterator it = record->ctor_begin(); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->ctor_end(); ++it) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->hasInlineBody()) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->isCopyConstructor() && 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !record->hasUserDeclaredCopyConstructor()) { 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(record_location, 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex class/struct needs an explicit out-of-line " 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "copy constructor."); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(it->getInnerLocStart(), 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex constructor has an inlined body."); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The destructor side is equivalent except that we don't check for 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trivial members; 20 ints don't need a destructor. 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dtor_score >= 10 && !record->hasTrivialDestructor()) { 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!record->hasUserDeclaredDestructor()) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning( 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) record_location, 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex class/struct needs an explicit out-of-line " 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "destructor."); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (CXXDestructorDecl* dtor = record->getDestructor()) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dtor->hasInlineBody()) { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning(dtor->getInnerLocStart(), 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Complex destructor has an inline body."); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckVirtualMethod(const CXXMethodDecl* method, 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool warn_on_inline_bodies) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!method->isVirtual()) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!method->isVirtualAsWritten()) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SourceLocation loc = method->getTypeSpecStartLoc(); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isa<CXXDestructorDecl>(method)) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loc = method->getInnerLocStart(); 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceManager& manager = instance().getSourceManager(); 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FullSourceLoc full_loc(loc, manager); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceLocation spelling_loc = manager.getSpellingLoc(loc); 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(full_loc, diag_method_requires_virtual_) 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << FixItHint::CreateInsertion(spelling_loc, "virtual "); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Virtual methods should not have inline definitions beyond "{}". This 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only matters for header files. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (warn_on_inline_bodies && method->hasBody() && 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) method->hasInlineBody()) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cs->size()) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emitWarning( 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cs->getLBracLoc(), 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "virtual methods with non-empty bodies shouldn't be " 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "declared inline."); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool InTestingNamespace(const Decl* record) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetNamespace(record).find("testing") != std::string::npos; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool IsMethodInBannedOrTestingNamespace(const CXXMethodDecl* method) { 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InBannedNamespace(method)) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods(); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != method->end_overridden_methods(); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++i) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CXXMethodDecl* overridden = *i; 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsMethodInBannedOrTestingNamespace(overridden) || 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InTestingNamespace(overridden)) { 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckOverriddenMethod(const CXXMethodDecl* method) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!method->size_overridden_methods() || method->getAttr<OverrideAttr>()) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isa<CXXDestructorDecl>(method) || method->isPure()) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsMethodInBannedOrTestingNamespace(method)) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceManager& manager = instance().getSourceManager(); 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceRange type_info_range = 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) method->getTypeSourceInfo()->getTypeLoc().getSourceRange(); 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FullSourceLoc loc(type_info_range.getBegin(), manager); 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Build the FixIt insertion point after the end of the method definition, 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // including any const-qualifiers and attributes, and before the opening 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // of the l-curly-brace (if inline) or the semi-color (if a declaration). 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceLocation spelling_end = 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manager.getSpellingLoc(type_info_range.getEnd()); 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (spelling_end.isValid()) { 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceLocation token_end = Lexer::getLocForEndOfToken( 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spelling_end, 0, manager, LangOptions()); 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(token_end, diag_method_requires_override_) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << FixItHint::CreateInsertion(token_end, " OVERRIDE"); 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(loc, diag_method_requires_override_); 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Makes sure there is a "virtual" keyword on virtual methods. 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trick to get around that. If a class has member variables whose types are 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in the "testing" namespace (which is how gmock works behind the scenes), 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there's a really high chance we won't care about these errors 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckVirtualMethods(SourceLocation record_location, 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool warn_on_inline_bodies) { 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::field_iterator it = record->field_begin(); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->field_end(); ++it) { 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CXXRecordDecl* record_type = 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->getTypeSourceInfo()->getTypeLoc().getTypePtr()-> 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getAsCXXRecordDecl(); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (record_type) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (InTestingNamespace(record_type)) { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CXXRecordDecl::method_iterator it = record->method_begin(); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != record->method_end(); ++it) { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore constructors and assignment operators. 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (isa<CXXDestructorDecl>(*it) && 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !record->hasUserDeclaredDestructor()) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore non-user-declared destructors. 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckVirtualMethod(*it, warn_on_inline_bodies); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckOverriddenMethod(*it); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CountType(const Type* type, 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* trivial_member, 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* non_trivial_member, 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* templated_non_trivial_member) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type->getTypeClass()) { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::Record: { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Simplifying; the whole class isn't trivial if the dtor is, but 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we use this as a signal about complexity. 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (TypeHasNonTrivialDtor(type)) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*trivial_member)++; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*non_trivial_member)++; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::TemplateSpecialization: { 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TemplateName name = 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dyn_cast<TemplateSpecializationType>(type)->getTemplateName(); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool whitelisted_template = false; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HACK: I'm at a loss about how to get the syntax checker to get 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whether a template is exterened or not. For the first pass here, 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just do retarded string comparisons. 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (TemplateDecl* decl = name.getAsTemplateDecl()) { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string base_name = decl->getNameAsString(); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base_name == "basic_string") 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) whitelisted_template = true; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (whitelisted_template) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*non_trivial_member)++; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*templated_non_trivial_member)++; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::Elaborated: { 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountType( 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dyn_cast<ElaboratedType>(type)->getNamedType().getTypePtr(), 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trivial_member, non_trivial_member, templated_non_trivial_member); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Type::Typedef: { 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (const TypedefType* TT = dyn_cast<TypedefType>(type)) { 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = TT->getDecl()->getUnderlyingType().getTypePtr(); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CountType(type, trivial_member, non_trivial_member, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) templated_non_trivial_member); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: { 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stupid assumption: anything we see that isn't the above is one of 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the 20 integer types. 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*trivial_member)++; 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check |record| for issues that are problematic for ref-counted types. 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Note that |record| may not be a ref-counted type, but a base class for 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // a type that is. 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If there are issues, update |loc| with the SourceLocation of the issue 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // and returns appropriately, or returns None if there are no issues. 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static RefcountIssue CheckRecordForRefcountIssue( 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CXXRecordDecl* record, 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceLocation &loc) { 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!record->hasUserDeclaredDestructor()) { 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) loc = record->getLocation(); 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ImplicitDestructor; 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (CXXDestructorDecl* dtor = record->getDestructor()) { 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dtor->getAccess() == AS_public) { 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) loc = dtor->getInnerLocStart(); 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return PublicDestructor; 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return None; 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Adds either a warning or error, based on the current handling of 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // -Werror. 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiagnosticsEngine::Level getErrorLevel() { 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return diagnostic().getWarningsAsErrors() ? 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiagnosticsEngine::Error : DiagnosticsEngine::Warning; 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns true if |base| specifies one of the Chromium reference counted 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // classes (base::RefCounted / base::RefCountedThreadSafe). 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static bool IsRefCountedCallback(const CXXBaseSpecifier* base, 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CXXBasePath& path, 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void* user_data) { 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FindBadConstructsConsumer* self = 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<FindBadConstructsConsumer*>(user_data); 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const TemplateSpecializationType* base_type = 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dyn_cast<TemplateSpecializationType>( 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UnwrapType(base->getType().getTypePtr())); 4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base_type) { 4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Base-most definition is not a template, so this cannot derive from 4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // base::RefCounted. However, it may still be possible to use with a 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // scoped_refptr<> and support ref-counting, so this is not a perfect 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // guarantee of safety. 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TemplateName name = base_type->getTemplateName(); 4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (TemplateDecl* decl = name.getAsTemplateDecl()) { 4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string base_name = decl->getNameAsString(); 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check for both base::RefCounted and base::RefCountedThreadSafe. 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base_name.compare(0, 10, "RefCounted") == 0 && 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self->GetNamespace(decl) == "base") { 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns true if |base| specifies a class that has a public destructor, 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // either explicitly or implicitly. 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static bool HasPublicDtorCallback(const CXXBaseSpecifier* base, 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CXXBasePath& path, 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void* user_data) { 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only examine paths that have public inheritance, as they are the 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // only ones which will result in the destructor potentially being 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // exposed. This check is largely redundant, as Chromium code should be 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // exclusively using public inheritance. 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (path.Access != AS_public) 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CXXRecordDecl* record = dyn_cast<CXXRecordDecl>( 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base->getType()->getAs<RecordType>()->getDecl()); 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceLocation unused; 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return None != CheckRecordForRefcountIssue(record, unused); 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Outputs a C++ inheritance chain as a diagnostic aid. 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void PrintInheritanceChain(const CXXBasePath& path) { 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (CXXBasePath::const_iterator it = path.begin(); it != path.end(); 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it) { 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(it->Base->getLocStart(), diag_note_inheritance_) 5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << it->Class << it->Base->getType(); 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned DiagnosticForIssue(RefcountIssue issue) { 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (issue) { 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ImplicitDestructor: 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return diag_no_explicit_dtor_; 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case PublicDestructor: 5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return diag_public_dtor_; 5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case None: 5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) assert(false && "Do not call DiagnosticForIssue with issue None"); 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) assert(false); 5374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return 0; 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check |record| to determine if it has any problematic refcounting 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // issues and, if so, print them as warnings/errors based on the current 5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // value of getErrorLevel(). 5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If |record| is a C++ class, and if it inherits from one of the Chromium 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // ref-counting classes (base::RefCounted / base::RefCountedThreadSafe), 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // ensure that there are no public destructors in the class hierarchy. This 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // is to guard against accidentally stack-allocating a RefCounted class or 5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // sticking it in a non-ref-counted container (like scoped_ptr<>). 5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void CheckRefCountedDtors(SourceLocation record_location, 5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CXXRecordDecl* record) { 5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Skip anonymous structs. 5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (record->getIdentifier() == NULL) 5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Determine if the current type is even ref-counted. 5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CXXBasePaths refcounted_path; 5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!record->lookupInBases( 5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &FindBadConstructsConsumer::IsRefCountedCallback, this, 5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refcounted_path)) { 5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // Class does not derive from a ref-counted base class. 5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Easy check: Check to see if the current type is problematic. 5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SourceLocation loc; 5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RefcountIssue issue = CheckRecordForRefcountIssue(record, loc); 5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (issue != None) { 5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(loc, DiagnosticForIssue(issue)); 5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PrintInheritanceChain(refcounted_path.front()); 5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (CXXDestructorDecl* dtor = 5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refcounted_path.begin()->back().Class->getDestructor()) { 5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (dtor->getAccess() == AS_protected && 5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !dtor->isVirtual()) { 5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) loc = dtor->getInnerLocStart(); 5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(loc, diag_protected_non_virtual_dtor_); 5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Long check: Check all possible base classes for problematic 5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // destructors. This checks for situations involving multiple 5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // inheritance, where the ref-counted class may be implementing an 5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // interface that has a public or implicit destructor. 5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // struct SomeInterface { 5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // virtual void DoFoo(); 5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // }; 5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // struct RefCountedInterface 5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // : public base::RefCounted<RefCountedInterface>, 5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // public SomeInterface { 5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // private: 5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // friend class base::Refcounted<RefCountedInterface>; 5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // virtual ~RefCountedInterface() {} 5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // }; 5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // While RefCountedInterface is "safe", in that its destructor is 5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // private, it's possible to do the following "unsafe" code: 6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // scoped_refptr<RefCountedInterface> some_class( 6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // new RefCountedInterface); 6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // // Calls SomeInterface::~SomeInterface(), which is unsafe. 6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // delete static_cast<SomeInterface*>(some_class.get()); 6044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!options_.check_base_classes) 6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Find all public destructors. This will record the class hierarchy 6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // that leads to the public destructor in |dtor_paths|. 6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CXXBasePaths dtor_paths; 6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!record->lookupInBases( 6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &FindBadConstructsConsumer::HasPublicDtorCallback, this, 6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dtor_paths)) { 6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (CXXBasePaths::const_paths_iterator it = dtor_paths.begin(); 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != dtor_paths.end(); ++it) { 6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The record with the problem will always be the last record 6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in the path, since it is the record that stopped the search. 6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CXXRecordDecl* problem_record = dyn_cast<CXXRecordDecl>( 6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it->back().Base->getType()->getAs<RecordType>()->getDecl()); 6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) issue = CheckRecordForRefcountIssue(problem_record, loc); 6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (issue == ImplicitDestructor) { 6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(record_location, diag_no_explicit_dtor_); 6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PrintInheritanceChain(refcounted_path.front()); 6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(loc, diag_note_implicit_dtor_) << problem_record; 6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PrintInheritanceChain(*it); 6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (issue == PublicDestructor) { 6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(record_location, diag_public_dtor_); 6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PrintInheritanceChain(refcounted_path.front()); 6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) diagnostic().Report(loc, diag_note_public_dtor_); 6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PrintInheritanceChain(*it); 6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Check for any problems with WeakPtrFactory class members. This currently 6404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // only checks that any WeakPtrFactory<T> member of T appears as the last 6414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // data member in T. We could consider checking for bad uses of 6424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // WeakPtrFactory to refer to other data members, but that would require 6434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // looking at the initializer list in constructors to see what the factory 6444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // points to. 6454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Note, if we later add other unrelated checks of data members, we should 6464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // consider collapsing them in to one loop to avoid iterating over the data 6474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // members more than once. 6484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void CheckWeakPtrFactoryMembers(SourceLocation record_location, 6494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CXXRecordDecl* record) { 6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Skip anonymous structs. 6514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (record->getIdentifier() == NULL) 6524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 6534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Iterate through members of the class. 6554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) RecordDecl::field_iterator iter(record->field_begin()), 6564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) the_end(record->field_end()); 6574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) SourceLocation weak_ptr_factory_location; // Invalid initially. 6584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (; iter != the_end; ++iter) { 6594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // If we enter the loop but have already seen a matching WeakPtrFactory, 6604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // it means there is at least one member after the factory. 6614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (weak_ptr_factory_location.isValid()) { 6624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) diagnostic().Report(weak_ptr_factory_location, 6634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) diag_weak_ptr_factory_order_); 6644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const TemplateSpecializationType* template_spec_type = 6664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) iter->getType().getTypePtr()->getAs<TemplateSpecializationType>(); 6674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (template_spec_type) { 6684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const TemplateDecl* template_decl = 6694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) template_spec_type->getTemplateName().getAsTemplateDecl(); 6704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (template_decl && template_spec_type->getNumArgs() >= 1) { 6714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (template_decl->getNameAsString().compare("WeakPtrFactory") == 0 && 6724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) GetNamespace(template_decl) == "base") { 6734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const TemplateArgument& arg = template_spec_type->getArg(0); 6744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (arg.getAsType().getTypePtr()->getAsCXXRecordDecl() == 6754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) record->getTypeForDecl()->getAsCXXRecordDecl()) { 6764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) weak_ptr_factory_location = iter->getLocation(); 6774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FindBadConstructsAction : public PluginASTAction { 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 6884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FindBadConstructsAction() { 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from PluginASTAction: 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance, 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::StringRef ref) { 6954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return new FindBadConstructsConsumer(instance, options_); 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool ParseArgs(const CompilerInstance& instance, 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& args) { 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool parsed = true; 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < args.size() && parsed; ++i) { 7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (args[i] == "skip-virtuals-in-implementations") { 7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rsleevi): Remove this once http://crbug.com/115047 is fixed. 7054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) options_.check_virtuals_in_implementations = false; 7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (args[i] == "check-base-classes") { 7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. 7084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) options_.check_base_classes = true; 709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (args[i] == "check-url-directory") { 710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(tfarina): Remove this once http://crbug.com/229660 is fixed. 7114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) options_.check_url_directory = true; 7124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else if (args[i] == "check-weak-ptr-factory-order") { 7134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(dmichael): Remove this once http://crbug.com/303818 is fixed. 7144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) options_.check_weak_ptr_factory_order = true; 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parsed = false; 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return parsed; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 7254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FindBadConstructsOptions options_; 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static FrontendPluginRegistry::Add<FindBadConstructsAction> 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)X("find-bad-constructs", "Finds bad C++ constructs"); 732