Fixed handling of macros with known value defined in header file in configuration splitting (#8404)
Added proper unit test for configuration validation to ensure that it actually works when cppcheck is executed
This commit is contained in:
parent
c312bbad78
commit
86a1b84b0c
|
@ -1110,9 +1110,9 @@ unsigned int simplecpp::TokenList::fileIndex(const std::string &filename)
|
||||||
namespace simplecpp {
|
namespace simplecpp {
|
||||||
class Macro {
|
class Macro {
|
||||||
public:
|
public:
|
||||||
explicit Macro(std::vector<std::string> &f) : nameTokDef(NULL), variadic(false), valueToken(NULL), endToken(NULL), files(f), tokenListDefine(f) {}
|
explicit Macro(std::vector<std::string> &f) : nameTokDef(NULL), variadic(false), valueToken(NULL), endToken(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(false) {}
|
||||||
|
|
||||||
Macro(const Token *tok, std::vector<std::string> &f) : nameTokDef(NULL), files(f), tokenListDefine(f) {
|
Macro(const Token *tok, std::vector<std::string> &f) : nameTokDef(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(true) {
|
||||||
if (sameline(tok->previous, tok))
|
if (sameline(tok->previous, tok))
|
||||||
throw std::runtime_error("bad macro syntax");
|
throw std::runtime_error("bad macro syntax");
|
||||||
if (tok->op != '#')
|
if (tok->op != '#')
|
||||||
|
@ -1128,7 +1128,7 @@ namespace simplecpp {
|
||||||
throw std::runtime_error("bad macro syntax");
|
throw std::runtime_error("bad macro syntax");
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro(const std::string &name, const std::string &value, std::vector<std::string> &f) : nameTokDef(NULL), files(f), tokenListDefine(f) {
|
Macro(const std::string &name, const std::string &value, std::vector<std::string> &f) : nameTokDef(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(false) {
|
||||||
const std::string def(name + ' ' + value);
|
const std::string def(name + ' ' + value);
|
||||||
std::istringstream istr(def);
|
std::istringstream istr(def);
|
||||||
tokenListDefine.readfile(istr);
|
tokenListDefine.readfile(istr);
|
||||||
|
@ -1136,12 +1136,13 @@ namespace simplecpp {
|
||||||
throw std::runtime_error("bad macro syntax");
|
throw std::runtime_error("bad macro syntax");
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro(const Macro ¯o) : nameTokDef(NULL), files(macro.files), tokenListDefine(macro.files) {
|
Macro(const Macro ¯o) : nameTokDef(NULL), files(macro.files), tokenListDefine(macro.files), valueDefinedInCode_(macro.valueDefinedInCode_) {
|
||||||
*this = macro;
|
*this = macro;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(const Macro ¯o) {
|
void operator=(const Macro ¯o) {
|
||||||
if (this != ¯o) {
|
if (this != ¯o) {
|
||||||
|
valueDefinedInCode_ = macro.valueDefinedInCode_;
|
||||||
if (macro.tokenListDefine.empty())
|
if (macro.tokenListDefine.empty())
|
||||||
parseDefine(macro.nameTokDef);
|
parseDefine(macro.nameTokDef);
|
||||||
else {
|
else {
|
||||||
|
@ -1151,6 +1152,10 @@ namespace simplecpp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool valueDefinedInCode() const {
|
||||||
|
return valueDefinedInCode_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand macro. This will recursively expand inner macros.
|
* Expand macro. This will recursively expand inner macros.
|
||||||
* @param output destination tokenlist
|
* @param output destination tokenlist
|
||||||
|
@ -1821,6 +1826,9 @@ namespace simplecpp {
|
||||||
|
|
||||||
/** usage of this macro */
|
/** usage of this macro */
|
||||||
mutable std::list<Location> usageList;
|
mutable std::list<Location> usageList;
|
||||||
|
|
||||||
|
/** was the value of this macro actually defined in the code? */
|
||||||
|
bool valueDefinedInCode_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2612,7 +2620,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
const Macro ¯o = macroIt->second;
|
const Macro ¯o = macroIt->second;
|
||||||
const std::list<Location> &usage = macro.usage();
|
const std::list<Location> &usage = macro.usage();
|
||||||
for (std::list<Location>::const_iterator usageIt = usage.begin(); usageIt != usage.end(); ++usageIt) {
|
for (std::list<Location>::const_iterator usageIt = usage.begin(); usageIt != usage.end(); ++usageIt) {
|
||||||
MacroUsage mu(usageIt->files);
|
MacroUsage mu(usageIt->files, macro.valueDefinedInCode());
|
||||||
mu.macroName = macro.name();
|
mu.macroName = macro.name();
|
||||||
mu.macroLocation = macro.defineLocation();
|
mu.macroLocation = macro.defineLocation();
|
||||||
mu.useLocation = *usageIt;
|
mu.useLocation = *usageIt;
|
||||||
|
|
|
@ -269,10 +269,11 @@ namespace simplecpp {
|
||||||
|
|
||||||
/** Tracking how macros are used */
|
/** Tracking how macros are used */
|
||||||
struct SIMPLECPP_LIB MacroUsage {
|
struct SIMPLECPP_LIB MacroUsage {
|
||||||
explicit MacroUsage(const std::vector<std::string> &f) : macroLocation(f), useLocation(f) {}
|
explicit MacroUsage(const std::vector<std::string> &f, bool macroValueKnown_) : macroLocation(f), useLocation(f), macroValueKnown(macroValueKnown_) {}
|
||||||
std::string macroName;
|
std::string macroName;
|
||||||
Location macroLocation;
|
Location macroLocation;
|
||||||
Location useLocation;
|
Location useLocation;
|
||||||
|
bool macroValueKnown;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -786,6 +786,8 @@ bool Preprocessor::validateCfg(const std::string &cfg, const std::list<simplecpp
|
||||||
continue;
|
continue;
|
||||||
const std::string macroName(define.substr(0, define.find('(')));
|
const std::string macroName(define.substr(0, define.find('(')));
|
||||||
for (const simplecpp::MacroUsage &mu : macroUsageList) {
|
for (const simplecpp::MacroUsage &mu : macroUsageList) {
|
||||||
|
if (mu.macroValueKnown)
|
||||||
|
continue;
|
||||||
if (mu.macroName != macroName)
|
if (mu.macroName != macroName)
|
||||||
continue;
|
continue;
|
||||||
bool directiveLocation = false;
|
bool directiveLocation = false;
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
TestPreprocessor()
|
TestPreprocessor()
|
||||||
: TestFixture("TestPreprocessor")
|
: TestFixture("TestPreprocessor")
|
||||||
, preprocessor0(settings0, this) {
|
, preprocessor0(settings0, this) {
|
||||||
|
settings0.addEnabled("information");
|
||||||
}
|
}
|
||||||
|
|
||||||
class OurPreprocessor : public Preprocessor {
|
class OurPreprocessor : public Preprocessor {
|
||||||
|
@ -231,7 +232,8 @@ private:
|
||||||
TEST_CASE(getConfigsU6);
|
TEST_CASE(getConfigsU6);
|
||||||
TEST_CASE(getConfigsU7);
|
TEST_CASE(getConfigsU7);
|
||||||
|
|
||||||
TEST_CASE(validateCfg);
|
TEST_CASE(validateCfg1);
|
||||||
|
TEST_CASE(validateCfg2);
|
||||||
|
|
||||||
TEST_CASE(if_sizeof);
|
TEST_CASE(if_sizeof);
|
||||||
|
|
||||||
|
@ -2209,11 +2211,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void validateCfg() {
|
void validateCfg1() {
|
||||||
Preprocessor preprocessor(settings0, this);
|
Preprocessor preprocessor(settings0, this);
|
||||||
|
|
||||||
std::vector<std::string> files(1, "test.c");
|
std::vector<std::string> files(1, "test.c");
|
||||||
simplecpp::MacroUsage macroUsage(files);
|
simplecpp::MacroUsage macroUsage(files, false);
|
||||||
macroUsage.useLocation.fileIndex = 0;
|
macroUsage.useLocation.fileIndex = 0;
|
||||||
macroUsage.useLocation.line = 1;
|
macroUsage.useLocation.line = 1;
|
||||||
macroUsage.macroName = "X";
|
macroUsage.macroName = "X";
|
||||||
|
@ -2224,6 +2226,19 @@ private:
|
||||||
ASSERT_EQUALS(false, preprocessor.validateCfg("A=42;X", macroUsageList));
|
ASSERT_EQUALS(false, preprocessor.validateCfg("A=42;X", macroUsageList));
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("X=1", macroUsageList));
|
ASSERT_EQUALS(true, preprocessor.validateCfg("X=1", macroUsageList));
|
||||||
ASSERT_EQUALS(true, preprocessor.validateCfg("Y", macroUsageList));
|
ASSERT_EQUALS(true, preprocessor.validateCfg("Y", macroUsageList));
|
||||||
|
|
||||||
|
macroUsageList.front().macroValueKnown = true; // #8404
|
||||||
|
ASSERT_EQUALS(true, preprocessor.validateCfg("X", macroUsageList));
|
||||||
|
}
|
||||||
|
|
||||||
|
void validateCfg2() {
|
||||||
|
const char filedata[] = "#ifdef ABC\n"
|
||||||
|
"#endif\n"
|
||||||
|
"int i = ABC;";
|
||||||
|
|
||||||
|
std::map<std::string, std::string> actual;
|
||||||
|
preprocess(filedata, actual, "file.cpp");
|
||||||
|
ASSERT_EQUALS("[file.cpp:3]: (information) Skipping configuration 'ABC' since the value of 'ABC' is unknown. Use -D if you want to check it. You can use -U to skip it explicitly.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_sizeof() { // #4071
|
void if_sizeof() { // #4071
|
||||||
|
|
Loading…
Reference in New Issue