/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2026 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "checkunusedfunctions.h"
#include "errortypes.h"
#include "fixture.h"
#include "helpers.h"
#include "platform.h"
#include "settings.h"
#include
#include
class TestUnusedFunctions : public TestFixture {
public:
TestUnusedFunctions() : TestFixture("TestUnusedFunctions") {}
private:
const Settings settings = settingsBuilder().severity(Severity::style).build();
void run() override {
mNewTemplate = true;
TEST_CASE(incondition);
TEST_CASE(return1);
TEST_CASE(return2);
TEST_CASE(return3);
TEST_CASE(callback1);
TEST_CASE(callback2);
TEST_CASE(else1);
TEST_CASE(functionpointer);
TEST_CASE(template1);
TEST_CASE(template2);
TEST_CASE(template3);
TEST_CASE(template4); // #9805
TEST_CASE(template5);
TEST_CASE(template6); // #10475 crash
TEST_CASE(template7); // #9766 crash
TEST_CASE(template8);
TEST_CASE(template9);
TEST_CASE(template10);
TEST_CASE(throwIsNotAFunction);
TEST_CASE(unusedError);
TEST_CASE(unusedMain);
TEST_CASE(initializationIsNotAFunction);
TEST_CASE(operator1); // #3195
TEST_CASE(operator2); // #7974
TEST_CASE(returnRef);
TEST_CASE(attribute); // #3471 - FP __attribute__(constructor)
TEST_CASE(initializer_list);
TEST_CASE(member_function_ternary);
TEST_CASE(boost);
TEST_CASE(enumValues);
TEST_CASE(recursive);
TEST_CASE(multipleFiles); // same function name in multiple files
TEST_CASE(lineNumber); // Ticket 3059
TEST_CASE(ignore_declaration); // ignore declaration
TEST_CASE(operatorOverload);
TEST_CASE(entrypointsWin);
TEST_CASE(entrypointsWinU);
TEST_CASE(entrypointsUnix);
TEST_CASE(virtualFunc);
TEST_CASE(parensInit);
TEST_CASE(typeInCast);
TEST_CASE(attributeCleanup);
TEST_CASE(attributeUnused);
TEST_CASE(attributeMaybeUnused);
TEST_CASE(staticFunction);
TEST_CASE(unnamedArg);
}
struct CheckOptions
{
Platform::Type platform = Platform::Type::Native;
bool cpp = true;
};
#define check(...) check_(__FILE__, __LINE__, __VA_ARGS__)
template
void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) {
// TODO: avoid copy
const Settings settings1 = (options.platform == Platform::Type::Native) ? settings : settingsBuilder(settings).platform(options.platform).build();
check_(file, line, code, settings1, options.cpp);
}
template
void check_(const char* file, int line, const char (&code)[size], const Settings& settings1, bool cpp = true) {
SimpleTokenizer tokenizer(settings1, *this, cpp);
ASSERT_LOC(tokenizer.tokenize(code), file, line);
// Check for unused functions..
CheckUnusedFunctions checkUnusedFunctions;
checkUnusedFunctions.parseTokens(tokenizer, settings1.library);
(checkUnusedFunctions.check)(settings1.library, *this); // TODO: check result
}
// TODO: get rid of this
void check_(const char* file, int line, const std::string& code ) {
// Tokenize..
SimpleTokenizer tokenizer(settings, *this);
ASSERT_LOC(tokenizer.tokenize(code), file, line);
// Check for unused functions..
CheckUnusedFunctions checkUnusedFunctions;
checkUnusedFunctions.parseTokens(tokenizer, settings.library);
(checkUnusedFunctions.check)(settings.library, *this); // TODO: check result
}
void incondition() {
check("int f1()\n"
"{\n"
" if (f1())\n"
" { }\n"
"}");
ASSERT_EQUALS("[test.cpp:1:5]: (style) The function 'f1' is never used. [unusedFunction]\n", errout_str());
}
void return1() {
check("int f1()\n"
"{\n"
" return f1();\n"
"}");
ASSERT_EQUALS("[test.cpp:1:5]: (style) The function 'f1' is never used. [unusedFunction]\n", errout_str());
}
void return2() {
check("char * foo()\n"
"{\n"
" return foo();\n"
"}");
ASSERT_EQUALS("[test.cpp:1:8]: (style) The function 'foo' is never used. [unusedFunction]\n", errout_str());
}
void return3() {
check("typedef void (*VoidFunc)();\n" // #9602
"void sayHello() {\n"
" printf(\"Hello World\\n\");\n"
"}\n"
"VoidFunc getEventHandler() {\n"
" return sayHello;\n"
"}\n"
"void indirectHello() {\n"
" VoidFunc handler = getEventHandler();\n"
" handler();\n"
"}\n"
"int main() {\n"
" indirectHello();\n"
"}");
ASSERT_EQUALS("", errout_str());
}
void callback1() {
check("void f1()\n"
"{\n"
" void (*f)() = cond ? f1 : NULL;\n"
"}");
ASSERT_EQUALS("[test.cpp:1:6]: (style) The function 'f1' is never used. [unusedFunction]\n", errout_str());
}
void callback2() { // #8677
check("class C {\n"
"public:\n"
" void callback();\n"
" void start();\n"
"};\n"
"\n"
"void C::callback() {}\n" //