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