Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stop pretending CheckUnusedFunctions is a real Check #5884

Merged
merged 9 commits into from
Feb 12, 2024
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ $(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/check.h lib/chec
$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checknullpointer.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkuninitvar.cpp

$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedfunctions.cpp

$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkunusedvar.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
Expand Down
64 changes: 31 additions & 33 deletions lib/checkunusedfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ void CheckUnusedFunctions::clear()
instance.mFunctionCalls.clear();
}

void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings)
void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings &settings)
{
const bool doMarkup = settings->library.markupFile(FileName);
const bool doMarkup = settings.library.markupFile(FileName);

// Function declarations..
if (!doMarkup) {
Expand Down Expand Up @@ -125,21 +125,21 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
lambdaEndToken = findLambdaEndToken(tok);

// parsing of library code to find called functions
if (settings->library.isexecutableblock(FileName, tok->str())) {
const Token * markupVarToken = tok->tokAt(settings->library.blockstartoffset(FileName));
if (settings.library.isexecutableblock(FileName, tok->str())) {
const Token * markupVarToken = tok->tokAt(settings.library.blockstartoffset(FileName));
// not found
if (!markupVarToken)
continue;
int scope = 0;
bool start = true;
// find all function calls in library code (starts with '(', not if or while etc)
while ((scope || start) && markupVarToken) {
if (markupVarToken->str() == settings->library.blockstart(FileName)) {
if (markupVarToken->str() == settings.library.blockstart(FileName)) {
scope++;
start = false;
} else if (markupVarToken->str() == settings->library.blockend(FileName))
} else if (markupVarToken->str() == settings.library.blockend(FileName))
scope--;
else if (!settings->library.iskeyword(FileName, markupVarToken->str())) {
else if (!settings.library.iskeyword(FileName, markupVarToken->str())) {
mFunctionCalls.insert(markupVarToken->str());
if (mFunctions.find(markupVarToken->str()) != mFunctions.end())
mFunctions[markupVarToken->str()].usedOtherFile = true;
Expand All @@ -157,18 +157,18 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
}

if (!doMarkup // only check source files
&& settings->library.isexporter(tok->str()) && tok->next() != nullptr) {
&& settings.library.isexporter(tok->str()) && tok->next() != nullptr) {
const Token * propToken = tok->next();
while (propToken && propToken->str() != ")") {
if (settings->library.isexportedprefix(tok->str(), propToken->str())) {
if (settings.library.isexportedprefix(tok->str(), propToken->str())) {
const Token* nextPropToken = propToken->next();
const std::string& value = nextPropToken->str();
if (mFunctions.find(value) != mFunctions.end()) {
mFunctions[value].usedOtherFile = true;
}
mFunctionCalls.insert(value);
}
if (settings->library.isexportedsuffix(tok->str(), propToken->str())) {
if (settings.library.isexportedsuffix(tok->str(), propToken->str())) {
const Token* prevPropToken = propToken->previous();
const std::string& value = prevPropToken->str();
if (value != ")" && mFunctions.find(value) != mFunctions.end()) {
Expand All @@ -180,7 +180,7 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
}
}

if (doMarkup && settings->library.isimporter(FileName, tok->str()) && tok->next()) {
if (doMarkup && settings.library.isimporter(FileName, tok->str()) && tok->next()) {
const Token * propToken = tok->next();
if (propToken->next()) {
propToken = propToken->next();
Expand All @@ -196,8 +196,8 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
}
}

if (settings->library.isreflection(tok->str())) {
const int argIndex = settings->library.reflectionArgument(tok->str());
if (settings.library.isreflection(tok->str())) {
const int argIndex = settings.library.reflectionArgument(tok->str());
if (argIndex >= 0) {
const Token * funcToken = tok->next();
int index = 0;
Expand Down Expand Up @@ -319,7 +319,7 @@ static bool isOperatorFunction(const std::string & funcName)
return std::find(additionalOperators.cbegin(), additionalOperators.cend(), funcName.substr(operatorPrefix.length())) != additionalOperators.cend();
}

bool CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings& settings) const
bool CheckUnusedFunctions::check(ErrorLogger& errorLogger, const Settings& settings) const
{
using ErrorParams = std::tuple<std::string, unsigned int, unsigned int, std::string>;
std::vector<ErrorParams> errors; // ensure well-defined order
Expand Down Expand Up @@ -353,7 +353,7 @@ bool CheckUnusedFunctions::check(ErrorLogger * const errorLogger, const Settings
return !errors.empty();
}

void CheckUnusedFunctions::unusedFunctionError(ErrorLogger * const errorLogger,
void CheckUnusedFunctions::unusedFunctionError(ErrorLogger& errorLogger,
const std::string &filename, unsigned int fileIndex, unsigned int lineNumber,
const std::string &funcname)
{
Expand All @@ -364,29 +364,27 @@ void CheckUnusedFunctions::unusedFunctionError(ErrorLogger * const errorLogger,
}

const ErrorMessage errmsg(std::move(locationList), emptyString, Severity::style, "$symbol:" + funcname + "\nThe function '$symbol' is never used.", "unusedFunction", CWE561, Certainty::normal);
if (errorLogger)
errorLogger->reportErr(errmsg);
else
Check::writeToErrorList(errmsg);
errorLogger.reportErr(errmsg);
}

Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const
void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Settings &settings)
{
if (!settings->checks.isEnabled(Checks::unusedFunction))
return nullptr;
if (settings->useSingleJob() && settings->buildDir.empty())
instance.parseTokens(*tokenizer, tokenizer->list.getFiles().front().c_str(), settings);
return nullptr;
if (!settings.checks.isEnabled(Checks::unusedFunction))
return;
if (settings.useSingleJob() && settings.buildDir.empty())
instance.parseTokens(tokenizer, tokenizer.list.getFiles().front().c_str(), settings);
}

bool CheckUnusedFunctions::analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger)
#define logChecker(id) \
do { \
const ErrorMessage errmsg({}, nullptr, Severity::internal, "logChecker", (id), CWE(0U), Certainty::normal); \
errorLogger.reportErr(errmsg); \
} while (false)

bool CheckUnusedFunctions::check(const Settings& settings, ErrorLogger &errorLogger)
{
(void)ctu;
(void)fileInfo;
CheckUnusedFunctions dummy(nullptr, &settings, &errorLogger);
dummy.
logChecker("CheckUnusedFunctions::analyseWholeProgram"); // unusedFunctions
return check(&errorLogger, settings);
logChecker("CheckUnusedFunctions::check"); // unusedFunction
return instance.check(errorLogger, settings);
}

CheckUnusedFunctions::FunctionDecl::FunctionDecl(const Function *f)
Expand Down Expand Up @@ -416,7 +414,7 @@ namespace {
};
}

void CheckUnusedFunctions::analyseWholeProgram(const Settings &settings, ErrorLogger * const errorLogger, const std::string &buildDir)
void CheckUnusedFunctions::analyseWholeProgram(const Settings &settings, ErrorLogger &errorLogger, const std::string &buildDir)
{
std::map<std::string, Location> decls;
std::set<std::string> calls;
Expand Down
54 changes: 14 additions & 40 deletions lib/checkunusedfunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#define checkunusedfunctionsH
//---------------------------------------------------------------------------

#include "check.h"
#include "config.h"

#include <list>
Expand All @@ -35,71 +34,46 @@ class Function;
class Settings;
class Tokenizer;

namespace CTU {
class FileInfo;
}

/// @addtogroup Checks
/** @brief Check for functions never called */
/// @{

class CPPCHECKLIB CheckUnusedFunctions : public Check {
class CPPCHECKLIB CheckUnusedFunctions {
friend class TestSuppressions;
friend class TestSingleExecutorBase;
friend class TestProcessExecutorBase;
friend class TestThreadExecutorBase;
friend class TestUnusedFunctions;

public:
/** @brief This constructor is used when registering the CheckUnusedFunctions */
CheckUnusedFunctions() : Check(myName()) {}

/** @brief This constructor is used when running checks. */
CheckUnusedFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(myName(), tokenizer, settings, errorLogger) {}
CheckUnusedFunctions() = default;

// Parse current tokens and determine..
// * Check what functions are used
// * What functions are declared
void parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings);
void parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings &settings);

// Return true if an error is reported.
bool check(ErrorLogger * const errorLogger, const Settings& settings) const;
static void parseTokens(const Tokenizer &tokenizer, const Settings &settings);

/** @brief Parse current TU and extract file info */
Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const override;
std::string analyzerInfo() const;

/** @brief Analyse all file infos for all TU */
bool analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override;
static void analyseWholeProgram(const Settings &settings, ErrorLogger& errorLogger, const std::string &buildDir);

std::string analyzerInfo() const;
static void getErrorMessages(ErrorLogger &errorLogger) {
unusedFunctionError(errorLogger, emptyString, 0, 0, "funcName");
}

/** @brief Combine and analyze all analyzerInfos for all TUs */
static void analyseWholeProgram(const Settings &settings, ErrorLogger * const errorLogger, const std::string &buildDir);
static bool check(const Settings& settings, ErrorLogger &errorLogger);

private:
static void clear();

void getErrorMessages(ErrorLogger *errorLogger, const Settings * /*settings*/) const override {
CheckUnusedFunctions::unusedFunctionError(errorLogger, emptyString, 0, 0, "funcName");
}

void runChecks(const Tokenizer & /*tokenizer*/, ErrorLogger * /*errorLogger*/) override {}
// Return true if an error is reported.
bool check(ErrorLogger& errorLogger, const Settings& settings) const;

/**
* Dummy implementation, just to provide error for --errorlist
*/
static void unusedFunctionError(ErrorLogger * const errorLogger,
static void unusedFunctionError(ErrorLogger& errorLogger,
const std::string &filename, unsigned int fileIndex, unsigned int lineNumber,
const std::string &funcname);

static std::string myName() {
return "Unused functions";
}

std::string classInfo() const override {
return "Check for functions that are never called\n";
}

struct CPPCHECKLIB FunctionUsage {
std::string filename;
unsigned int lineNumber{};
Expand Down
Loading
Loading