clang-tidy: [use-override] Remove 'override' if 'final' is also present.

Also, make warning more precise by distinguishing different cases.

llvm-svn: 210651
This commit is contained in:
Daniel Jasper 2014-06-11 12:18:24 +00:00
parent 9ae3d02193
commit 05bdb09da1
3 changed files with 35 additions and 9 deletions

View File

@ -61,14 +61,21 @@ void UseOverride::check(const MatchFinder::MatchResult &Result) {
Method->isOutOfLine())
return;
if ((Method->getAttr<clang::OverrideAttr>() != nullptr ||
Method->getAttr<clang::FinalAttr>() != nullptr) &&
!Method->isVirtualAsWritten())
bool HasVirtual = Method->isVirtualAsWritten();
bool HasOverride = Method->getAttr<OverrideAttr>();
bool HasFinal = Method->getAttr<FinalAttr>();
bool OnlyVirtualSpecified = HasVirtual && !HasOverride && !HasFinal;
unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
if (!OnlyVirtualSpecified && KeywordCount == 1)
return; // Nothing to do.
DiagnosticBuilder Diag =
diag(Method->getLocation(),
"Prefer using 'override' or 'final' instead of 'virtual'");
OnlyVirtualSpecified
? "Prefer using 'override' or 'final' instead of 'virtual'"
: "Use exactly one of 'virtual', 'override' and 'final'");
CharSourceRange FileRange =
Lexer::makeFileCharRange(CharSourceRange::getTokenRange(
@ -85,8 +92,7 @@ void UseOverride::check(const MatchFinder::MatchResult &Result) {
Result.Context->getLangOpts());
// Add 'override' on inline declarations that don't already have it.
if (Method->getAttr<clang::OverrideAttr>() == nullptr &&
Method->getAttr<clang::FinalAttr>() == nullptr) {
if (!HasFinal && !HasOverride) {
SourceLocation InsertLoc;
StringRef ReplacementText = "override ";
@ -120,6 +126,12 @@ void UseOverride::check(const MatchFinder::MatchResult &Result) {
Diag << FixItHint::CreateInsertion(InsertLoc, ReplacementText);
}
if (HasFinal && HasOverride) {
SourceLocation OverrideLoc = Method->getAttr<OverrideAttr>()->getLocation();
Diag << FixItHint::CreateRemoval(
CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc));
}
if (Method->isVirtualAsWritten()) {
for (Token Tok : Tokens) {
if (Tok.is(tok::raw_identifier) && GetText(Tok, Sources) == "virtual") {

View File

@ -25,6 +25,8 @@ struct Base {
virtual void j() const;
virtual MustUseResultObject k();
virtual bool l() MUST_USE_RESULT;
virtual void m();
};
struct SimpleCases : public Base {
@ -54,6 +56,9 @@ public:
// CHECK: {{^ MustUseResultObject k\(\) override;}}
virtual bool l() MUST_USE_RESULT; // Has an explicit attribute
// CHECK: {{^ bool l\(\) override MUST_USE_RESULT;}}
virtual void m() override final;
// CHECK: {{^ void m\(\) final;}}
};
void SimpleCases::i() {}
@ -125,6 +130,9 @@ struct Macros : public Base {
#define F virtual void f();
F
// CHECK: {{^ F}}
VIRTUAL void g() OVERRIDE final;
// CHECK: {{^ VIRTUAL void g\(\) final;}}
};
// Tests for templates.

View File

@ -7,6 +7,8 @@ struct Base {
virtual void b();
virtual void c();
virtual void d();
virtual void e();
virtual void f();
};
struct SimpleCases : public Base {
@ -15,11 +17,15 @@ public:
// CHECK: :[[@LINE-1]]:11: warning: Prefer using 'override' or 'final' instead of 'virtual'
void a();
// CHECK: :[[@LINE-1]]:8: warning: Prefer using
// CHECK: :[[@LINE-1]]:8: warning: Use exactly
virtual void b();
// CHECK: :[[@LINE-1]]:16: warning: Prefer using
void c() override;
virtual void c() override;
// CHECK: :[[@LINE-1]]:16: warning: Use exactly
void d() override final;
// CHECK: :[[@LINE-1]]:8: warning: Use exactly
void e() override;
// CHECK-NOT: :[[@LINE-1]]:{{.*}} warning:
void d() final;
void f() final;
// CHECK-NOT: :[[@LINE-1]]:{{.*}} warning:
};