Handle 'final' specifier better.

This commit is contained in:
Daniel Marjamäki 2018-04-27 14:57:43 +02:00
parent 5272197e3f
commit 25599a76a7
7 changed files with 42 additions and 56 deletions

View File

@ -2495,7 +2495,7 @@ void CheckClass::checkOverride()
if (!classScope->definedType || classScope->definedType->derivedFrom.empty()) if (!classScope->definedType || classScope->definedType->derivedFrom.empty())
continue; continue;
for (const Function &func : classScope->functionList) { for (const Function &func : classScope->functionList) {
if (func.hasOverrideKeyword()) if (func.hasOverrideSpecifier() || func.hasFinalSpecifier())
continue; continue;
const Function *baseFunc = func.getOverridenFunction(); const Function *baseFunc = func.getOverridenFunction();
if (baseFunc) if (baseFunc)
@ -2516,7 +2516,7 @@ void CheckClass::overrideError(const Function *funcInBase, const Function *funcI
reportError(errorPath, Severity::style, "missingOverride", reportError(errorPath, Severity::style, "missingOverride",
"$symbol:" + functionName + "\n" "$symbol:" + functionName + "\n"
"Function '$symbol' overrides function in base class but does not have the 'override' keyword.", "The function '$symbol' overrides a function in a base class but is not marked with a 'override' specifier.",
CWE(0U) /* Unknown CWE! */, CWE(0U) /* Unknown CWE! */,
false); false);
} }

View File

@ -1755,6 +1755,10 @@ Function::Function(const Tokenizer *_tokenizer, const Token *tok, const Scope *s
hasLvalRefQualifier(true); hasLvalRefQualifier(true);
else if (tok->str() == "&&") else if (tok->str() == "&&")
hasRvalRefQualifier(true); hasRvalRefQualifier(true);
else if (tok->str() == "override")
setFlag(fHasOverrideSpecifier, true);
else if (tok->str() == "final")
setFlag(fHasFinalSpecifier, true);
else if (tok->str() == "noexcept") { else if (tok->str() == "noexcept") {
isNoExcept(!Token::simpleMatch(tok->next(), "( false )")); isNoExcept(!Token::simpleMatch(tok->next(), "( false )"));
tok = tok->next(); tok = tok->next();

View File

@ -653,25 +653,26 @@ private:
class CPPCHECKLIB Function { class CPPCHECKLIB Function {
/** @brief flags mask used to access specific bit. */ /** @brief flags mask used to access specific bit. */
enum { enum {
fHasBody = (1 << 0), ///< @brief has implementation fHasBody = (1 << 0), ///< @brief has implementation
fIsInline = (1 << 1), ///< @brief implementation in class definition fIsInline = (1 << 1), ///< @brief implementation in class definition
fIsConst = (1 << 2), ///< @brief is const fIsConst = (1 << 2), ///< @brief is const
fIsVirtual = (1 << 3), ///< @brief is virtual fIsVirtual = (1 << 3), ///< @brief is virtual
fIsPure = (1 << 4), ///< @brief is pure virtual fIsPure = (1 << 4), ///< @brief is pure virtual
fIsStatic = (1 << 5), ///< @brief is static fIsStatic = (1 << 5), ///< @brief is static
fIsStaticLocal = (1 << 6), ///< @brief is static local fIsStaticLocal = (1 << 6), ///< @brief is static local
fIsExtern = (1 << 7), ///< @brief is extern fIsExtern = (1 << 7), ///< @brief is extern
fIsFriend = (1 << 8), ///< @brief is friend fIsFriend = (1 << 8), ///< @brief is friend
fIsExplicit = (1 << 9), ///< @brief is explicit fIsExplicit = (1 << 9), ///< @brief is explicit
fIsDefault = (1 << 10), ///< @brief is default fIsDefault = (1 << 10), ///< @brief is default
fIsDelete = (1 << 11), ///< @brief is delete fIsDelete = (1 << 11), ///< @brief is delete
fHasOverrideKeyword = (1 << 12), ///< @brief does declaration contain 'override' keyword? fHasOverrideSpecifier = (1 << 12), ///< @brief does declaration contain 'override' specifier?
fIsNoExcept = (1 << 13), ///< @brief is noexcept fHasFinalSpecifier = (1 << 13), ///< @brief does declaration contain 'final' specifier?
fIsThrow = (1 << 14), ///< @brief is throw fIsNoExcept = (1 << 14), ///< @brief is noexcept
fIsOperator = (1 << 15), ///< @brief is operator fIsThrow = (1 << 15), ///< @brief is throw
fHasLvalRefQual = (1 << 16), ///< @brief has & lvalue ref-qualifier fIsOperator = (1 << 16), ///< @brief is operator
fHasRvalRefQual = (1 << 17), ///< @brief has && rvalue ref-qualifier fHasLvalRefQual = (1 << 17), ///< @brief has & lvalue ref-qualifier
fIsVariadic = (1 << 18) ///< @brief is variadic fHasRvalRefQual = (1 << 18), ///< @brief has && rvalue ref-qualifier
fIsVariadic = (1 << 19) ///< @brief is variadic
}; };
/** /**
@ -806,8 +807,11 @@ public:
bool isThrow() const { bool isThrow() const {
return getFlag(fIsThrow); return getFlag(fIsThrow);
} }
bool hasOverrideKeyword() const { bool hasOverrideSpecifier() const {
return getFlag(fHasOverrideKeyword); return getFlag(fHasOverrideSpecifier);
}
bool hasFinalSpecifier() const {
return getFlag(fHasFinalSpecifier);
} }
bool isOperator() const { bool isOperator() const {
return getFlag(fIsOperator); return getFlag(fIsOperator);

View File

@ -103,7 +103,7 @@ const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &end
} }
if (cpp && tok->str() == ")") { if (cpp && tok->str() == ")") {
tok = tok->next(); tok = tok->next();
while (Token::Match(tok, "const|noexcept|override|volatile|&|&& !!(") || while (Token::Match(tok, "const|noexcept|override|final|volatile|&|&& !!(") ||
(Token::Match(tok, "%name% !!(") && tok->isUpperCaseName())) (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
tok = tok->next(); tok = tok->next();
if (tok && tok->str() == ")") if (tok && tok->str() == ")")
@ -9030,26 +9030,9 @@ void Tokenizer::simplifyKeyword()
tok->deleteNext(); tok->deleteNext();
continue; continue;
} }
// final:
// 2) void f() final; <- function is final
if (Token::Match(tok, ") const|override|final")) {
Token* specifier = tok->tokAt(2);
while (Token::Match(specifier, "const|override|final")) {
specifier=specifier->next();
}
if (Token::Match(specifier, "[{;]")) {
specifier = tok->next();
while (!Token::Match(specifier, "[{;]")) {
if (specifier->str()=="final")
specifier->deleteThis();
else
specifier=specifier->next();
}
}
}
// noexcept -> noexcept(true) // noexcept -> noexcept(true)
// 3) void f() noexcept; -> void f() noexcept(true); // 2) void f() noexcept; -> void f() noexcept(true);
if (Token::Match(tok, ") noexcept :|{|;|const|override|final")) { if (Token::Match(tok, ") noexcept :|{|;|const|override|final")) {
// Insertion is done in inverse order // Insertion is done in inverse order
// The brackets are linked together accordingly afterwards // The brackets are linked together accordingly afterwards

View File

@ -6619,7 +6619,15 @@ private:
void override1() { void override1() {
checkOverride("class Base { virtual void f(); };\n" checkOverride("class Base { virtual void f(); };\n"
"class Derived : Base { virtual void f(); };"); "class Derived : Base { virtual void f(); };");
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:2]: (style) Function 'f' overrides function in base class but does not have the 'override' keyword.\n", errout.str()); ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:2]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier.\n", errout.str());
checkOverride("class Base { virtual void f(); };\n"
"class Derived : Base { virtual void f() override; };");
ASSERT_EQUALS("", errout.str());
checkOverride("class Base { virtual void f(); };\n"
"class Derived : Base { virtual void f() final; };");
ASSERT_EQUALS("", errout.str());
} }
}; };

View File

@ -3268,7 +3268,6 @@ private:
ASSERT_EQUALS("int foo ( ) { }", tok("__inline int foo ( ) { }", true)); ASSERT_EQUALS("int foo ( ) { }", tok("__inline int foo ( ) { }", true));
ASSERT_EQUALS("int foo ( ) { }", tok("__forceinline int foo ( ) { }", true)); ASSERT_EQUALS("int foo ( ) { }", tok("__forceinline int foo ( ) { }", true));
ASSERT_EQUALS("int foo ( ) { }", tok("constexpr int foo() { }", true)); ASSERT_EQUALS("int foo ( ) { }", tok("constexpr int foo() { }", true));
ASSERT_EQUALS("class C { int f ( ) ; } ;", tok("class C { int f() final ; };", true));
ASSERT_EQUALS("void f ( ) { int final [ 10 ] ; }", tok("void f() { int final[10]; }", true)); ASSERT_EQUALS("void f ( ) { int final [ 10 ] ; }", tok("void f() { int final[10]; }", true));
ASSERT_EQUALS("int * p ;", tok("int * __restrict p;", "test.c")); ASSERT_EQUALS("int * p ;", tok("int * __restrict p;", "test.c"));
ASSERT_EQUALS("int * * p ;", tok("int * __restrict__ * p;", "test.c")); ASSERT_EQUALS("int * * p ;", tok("int * __restrict__ * p;", "test.c"));

View File

@ -4059,18 +4059,6 @@ private:
"}\n" "}\n"
"} ;"; "} ;";
ASSERT_EQUALS(out1, tokenizeAndStringify(in1)); ASSERT_EQUALS(out1, tokenizeAndStringify(in1));
const char in2[] = "class Derived{\n"
" virtual int test() final override;"
"};";
const char out2[] = "class Derived {\n"
"virtual int test ( ) override ; } ;";
ASSERT_EQUALS(out2, tokenizeAndStringify(in2));
const char in3[] = "class Derived{\n"
" virtual int test() final override const;"
"};";
const char out3[] = "class Derived {\n"
"virtual int test ( ) override const ; } ;";
ASSERT_EQUALS(out3, tokenizeAndStringify(in3));
const char in4 [] = "struct B final : A { void foo(); };"; const char in4 [] = "struct B final : A { void foo(); };";
const char out4 [] = "struct B : A { void foo ( ) ; } ;"; const char out4 [] = "struct B : A { void foo ( ) ; } ;";