Skip to content

Commit

Permalink
stop pretending CheckUnusedFunctions is a real Check (#5884)
Browse files Browse the repository at this point in the history
  • Loading branch information
firewave authored Feb 12, 2024
1 parent 0afe8a1 commit 40552e2
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 122 deletions.
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

0 comments on commit 40552e2

Please sign in to comment.