Handle 'final' specifier better.
This commit is contained in:
parent
5272197e3f
commit
25599a76a7
|
@ -2495,7 +2495,7 @@ void CheckClass::checkOverride()
|
|||
if (!classScope->definedType || classScope->definedType->derivedFrom.empty())
|
||||
continue;
|
||||
for (const Function &func : classScope->functionList) {
|
||||
if (func.hasOverrideKeyword())
|
||||
if (func.hasOverrideSpecifier() || func.hasFinalSpecifier())
|
||||
continue;
|
||||
const Function *baseFunc = func.getOverridenFunction();
|
||||
if (baseFunc)
|
||||
|
@ -2516,7 +2516,7 @@ void CheckClass::overrideError(const Function *funcInBase, const Function *funcI
|
|||
|
||||
reportError(errorPath, Severity::style, "missingOverride",
|
||||
"$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! */,
|
||||
false);
|
||||
}
|
||||
|
|
|
@ -1755,6 +1755,10 @@ Function::Function(const Tokenizer *_tokenizer, const Token *tok, const Scope *s
|
|||
hasLvalRefQualifier(true);
|
||||
else if (tok->str() == "&&")
|
||||
hasRvalRefQualifier(true);
|
||||
else if (tok->str() == "override")
|
||||
setFlag(fHasOverrideSpecifier, true);
|
||||
else if (tok->str() == "final")
|
||||
setFlag(fHasFinalSpecifier, true);
|
||||
else if (tok->str() == "noexcept") {
|
||||
isNoExcept(!Token::simpleMatch(tok->next(), "( false )"));
|
||||
tok = tok->next();
|
||||
|
|
|
@ -665,13 +665,14 @@ class CPPCHECKLIB Function {
|
|||
fIsExplicit = (1 << 9), ///< @brief is explicit
|
||||
fIsDefault = (1 << 10), ///< @brief is default
|
||||
fIsDelete = (1 << 11), ///< @brief is delete
|
||||
fHasOverrideKeyword = (1 << 12), ///< @brief does declaration contain 'override' keyword?
|
||||
fIsNoExcept = (1 << 13), ///< @brief is noexcept
|
||||
fIsThrow = (1 << 14), ///< @brief is throw
|
||||
fIsOperator = (1 << 15), ///< @brief is operator
|
||||
fHasLvalRefQual = (1 << 16), ///< @brief has & lvalue ref-qualifier
|
||||
fHasRvalRefQual = (1 << 17), ///< @brief has && rvalue ref-qualifier
|
||||
fIsVariadic = (1 << 18) ///< @brief is variadic
|
||||
fHasOverrideSpecifier = (1 << 12), ///< @brief does declaration contain 'override' specifier?
|
||||
fHasFinalSpecifier = (1 << 13), ///< @brief does declaration contain 'final' specifier?
|
||||
fIsNoExcept = (1 << 14), ///< @brief is noexcept
|
||||
fIsThrow = (1 << 15), ///< @brief is throw
|
||||
fIsOperator = (1 << 16), ///< @brief is operator
|
||||
fHasLvalRefQual = (1 << 17), ///< @brief has & lvalue ref-qualifier
|
||||
fHasRvalRefQual = (1 << 18), ///< @brief has && rvalue ref-qualifier
|
||||
fIsVariadic = (1 << 19) ///< @brief is variadic
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -806,8 +807,11 @@ public:
|
|||
bool isThrow() const {
|
||||
return getFlag(fIsThrow);
|
||||
}
|
||||
bool hasOverrideKeyword() const {
|
||||
return getFlag(fHasOverrideKeyword);
|
||||
bool hasOverrideSpecifier() const {
|
||||
return getFlag(fHasOverrideSpecifier);
|
||||
}
|
||||
bool hasFinalSpecifier() const {
|
||||
return getFlag(fHasFinalSpecifier);
|
||||
}
|
||||
bool isOperator() const {
|
||||
return getFlag(fIsOperator);
|
||||
|
|
|
@ -103,7 +103,7 @@ const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &end
|
|||
}
|
||||
if (cpp && tok->str() == ")") {
|
||||
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()))
|
||||
tok = tok->next();
|
||||
if (tok && tok->str() == ")")
|
||||
|
@ -9030,26 +9030,9 @@ void Tokenizer::simplifyKeyword()
|
|||
tok->deleteNext();
|
||||
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)
|
||||
// 3) void f() noexcept; -> void f() noexcept(true);
|
||||
// 2) void f() noexcept; -> void f() noexcept(true);
|
||||
if (Token::Match(tok, ") noexcept :|{|;|const|override|final")) {
|
||||
// Insertion is done in inverse order
|
||||
// The brackets are linked together accordingly afterwards
|
||||
|
|
|
@ -6619,7 +6619,15 @@ private:
|
|||
void override1() {
|
||||
checkOverride("class Base { virtual void f(); };\n"
|
||||
"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());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -3268,7 +3268,6 @@ private:
|
|||
ASSERT_EQUALS("int foo ( ) { }", tok("__inline int foo ( ) { }", true));
|
||||
ASSERT_EQUALS("int foo ( ) { }", tok("__forceinline 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("int * p ;", tok("int * __restrict p;", "test.c"));
|
||||
ASSERT_EQUALS("int * * p ;", tok("int * __restrict__ * p;", "test.c"));
|
||||
|
|
|
@ -4059,18 +4059,6 @@ private:
|
|||
"}\n"
|
||||
"} ;";
|
||||
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 out4 [] = "struct B : A { void foo ( ) ; } ;";
|
||||
|
|
Loading…
Reference in New Issue