Skip to content

Commit 2030801

Browse files
Taking care of operation overloading functions
1 parent eed9dfb commit 2030801

File tree

2 files changed

+120
-4
lines changed

2 files changed

+120
-4
lines changed

lib/checkunusedfunctions.cpp

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "tokenlist.h"
3030

3131
#include <tinyxml2.h>
32+
#include <algorithm>
3233
#include <cstdlib>
3334
#include <cstring>
3435
#include <istream>
@@ -231,6 +232,54 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
231232
}
232233

233234

235+
static bool isOperatorFunction(const std::string & funcName) {
236+
/* Operator functions are invalid function names for C, so no need to check
237+
* this in here. As result the returned error function might be incorrect.
238+
*
239+
* List of valid operators can be found at:
240+
* http://en.cppreference.com/w/cpp/language/operators
241+
*
242+
* Conversion functions must be a member function (at least for gcc), so no
243+
* need to cover them for unused functions.
244+
*
245+
* To speed up the comparision, not the whole list of operators is used.
246+
* Instead only the character after the operator prefix is checked to be a
247+
* none alpa numeric value, but the '_', to cover function names like
248+
* "operator_unused". In addition the following valid operators are checked:
249+
* - new
250+
* - new[]
251+
* - delete
252+
* - delete[]
253+
*/
254+
const std::string operatorPrefix = "operator";
255+
if (funcName.compare(0, operatorPrefix.length(), operatorPrefix) != 0) {
256+
return false;
257+
}
258+
259+
// Taking care of funcName == "operator", which is no valid operator
260+
if (funcName.length() == operatorPrefix.length()) {
261+
return false;
262+
}
263+
264+
const char firstOperatorChar = funcName[operatorPrefix.length()];
265+
if (firstOperatorChar == '_') {
266+
return false;
267+
}
268+
269+
if (!std::isalnum(firstOperatorChar)) {
270+
return true;
271+
}
272+
273+
const std::vector<std::string> additionalOperators = make_container< std::vector<std::string> >()
274+
<< "new"
275+
<< "new[]"
276+
<< "delete"
277+
<< "delete[]";
278+
279+
280+
return std::find(additionalOperators.begin(), additionalOperators.end(), funcName.substr(operatorPrefix.length())) != additionalOperators.end();;
281+
}
282+
234283

235284

236285
bool CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings& settings)
@@ -245,11 +294,13 @@ bool CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings
245294
it->first == "if")
246295
continue;
247296
if (!func.usedSameFile) {
297+
if (isOperatorFunction(it->first))
298+
continue;
248299
std::string filename;
249300
if (func.filename != "+")
250-
filename = func.filename;
251-
unusedFunctionError(errorLogger, filename, func.lineNumber, it->first);
252-
errors = true;
301+
filename = func.filename;
302+
unusedFunctionError(errorLogger, filename, func.lineNumber, it->first);
303+
errors = true;
253304
} else if (! func.usedOtherFile) {
254305
/** @todo add error message "function is only used in <file> it can be static" */
255306
/*
@@ -381,7 +432,7 @@ void CheckUnusedFunctions::analyseWholeProgram(ErrorLogger * const errorLogger,
381432
functionName == "if")
382433
continue;
383434

384-
if (calls.find(functionName) == calls.end()) {
435+
if (calls.find(functionName) == calls.end() && !isOperatorFunction(functionName)) {
385436
const Location &loc = decl->second;
386437
unusedFunctionError(errorLogger, loc.fileName, loc.lineNumber, functionName);
387438
}

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) {
@@ -390,6 +392,69 @@ class TestUnusedFunctions : public TestFixture {
390392
"void (*list[])(void) = {f}");
391393
ASSERT_EQUALS("", errout.str());
392394
}
395+
396+
void operatorOverload() {
397+
check("class A {\n"
398+
"private:\n"
399+
" friend std::ostream & operator<<(std::ostream &, const A&);\n"
400+
"};\n"
401+
"std::ostream & operator<<(std::ostream &os, const A&) {\n"
402+
" os << \"This is class A\";\n"
403+
"}");
404+
ASSERT_EQUALS("", errout.str());
405+
406+
check("class 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 &, const A &){ return A(); }\n"
411+
"A operator % (const A &, const A &){ return A(); }\n"
412+
"A operator & (const A &, const A &){ return A(); }\n"
413+
"A operator | (const A &, const A &){ return A(); }\n"
414+
"A operator ~ (const A &){ return A(); }\n"
415+
"A operator ! (const A &){ return A(); }\n"
416+
"bool operator < (const A &, const A &){ return true; }\n"
417+
"bool operator > (const A &, const A &){ return true; }\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 A &){ return A(); }\n"
423+
"A operator &= (const A &, const A &){ return A(); }\n"
424+
"A operator ^= (const A &, const A &){ return A(); }\n"
425+
"A operator |= (const A &, const A &){ return A(); }\n"
426+
"A operator << (const A &, const int){ return A(); }\n"
427+
"A operator >> (const A &, const int){ return A(); }\n"
428+
"A operator <<= (const A &, const int){ return A(); }\n"
429+
"A operator >>= (const A &, const int){ return A(); }\n"
430+
"bool operator == (const A &, const A &){ return true; }\n"
431+
"bool operator != (const A &, const A &){ return true; }\n"
432+
"bool operator <= (const A &, const A &){ return true; }\n"
433+
"bool operator >= (const A &, const A &){ return true; }\n"
434+
"A operator && (const A &, const int){ return A(); }\n"
435+
"A operator || (const A &, const int){ return A(); }\n"
436+
"A operator ++ (const A &, const int){ return A(); }\n"
437+
"A operator ++ (const A &){ return A(); }\n"
438+
"A operator -- (const A &, const int){ return A(); }\n"
439+
"A operator -- (const A &){ return A(); }\n"
440+
"A operator , (const A &, const A &){ return A(); }\n");
441+
ASSERT_EQUALS("", errout.str());
442+
443+
444+
check("class A {\n"
445+
"public:\n"
446+
" static void * operator new(std::size_t);\n"
447+
" static void * operator new[](std::size_t);\n"
448+
"};\n"
449+
"void * A::operator new(std::size_t s) {\n"
450+
" return malloc(s);\n"
451+
"}\n"
452+
"void * A::operator new[](std::size_t s) {\n"
453+
" return malloc(s);\n"
454+
"}");
455+
ASSERT_EQUALS("", errout.str());
456+
}
457+
393458
};
394459

395460
REGISTER_TEST(TestUnusedFunctions)

0 commit comments

Comments
 (0)