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 11 matching lines...) Expand all Loading... | |
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_url_directory(false), | 86 check_url_directory(false), |
82 check_weak_ptr_factory_order(false) { | 87 check_weak_ptr_factory_order(false), |
88 check_bad_enum_last_value(true) { | |
83 } | 89 } |
84 bool check_base_classes; | 90 bool check_base_classes; |
85 bool check_virtuals_in_implementations; | 91 bool check_virtuals_in_implementations; |
86 bool check_url_directory; | 92 bool check_url_directory; |
87 bool check_weak_ptr_factory_order; | 93 bool check_weak_ptr_factory_order; |
94 bool check_bad_enum_last_value; | |
88 }; | 95 }; |
89 | 96 |
90 // Searches for constructs that we know we don't want in the Chromium code base. | 97 // Searches for constructs that we know we don't want in the Chromium code base. |
91 class FindBadConstructsConsumer : public ChromeClassTester { | 98 class FindBadConstructsConsumer : public ChromeClassTester { |
92 public: | 99 public: |
93 FindBadConstructsConsumer(CompilerInstance& instance, | 100 FindBadConstructsConsumer(CompilerInstance& instance, |
94 const FindBadConstructsOptions& options) | 101 const FindBadConstructsOptions& options) |
95 : ChromeClassTester(instance, options.check_url_directory), | 102 : ChromeClassTester(instance, options.check_url_directory), |
96 options_(options) { | 103 options_(options) { |
97 // Register warning/error messages. | 104 // Register warning/error messages. |
98 diag_method_requires_override_ = diagnostic().getCustomDiagID( | 105 diag_method_requires_override_ = diagnostic().getCustomDiagID( |
99 getErrorLevel(), kMethodRequiresOverride); | 106 getErrorLevel(), kMethodRequiresOverride); |
100 diag_method_requires_virtual_ = diagnostic().getCustomDiagID( | 107 diag_method_requires_virtual_ = diagnostic().getCustomDiagID( |
101 getErrorLevel(), kMethodRequiresVirtual); | 108 getErrorLevel(), kMethodRequiresVirtual); |
102 diag_no_explicit_dtor_ = diagnostic().getCustomDiagID( | 109 diag_no_explicit_dtor_ = diagnostic().getCustomDiagID( |
103 getErrorLevel(), kNoExplicitDtor); | 110 getErrorLevel(), kNoExplicitDtor); |
104 diag_public_dtor_ = diagnostic().getCustomDiagID( | 111 diag_public_dtor_ = diagnostic().getCustomDiagID( |
105 getErrorLevel(), kPublicDtor); | 112 getErrorLevel(), kPublicDtor); |
106 diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( | 113 diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
107 getErrorLevel(), kProtectedNonVirtualDtor); | 114 getErrorLevel(), kProtectedNonVirtualDtor); |
108 diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID( | 115 diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID( |
109 getErrorLevel(), kWeakPtrFactoryOrder); | 116 getErrorLevel(), kWeakPtrFactoryOrder); |
117 diag_bad_enum_last_value_ = diagnostic().getCustomDiagID( | |
118 getErrorLevel(), kBadLastEnumValue); | |
110 | 119 |
111 // Registers notes to make it easier to interpret warnings. | 120 // Registers notes to make it easier to interpret warnings. |
112 diag_note_inheritance_ = diagnostic().getCustomDiagID( | 121 diag_note_inheritance_ = diagnostic().getCustomDiagID( |
113 DiagnosticsEngine::Note, kNoteInheritance); | 122 DiagnosticsEngine::Note, kNoteInheritance); |
114 diag_note_implicit_dtor_ = diagnostic().getCustomDiagID( | 123 diag_note_implicit_dtor_ = diagnostic().getCustomDiagID( |
115 DiagnosticsEngine::Note, kNoteImplicitDtor); | 124 DiagnosticsEngine::Note, kNoteImplicitDtor); |
116 diag_note_public_dtor_ = diagnostic().getCustomDiagID( | 125 diag_note_public_dtor_ = diagnostic().getCustomDiagID( |
117 DiagnosticsEngine::Note, kNotePublicDtor); | 126 DiagnosticsEngine::Note, kNotePublicDtor); |
118 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( | 127 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
119 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); | 128 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); |
(...skipping 16 matching lines...) Expand all Loading... | |
136 // virtual and OVERRIDE. | 145 // virtual and OVERRIDE. |
137 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); | 146 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); |
138 } | 147 } |
139 | 148 |
140 CheckRefCountedDtors(record_location, record); | 149 CheckRefCountedDtors(record_location, record); |
141 | 150 |
142 if (options_.check_weak_ptr_factory_order) | 151 if (options_.check_weak_ptr_factory_order) |
143 CheckWeakPtrFactoryMembers(record_location, record); | 152 CheckWeakPtrFactoryMembers(record_location, record); |
144 } | 153 } |
145 | 154 |
155 virtual void CheckChromeEnum(SourceLocation enum_location, | |
156 EnumDecl* enum_decl) { | |
157 if (options_.check_bad_enum_last_value) { | |
darin (slow to review)
2014/02/12 05:59:47
nit: I recommend returning early if this option is
| |
158 bool got_one = false; | |
159 llvm::APSInt max_so_far; | |
160 EnumDecl::enumerator_iterator iter; | |
161 for (iter = enum_decl->enumerator_begin(); | |
162 iter != enum_decl->enumerator_end(); ++iter) { | |
163 if (!got_one) { | |
164 max_so_far = iter->getInitVal(); | |
165 got_one = true; | |
166 } else if (iter->getInitVal() > max_so_far) | |
167 max_so_far = iter->getInitVal(); | |
168 } | |
169 for (iter = enum_decl->enumerator_begin(); | |
170 iter != enum_decl->enumerator_end(); ++iter) { | |
171 std::string name = iter->getNameAsString(); | |
172 if (((name.size() > 4 && | |
173 name.compare(name.size() - 4, 4, "Last") == 0) || | |
174 (name.size() > 5 && | |
175 name.compare(name.size() - 5, 5, "_LAST") == 0)) && | |
176 iter->getInitVal() < max_so_far) { | |
177 diagnostic().Report(iter->getLocation(), diag_bad_enum_last_value_); | |
178 } | |
179 } | |
180 } | |
181 } | |
182 | |
146 private: | 183 private: |
147 // The type of problematic ref-counting pattern that was encountered. | 184 // The type of problematic ref-counting pattern that was encountered. |
148 enum RefcountIssue { | 185 enum RefcountIssue { |
149 None, | 186 None, |
150 ImplicitDestructor, | 187 ImplicitDestructor, |
151 PublicDestructor | 188 PublicDestructor |
152 }; | 189 }; |
153 | 190 |
154 FindBadConstructsOptions options_; | 191 FindBadConstructsOptions options_; |
155 | 192 |
156 unsigned diag_method_requires_override_; | 193 unsigned diag_method_requires_override_; |
157 unsigned diag_method_requires_virtual_; | 194 unsigned diag_method_requires_virtual_; |
158 unsigned diag_no_explicit_dtor_; | 195 unsigned diag_no_explicit_dtor_; |
159 unsigned diag_public_dtor_; | 196 unsigned diag_public_dtor_; |
160 unsigned diag_protected_non_virtual_dtor_; | 197 unsigned diag_protected_non_virtual_dtor_; |
161 unsigned diag_weak_ptr_factory_order_; | 198 unsigned diag_weak_ptr_factory_order_; |
199 unsigned diag_bad_enum_last_value_; | |
162 unsigned diag_note_inheritance_; | 200 unsigned diag_note_inheritance_; |
163 unsigned diag_note_implicit_dtor_; | 201 unsigned diag_note_implicit_dtor_; |
164 unsigned diag_note_public_dtor_; | 202 unsigned diag_note_public_dtor_; |
165 unsigned diag_note_protected_non_virtual_dtor_; | 203 unsigned diag_note_protected_non_virtual_dtor_; |
166 | 204 |
167 // Prints errors if the constructor/destructor weight is too heavy. | 205 // Prints errors if the constructor/destructor weight is too heavy. |
168 void CheckCtorDtorWeight(SourceLocation record_location, | 206 void CheckCtorDtorWeight(SourceLocation record_location, |
169 CXXRecordDecl* record) { | 207 CXXRecordDecl* record) { |
170 // We don't handle anonymous structs. If this record doesn't have a | 208 // We don't handle anonymous structs. If this record doesn't have a |
171 // name, it's of the form: | 209 // name, it's of the form: |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
705 options_.check_virtuals_in_implementations = false; | 743 options_.check_virtuals_in_implementations = false; |
706 } else if (args[i] == "check-base-classes") { | 744 } else if (args[i] == "check-base-classes") { |
707 // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. | 745 // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. |
708 options_.check_base_classes = true; | 746 options_.check_base_classes = true; |
709 } else if (args[i] == "check-url-directory") { | 747 } else if (args[i] == "check-url-directory") { |
710 // TODO(tfarina): Remove this once http://crbug.com/229660 is fixed. | 748 // TODO(tfarina): Remove this once http://crbug.com/229660 is fixed. |
711 options_.check_url_directory = true; | 749 options_.check_url_directory = true; |
712 } else if (args[i] == "check-weak-ptr-factory-order") { | 750 } else if (args[i] == "check-weak-ptr-factory-order") { |
713 // TODO(dmichael): Remove this once http://crbug.com/303818 is fixed. | 751 // TODO(dmichael): Remove this once http://crbug.com/303818 is fixed. |
714 options_.check_weak_ptr_factory_order = true; | 752 options_.check_weak_ptr_factory_order = true; |
753 } else if (args[i] == "check-bad-enum-last-value") { | |
754 options_.check_bad_enum_last_value = true; | |
715 } else { | 755 } else { |
716 parsed = false; | 756 parsed = false; |
717 llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; | 757 llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; |
718 } | 758 } |
719 } | 759 } |
720 | 760 |
721 return parsed; | 761 return parsed; |
722 } | 762 } |
723 | 763 |
724 private: | 764 private: |
725 FindBadConstructsOptions options_; | 765 FindBadConstructsOptions options_; |
726 }; | 766 }; |
727 | 767 |
728 } // namespace | 768 } // namespace |
729 | 769 |
730 static FrontendPluginRegistry::Add<FindBadConstructsAction> | 770 static FrontendPluginRegistry::Add<FindBadConstructsAction> |
731 X("find-bad-constructs", "Finds bad C++ constructs"); | 771 X("find-bad-constructs", "Finds bad C++ constructs"); |
OLD | NEW |