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

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

Issue 10005022: Check for public dtors on base::RefCounted types (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Copyright update 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
« no previous file with comments | « tools/clang/plugins/ChromeClassTester.h ('k') | tools/clang/plugins/FindBadConstructs.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 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 // A general interface for filtering and only acting on classes in Chromium C++ 5 // A general interface for filtering and only acting on classes in Chromium C++
6 // code. 6 // code.
7 7
8 #include "ChromeClassTester.h" 8 #include "ChromeClassTester.h"
9 9
10 #include <sys/param.h> 10 #include <sys/param.h>
11 11
(...skipping 21 matching lines...) Expand all
33 } 33 }
34 34
35 } // namespace 35 } // namespace
36 36
37 ChromeClassTester::ChromeClassTester(CompilerInstance& instance) 37 ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
38 : instance_(instance), 38 : instance_(instance),
39 diagnostic_(instance.getDiagnostics()) { 39 diagnostic_(instance.getDiagnostics()) {
40 BuildBannedLists(); 40 BuildBannedLists();
41 } 41 }
42 42
43 void ChromeClassTester::BuildBannedLists() {
44 banned_namespaces_.push_back("std");
45 banned_namespaces_.push_back("__gnu_cxx");
46 banned_namespaces_.push_back("WebKit");
47
48 banned_directories_.push_back("third_party/");
49 banned_directories_.push_back("native_client/");
50 banned_directories_.push_back("breakpad/");
51 banned_directories_.push_back("courgette/");
52 banned_directories_.push_back("pdf/");
53 banned_directories_.push_back("ppapi/");
54 banned_directories_.push_back("usr/");
55 banned_directories_.push_back("testing/");
56 banned_directories_.push_back("googleurl/");
57 banned_directories_.push_back("v8/");
58 banned_directories_.push_back("dart/");
59 banned_directories_.push_back("sdch/");
60 banned_directories_.push_back("icu4c/");
61 banned_directories_.push_back("frameworks/");
62
63 // Don't check autogenerated headers.
64 // Make puts them below $(builddir_name)/.../gen and geni.
65 // Ninja puts them below OUTPUT_DIR/.../gen
66 // Xcode has a fixed output directory for everything.
67 banned_directories_.push_back("gen/");
68 banned_directories_.push_back("geni/");
69 banned_directories_.push_back("xcodebuild/");
70
71 // You are standing in a mazy of twisty dependencies, all resolved by
72 // putting everything in the header.
73 banned_directories_.push_back("automation/");
74
75 // Don't check system headers.
76 banned_directories_.push_back("/Developer/");
77
78 // Used in really low level threading code that probably shouldn't be out of
79 // lined.
80 ignored_record_names_.insert("ThreadLocalBoolean");
81
82 // A complicated pickle derived struct that is all packed integers.
83 ignored_record_names_.insert("Header");
84
85 // Part of the GPU system that uses multiple included header
86 // weirdness. Never getting this right.
87 ignored_record_names_.insert("Validators");
88
89 // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
90 ignored_record_names_.insert("AutocompleteController");
91 ignored_record_names_.insert("HistoryURLProvider");
92
93 // Because of chrome frame
94 ignored_record_names_.insert("ReliabilityTestSuite");
95
96 // Used over in the net unittests. A large enough bundle of integers with 1
97 // non-pod class member. Probably harmless.
98 ignored_record_names_.insert("MockTransaction");
99
100 // Used heavily in ui_unittests and once in views_unittests. Fixing this
101 // isn't worth the overhead of an additional library.
102 ignored_record_names_.insert("TestAnimationDelegate");
103
104 // Part of our public interface that nacl and friends use. (Arguably, this
105 // should mean that this is a higher priority but fixing this looks hard.)
106 ignored_record_names_.insert("PluginVersionInfo");
107 }
108
109 ChromeClassTester::~ChromeClassTester() {} 43 ChromeClassTester::~ChromeClassTester() {}
110 44
111 void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) { 45 void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
112 // We handle class types here where we have semantic information. We can only 46 // We handle class types here where we have semantic information. We can only
113 // check structs/classes/enums here, but we get a bunch of nice semantic 47 // check structs/classes/enums here, but we get a bunch of nice semantic
114 // information instead of just parsing information. 48 // information instead of just parsing information.
115 49
116 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) { 50 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
117 // If this is a POD or a class template or a type dependent on a 51 // If this is a POD or a class template or a type dependent on a
118 // templated class, assume there's no ctor/dtor/virtual method 52 // templated class, assume there's no ctor/dtor/virtual method
(...skipping 20 matching lines...) Expand all
139 73
140 // We ignore all classes that end with "Matcher" because they're probably 74 // We ignore all classes that end with "Matcher" because they're probably
141 // GMock artifacts. 75 // GMock artifacts.
142 if (ends_with(base_name, "Matcher")) 76 if (ends_with(base_name, "Matcher"))
143 return; 77 return;
144 78
145 CheckChromeClass(record_location, record); 79 CheckChromeClass(record_location, record);
146 } 80 }
147 } 81 }
148 82
149 void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) { 83 void ChromeClassTester::emitWarning(SourceLocation loc,
84 const char* raw_error) {
150 FullSourceLoc full(loc, instance().getSourceManager()); 85 FullSourceLoc full(loc, instance().getSourceManager());
151 std::string err; 86 std::string err;
152 err = "[chromium-style] "; 87 err = "[chromium-style] ";
153 err += raw_error; 88 err += raw_error;
154 DiagnosticsEngine::Level level = 89 DiagnosticsEngine::Level level =
155 diagnostic().getWarningsAsErrors() ? 90 diagnostic().getWarningsAsErrors() ?
156 DiagnosticsEngine::Error : 91 DiagnosticsEngine::Error :
157 DiagnosticsEngine::Warning; 92 DiagnosticsEngine::Warning;
158 unsigned id = diagnostic().getCustomDiagID(level, err); 93 unsigned id = diagnostic().getCustomDiagID(level, err);
159 DiagnosticBuilder B = diagnostic().Report(full, id); 94 DiagnosticBuilder B = diagnostic().Report(full, id);
160 } 95 }
161 96
162 bool ChromeClassTester::InTestingNamespace(const Decl* record) {
163 return GetNamespace(record).find("testing") != std::string::npos;
164 }
165
166 bool ChromeClassTester::InBannedNamespace(const Decl* record) { 97 bool ChromeClassTester::InBannedNamespace(const Decl* record) {
167 std::string n = GetNamespace(record); 98 std::string n = GetNamespace(record);
168 if (n != "") { 99 if (n != "") {
169 return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n) 100 return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
170 != banned_namespaces_.end(); 101 != banned_namespaces_.end();
171 } 102 }
172 103
173 return false; 104 return false;
174 } 105 }
175 106
176 std::string ChromeClassTester::GetNamespace(const Decl* record) { 107 std::string ChromeClassTester::GetNamespace(const Decl* record) {
177 return GetNamespaceImpl(record->getDeclContext(), ""); 108 return GetNamespaceImpl(record->getDeclContext(), "");
178 } 109 }
179 110
111 bool ChromeClassTester::InImplementationFile(SourceLocation record_location) {
112 std::string filename;
113 if (!GetFilename(record_location, &filename)) {
114 return false;
115 }
116
117 if (ends_with(filename, ".cc") || ends_with(filename, ".cpp") ||
118 ends_with(filename, ".mm")) {
119 return true;
120 }
121
122 return false;
123 }
124
125 void ChromeClassTester::BuildBannedLists() {
126 banned_namespaces_.push_back("std");
127 banned_namespaces_.push_back("__gnu_cxx");
128 banned_namespaces_.push_back("WebKit");
129
130 banned_directories_.push_back("third_party/");
131 banned_directories_.push_back("native_client/");
132 banned_directories_.push_back("breakpad/");
133 banned_directories_.push_back("courgette/");
134 banned_directories_.push_back("pdf/");
135 banned_directories_.push_back("ppapi/");
136 banned_directories_.push_back("usr/");
137 banned_directories_.push_back("testing/");
138 banned_directories_.push_back("googleurl/");
139 banned_directories_.push_back("v8/");
140 banned_directories_.push_back("dart/");
141 banned_directories_.push_back("sdch/");
142 banned_directories_.push_back("icu4c/");
143 banned_directories_.push_back("frameworks/");
144
145 // Don't check autogenerated headers.
146 // Make puts them below $(builddir_name)/.../gen and geni.
147 // Ninja puts them below OUTPUT_DIR/.../gen
148 // Xcode has a fixed output directory for everything.
149 banned_directories_.push_back("gen/");
150 banned_directories_.push_back("geni/");
151 banned_directories_.push_back("xcodebuild/");
152
153 // You are standing in a mazy of twisty dependencies, all resolved by
154 // putting everything in the header.
155 banned_directories_.push_back("automation/");
156
157 // Don't check system headers.
158 banned_directories_.push_back("/Developer/");
159
160 // Used in really low level threading code that probably shouldn't be out of
161 // lined.
162 ignored_record_names_.insert("ThreadLocalBoolean");
163
164 // A complicated pickle derived struct that is all packed integers.
165 ignored_record_names_.insert("Header");
166
167 // Part of the GPU system that uses multiple included header
168 // weirdness. Never getting this right.
169 ignored_record_names_.insert("Validators");
170
171 // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
172 ignored_record_names_.insert("AutocompleteController");
173 ignored_record_names_.insert("HistoryURLProvider");
174
175 // Because of chrome frame
176 ignored_record_names_.insert("ReliabilityTestSuite");
177
178 // Used over in the net unittests. A large enough bundle of integers with 1
179 // non-pod class member. Probably harmless.
180 ignored_record_names_.insert("MockTransaction");
181
182 // Used heavily in ui_unittests and once in views_unittests. Fixing this
183 // isn't worth the overhead of an additional library.
184 ignored_record_names_.insert("TestAnimationDelegate");
185
186 // Part of our public interface that nacl and friends use. (Arguably, this
187 // should mean that this is a higher priority but fixing this looks hard.)
188 ignored_record_names_.insert("PluginVersionInfo");
189 }
190
180 std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context, 191 std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
181 std::string candidate) { 192 const std::string& candidate) {
182 switch (context->getDeclKind()) { 193 switch (context->getDeclKind()) {
183 case Decl::TranslationUnit: { 194 case Decl::TranslationUnit: {
184 return candidate; 195 return candidate;
185 } 196 }
186 case Decl::Namespace: { 197 case Decl::Namespace: {
187 const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context); 198 const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
188 std::string name_str; 199 std::string name_str;
189 llvm::raw_string_ostream OS(name_str); 200 llvm::raw_string_ostream OS(name_str);
190 if (decl->isAnonymousNamespace()) 201 if (decl->isAnonymousNamespace())
191 OS << "<anonymous namespace>"; 202 OS << "<anonymous namespace>";
192 else 203 else
193 OS << *decl; 204 OS << *decl;
194 return GetNamespaceImpl(context->getParent(), 205 return GetNamespaceImpl(context->getParent(),
195 OS.str()); 206 OS.str());
196 } 207 }
197 default: { 208 default: {
198 return GetNamespaceImpl(context->getParent(), candidate); 209 return GetNamespaceImpl(context->getParent(), candidate);
199 } 210 }
200 } 211 }
201 } 212 }
202 213
203 bool ChromeClassTester::InBannedDirectory(SourceLocation loc) { 214 bool ChromeClassTester::InBannedDirectory(SourceLocation loc) {
204 const SourceManager &SM = instance_.getSourceManager(); 215 std::string filename;
205 SourceLocation spelling_location = SM.getSpellingLoc(loc); 216 if (!GetFilename(loc, &filename)) {
206 PresumedLoc ploc = SM.getPresumedLoc(spelling_location); 217 // If the filename cannot be determined, simply treat this as a banned
207 std::string buffer_name; 218 // location, instead of going through the full lookup process.
208 if (ploc.isInvalid()) {
209 // If we're in an invalid location, we're looking at things that aren't
210 // actually stated in the source; treat this as a banned location instead
211 // of going through our full lookup process.
212 return true; 219 return true;
213 } else { 220 }
214 std::string b = ploc.getFilename();
215 221
216 // We need to special case scratch space; which is where clang does its 222 // We need to special case scratch space; which is where clang does its
217 // macro expansion. We explicitly want to allow people to do otherwise bad 223 // macro expansion. We explicitly want to allow people to do otherwise bad
218 // things through macros that were defined due to third party libraries. 224 // things through macros that were defined due to third party libraries.
219 if (b == "<scratch space>") 225 if (filename == "<scratch space>")
220 return true; 226 return true;
221 227
222 // Don't complain about these things in implementation files. 228 // Don't complain about autogenerated protobuf files.
223 if (ends_with(b, ".cc") || ends_with(b, ".cpp") || ends_with(b, ".mm")) { 229 if (ends_with(filename, ".pb.h")) {
224 return true; 230 return true;
225 } 231 }
226 232
227 // Don't complain about autogenerated protobuf files. 233 // We need to munge the paths so that they are relative to the repository
228 if (ends_with(b, ".pb.h")) { 234 // srcroot. We first resolve the symlinktastic relative path and then
229 return true; 235 // remove our known srcroot from it if needed.
230 } 236 char resolvedPath[MAXPATHLEN];
237 if (realpath(filename.c_str(), resolvedPath)) {
238 filename = resolvedPath;
239 }
231 240
232 // We need to munge the paths so that they are relative to the repository 241 // On linux, chrome is often checked out to /usr/local/google. Due to the
233 // srcroot. We first resolve the symlinktastic relative path and then 242 // "usr" rule in banned_directories_, all diagnostics would be suppressed
234 // remove our known srcroot from it if needed. 243 // in that case. As a workaround, strip that prefix.
235 char resolvedPath[MAXPATHLEN]; 244 filename = lstrip(filename, "/usr/local/google");
236 if (realpath(b.c_str(), resolvedPath)) {
237 b = resolvedPath;
238 }
239 245
240 // On linux, chrome is often checked out to /usr/local/google. Due to the 246 for (std::vector<std::string>::const_iterator it =
241 // "usr" rule in banned_directories_, all diagnostics would be suppressed 247 banned_directories_.begin();
242 // in that case. As a workaround, strip that prefix. 248 it != banned_directories_.end(); ++it) {
243 b = lstrip(b, "/usr/local/google"); 249 // If we can find any of the banned path components in this path, then
244 250 // this file is rejected.
245 for (std::vector<std::string>::const_iterator it = 251 size_t index = filename.find(*it);
246 banned_directories_.begin(); 252 if (index != std::string::npos) {
247 it != banned_directories_.end(); ++it) { 253 bool matches_full_dir_name = index == 0 || filename[index - 1] == '/';
248 // If we can find any of the banned path components in this path, then 254 if ((*it)[0] == '/')
249 // this file is rejected. 255 matches_full_dir_name = true;
250 size_t index = b.find(*it); 256 if (matches_full_dir_name)
251 if (index != std::string::npos) { 257 return true;
252 bool matches_full_dir_name = index == 0 || b[index - 1] == '/';
253 if ((*it)[0] == '/')
254 matches_full_dir_name = true;
255 if (matches_full_dir_name)
256 return true;
257 }
258 } 258 }
259 } 259 }
260 260
261 return false; 261 return false;
262 } 262 }
263 263
264 bool ChromeClassTester::IsIgnoredType(const std::string& base_name) { 264 bool ChromeClassTester::IsIgnoredType(const std::string& base_name) {
265 return ignored_record_names_.find(base_name) != ignored_record_names_.end(); 265 return ignored_record_names_.find(base_name) != ignored_record_names_.end();
266 } 266 }
267
268 bool ChromeClassTester::GetFilename(SourceLocation loc,
269 std::string* filename) {
270 const SourceManager &SM = instance_.getSourceManager();
271 SourceLocation spelling_location = SM.getSpellingLoc(loc);
272 PresumedLoc ploc = SM.getPresumedLoc(spelling_location);
273 if (ploc.isInvalid()) {
274 // If we're in an invalid location, we're looking at things that aren't
275 // actually stated in the source.
276 return false;
277 }
278
279 *filename = ploc.getFilename();
280 return true;
281 }
OLDNEW
« no previous file with comments | « tools/clang/plugins/ChromeClassTester.h ('k') | tools/clang/plugins/FindBadConstructs.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698