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,
// TODO(tsepez): Enable this by default once http://crbug.com/356815
// and http://crbug.com/356816 are fixed.
options_.check_enum_last_value = true;
} else if (args[i] == "strict-virtual-specifiers") {
options_.strict_virtual_specifiers = true;
} else {
parsed = false;
llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n";
......
......@@ -5,6 +5,7 @@
#include "FindBadConstructsConsumer.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/AST/Attr.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/raw_ostream.h"
......@@ -15,9 +16,15 @@ namespace chrome_checker {
namespace {
const char kMethodRequiresOverride[] =
"[chromium-style] Overriding method must be marked with OVERRIDE.";
const char kMethodRequiresVirtual[] =
"[chromium-style] Overriding method must have \"virtual\" keyword.";
"[chromium-style] Overriding method must be marked with 'override' or "
"'final'.";
const char kRedundantVirtualSpecifier[] =
"[chromium-style] %0 is redundant; %1 implies %0.";
// http://llvm.org/bugs/show_bug.cgi?id=21051 has been filed to make this a
// Clang warning.
const char kBaseMethodVirtualAndFinal[] =
"[chromium-style] The virtual method does not override anything and is "
"final; consider making it non-virtual.";
const char kNoExplicitDtor[] =
"[chromium-style] Classes that are ref-counted should have explicit "
"destructors that are declared protected or private.";
......@@ -59,22 +66,47 @@ const Type* UnwrapType(const Type* type) {
return type;
}
FixItHint FixItRemovalForVirtual(const SourceManager& manager,
const CXXMethodDecl* method) {
// Unfortunately, there doesn't seem to be a good way to determine the
// location of the 'virtual' keyword. It's available in Declarator, but that
// isn't accessible from the AST. So instead, make an educated guess that the
// first token is probably the virtual keyword. Strictly speaking, this
// doesn't have to be true, but it probably will be.
// TODO(dcheng): Add a warning to force virtual to always appear first ;-)
SourceRange range(method->getLocStart());
// Get the spelling loc just in case it was expanded from a macro.
SourceRange spelling_range(manager.getSpellingLoc(range.getBegin()));
// Sanity check that the text looks like virtual.
StringRef text = clang::Lexer::getSourceText(
CharSourceRange::getTokenRange(spelling_range), manager, LangOptions());
if (text.trim() != "virtual")
return FixItHint();
return FixItHint::CreateRemoval(range);
}
} // namespace
FindBadConstructsConsumer::FindBadConstructsConsumer(CompilerInstance& instance,
const Options& options)
: ChromeClassTester(instance), options_(options) {
// Register warning/error messages.
// Messages for virtual method specifiers.
diag_method_requires_override_ =
diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresOverride);
diag_method_requires_virtual_ =
diagnostic().getCustomDiagID(getErrorLevel(), kMethodRequiresVirtual);
diag_redundant_virtual_specifier_ =
diagnostic().getCustomDiagID(getErrorLevel(), kRedundantVirtualSpecifier);
diag_base_method_virtual_and_final_ =
diagnostic().getCustomDiagID(getErrorLevel(), kBaseMethodVirtualAndFinal);
// Messages for destructors.
diag_no_explicit_dtor_ =
diagnostic().getCustomDiagID(getErrorLevel(), kNoExplicitDtor);
diag_public_dtor_ =
diagnostic().getCustomDiagID(getErrorLevel(), kPublicDtor);
diag_protected_non_virtual_dtor_ =
diagnostic().getCustomDiagID(getErrorLevel(), kProtectedNonVirtualDtor);
// Miscellaneous messages.
diag_weak_ptr_factory_order_ =
diagnostic().getCustomDiagID(getErrorLevel(), kWeakPtrFactoryOrder);
diag_bad_enum_last_value_ =
......@@ -103,8 +135,7 @@ void FindBadConstructsConsumer::CheckChromeClass(SourceLocation record_location,
bool warn_on_inline_bodies = !implementation_file;
// Check that all virtual methods are marked accordingly with both
// virtual and OVERRIDE.
// Check that all virtual methods are annotated with override or final.
CheckVirtualMethods(record_location, record, warn_on_inline_bodies);
CheckRefCountedDtors(record_location, record);
......@@ -250,35 +281,6 @@ void FindBadConstructsConsumer::CheckCtorDtorWeight(
}
}
void FindBadConstructsConsumer::CheckVirtualMethod(const CXXMethodDecl* method,
bool warn_on_inline_bodies) {
if (!method->isVirtual())
return;
if (!method->isVirtualAsWritten()) {
SourceLocation loc = method->getTypeSpecStartLoc();
if (isa<CXXDestructorDecl>(method))
loc = method->getInnerLocStart();
SourceManager& manager = instance().getSourceManager();
FullSourceLoc full_loc(loc, manager);
SourceLocation spelling_loc = manager.getSpellingLoc(loc);
diagnostic().Report(full_loc, diag_method_requires_virtual_)
<< FixItHint::CreateInsertion(spelling_loc, "virtual ");
}
// Virtual methods should not have inline definitions beyond "{}". This
// only matters for header files.
if (warn_on_inline_bodies && method->hasBody() && method->hasInlineBody()) {
if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) {
if (cs->size()) {
emitWarning(cs->getLBracLoc(),
"virtual methods with non-empty bodies shouldn't be "
"declared inline.");
}
}
}
}
bool FindBadConstructsConsumer::InTestingNamespace(const Decl* record) {
return GetNamespace(record).find("testing") != std::string::npos;
}
......@@ -300,47 +302,16 @@ bool FindBadConstructsConsumer::IsMethodInBannedOrTestingNamespace(
return false;
}
void FindBadConstructsConsumer::CheckOverriddenMethod(
const CXXMethodDecl* method) {
if (!method->size_overridden_methods() || method->getAttr<OverrideAttr>())
return;
if (isa<CXXDestructorDecl>(method) || method->isPure())
return;
if (IsMethodInBannedOrTestingNamespace(method))
return;
SourceManager& manager = instance().getSourceManager();
SourceRange type_info_range =
method->getTypeSourceInfo()->getTypeLoc().getSourceRange();
FullSourceLoc loc(type_info_range.getBegin(), manager);
// Build the FixIt insertion point after the end of the method definition,
// including any const-qualifiers and attributes, and before the opening
// of the l-curly-brace (if inline) or the semi-color (if a declaration).
SourceLocation spelling_end =
manager.getSpellingLoc(type_info_range.getEnd());
if (spelling_end.isValid()) {
SourceLocation token_end =
Lexer::getLocForEndOfToken(spelling_end, 0, manager, LangOptions());
diagnostic().Report(token_end, diag_method_requires_override_)
<< FixItHint::CreateInsertion(token_end, " OVERRIDE");
} else {
diagnostic().Report(loc, diag_method_requires_override_);
}
}
// Makes sure there is a "virtual" keyword on virtual methods.
//
// Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a
// trick to get around that. If a class has member variables whose types are
// in the "testing" namespace (which is how gmock works behind the scenes),
// there's a really high chance we won't care about these errors
// Checks that virtual methods are correctly annotated, and have no body in a
// header file.
void FindBadConstructsConsumer::CheckVirtualMethods(
SourceLocation record_location,
CXXRecordDecl* record,
bool warn_on_inline_bodies) {
// Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a
// trick to get around that. If a class has member variables whose types are
// in the "testing" namespace (which is how gmock works behind the scenes),
// there's a really high chance we won't care about these errors
for (CXXRecordDecl::field_iterator it = record->field_begin();
it != record->field_end();
++it) {
......@@ -363,9 +334,96 @@ void FindBadConstructsConsumer::CheckVirtualMethods(
} else if (isa<CXXDestructorDecl>(*it) &&
!record->hasUserDeclaredDestructor()) {
// Ignore non-user-declared destructors.
} else if (!it->isVirtual()) {
continue;
} else {
CheckVirtualSpecifiers(*it);
if (warn_on_inline_bodies)
CheckVirtualBodies(*it);
}
}
}
// Makes sure that virtual methods use the most appropriate specifier. If a
// virtual method overrides a method from a base class, only the override
// specifier should be used. If the method should not be overridden by derived
// classes, only the final specifier should be used.
void FindBadConstructsConsumer::CheckVirtualSpecifiers(
const CXXMethodDecl* method) {
bool is_override = method->size_overridden_methods() > 0;
bool has_virtual = method->isVirtualAsWritten();
OverrideAttr* override_attr = method->getAttr<OverrideAttr>();
FinalAttr* final_attr = method->getAttr<FinalAttr>();
if (method->isPure())
return;
if (IsMethodInBannedOrTestingNamespace(method))
return;
if (isa<CXXDestructorDecl>(method) && !options_.strict_virtual_specifiers)
return;
SourceManager& manager = instance().getSourceManager();
// Complain if a method is annotated virtual && (override || final).
if (has_virtual && (override_attr || final_attr) &&
options_.strict_virtual_specifiers) {
diagnostic().Report(method->getLocStart(),
diag_redundant_virtual_specifier_)
<< "'virtual'"
<< (override_attr ? static_cast<Attr*>(override_attr) : final_attr)
<< FixItRemovalForVirtual(manager, method);
}
// Complain if a method is an override and is not annotated with override or
// final.
if (is_override && !override_attr && !final_attr) {
SourceRange type_info_range =
method->getTypeSourceInfo()->getTypeLoc().getSourceRange();
FullSourceLoc loc(type_info_range.getBegin(), manager);
// Build the FixIt insertion point after the end of the method definition,
// including any const-qualifiers and attributes, and before the opening
// of the l-curly-brace (if inline) or the semi-color (if a declaration).
SourceLocation spelling_end =
manager.getSpellingLoc(type_info_range.getEnd());
if (spelling_end.isValid()) {
SourceLocation token_end =
Lexer::getLocForEndOfToken(spelling_end, 0, manager, LangOptions());
diagnostic().Report(token_end, diag_method_requires_override_)
<< FixItHint::CreateInsertion(token_end, " override");
} else {
CheckVirtualMethod(*it, warn_on_inline_bodies);
CheckOverriddenMethod(*it);
diagnostic().Report(loc, diag_method_requires_override_);
}
}
if (final_attr && override_attr && options_.strict_virtual_specifiers) {
diagnostic().Report(override_attr->getLocation(),
diag_redundant_virtual_specifier_)
<< override_attr << final_attr
<< FixItHint::CreateRemoval(override_attr->getRange());
}
if (final_attr && !is_override && options_.strict_virtual_specifiers) {
diagnostic().Report(method->getLocStart(),
diag_base_method_virtual_and_final_)
<< FixItRemovalForVirtual(manager, method)
<< FixItHint::CreateRemoval(final_attr->getRange());
}
}
void FindBadConstructsConsumer::CheckVirtualBodies(
const CXXMethodDecl* method) {
// Virtual methods should not have inline definitions beyond "{}". This
// only matters for header files.
if (method->hasBody() && method->hasInlineBody()) {
if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) {
if (cs->size()) {
emitWarning(cs->getLBracLoc(),
"virtual methods with non-empty bodies shouldn't be "
"declared inline.");
}
}
}
}
......
......@@ -36,10 +36,10 @@ class FindBadConstructsConsumer : public ChromeClassTester {
const Options& options);
// ChromeClassTester overrides:
virtual void CheckChromeClass(clang::SourceLocation record_location,
clang::CXXRecordDecl* record);
virtual void CheckChromeEnum(clang::SourceLocation enum_location,
clang::EnumDecl* enum_decl);
void CheckChromeClass(clang::SourceLocation record_location,
clang::CXXRecordDecl* record) override;
void CheckChromeEnum(clang::SourceLocation enum_location,
clang::EnumDecl* enum_decl) override;
private:
// The type of problematic ref-counting pattern that was encountered.
......@@ -48,16 +48,14 @@ class FindBadConstructsConsumer : public ChromeClassTester {
void CheckCtorDtorWeight(clang::SourceLocation record_location,
clang::CXXRecordDecl* record);
void CheckVirtualMethod(const clang::CXXMethodDecl* method,
bool warn_on_inline_bodies);
bool InTestingNamespace(const clang::Decl* record);
bool IsMethodInBannedOrTestingNamespace(const clang::CXXMethodDecl* method);
void CheckOverriddenMethod(const clang::CXXMethodDecl* method);
void CheckVirtualMethods(clang::SourceLocation record_location,
clang::CXXRecordDecl* record,
bool warn_on_inline_bodies);
void CheckVirtualSpecifiers(const clang::CXXMethodDecl* method);
void CheckVirtualBodies(const clang::CXXMethodDecl* method);
void CountType(const clang::Type* type,
int* trivial_member,
......@@ -85,7 +83,8 @@ class FindBadConstructsConsumer : public ChromeClassTester {
const Options options_;
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_public_dtor_;
unsigned diag_protected_non_virtual_dtor_;
......
......@@ -11,11 +11,13 @@ struct Options {
Options()
: check_base_classes(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_weak_ptr_factory_order;
bool check_enum_last_value;
bool strict_virtual_specifiers;
};
} // 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'.
^
OVERRIDE
/src/chrome-breakpad/src/myheader.h:124:21: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
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'.
^
OVERRIDE
override
2 warnings generated.
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();
^
OVERRIDE
./overridden_methods.h:52:34: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
./overridden_methods.h:52:34: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeInlineMethod() {}
^
OVERRIDE
./overridden_methods.h:56:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
./overridden_methods.h:56:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethod() const {}
^
OVERRIDE
./overridden_methods.h:58:53: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
./overridden_methods.h:58:53: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithExceptionSpec() throw() {}
^
OVERRIDE
./overridden_methods.h:61:67: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
./overridden_methods.h:61:67: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethodWithExceptionSpec() const throw(int) {}
^
OVERRIDE
./overridden_methods.h:63:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
./overridden_methods.h:63:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeNonPureBaseMethod() {}
^
OVERRIDE
./overridden_methods.h:65:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
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.
^
OVERRIDE
./overridden_methods.h:67:46: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
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.
^
OVERRIDE
overridden_methods.cpp:24:28: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
overridden_methods.cpp:24:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethod();
^
OVERRIDE
overridden_methods.cpp:28:34: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
overridden_methods.cpp:28:34: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeInlineMethod() {}
^
OVERRIDE
overridden_methods.cpp:32:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
overridden_methods.cpp:32:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethod() const {}
^
OVERRIDE
overridden_methods.cpp:34:53: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
overridden_methods.cpp:34:53: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethodWithExceptionSpec() throw() {}
^
OVERRIDE
overridden_methods.cpp:37:67: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
overridden_methods.cpp:37:67: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeConstMethodWithExceptionSpec() const throw(int) {}
^
OVERRIDE
overridden_methods.cpp:39:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
override
overridden_methods.cpp:39:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeNonPureBaseMethod() {}
^
OVERRIDE
overridden_methods.cpp:41:39: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
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.
^
OVERRIDE
overridden_methods.cpp:43:46: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
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.
^
OVERRIDE
override
16 warnings generated.
......@@ -33,7 +33,7 @@ do_testcase() {
flags="${flags} -isysroot $(xcrun --show-sdk-path) -stdlib=libstdc++"
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 -add-plugin -Xclang find-bad-constructs ${flags} ${1} 2>&1)"
local diffout="$(echo "${output}" | diff - "${2}")"
......@@ -44,6 +44,10 @@ do_testcase() {
echo "FAIL: ${1}"
echo "Output of compiler:"
echo "${output}"
cat > ${2}-actual << EOF
${output}
EOF
echo "Expected output:"
cat "${2}"
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 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "virtual_methods.h"
#include "virtual_bodies.h"
// Shouldn't warn about method usage in the implementation file.
class VirtualMethodsInImplementation {
......@@ -26,9 +26,12 @@ class ConcreteVirtualMethodsInImplementation
};
// Fill in the implementations
void VirtualMethodsInHeaders::MethodHasNoArguments() {}
void WarnOnMissingVirtual::MethodHasNoArguments() {}
void VirtualMethodsInImplementation::MethodHasNoArguments() {}
void VirtualMethodsInHeaders::MethodHasNoArguments() {
}
void WarnOnMissingVirtual::MethodHasNoArguments() {
}
void VirtualMethodsInImplementation::MethodHasNoArguments() {
}
int main() {
ConcreteVirtualMethodsInHeaders one;
......
......@@ -32,6 +32,7 @@ class VirtualMethodsInHeadersTesting : public VirtualMethodsInHeaders {
public:
// Don't complain about no virtual testing methods.
void MethodHasNoArguments();
private:
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