| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This file defines a bunch of recurring problems in the Chromium C++ code. | 5 // This file defines a bunch of recurring problems in the Chromium C++ code. |
| 6 // | 6 // |
| 7 // Checks that are implemented: | 7 // Checks that are implemented: |
| 8 // - Constructors/Destructors should not be inlined if they are of a complex | 8 // - Constructors/Destructors should not be inlined if they are of a complex |
| 9 // class type. | 9 // class type. |
| 10 // - Missing "virtual" keywords on methods that should be virtual. | 10 // - Missing "virtual" keywords on methods that should be virtual. |
| 11 // - Non-annotated overriding virtual methods. | 11 // - Non-annotated overriding virtual methods. |
| 12 // - Virtual methods with nonempty implementations in their headers. | 12 // - Virtual methods with nonempty implementations in their headers. |
| 13 // - Classes that derive from base::RefCounted / base::RefCountedThreadSafe | 13 // - Classes that derive from base::RefCounted / base::RefCountedThreadSafe |
| 14 // should have protected or private destructors. | 14 // should have protected or private destructors. |
| 15 // - WeakPtrFactory members that refer to their outer class should be the last | 15 // - WeakPtrFactory members that refer to their outer class should be the last |
| 16 // member. | 16 // member. |
| 17 // - Enum types with a xxxx_LAST or xxxxLast const actually have that constant |
| 18 // have the maximal value for that type. |
| 17 | 19 |
| 18 #include "clang/AST/ASTConsumer.h" | 20 #include "clang/AST/ASTConsumer.h" |
| 19 #include "clang/AST/AST.h" | 21 #include "clang/AST/AST.h" |
| 20 #include "clang/AST/Attr.h" | 22 #include "clang/AST/Attr.h" |
| 21 #include "clang/AST/CXXInheritance.h" | 23 #include "clang/AST/CXXInheritance.h" |
| 22 #include "clang/AST/TypeLoc.h" | 24 #include "clang/AST/TypeLoc.h" |
| 23 #include "clang/Basic/SourceManager.h" | 25 #include "clang/Basic/SourceManager.h" |
| 24 #include "clang/Frontend/CompilerInstance.h" | 26 #include "clang/Frontend/CompilerInstance.h" |
| 25 #include "clang/Frontend/FrontendPluginRegistry.h" | 27 #include "clang/Frontend/FrontendPluginRegistry.h" |
| 26 #include "clang/Lex/Lexer.h" | 28 #include "clang/Lex/Lexer.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 41 "destructors that are declared protected or private."; | 43 "destructors that are declared protected or private."; |
| 42 const char kPublicDtor[] = | 44 const char kPublicDtor[] = |
| 43 "[chromium-style] Classes that are ref-counted should have " | 45 "[chromium-style] Classes that are ref-counted should have " |
| 44 "destructors that are declared protected or private."; | 46 "destructors that are declared protected or private."; |
| 45 const char kProtectedNonVirtualDtor[] = | 47 const char kProtectedNonVirtualDtor[] = |
| 46 "[chromium-style] Classes that are ref-counted and have non-private " | 48 "[chromium-style] Classes that are ref-counted and have non-private " |
| 47 "destructors should declare their destructor virtual."; | 49 "destructors should declare their destructor virtual."; |
| 48 const char kWeakPtrFactoryOrder[] = | 50 const char kWeakPtrFactoryOrder[] = |
| 49 "[chromium-style] WeakPtrFactory members which refer to their outer class " | 51 "[chromium-style] WeakPtrFactory members which refer to their outer class " |
| 50 "must be the last member in the outer class definition."; | 52 "must be the last member in the outer class definition."; |
| 53 const char kBadLastEnumValue[] = |
| 54 "[chromium-style] _LAST/Last constants of enum types must have the maximal " |
| 55 "value for any constant of that type."; |
| 51 const char kNoteInheritance[] = | 56 const char kNoteInheritance[] = |
| 52 "[chromium-style] %0 inherits from %1 here"; | 57 "[chromium-style] %0 inherits from %1 here"; |
| 53 const char kNoteImplicitDtor[] = | 58 const char kNoteImplicitDtor[] = |
| 54 "[chromium-style] No explicit destructor for %0 defined"; | 59 "[chromium-style] No explicit destructor for %0 defined"; |
| 55 const char kNotePublicDtor[] = | 60 const char kNotePublicDtor[] = |
| 56 "[chromium-style] Public destructor declared here"; | 61 "[chromium-style] Public destructor declared here"; |
| 57 const char kNoteProtectedNonVirtualDtor[] = | 62 const char kNoteProtectedNonVirtualDtor[] = |
| 58 "[chromium-style] Protected non-virtual destructor declared here"; | 63 "[chromium-style] Protected non-virtual destructor declared here"; |
| 59 | 64 |
| 60 bool TypeHasNonTrivialDtor(const Type* type) { | 65 bool TypeHasNonTrivialDtor(const Type* type) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 71 if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) | 76 if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) |
| 72 return UnwrapType(elaborated->getNamedType().getTypePtr()); | 77 return UnwrapType(elaborated->getNamedType().getTypePtr()); |
| 73 if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) | 78 if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) |
| 74 return UnwrapType(typedefed->desugar().getTypePtr()); | 79 return UnwrapType(typedefed->desugar().getTypePtr()); |
| 75 return type; | 80 return type; |
| 76 } | 81 } |
| 77 | 82 |
| 78 struct FindBadConstructsOptions { | 83 struct FindBadConstructsOptions { |
| 79 FindBadConstructsOptions() : check_base_classes(false), | 84 FindBadConstructsOptions() : check_base_classes(false), |
| 80 check_virtuals_in_implementations(true), | 85 check_virtuals_in_implementations(true), |
| 81 check_weak_ptr_factory_order(false) { | 86 check_weak_ptr_factory_order(false), |
| 87 check_enum_last_value(false) { |
| 82 } | 88 } |
| 83 bool check_base_classes; | 89 bool check_base_classes; |
| 84 bool check_virtuals_in_implementations; | 90 bool check_virtuals_in_implementations; |
| 85 bool check_weak_ptr_factory_order; | 91 bool check_weak_ptr_factory_order; |
| 92 bool check_enum_last_value; |
| 86 }; | 93 }; |
| 87 | 94 |
| 88 // Searches for constructs that we know we don't want in the Chromium code base. | 95 // Searches for constructs that we know we don't want in the Chromium code base. |
| 89 class FindBadConstructsConsumer : public ChromeClassTester { | 96 class FindBadConstructsConsumer : public ChromeClassTester { |
| 90 public: | 97 public: |
| 91 FindBadConstructsConsumer(CompilerInstance& instance, | 98 FindBadConstructsConsumer(CompilerInstance& instance, |
| 92 const FindBadConstructsOptions& options) | 99 const FindBadConstructsOptions& options) |
| 93 : ChromeClassTester(instance), | 100 : ChromeClassTester(instance), |
| 94 options_(options) { | 101 options_(options) { |
| 95 // Register warning/error messages. | 102 // Register warning/error messages. |
| 96 diag_method_requires_override_ = diagnostic().getCustomDiagID( | 103 diag_method_requires_override_ = diagnostic().getCustomDiagID( |
| 97 getErrorLevel(), kMethodRequiresOverride); | 104 getErrorLevel(), kMethodRequiresOverride); |
| 98 diag_method_requires_virtual_ = diagnostic().getCustomDiagID( | 105 diag_method_requires_virtual_ = diagnostic().getCustomDiagID( |
| 99 getErrorLevel(), kMethodRequiresVirtual); | 106 getErrorLevel(), kMethodRequiresVirtual); |
| 100 diag_no_explicit_dtor_ = diagnostic().getCustomDiagID( | 107 diag_no_explicit_dtor_ = diagnostic().getCustomDiagID( |
| 101 getErrorLevel(), kNoExplicitDtor); | 108 getErrorLevel(), kNoExplicitDtor); |
| 102 diag_public_dtor_ = diagnostic().getCustomDiagID( | 109 diag_public_dtor_ = diagnostic().getCustomDiagID( |
| 103 getErrorLevel(), kPublicDtor); | 110 getErrorLevel(), kPublicDtor); |
| 104 diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( | 111 diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
| 105 getErrorLevel(), kProtectedNonVirtualDtor); | 112 getErrorLevel(), kProtectedNonVirtualDtor); |
| 106 diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID( | 113 diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID( |
| 107 getErrorLevel(), kWeakPtrFactoryOrder); | 114 getErrorLevel(), kWeakPtrFactoryOrder); |
| 115 diag_bad_enum_last_value_ = diagnostic().getCustomDiagID( |
| 116 getErrorLevel(), kBadLastEnumValue); |
| 108 | 117 |
| 109 // Registers notes to make it easier to interpret warnings. | 118 // Registers notes to make it easier to interpret warnings. |
| 110 diag_note_inheritance_ = diagnostic().getCustomDiagID( | 119 diag_note_inheritance_ = diagnostic().getCustomDiagID( |
| 111 DiagnosticsEngine::Note, kNoteInheritance); | 120 DiagnosticsEngine::Note, kNoteInheritance); |
| 112 diag_note_implicit_dtor_ = diagnostic().getCustomDiagID( | 121 diag_note_implicit_dtor_ = diagnostic().getCustomDiagID( |
| 113 DiagnosticsEngine::Note, kNoteImplicitDtor); | 122 DiagnosticsEngine::Note, kNoteImplicitDtor); |
| 114 diag_note_public_dtor_ = diagnostic().getCustomDiagID( | 123 diag_note_public_dtor_ = diagnostic().getCustomDiagID( |
| 115 DiagnosticsEngine::Note, kNotePublicDtor); | 124 DiagnosticsEngine::Note, kNotePublicDtor); |
| 116 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( | 125 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
| 117 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); | 126 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 134 // virtual and OVERRIDE. | 143 // virtual and OVERRIDE. |
| 135 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); | 144 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); |
| 136 } | 145 } |
| 137 | 146 |
| 138 CheckRefCountedDtors(record_location, record); | 147 CheckRefCountedDtors(record_location, record); |
| 139 | 148 |
| 140 if (options_.check_weak_ptr_factory_order) | 149 if (options_.check_weak_ptr_factory_order) |
| 141 CheckWeakPtrFactoryMembers(record_location, record); | 150 CheckWeakPtrFactoryMembers(record_location, record); |
| 142 } | 151 } |
| 143 | 152 |
| 153 virtual void CheckChromeEnum(SourceLocation enum_location, |
| 154 EnumDecl* enum_decl) { |
| 155 if (!options_.check_enum_last_value) |
| 156 return; |
| 157 |
| 158 bool got_one = false; |
| 159 bool is_signed = false; |
| 160 llvm::APSInt max_so_far; |
| 161 EnumDecl::enumerator_iterator iter; |
| 162 for (iter = enum_decl->enumerator_begin(); |
| 163 iter != enum_decl->enumerator_end(); ++iter) { |
| 164 llvm::APSInt current_value = iter->getInitVal(); |
| 165 if (!got_one) { |
| 166 max_so_far = current_value; |
| 167 is_signed = current_value.isSigned(); |
| 168 got_one = true; |
| 169 } else { |
| 170 if (is_signed != current_value.isSigned()) { |
| 171 // This only happens in some cases when compiling C (not C++) files, |
| 172 // so it is OK to bail out here. |
| 173 return; |
| 174 } |
| 175 if (current_value > max_so_far) |
| 176 max_so_far = current_value; |
| 177 } |
| 178 } |
| 179 for (iter = enum_decl->enumerator_begin(); |
| 180 iter != enum_decl->enumerator_end(); ++iter) { |
| 181 std::string name = iter->getNameAsString(); |
| 182 if (((name.size() > 4 && |
| 183 name.compare(name.size() - 4, 4, "Last") == 0) || |
| 184 (name.size() > 5 && |
| 185 name.compare(name.size() - 5, 5, "_LAST") == 0)) && |
| 186 iter->getInitVal() < max_so_far) { |
| 187 diagnostic().Report(iter->getLocation(), diag_bad_enum_last_value_); |
| 188 } |
| 189 } |
| 190 } |
| 191 |
| 144 private: | 192 private: |
| 145 // The type of problematic ref-counting pattern that was encountered. | 193 // The type of problematic ref-counting pattern that was encountered. |
| 146 enum RefcountIssue { | 194 enum RefcountIssue { |
| 147 None, | 195 None, |
| 148 ImplicitDestructor, | 196 ImplicitDestructor, |
| 149 PublicDestructor | 197 PublicDestructor |
| 150 }; | 198 }; |
| 151 | 199 |
| 152 FindBadConstructsOptions options_; | 200 FindBadConstructsOptions options_; |
| 153 | 201 |
| 154 unsigned diag_method_requires_override_; | 202 unsigned diag_method_requires_override_; |
| 155 unsigned diag_method_requires_virtual_; | 203 unsigned diag_method_requires_virtual_; |
| 156 unsigned diag_no_explicit_dtor_; | 204 unsigned diag_no_explicit_dtor_; |
| 157 unsigned diag_public_dtor_; | 205 unsigned diag_public_dtor_; |
| 158 unsigned diag_protected_non_virtual_dtor_; | 206 unsigned diag_protected_non_virtual_dtor_; |
| 159 unsigned diag_weak_ptr_factory_order_; | 207 unsigned diag_weak_ptr_factory_order_; |
| 208 unsigned diag_bad_enum_last_value_; |
| 160 unsigned diag_note_inheritance_; | 209 unsigned diag_note_inheritance_; |
| 161 unsigned diag_note_implicit_dtor_; | 210 unsigned diag_note_implicit_dtor_; |
| 162 unsigned diag_note_public_dtor_; | 211 unsigned diag_note_public_dtor_; |
| 163 unsigned diag_note_protected_non_virtual_dtor_; | 212 unsigned diag_note_protected_non_virtual_dtor_; |
| 164 | 213 |
| 165 // Prints errors if the constructor/destructor weight is too heavy. | 214 // Prints errors if the constructor/destructor weight is too heavy. |
| 166 void CheckCtorDtorWeight(SourceLocation record_location, | 215 void CheckCtorDtorWeight(SourceLocation record_location, |
| 167 CXXRecordDecl* record) { | 216 CXXRecordDecl* record) { |
| 168 // We don't handle anonymous structs. If this record doesn't have a | 217 // We don't handle anonymous structs. If this record doesn't have a |
| 169 // name, it's of the form: | 218 // name, it's of the form: |
| (...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 for (size_t i = 0; i < args.size() && parsed; ++i) { | 749 for (size_t i = 0; i < args.size() && parsed; ++i) { |
| 701 if (args[i] == "skip-virtuals-in-implementations") { | 750 if (args[i] == "skip-virtuals-in-implementations") { |
| 702 // TODO(rsleevi): Remove this once http://crbug.com/115047 is fixed. | 751 // TODO(rsleevi): Remove this once http://crbug.com/115047 is fixed. |
| 703 options_.check_virtuals_in_implementations = false; | 752 options_.check_virtuals_in_implementations = false; |
| 704 } else if (args[i] == "check-base-classes") { | 753 } else if (args[i] == "check-base-classes") { |
| 705 // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. | 754 // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. |
| 706 options_.check_base_classes = true; | 755 options_.check_base_classes = true; |
| 707 } else if (args[i] == "check-weak-ptr-factory-order") { | 756 } else if (args[i] == "check-weak-ptr-factory-order") { |
| 708 // TODO(dmichael): Remove this once http://crbug.com/303818 is fixed. | 757 // TODO(dmichael): Remove this once http://crbug.com/303818 is fixed. |
| 709 options_.check_weak_ptr_factory_order = true; | 758 options_.check_weak_ptr_factory_order = true; |
| 759 } else if (args[i] == "check-enum-last-value") { |
| 760 // TODO(tsepez): Enable this by default once http://crbug.com/356815 |
| 761 // and http://crbug.com/356816 are fixed. |
| 762 options_.check_enum_last_value = true; |
| 710 } else { | 763 } else { |
| 711 parsed = false; | 764 parsed = false; |
| 712 llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; | 765 llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; |
| 713 } | 766 } |
| 714 } | 767 } |
| 715 | 768 |
| 716 return parsed; | 769 return parsed; |
| 717 } | 770 } |
| 718 | 771 |
| 719 private: | 772 private: |
| 720 FindBadConstructsOptions options_; | 773 FindBadConstructsOptions options_; |
| 721 }; | 774 }; |
| 722 | 775 |
| 723 } // namespace | 776 } // namespace |
| 724 | 777 |
| 725 static FrontendPluginRegistry::Add<FindBadConstructsAction> | 778 static FrontendPluginRegistry::Add<FindBadConstructsAction> |
| 726 X("find-bad-constructs", "Finds bad C++ constructs"); | 779 X("find-bad-constructs", "Finds bad C++ constructs"); |
| OLD | NEW |