Index: tools/clang/plugins/FindBadConstructs.cpp |
diff --git a/tools/clang/plugins/FindBadConstructs.cpp b/tools/clang/plugins/FindBadConstructs.cpp |
index 9697c5f21104825a31c066099ca7ccea13d2ae9d..bdc497f64de99a0cad815473c6998195a88c52c0 100644 |
--- a/tools/clang/plugins/FindBadConstructs.cpp |
+++ b/tools/clang/plugins/FindBadConstructs.cpp |
@@ -12,6 +12,8 @@ |
// - Virtual methods with nonempty implementations in their headers. |
// - Classes that derive from base::RefCounted / base::RefCountedThreadSafe |
// should have protected or private destructors. |
+// - WeakPtrFactory members that refer to their outer class should be the last |
+// member. |
#include "clang/AST/ASTConsumer.h" |
#include "clang/AST/AST.h" |
@@ -43,6 +45,9 @@ const char kPublicDtor[] = |
const char kProtectedNonVirtualDtor[] = |
"[chromium-style] Classes that are ref-counted and have non-private " |
"destructors should declare their destructor virtual."; |
+const char kWeakPtrFactoryOrder[] = |
+ "[chromium-style] WeakPtrFactory members which refer to their outer class " |
+ "must be the last member in the outer class definition."; |
const char kNoteInheritance[] = |
"[chromium-style] %0 inherits from %1 here"; |
const char kNoteImplicitDtor[] = |
@@ -70,16 +75,25 @@ const Type* UnwrapType(const Type* type) { |
return type; |
} |
+struct FindBadConstructsOptions { |
+ FindBadConstructsOptions() : check_base_classes(false), |
+ check_virtuals_in_implementations(true), |
+ check_url_directory(false), |
+ check_weak_ptr_factory_order(false) { |
+ } |
+ bool check_base_classes; |
+ bool check_virtuals_in_implementations; |
+ bool check_url_directory; |
+ bool check_weak_ptr_factory_order; |
+}; |
+ |
// Searches for constructs that we know we don't want in the Chromium code base. |
class FindBadConstructsConsumer : public ChromeClassTester { |
public: |
FindBadConstructsConsumer(CompilerInstance& instance, |
- bool check_base_classes, |
- bool check_virtuals_in_implementations, |
- bool check_url_directory) |
- : ChromeClassTester(instance, check_url_directory), |
- check_base_classes_(check_base_classes), |
- check_virtuals_in_implementations_(check_virtuals_in_implementations) { |
+ const FindBadConstructsOptions& options) |
+ : ChromeClassTester(instance, options.check_url_directory), |
+ options_(options) { |
// Register warning/error messages. |
diag_method_requires_override_ = diagnostic().getCustomDiagID( |
getErrorLevel(), kMethodRequiresOverride); |
@@ -91,6 +105,8 @@ class FindBadConstructsConsumer : public ChromeClassTester { |
getErrorLevel(), kPublicDtor); |
diag_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID( |
getErrorLevel(), kProtectedNonVirtualDtor); |
+ diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID( |
+ getErrorLevel(), kWeakPtrFactoryOrder); |
// Registers notes to make it easier to interpret warnings. |
diag_note_inheritance_ = diagnostic().getCustomDiagID( |
@@ -113,7 +129,7 @@ class FindBadConstructsConsumer : public ChromeClassTester { |
CheckCtorDtorWeight(record_location, record); |
} |
- if (!implementation_file || check_virtuals_in_implementations_) { |
+ if (!implementation_file || options_.check_virtuals_in_implementations) { |
bool warn_on_inline_bodies = !implementation_file; |
// Check that all virtual methods are marked accordingly with both |
@@ -122,6 +138,9 @@ class FindBadConstructsConsumer : public ChromeClassTester { |
} |
CheckRefCountedDtors(record_location, record); |
+ |
+ if (options_.check_weak_ptr_factory_order) |
+ CheckWeakPtrFactoryMembers(record_location, record); |
} |
private: |
@@ -132,14 +151,14 @@ class FindBadConstructsConsumer : public ChromeClassTester { |
PublicDestructor |
}; |
- bool check_base_classes_; |
- bool check_virtuals_in_implementations_; |
+ FindBadConstructsOptions options_; |
unsigned diag_method_requires_override_; |
unsigned diag_method_requires_virtual_; |
unsigned diag_no_explicit_dtor_; |
unsigned diag_public_dtor_; |
unsigned diag_protected_non_virtual_dtor_; |
+ unsigned diag_weak_ptr_factory_order_; |
unsigned diag_note_inheritance_; |
unsigned diag_note_implicit_dtor_; |
unsigned diag_note_public_dtor_; |
@@ -514,6 +533,8 @@ class FindBadConstructsConsumer : public ChromeClassTester { |
assert(false && "Do not call DiagnosticForIssue with issue None"); |
return 0; |
} |
+ assert(false); |
+ return 0; |
} |
// Check |record| to determine if it has any problematic refcounting |
@@ -580,7 +601,7 @@ class FindBadConstructsConsumer : public ChromeClassTester { |
// new RefCountedInterface); |
// // Calls SomeInterface::~SomeInterface(), which is unsafe. |
// delete static_cast<SomeInterface*>(some_class.get()); |
- if (!check_base_classes_) |
+ if (!options_.check_base_classes) |
return; |
// Find all public destructors. This will record the class hierarchy |
@@ -614,23 +635,64 @@ class FindBadConstructsConsumer : public ChromeClassTester { |
} |
} |
} |
+ |
+ // Check for any problems with WeakPtrFactory class members. This currently |
+ // only checks that any WeakPtrFactory<T> member of T appears as the last |
+ // data member in T. We could consider checking for bad uses of |
+ // WeakPtrFactory to refer to other data members, but that would require |
+ // looking at the initializer list in constructors to see what the factory |
+ // points to. |
+ // Note, if we later add other unrelated checks of data members, we should |
+ // consider collapsing them in to one loop to avoid iterating over the data |
+ // members more than once. |
+ void CheckWeakPtrFactoryMembers(SourceLocation record_location, |
+ CXXRecordDecl* record) { |
+ // Skip anonymous structs. |
+ if (record->getIdentifier() == NULL) |
+ return; |
+ |
+ // Iterate through members of the class. |
+ RecordDecl::field_iterator iter(record->field_begin()), |
+ the_end(record->field_end()); |
+ SourceLocation weak_ptr_factory_location; // Invalid initially. |
+ for (; iter != the_end; ++iter) { |
+ // If we enter the loop but have already seen a matching WeakPtrFactory, |
+ // it means there is at least one member after the factory. |
+ if (weak_ptr_factory_location.isValid()) { |
+ diagnostic().Report(weak_ptr_factory_location, |
+ diag_weak_ptr_factory_order_); |
+ } |
+ const TemplateSpecializationType* template_spec_type = |
+ iter->getType().getTypePtr()->getAs<TemplateSpecializationType>(); |
+ if (template_spec_type) { |
+ const TemplateDecl* template_decl = |
+ template_spec_type->getTemplateName().getAsTemplateDecl(); |
+ if (template_decl && template_spec_type->getNumArgs() >= 1) { |
+ if (template_decl->getNameAsString().compare("WeakPtrFactory") == 0 && |
+ GetNamespace(template_decl) == "base") { |
+ const TemplateArgument& arg = template_spec_type->getArg(0); |
+ if (arg.getAsType().getTypePtr()->getAsCXXRecordDecl() == |
+ record->getTypeForDecl()->getAsCXXRecordDecl()) { |
+ weak_ptr_factory_location = iter->getLocation(); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ } |
}; |
+ |
class FindBadConstructsAction : public PluginASTAction { |
public: |
- FindBadConstructsAction() |
- : check_base_classes_(false), |
- check_virtuals_in_implementations_(true), |
- check_url_directory_(false) { |
+ FindBadConstructsAction() { |
} |
protected: |
// Overridden from PluginASTAction: |
virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance, |
llvm::StringRef ref) { |
- return new FindBadConstructsConsumer( |
- instance, check_base_classes_, check_virtuals_in_implementations_, |
- check_url_directory_); |
+ return new FindBadConstructsConsumer(instance, options_); |
} |
virtual bool ParseArgs(const CompilerInstance& instance, |
@@ -640,13 +702,16 @@ class FindBadConstructsAction : public PluginASTAction { |
for (size_t i = 0; i < args.size() && parsed; ++i) { |
if (args[i] == "skip-virtuals-in-implementations") { |
// TODO(rsleevi): Remove this once http://crbug.com/115047 is fixed. |
- check_virtuals_in_implementations_ = false; |
+ options_.check_virtuals_in_implementations = false; |
} else if (args[i] == "check-base-classes") { |
// TODO(rsleevi): Remove this once http://crbug.com/123295 is fixed. |
- check_base_classes_ = true; |
+ options_.check_base_classes = true; |
} else if (args[i] == "check-url-directory") { |
// TODO(tfarina): Remove this once http://crbug.com/229660 is fixed. |
- check_url_directory_ = true; |
+ options_.check_url_directory = true; |
+ } else if (args[i] == "check-weak-ptr-factory-order") { |
+ // TODO(dmichael): Remove this once http://crbug.com/303818 is fixed. |
+ options_.check_weak_ptr_factory_order = true; |
} else { |
parsed = false; |
llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; |
@@ -657,9 +722,7 @@ class FindBadConstructsAction : public PluginASTAction { |
} |
private: |
- bool check_base_classes_; |
- bool check_virtuals_in_implementations_; |
- bool check_url_directory_; |
+ FindBadConstructsOptions options_; |
}; |
} // namespace |