summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-28 17:12:14 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-28 17:12:14 +0000
commit8baf9323c867f81816a7095c978810af5cb7903b (patch)
tree0d8d7b24fc962711c194d99b78262efd1c7741ff /tools
parent3ff5f35aa4b4e6dd82ba60d9d248e9a4cd3da44e (diff)
downloadchromium_src-8baf9323c867f81816a7095c978810af5cb7903b.zip
chromium_src-8baf9323c867f81816a7095c978810af5cb7903b.tar.gz
chromium_src-8baf9323c867f81816a7095c978810af5cb7903b.tar.bz2
Extend Clang plugin to warn on missing OVERRIDE.
BUG=104314 TEST=none Review URL: http://codereview.chromium.org/8586037 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111712 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r--tools/clang/plugins/ChromeClassTester.cpp7
-rw-r--r--tools/clang/plugins/ChromeClassTester.h11
-rw-r--r--tools/clang/plugins/FindBadConstructs.cpp93
-rw-r--r--tools/clang/plugins/tests/overridden_methods.cpp14
-rw-r--r--tools/clang/plugins/tests/overridden_methods.h51
-rw-r--r--tools/clang/plugins/tests/overridden_methods.txt8
-rwxr-xr-xtools/clang/plugins/tests/test.sh2
-rw-r--r--tools/clang/plugins/tests/virtual_methods.h2
-rw-r--r--tools/clang/plugins/tests/virtual_methods.txt2
-rwxr-xr-xtools/clang/scripts/plugin_flags.sh3
10 files changed, 165 insertions, 28 deletions
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp
index 3499ca7..d191f52 100644
--- a/tools/clang/plugins/ChromeClassTester.cpp
+++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -43,6 +43,7 @@ ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
void ChromeClassTester::BuildBannedLists() {
banned_namespaces_.push_back("std");
banned_namespaces_.push_back("__gnu_cxx");
+ banned_namespaces_.push_back("WebKit");
banned_directories_.push_back("third_party/");
banned_directories_.push_back("native_client/");
@@ -153,11 +154,11 @@ void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) {
DiagnosticBuilder B = diagnostic().Report(full, id);
}
-bool ChromeClassTester::InTestingNamespace(Decl* record) {
+bool ChromeClassTester::InTestingNamespace(const Decl* record) {
return GetNamespace(record).find("testing") != std::string::npos;
}
-bool ChromeClassTester::InBannedNamespace(Decl* record) {
+bool ChromeClassTester::InBannedNamespace(const Decl* record) {
std::string n = GetNamespace(record);
if (n != "") {
return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
@@ -167,7 +168,7 @@ bool ChromeClassTester::InBannedNamespace(Decl* record) {
return false;
}
-std::string ChromeClassTester::GetNamespace(Decl* record) {
+std::string ChromeClassTester::GetNamespace(const Decl* record) {
return GetNamespaceImpl(record->getDeclContext(), "");
}
diff --git a/tools/clang/plugins/ChromeClassTester.h b/tools/clang/plugins/ChromeClassTester.h
index 81f3a50..5004f56 100644
--- a/tools/clang/plugins/ChromeClassTester.h
+++ b/tools/clang/plugins/ChromeClassTester.h
@@ -37,7 +37,11 @@ class ChromeClassTester : public clang::ASTConsumer {
// Utility method for subclasses to check if testing details are in this
// class. Some tests won't care if a class has a ::testing member and others
// will.
- bool InTestingNamespace(clang::Decl* record);
+ bool InTestingNamespace(const clang::Decl* record);
+
+ // Utility method for subclasses to check if this class is in a banned
+ // namespace.
+ bool InBannedNamespace(const clang::Decl* record);
private:
// Filtered versions of tags that are only called with things defined in
@@ -46,9 +50,8 @@ class ChromeClassTester : public clang::ASTConsumer {
clang::CXXRecordDecl* record) = 0;
// Utility methods used for filtering out non-chrome classes (and ones we
- // delibrately ignore) in HandleTagDeclDefinition().
- bool InBannedNamespace(clang::Decl* record);
- std::string GetNamespace(clang::Decl* record);
+ // deliberately ignore) in HandleTagDeclDefinition().
+ std::string GetNamespace(const clang::Decl* record);
std::string GetNamespaceImpl(const clang::DeclContext* context,
std::string candidate);
bool InBannedDirectory(clang::SourceLocation loc);
diff --git a/tools/clang/plugins/FindBadConstructs.cpp b/tools/clang/plugins/FindBadConstructs.cpp
index 191e413..fbc5274 100644
--- a/tools/clang/plugins/FindBadConstructs.cpp
+++ b/tools/clang/plugins/FindBadConstructs.cpp
@@ -8,6 +8,7 @@
// - Constructors/Destructors should not be inlined if they are of a complex
// class type.
// - Missing "virtual" keywords on methods that should be virtual.
+// - Non-annotated overriding virtual methods.
// - Virtual methods with nonempty implementations in their headers.
//
// Things that are still TODO:
@@ -38,8 +39,10 @@ bool TypeHasNonTrivialDtor(const Type* type) {
// Searches for constructs that we know we don't want in the Chromium code base.
class FindBadConstructsConsumer : public ChromeClassTester {
public:
- FindBadConstructsConsumer(CompilerInstance& instance)
- : ChromeClassTester(instance) {}
+ FindBadConstructsConsumer(CompilerInstance& instance,
+ bool skip_override)
+ : ChromeClassTester(instance),
+ skip_override_(skip_override) {}
virtual void CheckChromeClass(const SourceLocation& record_location,
CXXRecordDecl* record) {
@@ -47,7 +50,7 @@ class FindBadConstructsConsumer : public ChromeClassTester {
CheckVirtualMethods(record_location, record);
}
- // Prints errors if the constructor/destructor weight it too heavy.
+ // Prints errors if the constructor/destructor weight is too heavy.
void CheckCtorDtorWeight(const SourceLocation& record_location,
CXXRecordDecl* record) {
// We don't handle anonymous structs. If this record doesn't have a
@@ -136,16 +139,19 @@ class FindBadConstructsConsumer : public ChromeClassTester {
}
}
- void CheckVirtualMethod(const CXXMethodDecl *method) {
- SourceLocation loc = method->getTypeSpecStartLoc();
- if (isa<CXXDestructorDecl>(method))
- loc = method->getInnerLocStart();
+ void CheckVirtualMethod(const CXXMethodDecl* method) {
+ if (!method->isVirtual())
+ return;
- if (method->isVirtual() && !method->isVirtualAsWritten())
+ if (!method->isVirtualAsWritten()) {
+ SourceLocation loc = method->getTypeSpecStartLoc();
+ if (isa<CXXDestructorDecl>(method))
+ loc = method->getInnerLocStart();
emitWarning(loc, "Overriding method must have \"virtual\" keyword.");
+ }
// Virtual methods should not have inline definitions beyond "{}".
- if (method->isVirtual() && method->hasBody() && method->hasInlineBody()) {
+ if (method->hasBody() && method->hasInlineBody()) {
if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) {
if (cs->size()) {
emitWarning(
@@ -157,6 +163,37 @@ class FindBadConstructsConsumer : public ChromeClassTester {
}
}
+ bool IsMethodInBannedNamespace(const CXXMethodDecl* method) {
+ if (InBannedNamespace(method))
+ return true;
+ for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods();
+ i != method->end_overridden_methods();
+ ++i) {
+ const CXXMethodDecl* overridden = *i;
+ if (IsMethodInBannedNamespace(overridden))
+ return true;
+ }
+
+ return false;
+ }
+
+ void CheckOverriddenMethod(const CXXMethodDecl* method) {
+ if (skip_override_)
+ return;
+
+ if (!method->size_overridden_methods() || method->getAttr<OverrideAttr>())
+ return;
+
+ if (isa<CXXDestructorDecl>(method) || method->isPure())
+ return;
+
+ if (IsMethodInBannedNamespace(method))
+ return;
+
+ SourceLocation loc = method->getTypeSpecStartLoc();
+ emitWarning(loc, "Overriding method must be marked with OVERRIDE.");
+ }
+
// Makes sure there is a "virtual" keyword on virtual methods and that there
// are no inline function bodies on them (but "{}" is allowed).
//
@@ -180,14 +217,14 @@ class FindBadConstructsConsumer : public ChromeClassTester {
for (CXXRecordDecl::method_iterator it = record->method_begin();
it != record->method_end(); ++it) {
- if (it->isCopyAssignmentOperator() ||
- dyn_cast<CXXConstructorDecl>(*it)) {
+ if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) {
// Ignore constructors and assignment operators.
- } else if (dyn_cast<CXXDestructorDecl>(*it) &&
+ } else if (isa<CXXDestructorDecl>(*it) &&
!record->hasUserDeclaredDestructor()) {
- // Ignore non-userdeclared destructors.
+ // Ignore non-user-declared destructors.
} else {
CheckVirtualMethod(*it);
+ CheckOverriddenMethod(*it);
}
}
}
@@ -233,7 +270,7 @@ class FindBadConstructsConsumer : public ChromeClassTester {
break;
}
case Type::Typedef: {
- while (const TypedefType *TT = dyn_cast<TypedefType>(type)) {
+ while (const TypedefType* TT = dyn_cast<TypedefType>(type)) {
type = TT->getDecl()->getUnderlyingType().getTypePtr();
}
CountType(type, trivial_member, non_trivial_member,
@@ -248,19 +285,41 @@ class FindBadConstructsConsumer : public ChromeClassTester {
}
}
}
+
+ private:
+ // TODO(avi): Remove this (and all related code) once the override warning is
+ // enabled on all bots.
+ bool skip_override_;
};
class FindBadConstructsAction : public PluginASTAction {
+ public:
+ FindBadConstructsAction() : skip_override_(false) {
+ }
+
protected:
ASTConsumer* CreateASTConsumer(CompilerInstance &CI, llvm::StringRef ref) {
- return new FindBadConstructsConsumer(CI);
+ return new FindBadConstructsConsumer(CI, skip_override_);
}
bool ParseArgs(const CompilerInstance &CI,
const std::vector<std::string>& args) {
- // We don't take any additional arguments here.
- return true;
+ bool parsed = true;
+
+ for (size_t i = 0; i < args.size() && parsed; ++i) {
+ if (args[i] == "skip-override") {
+ skip_override_ = true;
+ } else {
+ parsed = false;
+ llvm::errs() << "Unknown arg: " << args[i] << "\n";
+ }
+ }
+
+ return parsed;
}
+
+ private:
+ bool skip_override_;
};
} // namespace
diff --git a/tools/clang/plugins/tests/overridden_methods.cpp b/tools/clang/plugins/tests/overridden_methods.cpp
new file mode 100644
index 0000000..f81d3a2
--- /dev/null
+++ b/tools/clang/plugins/tests/overridden_methods.cpp
@@ -0,0 +1,14 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "overridden_methods.h"
+
+// Fill in the implementations
+void DerivedClass::SomeMethod() {}
+void DerivedClass::SomeOtherMethod() {}
+void DerivedClass::WebKitModifiedSomething() {}
+
+int main() {
+ DerivedClass something;
+}
diff --git a/tools/clang/plugins/tests/overridden_methods.h b/tools/clang/plugins/tests/overridden_methods.h
new file mode 100644
index 0000000..08ef0a5
--- /dev/null
+++ b/tools/clang/plugins/tests/overridden_methods.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OVERRIDDEN_METHODS_H_
+#define OVERRIDDEN_METHODS_H_
+
+// Should warn about overriding of methods.
+class BaseClass {
+ public:
+ virtual ~BaseClass() {}
+ virtual void SomeMethod() = 0;
+ virtual void SomeOtherMethod() = 0;
+ virtual void SomeInlineMethod() = 0;
+};
+
+class InterimClass : public BaseClass {
+ // Should not warn about pure virtual methods.
+ virtual void SomeMethod() = 0;
+};
+
+namespace WebKit {
+class WebKitObserver {
+ public:
+ virtual void WebKitModifiedSomething() {};
+};
+} // namespace WebKit
+
+namespace webkit_glue {
+class WebKitObserverImpl : WebKit::WebKitObserver {
+ public:
+ virtual void WebKitModifiedSomething() {};
+};
+} // namespace webkit_glue
+
+class DerivedClass : public InterimClass,
+ public webkit_glue::WebKitObserverImpl {
+ public:
+ // Should not warn about destructors.
+ virtual ~DerivedClass() {}
+ // Should warn.
+ virtual void SomeMethod();
+ // Should not warn if marked as override.
+ virtual void SomeOtherMethod() override;
+ // Should warn for inline implementations.
+ virtual void SomeInlineMethod() {}
+ // Should not warn if overriding a method whose origin is WebKit.
+ virtual void WebKitModifiedSomething();
+};
+
+#endif // OVERRIDDEN_METHODS_H_
diff --git a/tools/clang/plugins/tests/overridden_methods.txt b/tools/clang/plugins/tests/overridden_methods.txt
new file mode 100644
index 0000000..da3c58f
--- /dev/null
+++ b/tools/clang/plugins/tests/overridden_methods.txt
@@ -0,0 +1,8 @@
+In file included from overridden_methods.cpp:5:
+./overridden_methods.h:42:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeMethod();
+ ^
+./overridden_methods.h:46:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeInlineMethod() {}
+ ^
+2 warnings generated.
diff --git a/tools/clang/plugins/tests/test.sh b/tools/clang/plugins/tests/test.sh
index fcfd213..262ebbb 100755
--- a/tools/clang/plugins/tests/test.sh
+++ b/tools/clang/plugins/tests/test.sh
@@ -23,7 +23,7 @@ usage() {
# Runs a single test case.
do_testcase() {
- local output="$("${CLANG_DIR}"/bin/clang -c \
+ local output="$("${CLANG_DIR}"/bin/clang -c -Wno-c++11-extensions \
-Xclang -load -Xclang "${CLANG_DIR}"/lib/libFindBadConstructs.${LIB} \
-Xclang -plugin -Xclang find-bad-constructs ${1} 2>&1)"
local diffout="$(echo "${output}" | diff - "${2}")"
diff --git a/tools/clang/plugins/tests/virtual_methods.h b/tools/clang/plugins/tests/virtual_methods.h
index d256f07..d9fbf96 100644
--- a/tools/clang/plugins/tests/virtual_methods.h
+++ b/tools/clang/plugins/tests/virtual_methods.h
@@ -20,7 +20,7 @@ class VirtualMethodsInHeaders {
// Complain on missing 'virtual' keyword in overrides.
class WarnOnMissingVirtual : public VirtualMethodsInHeaders {
public:
- void MethodHasNoArguments();
+ void MethodHasNoArguments() override;
};
// Don't complain about things in a 'testing' namespace.
diff --git a/tools/clang/plugins/tests/virtual_methods.txt b/tools/clang/plugins/tests/virtual_methods.txt
index 5eb6657..571d6d6 100644
--- a/tools/clang/plugins/tests/virtual_methods.txt
+++ b/tools/clang/plugins/tests/virtual_methods.txt
@@ -3,6 +3,6 @@ In file included from virtual_methods.cpp:5:
virtual bool ComplainAboutThis() { return true; }
^
./virtual_methods.h:23:3: warning: [chromium-style] Overriding method must have "virtual" keyword.
- void MethodHasNoArguments();
+ void MethodHasNoArguments() override;
^
2 warnings generated.
diff --git a/tools/clang/scripts/plugin_flags.sh b/tools/clang/scripts/plugin_flags.sh
index ec3eed6c..c4deb9c 100755
--- a/tools/clang/scripts/plugin_flags.sh
+++ b/tools/clang/scripts/plugin_flags.sh
@@ -17,4 +17,5 @@ else
fi
echo -Xclang -load -Xclang $CLANG_LIB_PATH/libFindBadConstructs.$LIBSUFFIX \
- -Xclang -add-plugin -Xclang find-bad-constructs
+ -Xclang -add-plugin -Xclang find-bad-constructs \
+ -Xclang -plugin-arg-find-bad-constructs -Xclang skip-override