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 #include "FindBadConstructsConsumer.h" | 5 #include "FindBadConstructsConsumer.h" |
6 | 6 |
7 #include "clang/Frontend/CompilerInstance.h" | 7 #include "clang/Frontend/CompilerInstance.h" |
8 #include "clang/AST/Attr.h" | |
8 #include "clang/Lex/Lexer.h" | 9 #include "clang/Lex/Lexer.h" |
9 #include "llvm/Support/raw_ostream.h" | 10 #include "llvm/Support/raw_ostream.h" |
10 | 11 |
11 using namespace clang; | 12 using namespace clang; |
12 | 13 |
13 namespace chrome_checker { | 14 namespace chrome_checker { |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 const char kMethodRequiresOverride[] = | 18 const char kMethodRequiresOverride[] = |
18 "[chromium-style] Overriding method must be marked with OVERRIDE."; | 19 "[chromium-style] Overriding method must be marked with 'override' or " |
19 const char kMethodRequiresVirtual[] = | 20 "'final'."; |
20 "[chromium-style] Overriding method must have \"virtual\" keyword."; | 21 const char kRedundantVirtualSpecifier[] = |
22 "[chromium-style] %0 is redundant; %1 implies %0."; | |
23 // http://llvm.org/bugs/show_bug.cgi?id=21051 has been filed to make this a | |
24 // Clang warning. | |
25 const char kBaseMethodVirtualAndFinal[] = | |
26 "[chromium-style] The virtual method does not override anything and is " | |
27 "final; consider making it non-virtual."; | |
21 const char kNoExplicitDtor[] = | 28 const char kNoExplicitDtor[] = |
22 "[chromium-style] Classes that are ref-counted should have explicit " | 29 "[chromium-style] Classes that are ref-counted should have explicit " |
23 "destructors that are declared protected or private."; | 30 "destructors that are declared protected or private."; |
24 const char kPublicDtor[] = | 31 const char kPublicDtor[] = |
25 "[chromium-style] Classes that are ref-counted should have " | 32 "[chromium-style] Classes that are ref-counted should have " |
26 "destructors that are declared protected or private."; | 33 "destructors that are declared protected or private."; |
27 const char kProtectedNonVirtualDtor[] = | 34 const char kProtectedNonVirtualDtor[] = |
28 "[chromium-style] Classes that are ref-counted and have non-private " | 35 "[chromium-style] Classes that are ref-counted and have non-private " |
29 "destructors should declare their destructor virtual."; | 36 "destructors should declare their destructor virtual."; |
30 const char kWeakPtrFactoryOrder[] = | 37 const char kWeakPtrFactoryOrder[] = |
(...skipping 21 matching lines...) Expand all Loading... | |
52 // any namespace qualifiers. This is similar to desugaring, except that for | 59 // any namespace qualifiers. This is similar to desugaring, except that for |
53 // ElaboratedTypes, desugar will unwrap too much. | 60 // ElaboratedTypes, desugar will unwrap too much. |
54 const Type* UnwrapType(const Type* type) { | 61 const Type* UnwrapType(const Type* type) { |
55 if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) | 62 if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) |
56 return UnwrapType(elaborated->getNamedType().getTypePtr()); | 63 return UnwrapType(elaborated->getNamedType().getTypePtr()); |
57 if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) | 64 if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) |
58 return UnwrapType(typedefed->desugar().getTypePtr()); | 65 return UnwrapType(typedefed->desugar().getTypePtr()); |
59 return type; | 66 return type; |
60 } | 67 } |
61 | 68 |
69 FixItHint FixItRemovalForVirtual(const SourceManager& manager, | |
70 const CXXMethodDecl* method) { | |
71 // Unfortunately, there doesn't seem to be a good way to determine the | |
72 // location | |
73 // of the 'virtual' keyword. It's available in Declarator, but that isn't | |
74 // accessible from the AST. So instead, make an educated guess that the first | |
75 // token is probably the virtual keyword. Strictly speaking, this doesn't have | |
76 // to be true, but it probably will be. | |
77 // TODO(dcheng): Add a warning to force virtual to always appear first ;-) | |
78 SourceRange range(method->getLocStart(), | |
79 Lexer::getLocForEndOfToken( | |
80 method->getLocStart(), 0, manager, LangOptions())); | |
81 // Get the spelling loc just in case it was expanded from a macro... | |
82 SourceRange spelling_range(manager.getSpellingLoc(range.getBegin()), | |
83 manager.getSpellingLoc(range.getEnd())); | |
84 // Sanity check that the text looks like virtual. | |
85 StringRef text = clang::Lexer::getSourceText( | |
86 CharSourceRange::getCharRange(spelling_range), manager, LangOptions()); | |
87 if (!text.startswith("virtual")) | |
hans
2014/09/27 00:36:10
Any reason not to check if (text != "virtual") ?
dcheng
2014/09/28 18:35:39
I was worried about whitespace, but I forgot about
| |
88 return FixItHint(); | |
89 return FixItHint::CreateRemoval(range); | |
90 } | |
91 | |
62 } // namespace | 92 } // namespace |
63 | 93 |
64 FindBadConstructsConsumer::FindBadConstructsConsumer(CompilerInstance& instance, | 94 FindBadConstructsConsumer::FindBadConstructsConsumer(CompilerInstance& instance, |
65 const Options& options) | 95 const Options& options) |
66 : ChromeClassTester(instance), options_(options) { | 96 : ChromeClassTester(instance), options_(options) { |
67 // Register warning/error messages. | 97 // Messages for virtual method specifiers. |
68 diag_method_requires_override_ = | 98 diag_method_requires_override_ = |
69 diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresOverride); | 99 diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresOverride); |
70 diag_method_requires_virtual_ = | 100 diag_redundant_virtual_specifier_ = |
71 diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresVirtual); | 101 diagnostic().getCustomDiagID(getErrorLevel(), kRedundantVirtualSpecifier); |
102 diag_base_method_virtual_and_final_ = | |
103 diagnostic().getCustomDiagID(getErrorLevel(), kBaseMethodVirtualAndFinal); | |
104 | |
105 // Messages for destructors. | |
72 diag_no_explicit_dtor_ = | 106 diag_no_explicit_dtor_ = |
73 diagnostic().getCustomDiagID(getErrorLevel(), kNoExplicitDtor); | 107 diagnostic().getCustomDiagID(getErrorLevel(), kNoExplicitDtor); |
74 diag_public_dtor_ = | 108 diag_public_dtor_ = |
75 diagnostic().getCustomDiagID(getErrorLevel(), kPublicDtor); | 109 diagnostic().getCustomDiagID(getErrorLevel(), kPublicDtor); |
76 diag_protected_non_virtual_dtor_ = | 110 diag_protected_non_virtual_dtor_ = |
77 diagnostic().getCustomDiagID(getErrorLevel(), kProtectedNonVirtualDtor); | 111 diagnostic().getCustomDiagID(getErrorLevel(), kProtectedNonVirtualDtor); |
112 | |
113 // Miscellaneous messages. | |
78 diag_weak_ptr_factory_order_ = | 114 diag_weak_ptr_factory_order_ = |
79 diagnostic().getCustomDiagID(getErrorLevel(), kWeakPtrFactoryOrder); | 115 diagnostic().getCustomDiagID(getErrorLevel(), kWeakPtrFactoryOrder); |
80 diag_bad_enum_last_value_ = | 116 diag_bad_enum_last_value_ = |
81 diagnostic().getCustomDiagID(getErrorLevel(), kBadLastEnumValue); | 117 diagnostic().getCustomDiagID(getErrorLevel(), kBadLastEnumValue); |
82 | 118 |
83 // Registers notes to make it easier to interpret warnings. | 119 // Registers notes to make it easier to interpret warnings. |
84 diag_note_inheritance_ = | 120 diag_note_inheritance_ = |
85 diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNoteInheritance); | 121 diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNoteInheritance); |
86 diag_note_implicit_dtor_ = | 122 diag_note_implicit_dtor_ = |
87 diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNoteImplicitDtor); | 123 diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNoteImplicitDtor); |
88 diag_note_public_dtor_ = | 124 diag_note_public_dtor_ = |
89 diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNotePublicDtor); | 125 diagnostic().getCustomDiagID(DiagnosticsEngine::Note, kNotePublicDtor); |
90 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( | 126 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
91 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); | 127 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); |
92 } | 128 } |
93 | 129 |
94 void FindBadConstructsConsumer::CheckChromeClass(SourceLocation record_location, | 130 void FindBadConstructsConsumer::CheckChromeClass(SourceLocation record_location, |
95 CXXRecordDecl* record) { | 131 CXXRecordDecl* record) { |
96 bool implementation_file = InImplementationFile(record_location); | 132 bool implementation_file = InImplementationFile(record_location); |
97 | 133 |
98 if (!implementation_file) { | 134 if (!implementation_file) { |
99 // Only check for "heavy" constructors/destructors in header files; | 135 // Only check for "heavy" constructors/destructors in header files; |
100 // within implementation files, there is no performance cost. | 136 // within implementation files, there is no performance cost. |
101 CheckCtorDtorWeight(record_location, record); | 137 CheckCtorDtorWeight(record_location, record); |
102 } | 138 } |
103 | 139 |
104 bool warn_on_inline_bodies = !implementation_file; | 140 bool warn_on_inline_bodies = !implementation_file; |
105 | 141 |
106 // Check that all virtual methods are marked accordingly with both | 142 // Check that all virtual methods are annotated with override or final. |
107 // virtual and OVERRIDE. | |
108 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); | 143 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); |
109 | 144 |
110 CheckRefCountedDtors(record_location, record); | 145 CheckRefCountedDtors(record_location, record); |
111 | 146 |
112 if (options_.check_weak_ptr_factory_order) | 147 if (options_.check_weak_ptr_factory_order) |
113 CheckWeakPtrFactoryMembers(record_location, record); | 148 CheckWeakPtrFactoryMembers(record_location, record); |
114 } | 149 } |
115 | 150 |
116 void FindBadConstructsConsumer::CheckChromeEnum(SourceLocation enum_location, | 151 void FindBadConstructsConsumer::CheckChromeEnum(SourceLocation enum_location, |
117 EnumDecl* enum_decl) { | 152 EnumDecl* enum_decl) { |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 "destructor."); | 278 "destructor."); |
244 } else if (CXXDestructorDecl* dtor = record->getDestructor()) { | 279 } else if (CXXDestructorDecl* dtor = record->getDestructor()) { |
245 if (dtor->hasInlineBody()) { | 280 if (dtor->hasInlineBody()) { |
246 emitWarning(dtor->getInnerLocStart(), | 281 emitWarning(dtor->getInnerLocStart(), |
247 "Complex destructor has an inline body."); | 282 "Complex destructor has an inline body."); |
248 } | 283 } |
249 } | 284 } |
250 } | 285 } |
251 } | 286 } |
252 | 287 |
253 void FindBadConstructsConsumer::CheckVirtualMethod(const CXXMethodDecl* method, | |
254 bool warn_on_inline_bodies) { | |
255 if (!method->isVirtual()) | |
256 return; | |
257 | |
258 if (!method->isVirtualAsWritten()) { | |
259 SourceLocation loc = method->getTypeSpecStartLoc(); | |
260 if (isa<CXXDestructorDecl>(method)) | |
261 loc = method->getInnerLocStart(); | |
262 SourceManager& manager = instance().getSourceManager(); | |
263 FullSourceLoc full_loc(loc, manager); | |
264 SourceLocation spelling_loc = manager.getSpellingLoc(loc); | |
265 diagnostic().Report(full_loc, diag_method_requires_virtual_) | |
266 << FixItHint::CreateInsertion(spelling_loc, "virtual "); | |
267 } | |
268 | |
269 // Virtual methods should not have inline definitions beyond "{}". This | |
270 // only matters for header files. | |
271 if (warn_on_inline_bodies && method->hasBody() && method->hasInlineBody()) { | |
272 if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) { | |
273 if (cs->size()) { | |
274 emitWarning(cs->getLBracLoc(), | |
275 "virtual methods with non-empty bodies shouldn't be " | |
276 "declared inline."); | |
277 } | |
278 } | |
279 } | |
280 } | |
281 | |
282 bool FindBadConstructsConsumer::InTestingNamespace(const Decl* record) { | 288 bool FindBadConstructsConsumer::InTestingNamespace(const Decl* record) { |
283 return GetNamespace(record).find("testing") != std::string::npos; | 289 return GetNamespace(record).find("testing") != std::string::npos; |
284 } | 290 } |
285 | 291 |
286 bool FindBadConstructsConsumer::IsMethodInBannedOrTestingNamespace( | 292 bool FindBadConstructsConsumer::IsMethodInBannedOrTestingNamespace( |
287 const CXXMethodDecl* method) { | 293 const CXXMethodDecl* method) { |
288 if (InBannedNamespace(method)) | 294 if (InBannedNamespace(method)) |
289 return true; | 295 return true; |
290 for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods(); | 296 for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods(); |
291 i != method->end_overridden_methods(); | 297 i != method->end_overridden_methods(); |
292 ++i) { | 298 ++i) { |
293 const CXXMethodDecl* overridden = *i; | 299 const CXXMethodDecl* overridden = *i; |
294 if (IsMethodInBannedOrTestingNamespace(overridden) || | 300 if (IsMethodInBannedOrTestingNamespace(overridden) || |
295 InTestingNamespace(overridden)) { | 301 InTestingNamespace(overridden)) { |
296 return true; | 302 return true; |
297 } | 303 } |
298 } | 304 } |
299 | 305 |
300 return false; | 306 return false; |
301 } | 307 } |
302 | 308 |
303 void FindBadConstructsConsumer::CheckOverriddenMethod( | 309 // Checks that virtual methods are correctly annotated, and have no body in a |
304 const CXXMethodDecl* method) { | 310 // header file. |
305 if (!method->size_overridden_methods() || method->getAttr<OverrideAttr>()) | |
306 return; | |
307 | |
308 if (isa<CXXDestructorDecl>(method) || method->isPure()) | |
309 return; | |
310 | |
311 if (IsMethodInBannedOrTestingNamespace(method)) | |
312 return; | |
313 | |
314 SourceManager& manager = instance().getSourceManager(); | |
315 SourceRange type_info_range = | |
316 method->getTypeSourceInfo()->getTypeLoc().getSourceRange(); | |
317 FullSourceLoc loc(type_info_range.getBegin(), manager); | |
318 | |
319 // Build the FixIt insertion point after the end of the method definition, | |
320 // including any const-qualifiers and attributes, and before the opening | |
321 // of the l-curly-brace (if inline) or the semi-color (if a declaration). | |
322 SourceLocation spelling_end = | |
323 manager.getSpellingLoc(type_info_range.getEnd()); | |
324 if (spelling_end.isValid()) { | |
325 SourceLocation token_end = | |
326 Lexer::getLocForEndOfToken(spelling_end, 0, manager, LangOptions()); | |
327 diagnostic().Report(token_end, diag_method_requires_override_) | |
328 << FixItHint::CreateInsertion(token_end, " OVERRIDE"); | |
329 } else { | |
330 diagnostic().Report(loc, diag_method_requires_override_); | |
331 } | |
332 } | |
333 | |
334 // Makes sure there is a "virtual" keyword on virtual methods. | |
335 // | |
336 // Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a | |
337 // trick to get around that. If a class has member variables whose types are | |
338 // in the "testing" namespace (which is how gmock works behind the scenes), | |
339 // there's a really high chance we won't care about these errors | |
340 void FindBadConstructsConsumer::CheckVirtualMethods( | 311 void FindBadConstructsConsumer::CheckVirtualMethods( |
341 SourceLocation record_location, | 312 SourceLocation record_location, |
342 CXXRecordDecl* record, | 313 CXXRecordDecl* record, |
343 bool warn_on_inline_bodies) { | 314 bool warn_on_inline_bodies) { |
315 // Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a | |
316 // trick to get around that. If a class has member variables whose types are | |
317 // in the "testing" namespace (which is how gmock works behind the scenes), | |
318 // there's a really high chance we won't care about these errors | |
344 for (CXXRecordDecl::field_iterator it = record->field_begin(); | 319 for (CXXRecordDecl::field_iterator it = record->field_begin(); |
345 it != record->field_end(); | 320 it != record->field_end(); |
346 ++it) { | 321 ++it) { |
347 CXXRecordDecl* record_type = it->getTypeSourceInfo() | 322 CXXRecordDecl* record_type = it->getTypeSourceInfo() |
348 ->getTypeLoc() | 323 ->getTypeLoc() |
349 .getTypePtr() | 324 .getTypePtr() |
350 ->getAsCXXRecordDecl(); | 325 ->getAsCXXRecordDecl(); |
351 if (record_type) { | 326 if (record_type) { |
352 if (InTestingNamespace(record_type)) { | 327 if (InTestingNamespace(record_type)) { |
353 return; | 328 return; |
354 } | 329 } |
355 } | 330 } |
356 } | 331 } |
357 | 332 |
358 for (CXXRecordDecl::method_iterator it = record->method_begin(); | 333 for (CXXRecordDecl::method_iterator it = record->method_begin(); |
359 it != record->method_end(); | 334 it != record->method_end(); |
360 ++it) { | 335 ++it) { |
361 if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) { | 336 if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) { |
362 // Ignore constructors and assignment operators. | 337 // Ignore constructors and assignment operators. |
363 } else if (isa<CXXDestructorDecl>(*it) && | 338 } else if (isa<CXXDestructorDecl>(*it) && |
364 !record->hasUserDeclaredDestructor()) { | 339 !record->hasUserDeclaredDestructor()) { |
365 // Ignore non-user-declared destructors. | 340 // Ignore non-user-declared destructors. |
341 } else if (!it->isVirtual()) { | |
342 continue; | |
366 } else { | 343 } else { |
367 CheckVirtualMethod(*it, warn_on_inline_bodies); | 344 CheckVirtualSpecifiers(*it); |
368 CheckOverriddenMethod(*it); | 345 if (warn_on_inline_bodies) |
346 CheckVirtualBodies(*it); | |
369 } | 347 } |
370 } | 348 } |
371 } | 349 } |
350 | |
351 // Makes sure that virtual methods use the most appropriate specifier. If a | |
352 // virtual method overrides a method from a base class, only the override | |
353 // specifier should be used. If the method should not be overridden by derived | |
354 // classes, only the final specifier should be used. | |
355 void FindBadConstructsConsumer::CheckVirtualSpecifiers( | |
356 const CXXMethodDecl* method) { | |
357 bool is_override = method->size_overridden_methods() > 0; | |
358 bool has_virtual = method->isVirtualAsWritten(); | |
359 OverrideAttr* override_attr = method->getAttr<OverrideAttr>(); | |
360 FinalAttr* final_attr = method->getAttr<FinalAttr>(); | |
361 | |
362 if (method->isPure()) | |
363 return; | |
364 | |
365 if (IsMethodInBannedOrTestingNamespace(method)) | |
366 return; | |
367 | |
368 if (isa<CXXDestructorDecl>(method) && !options_.strict_virtual_specifiers) | |
369 return; | |
370 | |
371 SourceManager& manager = instance().getSourceManager(); | |
372 | |
373 // Complain if a method is annotated virtual && (override || final). | |
374 if (has_virtual && (override_attr || final_attr) && | |
375 options_.strict_virtual_specifiers) { | |
376 diagnostic().Report(method->getLocStart(), | |
377 diag_redundant_virtual_specifier_) | |
378 << "'virtual'" | |
379 << (override_attr ? static_cast<Attr*>(override_attr) : final_attr) | |
380 << FixItRemovalForVirtual(manager, method); | |
381 } | |
382 | |
383 // Complain if a method is an override and is not annotated with override or | |
384 // final. | |
385 if (is_override && !override_attr && !final_attr) { | |
386 SourceRange type_info_range = | |
387 method->getTypeSourceInfo()->getTypeLoc().getSourceRange(); | |
388 FullSourceLoc loc(type_info_range.getBegin(), manager); | |
389 | |
390 // Build the FixIt insertion point after the end of the method definition, | |
391 // including any const-qualifiers and attributes, and before the opening | |
392 // of the l-curly-brace (if inline) or the semi-color (if a declaration). | |
393 SourceLocation spelling_end = | |
394 manager.getSpellingLoc(type_info_range.getEnd()); | |
395 if (spelling_end.isValid()) { | |
396 SourceLocation token_end = | |
397 Lexer::getLocForEndOfToken(spelling_end, 0, manager, LangOptions()); | |
398 diagnostic().Report(token_end, diag_method_requires_override_) | |
399 << FixItHint::CreateInsertion(token_end, " override"); | |
400 } else { | |
401 diagnostic().Report(loc, diag_method_requires_override_); | |
402 } | |
403 } | |
404 | |
405 if (final_attr && override_attr && options_.strict_virtual_specifiers) { | |
406 diagnostic().Report(override_attr->getLocation(), | |
407 diag_redundant_virtual_specifier_) | |
408 << override_attr << final_attr | |
409 << FixItHint::CreateRemoval(override_attr->getRange()); | |
410 } | |
411 | |
412 if (final_attr && !is_override && options_.strict_virtual_specifiers) { | |
413 diagnostic().Report(method->getLocStart(), | |
414 diag_base_method_virtual_and_final_) | |
415 << FixItRemovalForVirtual(manager, method) | |
416 << FixItHint::CreateRemoval(final_attr->getRange()); | |
417 } | |
418 } | |
419 | |
420 void FindBadConstructsConsumer::CheckVirtualBodies( | |
421 const CXXMethodDecl* method) { | |
422 // Virtual methods should not have inline definitions beyond "{}". This | |
423 // only matters for header files. | |
424 if (method->hasBody() && method->hasInlineBody()) { | |
425 if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) { | |
426 if (cs->size()) { | |
427 emitWarning(cs->getLBracLoc(), | |
428 "virtual methods with non-empty bodies shouldn't be " | |
429 "declared inline."); | |
430 } | |
431 } | |
432 } | |
433 } | |
372 | 434 |
373 void FindBadConstructsConsumer::CountType(const Type* type, | 435 void FindBadConstructsConsumer::CountType(const Type* type, |
374 int* trivial_member, | 436 int* trivial_member, |
375 int* non_trivial_member, | 437 int* non_trivial_member, |
376 int* templated_non_trivial_member) { | 438 int* templated_non_trivial_member) { |
377 switch (type->getTypeClass()) { | 439 switch (type->getTypeClass()) { |
378 case Type::Record: { | 440 case Type::Record: { |
379 // Simplifying; the whole class isn't trivial if the dtor is, but | 441 // Simplifying; the whole class isn't trivial if the dtor is, but |
380 // we use this as a signal about complexity. | 442 // we use this as a signal about complexity. |
381 if (TypeHasNonTrivialDtor(type)) | 443 if (TypeHasNonTrivialDtor(type)) |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
676 record->getTypeForDecl()->getAsCXXRecordDecl()) { | 738 record->getTypeForDecl()->getAsCXXRecordDecl()) { |
677 weak_ptr_factory_location = iter->getLocation(); | 739 weak_ptr_factory_location = iter->getLocation(); |
678 } | 740 } |
679 } | 741 } |
680 } | 742 } |
681 } | 743 } |
682 } | 744 } |
683 } | 745 } |
684 | 746 |
685 } // namespace chrome_checker | 747 } // namespace chrome_checker |
OLD | NEW |