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 {
|
||||
class Macro {
|
||||
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))
|
||||
throw std::runtime_error("bad macro syntax");
|
||||
if (tok->op != '#')
|
||||
|
@ -1128,7 +1128,7 @@ namespace simplecpp {
|
|||
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);
|
||||
std::istringstream istr(def);
|
||||
tokenListDefine.readfile(istr);
|
||||
|
@ -1136,12 +1136,13 @@ namespace simplecpp {
|
|||
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;
|
||||
}
|
||||
|
||||
void operator=(const Macro ¯o) {
|
||||
if (this != ¯o) {
|
||||
valueDefinedInCode_ = macro.valueDefinedInCode_;
|
||||
if (macro.tokenListDefine.empty())
|
||||
parseDefine(macro.nameTokDef);
|
||||
else {
|
||||
|
@ -1151,6 +1152,10 @@ namespace simplecpp {
|
|||
}
|
||||
}
|
||||
|
||||
bool valueDefinedInCode() const {
|
||||
return valueDefinedInCode_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand macro. This will recursively expand inner macros.
|
||||
* @param output destination tokenlist
|
||||
|
@ -1821,6 +1826,9 @@ namespace simplecpp {
|
|||
|
||||
/** usage of this macro */
|
||||
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 std::list<Location> &usage = macro.usage();
|
||||
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.macroLocation = macro.defineLocation();
|
||||
mu.useLocation = *usageIt;
|
||||
|
|
|
@ -269,10 +269,11 @@ namespace simplecpp {
|
|||
|
||||
/** Tracking how macros are used */
|
||||
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;
|
||||
Location macroLocation;
|
||||
Location useLocation;
|
||||
bool macroValueKnown;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -786,6 +786,8 @@ bool Preprocessor::validateCfg(const std::string &cfg, const std::list<simplecpp
|
|||
continue;
|
||||
const std::string macroName(define.substr(0, define.find('(')));
|
||||
for (const simplecpp::MacroUsage &mu : macroUsageList) {
|
||||
if (mu.macroValueKnown)
|
||||
continue;
|
||||
if (mu.macroName != macroName)
|
||||
continue;
|
||||
bool directiveLocation = false;
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
TestPreprocessor()
|
||||
: TestFixture("TestPreprocessor")
|
||||
, preprocessor0(settings0, this) {
|
||||
settings0.addEnabled("information");
|
||||
}
|
||||
|
||||
class OurPreprocessor : public Preprocessor {
|
||||
|
@ -231,7 +232,8 @@ private:
|
|||
TEST_CASE(getConfigsU6);
|
||||
TEST_CASE(getConfigsU7);
|
||||
|
||||
TEST_CASE(validateCfg);
|
||||
TEST_CASE(validateCfg1);
|
||||
TEST_CASE(validateCfg2);
|
||||
|
||||
TEST_CASE(if_sizeof);
|
||||
|
||||
|
@ -2209,11 +2211,11 @@ private:
|
|||
}
|
||||
|
||||
|
||||
void validateCfg() {
|
||||
void validateCfg1() {
|
||||
Preprocessor preprocessor(settings0, this);
|
||||
|
||||
std::vector<std::string> files(1, "test.c");
|
||||
simplecpp::MacroUsage macroUsage(files);
|
||||
simplecpp::MacroUsage macroUsage(files, false);
|
||||
macroUsage.useLocation.fileIndex = 0;
|
||||
macroUsage.useLocation.line = 1;
|
||||
macroUsage.macroName = "X";
|
||||
|
@ -2224,6 +2226,19 @@ private:
|
|||
ASSERT_EQUALS(false, preprocessor.validateCfg("A=42;X", macroUsageList));
|
||||
ASSERT_EQUALS(true, preprocessor.validateCfg("X=1", 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
|
||||
|
|
Loading…
Reference in New Issue