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())
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
|
@ -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 ( ) ; } ;";
|
||||||
|
|
Loading…
Reference in New Issue