Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 53 additions & 6 deletions lib/checkunusedfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,49 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
}


static bool isOperatorFunction(const std::string & funcName) {
/* Operator functions are invalid function names for C, so no need to check
* this in here. As result the returned error function might be incorrect.
*
* List of valid operators can be found at:
* http://en.cppreference.com/w/cpp/language/operators
*
* Conversion functions must be a member function (at least for gcc), so no
* need to cover them for unused functions
*
* Literal functions are treated at a different place, so no check is done
* in here
*/
const std::string operatorPrefix = "operator";
if (funcName.compare(0, operatorPrefix.length(), operatorPrefix) != 0) {
return false;
}

std::string opName = funcName.substr(operatorPrefix.length());

/* Operation overload + allocation/deallocation
*
* Don't treat the following, as they have to be a member function:
* '=', '()', '[]', '->', '->*'
*/
const std::vector<std::string> knownOperators = {
"+", "-", "*", "/", "%", "&", "|", "~", "!", "<", ">", "+=", "-=",
"*=", "/=", "%=", "^=", "&=", "|=", "<<", ">>", ">>=", "<<=", "==",
"!=", "<=", ">=", "&&", "||", "++", "--", ",",
// Allocation variants; space is delete within the simplification
"new", "new[]",
// Deallocation variants; space is delete within the simplification
"delete", "delete[]"
};
for (auto const & curOp : knownOperators) {
Copy link
Copy Markdown
Owner

@danmar danmar Oct 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't use a ranged for loop. That is C++11. It seems clumpsy to check for every known operator. If opName is any operator (!std::isalnum(opName[0] && opName[0] != '_')) then I think this function could return true.

if (curOp == opName) {
return true;
}
}

return false;
}



void CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings& settings)
Expand All @@ -248,10 +291,12 @@ void CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings
it->first == "if")
continue;
if (!func.usedSameFile) {
std::string filename;
if (func.filename != "+")
filename = func.filename;
unusedFunctionError(errorLogger, filename, func.lineNumber, it->first);
if (!isOperatorFunction(it->first)) {
std::string filename;
if (func.filename != "+")
filename = func.filename;
unusedFunctionError(errorLogger, filename, func.lineNumber, it->first);
}
} else if (! func.usedOtherFile) {
/** @todo add error message "function is only used in <file> it can be static" */
/*
Expand Down Expand Up @@ -382,8 +427,10 @@ void CheckUnusedFunctions::analyseWholeProgram(ErrorLogger * const errorLogger,
continue;

if (calls.find(functionName) == calls.end()) {
const Location &loc = decl->second;
unusedFunctionError(errorLogger, loc.fileName, loc.lineNumber, functionName);
if (!isOperatorFunction(functionName)) {
const Location &loc = decl->second;
unusedFunctionError(errorLogger, loc.fileName, loc.lineNumber, functionName);
}
}
}
}
65 changes: 65 additions & 0 deletions test/testunusedfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class TestUnusedFunctions : public TestFixture {
TEST_CASE(lineNumber); // Ticket 3059

TEST_CASE(ignore_declaration); // ignore declaration

TEST_CASE(operatorOverload);
}

void check(const char code[], Settings::PlatformType platform = Settings::Native) {
Expand Down Expand Up @@ -386,6 +388,69 @@ class TestUnusedFunctions : public TestFixture {
"void (*list[])(void) = {f}");
ASSERT_EQUALS("", errout.str());
}

void operatorOverload() {
check("class A {\n"
"private:\n"
" friend std::ostream & operator<<(std::ostream &, const A&);\n"
"};\n"
"std::ostream & operator<<(std::ostream &os, const A&) {\n"
" os << \"This is class A\";\n"
"}");
ASSERT_EQUALS("", errout.str());

check("class A{};\n"
"A operator + (const A &, const A &){ return A(); }\n"
"A operator - (const A &, const A &){ return A(); }\n"
"A operator * (const A &, const A &){ return A(); }\n"
"A operator / (const A &, const A &){ return A(); }\n"
"A operator % (const A &, const A &){ return A(); }\n"
"A operator & (const A &, const A &){ return A(); }\n"
"A operator | (const A &, const A &){ return A(); }\n"
"A operator ~ (const A &){ return A(); }\n"
"A operator ! (const A &){ return A(); }\n"
"bool operator < (const A &, const A &){ return true; }\n"
"bool operator > (const A &, const A &){ return true; }\n"
"A operator += (const A &, const A &){ return A(); }\n"
"A operator -= (const A &, const A &){ return A(); }\n"
"A operator *= (const A &, const A &){ return A(); }\n"
"A operator /= (const A &, const A &){ return A(); }\n"
"A operator %= (const A &, const A &){ return A(); }\n"
"A operator &= (const A &, const A &){ return A(); }\n"
"A operator ^= (const A &, const A &){ return A(); }\n"
"A operator |= (const A &, const A &){ return A(); }\n"
"A operator << (const A &, const int){ return A(); }\n"
"A operator >> (const A &, const int){ return A(); }\n"
"A operator <<= (const A &, const int){ return A(); }\n"
"A operator >>= (const A &, const int){ return A(); }\n"
"bool operator == (const A &, const A &){ return true; }\n"
"bool operator != (const A &, const A &){ return true; }\n"
"bool operator <= (const A &, const A &){ return true; }\n"
"bool operator >= (const A &, const A &){ return true; }\n"
"A operator && (const A &, const int){ return A(); }\n"
"A operator || (const A &, const int){ return A(); }\n"
"A operator ++ (const A &, const int){ return A(); }\n"
"A operator ++ (const A &){ return A(); }\n"
"A operator -- (const A &, const int){ return A(); }\n"
"A operator -- (const A &){ return A(); }\n"
"A operator , (const A &, const A &){ return A(); }\n");
ASSERT_EQUALS("", errout.str());


check("class A {\n"
"public:\n"
" static void * operator new(std::size_t);\n"
" static void * operator new[](std::size_t);\n"
"};\n"
"void * A::operator new(std::size_t s) {\n"
" return malloc(s);\n"
"}\n"
"void * A::operator new[](std::size_t s) {\n"
" return malloc(s);\n"
"}");
ASSERT_EQUALS("", errout.str());
}

};

REGISTER_TEST(TestUnusedFunctions)