Skip to content

Commit b01f29a

Browse files
Leander SchultenLeander Schulten
authored andcommitted
Fix wrong logic where should be thrown and there not
1 parent db11aab commit b01f29a

2 files changed

Lines changed: 31 additions & 27 deletions

File tree

lib/importproject.cpp

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -605,21 +605,29 @@ namespace {
605605
// see https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions
606606
// properties are .NET String objects and you can call any of its members on them
607607
bool conditionIsTrue(const ProjectConfiguration &p, const std::string &filename, std::vector<std::string> &errors) const {
608-
return conditionIsTrue(mCondition, p, filename, errors);
608+
if (mCondition.empty())
609+
return true;
610+
try {
611+
return evalCondition(mCondition, p);
612+
}
613+
catch (const std::runtime_error& r)
614+
{
615+
errors.emplace_back(filename + ": Can not evaluate condition '" + mCondition + "': " + r.what());
616+
return false;
617+
}
609618
}
610619

611-
static bool conditionIsTrue(const std::string& condition, const ProjectConfiguration &p, const std::string &filename, std::vector<std::string> &errors) {
612-
if (condition.empty())
613-
return true;
614-
std::string c = '(' + condition + ");";
620+
static bool evalCondition(const std::string& condition, const ProjectConfiguration &p) {
621+
std::string c = '(' + condition + ")";
615622
replaceAll(c, "$(Configuration)", p.configuration);
616623
replaceAll(c, "$(Platform)", p.platformStr);
617624

618-
// TODO: improve evaluation
619625
const Settings s;
620626
TokenList tokenlist(s, Standards::Language::C);
621-
tokenlist.createTokensFromBuffer(c.data(), c.size()); // TODO: check result
622-
// TODO: put in a helper
627+
if (!tokenlist.createTokensFromBuffer(c.data(), c.size())) {
628+
throw std::runtime_error("Can not tokenize condition");
629+
}
630+
623631
// generate links
624632
{
625633
std::stack<Token*> lpar;
@@ -653,49 +661,44 @@ namespace {
653661
return execute(tok->astTop(), p) == "True";
654662
}
655663
}
656-
657664
throw std::runtime_error("Invalid condition: '" + condition + "'");
658665
}
666+
667+
659668
private:
660669

661-
static std::string executeOp1(const Token* tok, const ProjectConfiguration &p, bool b=false) {
662-
const std::string result = execute(tok->astOperand1(), p);
663-
if (b)
664-
return (result != "False" && !result.empty()) ? "True" : "False";
665-
return result;
670+
static std::string executeOp1(const Token* tok, const ProjectConfiguration &p) {
671+
return execute(tok->astOperand1(), p);
666672
}
667673

668-
static std::string executeOp2(const Token* tok, const ProjectConfiguration &p, bool b=false) {
669-
const std::string result = execute(tok->astOperand2(), p);
670-
if (b)
671-
return (result != "False" && !result.empty()) ? "True" : "False";
672-
return result;
674+
static std::string executeOp2(const Token* tok, const ProjectConfiguration &p) {
675+
return execute(tok->astOperand2(), p);
673676
}
674677

675678
static std::string execute(const Token* tok, const ProjectConfiguration &p) {
676679
if (!tok)
677680
throw std::runtime_error("Missing operator");
678681
auto boolResult = [](bool b) -> std::string { return b ? "True" : "False"; };
679682
if (tok->isUnaryOp("!"))
680-
return boolResult(executeOp1(tok, p, true) == "False");
683+
return boolResult(executeOp1(tok, p) == "False");
681684
if (tok->str() == "==")
682685
return boolResult(executeOp1(tok, p) == executeOp2(tok, p));
683686
if (tok->str() == "!=")
684687
return boolResult(executeOp1(tok, p) != executeOp2(tok, p));
685688
if (tok->str() == "&&")
686-
return boolResult(executeOp1(tok, p, true) == "True" && executeOp2(tok, p, true) == "True");
689+
return boolResult(executeOp1(tok, p) == "True" && executeOp2(tok, p) == "True");
687690
if (tok->str() == "||")
688-
return boolResult(executeOp1(tok, p, true) == "True" || executeOp2(tok, p, true) == "True");
691+
return boolResult(executeOp1(tok, p) == "True" || executeOp2(tok, p) == "True");
689692
if (tok->str() == "(" && Token::Match(tok->previous(), "$ ( %name% . %name% (")) {
690693
const std::string propertyName = tok->next()->str();
691694
std::string propertyValue;
692695
if (propertyName == "Configuration")
693696
propertyValue = p.configuration;
694697
else if (propertyName == "Platform")
695-
propertyValue = p.platform;
698+
propertyValue = p.platformStr;
696699
else
697700
throw std::runtime_error("Unhandled property '" + propertyName + "'");
698-
const std::string method = tok->strAt(3);
701+
const std::string& method = tok->strAt(3);
699702
std::string arg = executeOp2(tok->tokAt(4), p);
700703
if (arg.size() >= 2 && arg[0] == '\'')
701704
arg = arg.substr(1, arg.size() - 2);
@@ -707,7 +710,7 @@ namespace {
707710
return boolResult(startsWith(propertyValue,arg));
708711
throw std::runtime_error("Unhandled method '" + method + "'");
709712
}
710-
if (tok->str().size() >= 2 && tok->str()[0] == '\'')
713+
if (tok->str().size() >= 2 && tok->str()[0] == '\'') // String Literal
711714
return tok->str();
712715

713716
throw std::runtime_error("Unknown/unhandled operator/operand '" + tok->str() + "'");
@@ -1702,5 +1705,5 @@ bool cppcheck::testing::evaluateVcxprojCondition(const std::string& condition, c
17021705
p.configuration = configuration;
17031706
p.platformStr = platform;
17041707
std::vector<std::string> errors;
1705-
return ConditionalGroup::conditionIsTrue(condition, p, "file.vcxproj", errors) && errors.empty();
1708+
return ConditionalGroup::evalCondition(condition, p);
17061709
}

test/testimportproject.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,8 +708,9 @@ class TestImportProject : public TestFixture {
708708
ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("('' == ''", "", ""), std::runtime_error, "'(' without closing ')'!");
709709
ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '')", "", ""), std::runtime_error, "unmatched ')' in condition '' == '')");
710710
ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("''", "", ""), std::runtime_error, "Invalid condition: ''''");
711-
ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '", "", ""), std::runtime_error, "Invalid condition: ''' == ''");
711+
ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '", "", ""), std::runtime_error, "Can not tokenize condition");
712712
ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("$(Configuration.Lower())", "", ""), std::runtime_error, "Missing operator");
713+
ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("' ' && ' '", "", ""), std::runtime_error, "Missing operator");
713714
}
714715

715716
// TODO: test fsParseCommand()

0 commit comments

Comments
 (0)