| 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 |
| 16 // member. |
| 15 | 17 |
| 16 #include "clang/AST/ASTConsumer.h" | 18 #include "clang/AST/ASTConsumer.h" |
| 17 #include "clang/AST/AST.h" | 19 #include "clang/AST/AST.h" |
| 18 #include "clang/AST/Attr.h" | 20 #include "clang/AST/Attr.h" |
| 19 #include "clang/AST/CXXInheritance.h" | 21 #include "clang/AST/CXXInheritance.h" |
| 20 #include "clang/AST/TypeLoc.h" | 22 #include "clang/AST/TypeLoc.h" |
| 21 #include "clang/Basic/SourceManager.h" | 23 #include "clang/Basic/SourceManager.h" |
| 22 #include "clang/Frontend/CompilerInstance.h" | 24 #include "clang/Frontend/CompilerInstance.h" |
| 23 #include "clang/Frontend/FrontendPluginRegistry.h" | 25 #include "clang/Frontend/FrontendPluginRegistry.h" |
| 24 #include "clang/Lex/Lexer.h" | 26 #include "clang/Lex/Lexer.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 36 "[chromium-style] Overriding method must have \"virtual\" keyword."; | 38 "[chromium-style] Overriding method must have \"virtual\" keyword."; |
| 37 const char kNoExplicitDtor[] = | 39 const char kNoExplicitDtor[] = |
| 38 "[chromium-style] Classes that are ref-counted should have explicit " | 40 "[chromium-style] Classes that are ref-counted should have explicit " |
| 39 "destructors that are declared protected or private."; | 41 "destructors that are declared protected or private."; |
| 40 const char kPublicDtor[] = | 42 const char kPublicDtor[] = |
| 41 "[chromium-style] Classes that are ref-counted should have " | 43 "[chromium-style] Classes that are ref-counted should have " |
| 42 "destructors that are declared protected or private."; | 44 "destructors that are declared protected or private."; |
| 43 const char kProtectedNonVirtualDtor[] = | 45 const char kProtectedNonVirtualDtor[] = |
| 44 "[chromium-style] Classes that are ref-counted and have non-private " | 46 "[chromium-style] Classes that are ref-counted and have non-private " |
| 45 "destructors should declare their destructor virtual."; | 47 "destructors should declare their destructor virtual."; |
| 48 const char kWeakPtrFactoryOrder[] = |
| 49 "[chromium-style] WeakPtrFactory members which refer to their outer class " |
| 50 "must be the last member in the outer class definition."; |
| 46 const char kNoteInheritance[] = | 51 const char kNoteInheritance[] = |
| 47 "[chromium-style] %0 inherits from %1 here"; | 52 "[chromium-style] %0 inherits from %1 here"; |
| 48 const char kNoteImplicitDtor[] = | 53 const char kNoteImplicitDtor[] = |
| 49 "[chromium-style] No explicit destructor for %0 defined"; | 54 "[chromium-style] No explicit destructor for %0 defined"; |
| 50 const char kNotePublicDtor[] = | 55 const char kNotePublicDtor[] = |
| 51 "[chromium-style] Public destructor declared here"; | 56 "[chromium-style] Public destructor declared here"; |
| 52 const char kNoteProtectedNonVirtualDtor[] = | 57 const char kNoteProtectedNonVirtualDtor[] = |
| 53 "[chromium-style] Protected non-virtual destructor declared here"; | 58 "[chromium-style] Protected non-virtual destructor declared here"; |
| 54 | 59 |
| 55 bool TypeHasNonTrivialDtor(const Type* type) { | 60 bool TypeHasNonTrivialDtor(const Type* type) { |
| 56 if (const CXXRecordDecl* cxx_r = type->getPointeeCXXRecordDecl()) | 61 if (const CXXRecordDecl* cxx_r = type->getPointeeCXXRecordDecl()) |
| 57 return cxx_r->hasTrivialDestructor(); | 62 return cxx_r->hasTrivialDestructor(); |
| 58 | 63 |
| 59 return false; | 64 return false; |
| 60 } | 65 } |
| 61 | 66 |
| 62 // Returns the underlying Type for |type| by expanding typedefs and removing | 67 // Returns the underlying Type for |type| by expanding typedefs and removing |
| 63 // any namespace qualifiers. This is similar to desugaring, except that for | 68 // any namespace qualifiers. This is similar to desugaring, except that for |
| 64 // ElaboratedTypes, desugar will unwrap too much. | 69 // ElaboratedTypes, desugar will unwrap too much. |
| 65 const Type* UnwrapType(const Type* type) { | 70 const Type* UnwrapType(const Type* type) { |
| 66 if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) | 71 if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type)) |
| 67 return UnwrapType(elaborated->getNamedType().getTypePtr()); | 72 return UnwrapType(elaborated->getNamedType().getTypePtr()); |
| 68 if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) | 73 if (const TypedefType* typedefed = dyn_cast<TypedefType>(type)) |
| 69 return UnwrapType(typedefed->desugar().getTypePtr()); | 74 return UnwrapType(typedefed->desugar().getTypePtr()); |
| 70 return type; | 75 return type; |
| 71 } | 76 } |
| 72 | 77 |
| 78 struct FindBadConstructsOptions { |
| 79 FindBadConstructsOptions() : check_base_classes(false), |
| 80 check_virtuals_in_implementations(true), |
| 81 check_url_directory(false), |
| 82 check_weak_ptr_factory_order(false) { |
| 83 } |
| 84 bool check_base_classes; |
| 85 bool check_virtuals_in_implementations; |
| 86 bool check_url_directory; |
| 87 bool check_weak_ptr_factory_order; |
| 88 }; |
| 89 |
| 73 // Searches for constructs that we know we don't want in the Chromium code base. | 90 // Searches for constructs that we know we don't want in the Chromium code base. |
| 74 class FindBadConstructsConsumer : public ChromeClassTester { | 91 class FindBadConstructsConsumer : public ChromeClassTester { |
| 75 public: | 92 public: |
| 76 FindBadConstructsConsumer(CompilerInstance& instance, | 93 FindBadConstructsConsumer(CompilerInstance& instance, |
| 77 bool check_base_classes, | 94 const FindBadConstructsOptions& options) |
| 78 bool check_virtuals_in_implementations, | 95 : ChromeClassTester(instance, options.check_url_directory), |
| 79 bool check_url_directory) | 96 options_(options) { |
| 80 : ChromeClassTester(instance, check_url_directory), | |
| 81 check_base_classes_(check_base_classes), | |
| 82 check_virtuals_in_implementations_(check_virtuals_in_implementations) { | |
| 83 // Register warning/error messages. | 97 // Register warning/error messages. |
| 84 diag_method_requires_override_ = diagnostic().getCustomDiagID( | 98 diag_method_requires_override_ = diagnostic().getCustomDiagID( |
| 85 getErrorLevel(), kMethodRequiresOverride); | 99 getErrorLevel(), kMethodRequiresOverride); |
| 86 diag_method_requires_virtual_ = diagnostic().getCustomDiagID( | 100 diag_method_requires_virtual_ = diagnostic().getCustomDiagID( |
| 87 getErrorLevel(), kMethodRequiresVirtual); | 101 getErrorLevel(), kMethodRequiresVirtual); |
| 88 diag_no_explicit_dtor_ = diagnostic().getCustomDiagID( | 102 diag_no_explicit_dtor_ = diagnostic().getCustomDiagID( |
| 89 getErrorLevel(), kNoExplicitDtor); | 103 getErrorLevel(), kNoExplicitDtor); |
| 90 diag_public_dtor_ = diagnostic().getCustomDiagID( | 104 diag_public_dtor_ = diagnostic().getCustomDiagID( |
| 91 getErrorLevel(), kPublicDtor); | 105 getErrorLevel(), kPublicDtor); |
| 92 diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( | 106 diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
| 93 getErrorLevel(), kProtectedNonVirtualDtor); | 107 getErrorLevel(), kProtectedNonVirtualDtor); |
| 108 diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID( |
| 109 getErrorLevel(), kWeakPtrFactoryOrder); |
| 94 | 110 |
| 95 // Registers notes to make it easier to interpret warnings. | 111 // Registers notes to make it easier to interpret warnings. |
| 96 diag_note_inheritance_ = diagnostic().getCustomDiagID( | 112 diag_note_inheritance_ = diagnostic().getCustomDiagID( |
| 97 DiagnosticsEngine::Note, kNoteInheritance); | 113 DiagnosticsEngine::Note, kNoteInheritance); |
| 98 diag_note_implicit_dtor_ = diagnostic().getCustomDiagID( | 114 diag_note_implicit_dtor_ = diagnostic().getCustomDiagID( |
| 99 DiagnosticsEngine::Note, kNoteImplicitDtor); | 115 DiagnosticsEngine::Note, kNoteImplicitDtor); |
| 100 diag_note_public_dtor_ = diagnostic().getCustomDiagID( | 116 diag_note_public_dtor_ = diagnostic().getCustomDiagID( |
| 101 DiagnosticsEngine::Note, kNotePublicDtor); | 117 DiagnosticsEngine::Note, kNotePublicDtor); |
| 102 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( | 118 diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
| 103 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); | 119 DiagnosticsEngine::Note, kNoteProtectedNonVirtualDtor); |
| 104 } | 120 } |
| 105 | 121 |
| 106 virtual void CheckChromeClass(SourceLocation record_location, | 122 virtual void CheckChromeClass(SourceLocation record_location, |
| 107 CXXRecordDecl* record) { | 123 CXXRecordDecl* record) { |
| 108 bool implementation_file = InImplementationFile(record_location); | 124 bool implementation_file = InImplementationFile(record_location); |
| 109 | 125 |
| 110 if (!implementation_file) { | 126 if (!implementation_file) { |
| 111 // Only check for "heavy" constructors/destructors in header files; | 127 // Only check for "heavy" constructors/destructors in header files; |
| 112 // within implementation files, there is no performance cost. | 128 // within implementation files, there is no performance cost. |
| 113 CheckCtorDtorWeight(record_location, record); | 129 CheckCtorDtorWeight(record_location, record); |
| 114 } | 130 } |
| 115 | 131 |
| 116 if (!implementation_file || check_virtuals_in_implementations_) { | 132 if (!implementation_file || options_.check_virtuals_in_implementations) { |
| 117 bool warn_on_inline_bodies = !implementation_file; | 133 bool warn_on_inline_bodies = !implementation_file; |
| 118 | 134 |
| 119 // Check that all virtual methods are marked accordingly with both | 135 // Check that all virtual methods are marked accordingly with both |
| 120 // virtual and OVERRIDE. | 136 // virtual and OVERRIDE. |
| 121 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); | 137 CheckVirtualMethods(record_location, record, warn_on_inline_bodies); |
| 122 } | 138 } |
| 123 | 139 |
| 124 CheckRefCountedDtors(record_location, record); | 140 CheckRefCountedDtors(record_location, record); |
| 141 |
| 142 if (options_.check_weak_ptr_factory_order) |
| 143 CheckWeakPtrFactoryMembers(record_location, record); |
| 125 } | 144 } |
| 126 | 145 |
| 127 private: | 146 private: |
| 128 // The type of problematic ref-counting pattern that was encountered. | 147 // The type of problematic ref-counting pattern that was encountered. |
| 129 enum RefcountIssue { | 148 enum RefcountIssue { |
| 130 None, | 149 None, |
| 131 ImplicitDestructor, | 150 ImplicitDestructor, |
| 132 PublicDestructor | 151 PublicDestructor |
| 133 }; | 152 }; |
| 134 | 153 |
| 135 bool check_base_classes_; | 154 FindBadConstructsOptions options_; |
| 136 bool check_virtuals_in_implementations_; | |
| 137 | 155 |
| 138 unsigned diag_method_requires_override_; | 156 unsigned diag_method_requires_override_; |
| 139 unsigned diag_method_requires_virtual_; | 157 unsigned diag_method_requires_virtual_; |
| 140 unsigned diag_no_explicit_dtor_; | 158 unsigned diag_no_explicit_dtor_; |
| 141 unsigned diag_public_dtor_; | 159 unsigned diag_public_dtor_; |
| 142 unsigned diag_protected_non_virtual_dtor_; | 160 unsigned diag_protected_non_virtual_dtor_; |
| 161 unsigned diag_weak_ptr_factory_order_; |
| 143 unsigned diag_note_inheritance_; | 162 unsigned diag_note_inheritance_; |
| 144 unsigned diag_note_implicit_dtor_; | 163 unsigned diag_note_implicit_dtor_; |
| 145 unsigned diag_note_public_dtor_; | 164 unsigned diag_note_public_dtor_; |
| 146 unsigned diag_note_protected_non_virtual_dtor_; | 165 unsigned diag_note_protected_non_virtual_dtor_; |
| 147 | 166 |
| 148 // Prints errors if the constructor/destructor weight is too heavy. | 167 // Prints errors if the constructor/destructor weight is too heavy. |
| 149 void CheckCtorDtorWeight(SourceLocation record_location, | 168 void CheckCtorDtorWeight(SourceLocation record_location, |
| 150 CXXRecordDecl* record) { | 169 CXXRecordDecl* record) { |
| 151 // We don't handle anonymous structs. If this record doesn't have a | 170 // We don't handle anonymous structs. If this record doesn't have a |
| 152 // name, it's of the form: | 171 // name, it's of the form: |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 unsigned DiagnosticForIssue(RefcountIssue issue) { | 526 unsigned DiagnosticForIssue(RefcountIssue issue) { |
| 508 switch (issue) { | 527 switch (issue) { |
| 509 case ImplicitDestructor: | 528 case ImplicitDestructor: |
| 510 return diag_no_explicit_dtor_; | 529 return diag_no_explicit_dtor_; |
| 511 case PublicDestructor: | 530 case PublicDestructor: |
| 512 return diag_public_dtor_; | 531 return diag_public_dtor_; |
| 513 case None: | 532 case None: |
| 514 assert(false && "Do not call DiagnosticForIssue with issue None"); | 533 assert(false && "Do not call DiagnosticForIssue with issue None"); |
| 515 return 0; | 534 return 0; |
| 516 } | 535 } |
| 536 assert(false); |
| 537 return 0; |
| 517 } | 538 } |
| 518 | 539 |
| 519 // Check |record| to determine if it has any problematic refcounting | 540 // Check |record| to determine if it has any problematic refcounting |
| 520 // issues and, if so, print them as warnings/errors based on the current | 541 // issues and, if so, print them as warnings/errors based on the current |
| 521 // value of getErrorLevel(). | 542 // value of getErrorLevel(). |
| 522 // | 543 // |
| 523 // If |record| is a C++ class, and if it inherits from one of the Chromium | 544 // If |record| is a C++ class, and if it inherits from one of the Chromium |
| 524 // ref-counting classes (base::RefCounted / base::RefCountedThreadSafe), | 545 // ref-counting classes (base::RefCounted / base::RefCountedThreadSafe), |
| 525 // ensure that there are no public destructors in the class hierarchy. This | 546 // ensure that there are no public destructors in the class hierarchy. This |
| 526 // is to guard against accidentally stack-allocating a RefCounted class or | 547 // is to guard against accidentally stack-allocating a RefCounted class or |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 // friend class base::Refcounted<RefCountedInterface>; | 594 // friend class base::Refcounted<RefCountedInterface>; |
| 574 // virtual ~RefCountedInterface() {} | 595 // virtual ~RefCountedInterface() {} |
| 575 // }; | 596 // }; |
| 576 // | 597 // |
| 577 // While RefCountedInterface is "safe", in that its destructor is | 598 // While RefCountedInterface is "safe", in that its destructor is |
| 578 // private, it's possible to do the following "unsafe" code: | 599 // private, it's possible to do the following "unsafe" code: |
| 579 // scoped_refptr<RefCountedInterface> some_class( | 600 // scoped_refptr<RefCountedInterface> some_class( |
| 580 // new RefCountedInterface); | 601 // new RefCountedInterface); |
| 581 // // Calls SomeInterface::~SomeInterface(), which is unsafe. | 602 // // Calls SomeInterface::~SomeInterface(), which is unsafe. |
| 582 // delete static_cast<SomeInterface*>(some_class.get()); | 603 // delete static_cast<SomeInterface*>(some_class.get()); |
| 583 if (!check_base_classes_) | 604 if (!options_.check_base_classes) |
| 584 return; | 605 return; |
| 585 | 606 |
| 586 // Find all public destructors. This will record the class hierarchy | 607 // Find all public destructors. This will record the class hierarchy |
| 587 // that leads to the public destructor in |dtor_paths|. | 608 // that leads to the public destructor in |dtor_paths|. |
| 588 CXXBasePaths dtor_paths; | 609 CXXBasePaths dtor_paths; |
| 589 if (!record->lookupInBases( | 610 if (!record->lookupInBases( |
| 590 &FindBadConstructsConsumer::HasPublicDtorCallback, this, | 611 &FindBadConstructsConsumer::HasPublicDtorCallback, this, |
| 591 dtor_paths)) { | 612 dtor_paths)) { |
| 592 return; | 613 return; |
| 593 } | 614 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 607 diagnostic().Report(loc, diag_note_implicit_dtor_) << problem_record; | 628 diagnostic().Report(loc, diag_note_implicit_dtor_) << problem_record; |
| 608 PrintInheritanceChain(*it); | 629 PrintInheritanceChain(*it); |
| 609 } else if (issue == PublicDestructor) { | 630 } else if (issue == PublicDestructor) { |
| 610 diagnostic().Report(record_location, diag_public_dtor_); | 631 diagnostic().Report(record_location, diag_public_dtor_); |
| 611 PrintInheritanceChain(refcounted_path.front()); | 632 PrintInheritanceChain(refcounted_path.front()); |
| 612 diagnostic().Report(loc, diag_note_public_dtor_); | 633 diagnostic().Report(loc, diag_note_public_dtor_); |
| 613 PrintInheritanceChain(*it); | 634 PrintInheritanceChain(*it); |
| 614 } | 635 } |
| 615 } | 636 } |
| 616 } | 637 } |
| 638 |
| 639 // Check for any problems with WeakPtrFactory class members. This currently |
| 640 // only checks that any WeakPtrFactory<T> member of T appears as the last |
| 641 // data member in T. We could consider checking for bad uses of |
| 642 // WeakPtrFactory to refer to other data members, but that would require |
| 643 // looking at the initializer list in constructors to see what the factory |
| 644 // points to. |
| 645 // Note, if we later add other unrelated checks of data members, we should |
| 646 // consider collapsing them in to one loop to avoid iterating over the data |
| 647 // members more than once. |
| 648 void CheckWeakPtrFactoryMembers(SourceLocation record_location, |
| 649 CXXRecordDecl* record) { |
| 650 // Skip anonymous structs. |
| 651 if (record->getIdentifier() == NULL) |
| 652 return; |
| 653 |
| 654 // Iterate through members of the class. |
| 655 RecordDecl::field_iterator iter(record->field_begin()), |
| 656 the_end(record->field_end()); |
| 657 SourceLocation weak_ptr_factory_location; // Invalid initially. |
| 658 for (; iter != the_end; ++iter) { |
| 659 // If we enter the loop but have already seen a matching WeakPtrFactory, |
| 660 // it means there is at least one member after the factory. |
| 661 if (weak_ptr_factory_location.isValid()) { |
| 662 diagnostic().Report(weak_ptr_factory_location, |
| 663 diag_weak_ptr_factory_order_); |
| 664 } |
| 665 const TemplateSpecializationType* template_spec_type = |
| 666 iter->getType().getTypePtr()->getAs<TemplateSpecializationType>(); |
| 667 if (template_spec_type) { |
| 668 const TemplateDecl* template_decl = |
| 669 template_spec_type->getTemplateName().getAsTemplateDecl(); |
| 670 if (template_decl && template_spec_type->getNumArgs() >= 1) { |
| 671 if (template_decl->getNameAsString().compare("WeakPtrFactory") == 0 && |
| 672 GetNamespace(template_decl) == "base") { |
| 673 const TemplateArgument& arg = template_spec_type->getArg(0); |
| 674 if (arg.getAsType().getTypePtr()->getAsCXXRecordDecl() == |
| 675 record->getTypeForDecl()->getAsCXXRecordDecl()) { |
| 676 weak_ptr_factory_location = iter->getLocation(); |
| 677 } |
| 678 } |
| 679 } |
| 680 } |
| 681 } |
| 682 } |
| 617 }; | 683 }; |
| 618 | 684 |
| 685 |
| 619 class FindBadConstructsAction : public PluginASTAction { | 686 class FindBadConstructsAction : public PluginASTAction { |
| 620 public: | 687 public: |
| 621 FindBadConstructsAction() | 688 FindBadConstructsAction() { |
| 622 : check_base_classes_(false), | |
| 623 check_virtuals_in_implementations_(true), | |
| 624 check_url_directory_(false) { | |
| 625 } | 689 } |
| 626 | 690 |
| 627 protected: | 691 protected: |
| 628 // Overridden from PluginASTAction: | 692 // Overridden from PluginASTAction: |
| 629 virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance, | 693 virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance, |
| 630 llvm::StringRef ref) { | 694 llvm::StringRef ref) { |
| 631 return new FindBadConstructsConsumer( | 695 return new FindBadConstructsConsumer(instance, options_); |
| 632 instance, check_base_classes_, check_virtuals_in_implementations_, | |
| 633 check_url_directory_); | |
| 634 } | 696 } |
| 635 | 697 |
| 636 virtual bool ParseArgs(const CompilerInstance& instance, | 698 virtual bool ParseArgs(const CompilerInstance& instance, |
| 637 const std::vector<std::string>& args) { | 699 const std::vector<std::string>& args) { |
| 638 bool parsed = true; | 700 bool parsed = true; |
| 639 | 701 |
| 640 for (size_t i = 0; i < args.size() && parsed; ++i) { | 702 for (size_t i = 0; i < args.size() && parsed; ++i) { |
| 641 if (args[i] == "skip-virtuals-in-implementations") { | 703 if (args[i] == "skip-virtuals-in-implementations") { |
| 642 // TODO(rsleevi): Remove this once http://crbug.com/115047 is fixed. | 704 // TODO(rsleevi): Remove this once http://crbug.com/115047 is fixed. |
| 643 check_virtuals_in_implementations_ = false; | 705 options_.check_virtuals_in_implementations = false; |
| 644 } else if (args[i] == "check-base-classes") { | 706 } else if (args[i] == "check-base-classes") { |
| 645 // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. | 707 // TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. |
| 646 check_base_classes_ = true; | 708 options_.check_base_classes = true; |
| 647 } else if (args[i] == "check-url-directory") { | 709 } else if (args[i] == "check-url-directory") { |
| 648 // TODO(tfarina): Remove this once http://crbug.com/229660 is fixed. | 710 // TODO(tfarina): Remove this once http://crbug.com/229660 is fixed. |
| 649 check_url_directory_ = true; | 711 options_.check_url_directory = true; |
| 712 } else if (args[i] == "check-weak-ptr-factory-order") { |
| 713 // TODO(dmichael): Remove this once http://crbug.com/303818 is fixed. |
| 714 options_.check_weak_ptr_factory_order = true; |
| 650 } else { | 715 } else { |
| 651 parsed = false; | 716 parsed = false; |
| 652 llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; | 717 llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; |
| 653 } | 718 } |
| 654 } | 719 } |
| 655 | 720 |
| 656 return parsed; | 721 return parsed; |
| 657 } | 722 } |
| 658 | 723 |
| 659 private: | 724 private: |
| 660 bool check_base_classes_; | 725 FindBadConstructsOptions options_; |
| 661 bool check_virtuals_in_implementations_; | |
| 662 bool check_url_directory_; | |
| 663 }; | 726 }; |
| 664 | 727 |
| 665 } // namespace | 728 } // namespace |
| 666 | 729 |
| 667 static FrontendPluginRegistry::Add<FindBadConstructsAction> | 730 static FrontendPluginRegistry::Add<FindBadConstructsAction> |
| 668 X("find-bad-constructs", "Finds bad C++ constructs"); | 731 X("find-bad-constructs", "Finds bad C++ constructs"); |
| OLD | NEW |