Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: tools/clang/plugins/FindBadConstructs.cpp

Issue 10005022: Check for public dtors on base::RefCounted types (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Just RefCounted Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 // 13 // - Classes that derive from base::RefCounted / base::RefCountedThreadSafe
14 // Things that are still TODO: 14 // should have protected or private destructors.
15 // - Deriving from base::RefCounted and friends should mandate non-public
16 // destructors.
17 15
18 #include "clang/Frontend/FrontendPluginRegistry.h" 16 #include "clang/Frontend/FrontendPluginRegistry.h"
19 #include "clang/AST/ASTConsumer.h" 17 #include "clang/AST/ASTConsumer.h"
20 #include "clang/AST/AST.h" 18 #include "clang/AST/AST.h"
19 #include "clang/AST/CXXInheritance.h"
21 #include "clang/AST/TypeLoc.h" 20 #include "clang/AST/TypeLoc.h"
22 #include "clang/Basic/SourceManager.h" 21 #include "clang/Basic/SourceManager.h"
23 #include "clang/Frontend/CompilerInstance.h" 22 #include "clang/Frontend/CompilerInstance.h"
24 #include "llvm/Support/raw_ostream.h" 23 #include "llvm/Support/raw_ostream.h"
25 24
26 #include "ChromeClassTester.h" 25 #include "ChromeClassTester.h"
27 26
28 using namespace clang; 27 using namespace clang;
29 28
30 namespace { 29 namespace {
31 30
32 bool TypeHasNonTrivialDtor(const Type* type) { 31 bool TypeHasNonTrivialDtor(const Type* type) {
33 if (const CXXRecordDecl* cxx_r = type->getCXXRecordDeclForPointerType()) 32 if (const CXXRecordDecl* cxx_r = type->getCXXRecordDeclForPointerType())
34 return cxx_r->hasTrivialDestructor(); 33 return cxx_r->hasTrivialDestructor();
35 34
36 return false; 35 return false;
37 } 36 }
38 37
39 // Searches for constructs that we know we don't want in the Chromium code base. 38 // Searches for constructs that we know we don't want in the Chromium code base.
40 class FindBadConstructsConsumer : public ChromeClassTester { 39 class FindBadConstructsConsumer : public ChromeClassTester {
41 public: 40 public:
42 FindBadConstructsConsumer(CompilerInstance& instance) 41 FindBadConstructsConsumer(CompilerInstance& instance)
43 : ChromeClassTester(instance) {} 42 : ChromeClassTester(instance) {}
44 43
45 virtual void CheckChromeClass(const SourceLocation& record_location, 44 virtual void CheckChromeClass(const SourceLocation& record_location,
46 CXXRecordDecl* record) { 45 CXXRecordDecl* record) {
47 CheckCtorDtorWeight(record_location, record); 46 bool implementation_file = InImplementationFile(record_location);
48 CheckVirtualMethods(record_location, record); 47
48 if (!implementation_file) {
49 // Only check for "heavy" constructors/destructors in header files;
50 // within implementation files, there is no performance cost.
51 CheckCtorDtorWeight(record_location, record);
52
53 // Check that all virtual methods are marked accordingly with both
54 // virtual and OVERRIDE.
55 CheckVirtualMethods(record_location, record);
56 }
57
58 CheckRefCountedDtors(record_location, record);
59 }
60
61 // Returns true if |base| specifies one of the Chromium reference counted
62 // classes (base::RefCounted / base::RefCountedThreadSafe). |user_data| is
63 // ignored.
64 static bool IsRefCountedCallback(const CXXBaseSpecifier* base,
65 CXXBasePath& path,
66 void* user_data) {
67 FindBadConstructsConsumer* self =
68 static_cast<FindBadConstructsConsumer*>(user_data);
69 if (base->getTypeSourceInfo()->getTypeLoc().getTypeLocClass() !=
70 TypeLoc::TemplateSpecialization) {
71 return false;
72 }
73
74 const TemplateSpecializationType* base_type =
75 dyn_cast<TemplateSpecializationType>(base->getType());
76 TemplateName name = base_type->getTemplateName();
77
78 if (TemplateDecl* decl = name.getAsTemplateDecl()) {
79 std::string base_name = decl->getNameAsString();
80 if (base_name.compare(0, 10, "RefCounted") == 0 &&
81 self->GetNamespace(decl) == "base") {
82 return true;
83 }
84 }
85 return false;
86 }
87
88 // Prints errors if the destructor of a RefCounted class is public.
89 void CheckRefCountedDtors(const SourceLocation& record_location,
90 CXXRecordDecl* record) {
91 // Skip anonymous structs.
92 if (record->getIdentifier() == NULL)
93 return;
94
95 CXXBasePaths paths;
96 if (!record->lookupInBases(
97 &FindBadConstructsConsumer::IsRefCountedCallback, this, paths)) {
98 return; // Class does not derive from a ref-counted base class.
99 }
100
101 if (!record->hasUserDeclaredDestructor()) {
102 emitWarning(
103 record_location,
104 "Classes that are ref-counted should have explicit "
105 "destructors that are protected or private.");
106 } else if (CXXDestructorDecl* dtor = record->getDestructor()) {
107 if (dtor->getAccess() == AS_public) {
108 emitWarning(
109 dtor->getInnerLocStart(),
110 "Classes that are ref-counted should not have "
111 "public destructors.");
112 }
113 }
49 } 114 }
50 115
51 // Prints errors if the constructor/destructor weight is too heavy. 116 // Prints errors if the constructor/destructor weight is too heavy.
52 void CheckCtorDtorWeight(const SourceLocation& record_location, 117 void CheckCtorDtorWeight(const SourceLocation& record_location,
53 CXXRecordDecl* record) { 118 CXXRecordDecl* record) {
54 // We don't handle anonymous structs. If this record doesn't have a 119 // We don't handle anonymous structs. If this record doesn't have a
55 // name, it's of the form: 120 // name, it's of the form:
56 // 121 //
57 // struct { 122 // struct {
58 // ... 123 // ...
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 if (cs->size()) { 219 if (cs->size()) {
155 emitWarning( 220 emitWarning(
156 cs->getLBracLoc(), 221 cs->getLBracLoc(),
157 "virtual methods with non-empty bodies shouldn't be " 222 "virtual methods with non-empty bodies shouldn't be "
158 "declared inline."); 223 "declared inline.");
159 } 224 }
160 } 225 }
161 } 226 }
162 } 227 }
163 228
229 bool InTestingNamespace(const Decl* record) {
230 return GetNamespace(record).find("testing") != std::string::npos;
231 }
232
164 bool IsMethodInBannedNamespace(const CXXMethodDecl* method) { 233 bool IsMethodInBannedNamespace(const CXXMethodDecl* method) {
165 if (InBannedNamespace(method)) 234 if (InBannedNamespace(method))
166 return true; 235 return true;
167 for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods(); 236 for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods();
168 i != method->end_overridden_methods(); 237 i != method->end_overridden_methods();
169 ++i) { 238 ++i) {
170 const CXXMethodDecl* overridden = *i; 239 const CXXMethodDecl* overridden = *i;
171 if (IsMethodInBannedNamespace(overridden)) 240 if (IsMethodInBannedNamespace(overridden))
172 return true; 241 return true;
173 } 242 }
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 const std::vector<std::string>& args) { 361 const std::vector<std::string>& args) {
293 // We don't take any additional arguments here. 362 // We don't take any additional arguments here.
294 return true; 363 return true;
295 } 364 }
296 }; 365 };
297 366
298 } // namespace 367 } // namespace
299 368
300 static FrontendPluginRegistry::Add<FindBadConstructsAction> 369 static FrontendPluginRegistry::Add<FindBadConstructsAction>
301 X("find-bad-constructs", "Finds bad C++ constructs"); 370 X("find-bad-constructs", "Finds bad C++ constructs");
OLDNEW
« tools/clang/plugins/ChromeClassTester.cpp ('K') | « tools/clang/plugins/ChromeClassTester.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698