Commit 993e04f7 authored by dcheng's avatar dcheng Committed by Commit bot

Update plugin to handle new style rules for virtual specifiers.

Implements several new checks in the plugin, gated behind a flag:
- Only one of {virtual,override,final} should be ever used.
- Destructors must also be annotated correctly.
- A virtual final method that doesn't override anything should be
  devirtualized.

The test harness for the Chrome plugin has also been updated to stop
it from littering the source tree with object files, and to make the
golden files easier to update.

BUG=417463

Review URL: https://codereview.chromium.org/597863002

Cr-Commit-Position: refs/heads/master@{#297129}
parent a0fd0993
...@@ -36,6 +36,8 @@ bool FindBadConstructsAction::ParseArgs(const CompilerInstance& instance, ...@@ -36,6 +36,8 @@ bool FindBadConstructsAction::ParseArgs(const CompilerInstance& instance,
// TODO(tsepez): Enable this by default once http://crbug.com/356815 // TODO(tsepez): Enable this by default once http://crbug.com/356815
// and http://crbug.com/356816 are fixed. // and http://crbug.com/356816 are fixed.
options_.check_enum_last_value = true; options_.check_enum_last_value = true;
} else if (args[i] == "strict-virtual-specifiers") {
options_.strict_virtual_specifiers = true;
} else { } else {
parsed = false; parsed = false;
llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n"; llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n";
......
...@@ -36,10 +36,10 @@ class FindBadConstructsConsumer : public ChromeClassTester { ...@@ -36,10 +36,10 @@ class FindBadConstructsConsumer : public ChromeClassTester {
const Options& options); const Options& options);
// ChromeClassTester overrides: // ChromeClassTester overrides:
virtual void CheckChromeClass(clang::SourceLocation record_location, void CheckChromeClass(clang::SourceLocation record_location,
clang::CXXRecordDecl* record); clang::CXXRecordDecl* record) override;
virtual void CheckChromeEnum(clang::SourceLocation enum_location, void CheckChromeEnum(clang::SourceLocation enum_location,
clang::EnumDecl* enum_decl); clang::EnumDecl* enum_decl) override;
private: private:
// The type of problematic ref-counting pattern that was encountered. // The type of problematic ref-counting pattern that was encountered.
...@@ -48,16 +48,14 @@ class FindBadConstructsConsumer : public ChromeClassTester { ...@@ -48,16 +48,14 @@ class FindBadConstructsConsumer : public ChromeClassTester {
void CheckCtorDtorWeight(clang::SourceLocation record_location, void CheckCtorDtorWeight(clang::SourceLocation record_location,
clang::CXXRecordDecl* record); clang::CXXRecordDecl* record);
void CheckVirtualMethod(const clang::CXXMethodDecl* method,
bool warn_on_inline_bodies);
bool InTestingNamespace(const clang::Decl* record); bool InTestingNamespace(const clang::Decl* record);
bool IsMethodInBannedOrTestingNamespace(const clang::CXXMethodDecl* method); bool IsMethodInBannedOrTestingNamespace(const clang::CXXMethodDecl* method);
void CheckOverriddenMethod(const clang::CXXMethodDecl* method);
void CheckVirtualMethods(clang::SourceLocation record_location, void CheckVirtualMethods(clang::SourceLocation record_location,
clang::CXXRecordDecl* record, clang::CXXRecordDecl* record,
bool warn_on_inline_bodies); bool warn_on_inline_bodies);
void CheckVirtualSpecifiers(const clang::CXXMethodDecl* method);
void CheckVirtualBodies(const clang::CXXMethodDecl* method);
void CountType(const clang::Type* type, void CountType(const clang::Type* type,
int* trivial_member, int* trivial_member,
...@@ -85,7 +83,8 @@ class FindBadConstructsConsumer : public ChromeClassTester { ...@@ -85,7 +83,8 @@ class FindBadConstructsConsumer : public ChromeClassTester {
const Options options_; const Options options_;
unsigned diag_method_requires_override_; unsigned diag_method_requires_override_;
unsigned diag_method_requires_virtual_; unsigned diag_redundant_virtual_specifier_;
unsigned diag_base_method_virtual_and_final_;
unsigned diag_no_explicit_dtor_; unsigned diag_no_explicit_dtor_;
unsigned diag_public_dtor_; unsigned diag_public_dtor_;
unsigned diag_protected_non_virtual_dtor_; unsigned diag_protected_non_virtual_dtor_;
......
...@@ -11,11 +11,13 @@ struct Options { ...@@ -11,11 +11,13 @@ struct Options {
Options() Options()
: check_base_classes(false), : check_base_classes(false),
check_weak_ptr_factory_order(false), check_weak_ptr_factory_order(false),
check_enum_last_value(false) {} check_enum_last_value(false),
strict_virtual_specifiers(false) {}
bool check_base_classes; bool check_base_classes;
bool check_weak_ptr_factory_order; bool check_weak_ptr_factory_order;
bool check_enum_last_value; bool check_enum_last_value;
bool strict_virtual_specifiers;
}; };
} // namespace chrome_checker } // namespace chrome_checker
......
/src/chromium/src/myheader.h:2:21: warning: [chromium-style] Overriding method must be marked with OVERRIDE. /src/chromium/src/myheader.h:2:21: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void foo(); // Should warn about missing 'override'. virtual void foo(); // Should warn about missing 'override'.
^ ^
OVERRIDE override
/src/chrome-breakpad/src/myheader.h:124:21: warning: [chromium-style] Overriding method must be marked with OVERRIDE. /src/chrome-breakpad/src/myheader.h:124:21: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void foo(); // Should warn about missing 'override'. virtual void foo(); // Should warn about missing 'override'.
^ ^
OVERRIDE override
2 warnings generated. 2 warnings generated.
In file included from overridden_methods.cpp:5: In file included from overridden_methods.cpp:5:
./overridden_methods.h:48:28: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:48:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethod(); virtual void SomeMethod();
^ ^
OVERRIDE override
./overridden_methods.h:52:34: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:52:34: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeInlineMethod() {} virtual void SomeInlineMethod() {}
^ ^
OVERRIDE override
./overridden_methods.h:56:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:56:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethod() const {} virtual void SomeConstMethod() const {}
^ ^
OVERRIDE override
./overridden_methods.h:58:53: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:58:53: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithExceptionSpec() throw() {} virtual void SomeMethodWithExceptionSpec() throw() {}
^ ^
OVERRIDE override
./overridden_methods.h:61:67: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:61:67: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethodWithExceptionSpec() const throw(int) {} virtual void SomeConstMethodWithExceptionSpec() const throw(int) {}
^ ^
OVERRIDE override
./overridden_methods.h:63:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:63:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeNonPureBaseMethod() {} virtual void SomeNonPureBaseMethod() {}
^ ^
OVERRIDE override
./overridden_methods.h:65:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:65:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithComment(); // This is a comment. virtual void SomeMethodWithComment(); // This is a comment.
^ ^
OVERRIDE override
./overridden_methods.h:67:46: warning: [chromium-style] Overriding method must be marked with OVERRIDE. ./overridden_methods.h:67:46: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithCommentAndBody() {} // This is a comment. virtual void SomeMethodWithCommentAndBody() {} // This is a comment.
^ ^
OVERRIDE override
overridden_methods.cpp:24:28: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:24:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethod(); virtual void SomeMethod();
^ ^
OVERRIDE override
overridden_methods.cpp:28:34: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:28:34: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeInlineMethod() {} virtual void SomeInlineMethod() {}
^ ^
OVERRIDE override
overridden_methods.cpp:32:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:32:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethod() const {} virtual void SomeConstMethod() const {}
^ ^
OVERRIDE override
overridden_methods.cpp:34:53: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:34:53: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithExceptionSpec() throw() {} virtual void SomeMethodWithExceptionSpec() throw() {}
^ ^
OVERRIDE override
overridden_methods.cpp:37:67: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:37:67: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethodWithExceptionSpec() const throw(int) {} virtual void SomeConstMethodWithExceptionSpec() const throw(int) {}
^ ^
OVERRIDE override
overridden_methods.cpp:39:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:39:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeNonPureBaseMethod() {} virtual void SomeNonPureBaseMethod() {}
^ ^
OVERRIDE override
overridden_methods.cpp:41:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:41:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithComment(); // This is a comment. virtual void SomeMethodWithComment(); // This is a comment.
^ ^
OVERRIDE override
overridden_methods.cpp:43:46: warning: [chromium-style] Overriding method must be marked with OVERRIDE. overridden_methods.cpp:43:46: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithCommentAndBody() {} // This is a comment. virtual void SomeMethodWithCommentAndBody() {} // This is a comment.
^ ^
OVERRIDE override
16 warnings generated. 16 warnings generated.
...@@ -33,7 +33,7 @@ do_testcase() { ...@@ -33,7 +33,7 @@ do_testcase() {
flags="${flags} -isysroot $(xcrun --show-sdk-path) -stdlib=libstdc++" flags="${flags} -isysroot $(xcrun --show-sdk-path) -stdlib=libstdc++"
fi fi
local output="$("${CLANG_PATH}" -c -Wno-c++11-extensions \ local output="$("${CLANG_PATH}" -fsyntax-only -Wno-c++11-extensions \
-Xclang -load -Xclang "${PLUGIN_PATH}" \ -Xclang -load -Xclang "${PLUGIN_PATH}" \
-Xclang -add-plugin -Xclang find-bad-constructs ${flags} ${1} 2>&1)" -Xclang -add-plugin -Xclang find-bad-constructs ${flags} ${1} 2>&1)"
local diffout="$(echo "${output}" | diff - "${2}")" local diffout="$(echo "${output}" | diff - "${2}")"
...@@ -44,6 +44,10 @@ do_testcase() { ...@@ -44,6 +44,10 @@ do_testcase() {
echo "FAIL: ${1}" echo "FAIL: ${1}"
echo "Output of compiler:" echo "Output of compiler:"
echo "${output}" echo "${output}"
cat > ${2}-actual << EOF
${output}
EOF
echo "Expected output:" echo "Expected output:"
cat "${2}" cat "${2}"
echo echo
......
// Copyright 2014 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.
#define VIRTUAL virtual
#define VIRTUAL_VOID virtual void
class A {
public:
VIRTUAL void F() final {}
// Make sure an out-of-place virtual doesn't cause an incorrect fixit removal
// to be emitted.
void VIRTUAL G() final {}
// Make sure a fixit removal isn't generated for macros that expand to more
// than just 'virtual'.
VIRTUAL_VOID H() final {}
};
-Xclang -plugin-arg-find-bad-constructs -Xclang strict-virtual-specifiers
virtual_base_method_also_final.cpp:10:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'.
VIRTUAL void F() final {}
^~~~~~~~
virtual_base_method_also_final.cpp:5:17: note: expanded from macro 'VIRTUAL'
#define VIRTUAL virtual
^
virtual_base_method_also_final.cpp:10:3: warning: [chromium-style] The virtual method does not override anything and is final; consider making it non-virtual.
VIRTUAL void F() final {}
^~~~~~~~ ~~~~~~
virtual_base_method_also_final.cpp:5:17: note: expanded from macro 'VIRTUAL'
#define VIRTUAL virtual
^
virtual_base_method_also_final.cpp:13:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'.
void VIRTUAL G() final {}
^
virtual_base_method_also_final.cpp:13:3: warning: [chromium-style] The virtual method does not override anything and is final; consider making it non-virtual.
void VIRTUAL G() final {}
^ ~~~~~~
virtual_base_method_also_final.cpp:16:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'.
VIRTUAL_VOID H() final {}
^
virtual_base_method_also_final.cpp:6:22: note: expanded from macro 'VIRTUAL_VOID'
#define VIRTUAL_VOID virtual void
^
virtual_base_method_also_final.cpp:16:3: warning: [chromium-style] The virtual method does not override anything and is final; consider making it non-virtual.
virtual_base_method_also_final.cpp:6:22: note: expanded from macro 'VIRTUAL_VOID'
#define VIRTUAL_VOID virtual void
^
6 warnings generated.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "virtual_methods.h" #include "virtual_bodies.h"
// Shouldn't warn about method usage in the implementation file. // Shouldn't warn about method usage in the implementation file.
class VirtualMethodsInImplementation { class VirtualMethodsInImplementation {
...@@ -26,9 +26,12 @@ class ConcreteVirtualMethodsInImplementation ...@@ -26,9 +26,12 @@ class ConcreteVirtualMethodsInImplementation
}; };
// Fill in the implementations // Fill in the implementations
void VirtualMethodsInHeaders::MethodHasNoArguments() {} void VirtualMethodsInHeaders::MethodHasNoArguments() {
void WarnOnMissingVirtual::MethodHasNoArguments() {} }
void VirtualMethodsInImplementation::MethodHasNoArguments() {} void WarnOnMissingVirtual::MethodHasNoArguments() {
}
void VirtualMethodsInImplementation::MethodHasNoArguments() {
}
int main() { int main() {
ConcreteVirtualMethodsInHeaders one; ConcreteVirtualMethodsInHeaders one;
......
...@@ -32,6 +32,7 @@ class VirtualMethodsInHeadersTesting : public VirtualMethodsInHeaders { ...@@ -32,6 +32,7 @@ class VirtualMethodsInHeadersTesting : public VirtualMethodsInHeaders {
public: public:
// Don't complain about no virtual testing methods. // Don't complain about no virtual testing methods.
void MethodHasNoArguments(); void MethodHasNoArguments();
private: private:
testing::TestStruct tester_; testing::TestStruct tester_;
}; };
......
In file included from virtual_bodies.cpp:5:
./virtual_bodies.h:17:36: warning: [chromium-style] virtual methods with non-empty bodies shouldn't be declared inline.
virtual bool ComplainAboutThis() { return true; }
^
1 warning generated.
In file included from virtual_methods.cpp:5:
./virtual_methods.h:17:36: warning: [chromium-style] virtual methods with non-empty bodies shouldn't be declared inline.
virtual bool ComplainAboutThis() { return true; }
^
./virtual_methods.h:23:3: warning: [chromium-style] Overriding method must have "virtual" keyword.
void MethodHasNoArguments() override;
^
virtual
2 warnings generated.
// Copyright 2014 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.
//
// Tests for chromium style checks for virtual/override/final specifiers on
// virtual methods.
// Purposely use macros to test that the FixIt hints don't try to remove the
// macro body.
#define OVERRIDE override
#define FINAL final
// Base class can only use virtual.
class Base {
public:
virtual ~Base() {}
virtual void F() = 0;
};
// Derived classes correctly use only override or final specifier.
class CorrectOverride : public Base {
public:
~CorrectOverride() OVERRIDE {}
void F() OVERRIDE {}
};
class CorrectFinal : public CorrectOverride {
public:
~CorrectFinal() FINAL {}
void F() FINAL {}
};
// No override on an overridden method should trigger a diagnostic.
class MissingOverride : public Base {
public:
~MissingOverride() {}
void F() {}
};
// Redundant specifiers should trigger a diagnostic.
class VirtualAndOverride : public Base {
public:
virtual ~VirtualAndOverride() OVERRIDE {}
virtual void F() OVERRIDE {}
};
class VirtualAndFinal : public Base {
public:
virtual ~VirtualAndFinal() FINAL {}
virtual void F() FINAL {}
};
class VirtualAndOverrideFinal : public Base {
public:
virtual ~VirtualAndOverrideFinal() OVERRIDE FINAL {}
virtual void F() OVERRIDE FINAL {}
};
class OverrideAndFinal : public Base {
public:
~OverrideAndFinal() OVERRIDE FINAL {}
void F() OVERRIDE FINAL {}
};
-Xclang -plugin-arg-find-bad-constructs -Xclang strict-virtual-specifiers
virtual_specifiers.cpp:36:21: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
~MissingOverride() {}
^
override
virtual_specifiers.cpp:37:11: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
void F() {}
^
override
virtual_specifiers.cpp:43:3: warning: [chromium-style] 'virtual' is redundant; 'override' implies 'virtual'.
virtual ~VirtualAndOverride() OVERRIDE {}
^~~~~~~~
virtual_specifiers.cpp:44:3: warning: [chromium-style] 'virtual' is redundant; 'override' implies 'virtual'.
virtual void F() OVERRIDE {}
^~~~~~~~
virtual_specifiers.cpp:49:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'.
virtual ~VirtualAndFinal() FINAL {}
^~~~~~~~
virtual_specifiers.cpp:50:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'.
virtual void F() FINAL {}
^~~~~~~~
virtual_specifiers.cpp:55:3: warning: [chromium-style] 'virtual' is redundant; 'override' implies 'virtual'.
virtual ~VirtualAndOverrideFinal() OVERRIDE FINAL {}
^~~~~~~~
virtual_specifiers.cpp:55:38: warning: [chromium-style] 'override' is redundant; 'final' implies 'override'.
virtual ~VirtualAndOverrideFinal() OVERRIDE FINAL {}
^~~~~~~~~
virtual_specifiers.cpp:10:18: note: expanded from macro 'OVERRIDE'
#define OVERRIDE override
^
virtual_specifiers.cpp:56:3: warning: [chromium-style] 'virtual' is redundant; 'override' implies 'virtual'.
virtual void F() OVERRIDE FINAL {}
^~~~~~~~
virtual_specifiers.cpp:56:20: warning: [chromium-style] 'override' is redundant; 'final' implies 'override'.
virtual void F() OVERRIDE FINAL {}
^~~~~~~~~
virtual_specifiers.cpp:10:18: note: expanded from macro 'OVERRIDE'
#define OVERRIDE override
^
virtual_specifiers.cpp:61:23: warning: [chromium-style] 'override' is redundant; 'final' implies 'override'.
~OverrideAndFinal() OVERRIDE FINAL {}
^~~~~~~~~
virtual_specifiers.cpp:10:18: note: expanded from macro 'OVERRIDE'
#define OVERRIDE override
^
virtual_specifiers.cpp:62:12: warning: [chromium-style] 'override' is redundant; 'final' implies 'override'.
void F() OVERRIDE FINAL {}
^~~~~~~~~
virtual_specifiers.cpp:10:18: note: expanded from macro 'OVERRIDE'
#define OVERRIDE override
^
12 warnings generated.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment