Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,12 +428,15 @@ static std::string readcondition(const simplecpp::Token *iftok, const std::set<s
}

std::set<std::string> configset;
bool isNotDefinedMacro = false;
for (; sameline(iftok,cond); cond = cond->next) {
if (cond->op == '!') {
if (!sameline(iftok,cond->next) || !cond->next->name)
break;
if (cond->next->str() == "defined")
if (cond->next->str() == "defined") {
isNotDefinedMacro = true;
continue;
}
configset.insert(cond->next->str() + "=0");
continue;
}
Expand All @@ -444,8 +447,15 @@ static std::string readcondition(const simplecpp::Token *iftok, const std::set<s
break;
if (dtok->op == '(')
dtok = dtok->next;
if (sameline(iftok,dtok) && dtok->name && defined.find(dtok->str()) == defined.end() && undefined.find(dtok->str()) == undefined.end())
configset.insert(dtok->str());

if (sameline(iftok,dtok) && dtok->name && defined.find(dtok->str()) == defined.end() && undefined.find(dtok->str()) == undefined.end()) {
if (!isNotDefinedMacro) {
configset.insert(dtok->str() + "=" + dtok->str()); // if defined is set to itself.
} else {
configset.insert(dtok->str());
}
}
isNotDefinedMacro = false;
}
std::string cfgStr;
for (const std::string &s : configset) {
Expand All @@ -464,10 +474,11 @@ static bool hasDefine(const std::string &userDefines, const std::string &cfg)

std::string::size_type pos = 0;
while (pos < userDefines.size()) {
pos = userDefines.find(cfg, pos);
const std::string::size_type eq = cfg.find('=');
pos = (eq == std::string::npos) ? userDefines.find(cfg, pos) : userDefines.find(cfg.substr(0, eq), pos);
if (pos == std::string::npos)
break;
const std::string::size_type pos2 = pos + cfg.size();
const std::string::size_type pos2 = (eq == std::string::npos) ? pos + cfg.size() : pos + eq;
if ((pos == 0 || userDefines[pos-1U] == ';') && (pos2 == userDefines.size() || userDefines[pos2] == '='))
return true;
pos = pos2;
Expand Down Expand Up @@ -553,8 +564,11 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set<std::string>
const simplecpp::Token *expr1 = cmdtok->next;
if (sameline(tok,expr1) && expr1->name && !sameline(tok,expr1->next))
config = expr1->str();
if (defined.find(config) != defined.end())
if (defined.find(config) != defined.end()) {
config.clear();
} else if ((cmdtok->str() == "ifdef") && sameline(cmdtok,expr1) && !config.empty()) {
config.append("=" + expr1->str()); //Set equal to itself if ifdef.
}
} else if (cmdtok->str() == "if") {
config = readcondition(cmdtok, defined, undefined);
}
Expand Down Expand Up @@ -594,6 +608,24 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set<std::string>
}
}

// check if config already exists in the ret set, but as a more general or more specific version
if (cmdtok->str() != "ifndef")
{
const std::string::size_type eq = config.find('=');
const std::string config2 = (eq != std::string::npos) ? config.substr(0, eq) : config + "=" + config;
const std::set<std::string>::iterator it2 = ret.find(config2);
if (it2 != ret.end()) {
if (eq != std::string::npos) {
// The instance in ret is more general than the one in config (have =value), keep the one in ret
config.erase();
continue;
} else {
// The instance in ret is more specific than the one in config (no =value), replace it with the one in config
ret.erase(it2);
}
}
}

configs_if.push_back((cmdtok->str() == "ifndef") ? std::string() : config);
configs_ifndef.push_back((cmdtok->str() == "ifndef") ? std::move(config) : std::string());
ret.insert(cfg(configs_if,userDefines));
Expand Down
2 changes: 1 addition & 1 deletion test/testcppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ class TestCppcheck : public TestFixture {
// the internal errorlist is cleared after each check() call
ASSERT_EQUALS(1, errorLogger.errmsgs.size());
auto it = errorLogger.errmsgs.cbegin();
ASSERT_EQUALS("test.cpp:0:0: information: The configuration 'X' was not checked because its code equals another one. [purgedConfiguration]",
ASSERT_EQUALS("test.cpp:0:0: information: The configuration 'X=X' was not checked because its code equals another one. [purgedConfiguration]",
it->toString(false, templateFormat, ""));
}

Expand Down
Loading
Loading