Skip to content

Commit 0c6fdf0

Browse files
Taking care of operation overloading functions
1 parent 7e92535 commit 0c6fdf0

2 files changed

Lines changed: 118 additions & 6 deletions

File tree

lib/checkunusedfunctions.cpp

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,49 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
235235
}
236236

237237

238+
static bool isOperatorFunction(const std::string & funcName) {
239+
/* Operator functions are invalid function names for C, so no need to check
240+
* this in here. As result the returned error function might be incorrect.
241+
*
242+
* List of valid operators can be found at:
243+
* http://en.cppreference.com/w/cpp/language/operators
244+
*
245+
* Conversion functions must be a member function (at least for gcc), so no
246+
* need to cover them for unused functions
247+
*
248+
* Literal functions are treated at a different place, so no check is done
249+
* in here
250+
*/
251+
const std::string operatorPrefix = "operator";
252+
if (funcName.compare(0, operatorPrefix.length(), operatorPrefix) != 0) {
253+
return false;
254+
}
255+
256+
std::string opName = funcName.substr(operatorPrefix.length());
257+
258+
/* Operation overload + allocation/deallocation
259+
*
260+
* Don't treat the following, as they have to be a member function:
261+
* '=', '()', '[]', '->', '->*'
262+
*/
263+
const std::vector<std::string> knownOperators = {
264+
"+", "-", "*", "/", "%", "&", "|", "~", "!", "<", ">", "+=", "-=",
265+
"*=", "/=", "%=", "^=", "&=", "|=", "<<", ">>", ">>=", "<<=", "==",
266+
"!=", "<=", ">=", "&&", "||", "++", "--", ",",
267+
// Allocation variants; space is delete within the simplification
268+
"new", "new[]",
269+
// Deallocation variants; space is delete within the simplification
270+
"delete", "delete[]"
271+
};
272+
for (auto const & curOp : knownOperators) {
273+
if (curOp == opName) {
274+
return true;
275+
}
276+
}
277+
278+
return false;
279+
}
280+
238281

239282

240283
void CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings& settings)
@@ -248,10 +291,12 @@ void CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings
248291
it->first == "if")
249292
continue;
250293
if (!func.usedSameFile) {
251-
std::string filename;
252-
if (func.filename != "+")
253-
filename = func.filename;
254-
unusedFunctionError(errorLogger, filename, func.lineNumber, it->first);
294+
if (!isOperatorFunction(it->first)) {
295+
std::string filename;
296+
if (func.filename != "+")
297+
filename = func.filename;
298+
unusedFunctionError(errorLogger, filename, func.lineNumber, it->first);
299+
}
255300
} else if (! func.usedOtherFile) {
256301
/** @todo add error message "function is only used in <file> it can be static" */
257302
/*
@@ -382,8 +427,10 @@ void CheckUnusedFunctions::analyseWholeProgram(ErrorLogger * const errorLogger,
382427
continue;
383428

384429
if (calls.find(functionName) == calls.end()) {
385-
const Location &loc = decl->second;
386-
unusedFunctionError(errorLogger, loc.fileName, loc.lineNumber, functionName);
430+
if (!isOperatorFunction(functionName)) {
431+
const Location &loc = decl->second;
432+
unusedFunctionError(errorLogger, loc.fileName, loc.lineNumber, functionName);
433+
}
387434
}
388435
}
389436
}

test/testunusedfunctions.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class TestUnusedFunctions : public TestFixture {
6161
TEST_CASE(lineNumber); // Ticket 3059
6262

6363
TEST_CASE(ignore_declaration); // ignore declaration
64+
65+
TEST_CASE(operatorOverload);
6466
}
6567

6668
void check(const char code[], Settings::PlatformType platform = Settings::Native) {
@@ -386,6 +388,69 @@ class TestUnusedFunctions : public TestFixture {
386388
"void (*list[])(void) = {f}");
387389
ASSERT_EQUALS("", errout.str());
388390
}
391+
392+
void operatorOverload() {
393+
check("class A {\n"
394+
"private:\n"
395+
" friend std::ostream & operator<<(std::ostream &, const A&);\n"
396+
"};\n"
397+
"std::ostream & operator<<(std::ostream &os, const A&) {\n"
398+
" os << \"This is class A\";\n"
399+
"}");
400+
ASSERT_EQUALS("", errout.str());
401+
402+
check("class A{};\n"
403+
"A operator + (const A &, const A &){ return A(); }\n"
404+
"A operator - (const A &, const A &){ return A(); }\n"
405+
"A operator * (const A &, const A &){ return A(); }\n"
406+
"A operator / (const A &, const A &){ return A(); }\n"
407+
"A operator % (const A &, const A &){ return A(); }\n"
408+
"A operator & (const A &, const A &){ return A(); }\n"
409+
"A operator | (const A &, const A &){ return A(); }\n"
410+
"A operator ~ (const A &){ return A(); }\n"
411+
"A operator ! (const A &){ return A(); }\n"
412+
"bool operator < (const A &, const A &){ return true; }\n"
413+
"bool operator > (const A &, const A &){ return true; }\n"
414+
"A operator += (const A &, const A &){ return A(); }\n"
415+
"A operator -= (const A &, const A &){ return A(); }\n"
416+
"A operator *= (const A &, const A &){ return A(); }\n"
417+
"A operator /= (const A &, const A &){ return A(); }\n"
418+
"A operator %= (const A &, const A &){ return A(); }\n"
419+
"A operator &= (const A &, const A &){ return A(); }\n"
420+
"A operator ^= (const A &, const A &){ return A(); }\n"
421+
"A operator |= (const A &, const A &){ return A(); }\n"
422+
"A operator << (const A &, const int){ return A(); }\n"
423+
"A operator >> (const A &, const int){ return A(); }\n"
424+
"A operator <<= (const A &, const int){ return A(); }\n"
425+
"A operator >>= (const A &, const int){ return A(); }\n"
426+
"bool operator == (const A &, const A &){ return true; }\n"
427+
"bool operator != (const A &, const A &){ return true; }\n"
428+
"bool operator <= (const A &, const A &){ return true; }\n"
429+
"bool operator >= (const A &, const A &){ return true; }\n"
430+
"A operator && (const A &, const int){ return A(); }\n"
431+
"A operator || (const A &, const int){ return A(); }\n"
432+
"A operator ++ (const A &, const int){ return A(); }\n"
433+
"A operator ++ (const A &){ return A(); }\n"
434+
"A operator -- (const A &, const int){ return A(); }\n"
435+
"A operator -- (const A &){ return A(); }\n"
436+
"A operator , (const A &, const A &){ return A(); }\n");
437+
ASSERT_EQUALS("", errout.str());
438+
439+
440+
check("class A {\n"
441+
"public:\n"
442+
" static void * operator new(std::size_t);\n"
443+
" static void * operator new[](std::size_t);\n"
444+
"};\n"
445+
"void * A::operator new(std::size_t s) {\n"
446+
" return malloc(s);\n"
447+
"}\n"
448+
"void * A::operator new[](std::size_t s) {\n"
449+
" return malloc(s);\n"
450+
"}");
451+
ASSERT_EQUALS("", errout.str());
452+
}
453+
389454
};
390455

391456
REGISTER_TEST(TestUnusedFunctions)

0 commit comments

Comments
 (0)