Fix uselessOverride FPs (#5223)
This commit is contained in:
parent
fa03f49d2b
commit
c738627d15
|
@ -2886,8 +2886,18 @@ void CheckClass::checkDuplInheritedMembers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase)
|
namespace {
|
||||||
|
struct DuplMemberInfo {
|
||||||
|
DuplMemberInfo(const Variable* cv, const Variable* pcv, const Type::BaseInfo* pc) : classVar(cv), parentClassVar(pcv), parentClass(pc) {}
|
||||||
|
const Variable* classVar;
|
||||||
|
const Variable* parentClassVar;
|
||||||
|
const Type::BaseInfo* parentClass;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<DuplMemberInfo> hasDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase)
|
||||||
{
|
{
|
||||||
|
std::vector<DuplMemberInfo> results;
|
||||||
for (const Type::BaseInfo &parentClassIt : typeBase->derivedFrom) {
|
for (const Type::BaseInfo &parentClassIt : typeBase->derivedFrom) {
|
||||||
// Check if there is info about the 'Base' class
|
// Check if there is info about the 'Base' class
|
||||||
if (!parentClassIt.type || !parentClassIt.type->classScope)
|
if (!parentClassIt.type || !parentClassIt.type->classScope)
|
||||||
|
@ -2898,16 +2908,26 @@ void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, con
|
||||||
// Check if they have a member variable in common
|
// Check if they have a member variable in common
|
||||||
for (const Variable &classVarIt : typeCurrent->classScope->varlist) {
|
for (const Variable &classVarIt : typeCurrent->classScope->varlist) {
|
||||||
for (const Variable &parentClassVarIt : parentClassIt.type->classScope->varlist) {
|
for (const Variable &parentClassVarIt : parentClassIt.type->classScope->varlist) {
|
||||||
if (classVarIt.name() == parentClassVarIt.name() && !parentClassVarIt.isPrivate()) { // Check if the class and its parent have a common variable
|
if (classVarIt.name() == parentClassVarIt.name() && !parentClassVarIt.isPrivate()) // Check if the class and its parent have a common variable
|
||||||
duplInheritedMembersError(classVarIt.nameToken(), parentClassVarIt.nameToken(),
|
results.emplace_back(&classVarIt, &parentClassVarIt, &parentClassIt);
|
||||||
typeCurrent->name(), parentClassIt.type->name(), classVarIt.name(),
|
}
|
||||||
|
}
|
||||||
|
if (typeCurrent != parentClassIt.type) {
|
||||||
|
const auto recursive = hasDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type);
|
||||||
|
results.insert(results.end(), recursive.begin(), recursive.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase)
|
||||||
|
{
|
||||||
|
const auto results = hasDuplInheritedMembersRecursive(typeCurrent, typeBase);
|
||||||
|
for (const auto& r : results) {
|
||||||
|
duplInheritedMembersError(r.classVar->nameToken(), r.parentClassVar->nameToken(),
|
||||||
|
typeCurrent->name(), r.parentClass->type->name(), r.classVar->name(),
|
||||||
typeCurrent->classScope->type == Scope::eStruct,
|
typeCurrent->classScope->type == Scope::eStruct,
|
||||||
parentClassIt.type->classScope->type == Scope::eStruct);
|
r.parentClass->type->classScope->type == Scope::eStruct);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeCurrent != parentClassIt.type)
|
|
||||||
checkDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3084,6 +3104,8 @@ static bool compareTokenRanges(const Token* start1, const Token* end1, const Tok
|
||||||
while (tok1 && tok2) {
|
while (tok1 && tok2) {
|
||||||
if (tok1->str() != tok2->str())
|
if (tok1->str() != tok2->str())
|
||||||
break;
|
break;
|
||||||
|
if (tok1->str() == "this")
|
||||||
|
break;
|
||||||
if (tok1 == end1 && tok2 == end2) {
|
if (tok1 == end1 && tok2 == end2) {
|
||||||
isEqual = true;
|
isEqual = true;
|
||||||
break;
|
break;
|
||||||
|
@ -3116,6 +3138,10 @@ void CheckClass::checkUselessOverride()
|
||||||
return f.name() == func.name();
|
return f.name() == func.name();
|
||||||
}))
|
}))
|
||||||
continue;
|
continue;
|
||||||
|
if (func.token->isExpandedMacro() || baseFunc->token->isExpandedMacro())
|
||||||
|
continue;
|
||||||
|
if (!classScope->definedType || !hasDuplInheritedMembersRecursive(classScope->definedType, classScope->definedType).empty()) // bailout for shadowed member variables
|
||||||
|
continue;
|
||||||
if (baseFunc->functionScope) {
|
if (baseFunc->functionScope) {
|
||||||
bool isSameCode = compareTokenRanges(baseFunc->argDef, baseFunc->argDef->link(), func.argDef, func.argDef->link()); // function arguments
|
bool isSameCode = compareTokenRanges(baseFunc->argDef, baseFunc->argDef->link(), func.argDef, func.argDef->link()); // function arguments
|
||||||
if (isSameCode) {
|
if (isSameCode) {
|
||||||
|
|
|
@ -8347,12 +8347,20 @@ private:
|
||||||
|
|
||||||
const Settings settings = settingsBuilder().severity(Severity::style).build();
|
const Settings settings = settingsBuilder().severity(Severity::style).build();
|
||||||
|
|
||||||
Preprocessor preprocessor(settings);
|
// Raw tokens..
|
||||||
|
std::vector<std::string> files(1, "test.cpp");
|
||||||
|
std::istringstream istr(code);
|
||||||
|
const simplecpp::TokenList tokens1(istr, files, files[0]);
|
||||||
|
|
||||||
|
// Preprocess..
|
||||||
|
simplecpp::TokenList tokens2(files);
|
||||||
|
std::map<std::string, simplecpp::TokenList*> filedata;
|
||||||
|
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI());
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this, &preprocessor);
|
Tokenizer tokenizer(&settings, this);
|
||||||
std::istringstream istr(code);
|
tokenizer.createTokens(std::move(tokens2));
|
||||||
ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line);
|
ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
|
||||||
|
|
||||||
// Check..
|
// Check..
|
||||||
CheckClass checkClass(&tokenizer, &settings, this);
|
CheckClass checkClass(&tokenizer, &settings, this);
|
||||||
|
@ -8465,6 +8473,36 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:9]: (style) The function 'g' overrides a function in a base class but is identical to the overridden function\n"
|
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:9]: (style) The function 'g' overrides a function in a base class but is identical to the overridden function\n"
|
||||||
"[test.cpp:5] -> [test.cpp:11]: (style) The function 'j' overrides a function in a base class but is identical to the overridden function\n",
|
"[test.cpp:5] -> [test.cpp:11]: (style) The function 'j' overrides a function in a base class but is identical to the overridden function\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
|
checkUselessOverride("struct B : std::exception {\n"
|
||||||
|
" virtual void f() { throw *this; }\n"
|
||||||
|
"};\n"
|
||||||
|
"struct D : B {\n"
|
||||||
|
" void f() override { throw *this; }\n"
|
||||||
|
"};\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkUselessOverride("#define MACRO virtual void f() {}\n"
|
||||||
|
"struct B {\n"
|
||||||
|
" MACRO\n"
|
||||||
|
"};\n"
|
||||||
|
"struct D : B {\n"
|
||||||
|
" MACRO\n"
|
||||||
|
"};\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkUselessOverride("struct B {\n"
|
||||||
|
" B() = default;\n"
|
||||||
|
" explicit B(int i) : m(i) {}\n"
|
||||||
|
" int m{};\n"
|
||||||
|
" virtual int f() const { return m; }\n"
|
||||||
|
"};\n"
|
||||||
|
"struct D : B {\n"
|
||||||
|
" explicit D(int i) : m(i) {}\n"
|
||||||
|
" int m{};\n"
|
||||||
|
" int f() const override { return m; }\n"
|
||||||
|
"};\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
#define checkUnsafeClassRefMember(code) checkUnsafeClassRefMember_(code, __FILE__, __LINE__)
|
#define checkUnsafeClassRefMember(code) checkUnsafeClassRefMember_(code, __FILE__, __LINE__)
|
||||||
|
|
Loading…
Reference in New Issue