Skip to content

Commit 2018387

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

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
@@ -552,21 +552,29 @@ namespace {
552552
// see https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions
553553
// properties are .NET String objects and you can call any of its members on them
554554
bool conditionIsTrue(const ProjectConfiguration &p, const std::string &filename, std::vector<std::string> &errors) const {
555-
return conditionIsTrue(mCondition, p, filename, errors);
555+
if (mCondition.empty())
556+
return true;
557+
try {
558+
return evalCondition(mCondition, p);
559+
}
560+
catch (const std::runtime_error& r)
561+
{
562+
errors.emplace_back(filename + ": Can not evaluate condition '" + mCondition + "': " + r.what());
563+
return false;
564+
}
556565
}
557566

558-
static bool conditionIsTrue(const std::string& condition, const ProjectConfiguration &p, const std::string &filename, std::vector<std::string> &errors) {
559-
if (condition.empty())
560-
return true;
561-
std::string c = '(' + condition + ");";
567+
static bool evalCondition(const std::string& condition, const ProjectConfiguration &p) {
568+
std::string c = '(' + condition + ")";
562569
replaceAll(c, "$(Configuration)", p.configuration);
563570
replaceAll(c, "$(Platform)", p.platformStr);
564571

565-
// TODO: improve evaluation
566572
const Settings s;
567573
TokenList tokenlist(s, Standards::Language::C);
568-
tokenlist.createTokensFromBuffer(c.data(), c.size()); // TODO: check result
569-
// TODO: put in a helper
574+
if (!tokenlist.createTokensFromBuffer(c.data(), c.size())) {
575+
throw std::runtime_error("Can not tokenize condition");
576+
}
577+
570578
// generate links
571579
{
572580
std::stack<Token*> lpar;
@@ -600,49 +608,44 @@ namespace {
600608
return execute(tok->astTop(), p) == "True";
601609
}
602610
}
603-
604611
throw std::runtime_error("Invalid condition: '" + condition + "'");
605612
}
613+
614+
606615
private:
607616

608-
static std::string executeOp1(const Token* tok, const ProjectConfiguration &p, bool b=false) {
609-
const std::string result = execute(tok->astOperand1(), p);
610-
if (b)
611-
return (result != "False" && !result.empty()) ? "True" : "False";
612-
return result;
617+
static std::string executeOp1(const Token* tok, const ProjectConfiguration &p) {
618+
return execute(tok->astOperand1(), p);
613619
}
614620

615-
static std::string executeOp2(const Token* tok, const ProjectConfiguration &p, bool b=false) {
616-
const std::string result = execute(tok->astOperand2(), p);
617-
if (b)
618-
return (result != "False" && !result.empty()) ? "True" : "False";
619-
return result;
621+
static std::string executeOp2(const Token* tok, const ProjectConfiguration &p) {
622+
return execute(tok->astOperand2(), p);
620623
}
621624

622625
static std::string execute(const Token* tok, const ProjectConfiguration &p) {
623626
if (!tok)
624627
throw std::runtime_error("Missing operator");
625628
auto boolResult = [](bool b) -> std::string { return b ? "True" : "False"; };
626629
if (tok->isUnaryOp("!"))
627-
return boolResult(executeOp1(tok, p, true) == "False");
630+
return boolResult(executeOp1(tok, p) == "False");
628631
if (tok->str() == "==")
629632
return boolResult(executeOp1(tok, p) == executeOp2(tok, p));
630633
if (tok->str() == "!=")
631634
return boolResult(executeOp1(tok, p) != executeOp2(tok, p));
632635
if (tok->str() == "&&")
633-
return boolResult(executeOp1(tok, p, true) == "True" && executeOp2(tok, p, true) == "True");
636+
return boolResult(executeOp1(tok, p) == "True" && executeOp2(tok, p) == "True");
634637
if (tok->str() == "||")
635-
return boolResult(executeOp1(tok, p, true) == "True" || executeOp2(tok, p, true) == "True");
638+
return boolResult(executeOp1(tok, p) == "True" || executeOp2(tok, p) == "True");
636639
if (tok->str() == "(" && Token::Match(tok->previous(), "$ ( %name% . %name% (")) {
637640
const std::string propertyName = tok->next()->str();
638641
std::string propertyValue;
639642
if (propertyName == "Configuration")
640643
propertyValue = p.configuration;
641644
else if (propertyName == "Platform")
642-
propertyValue = p.platform;
645+
propertyValue = p.platformStr;
643646
else
644647
throw std::runtime_error("Unhandled property '" + propertyName + "'");
645-
const std::string method = tok->strAt(3);
648+
const std::string& method = tok->strAt(3);
646649
std::string arg = executeOp2(tok->tokAt(4), p);
647650
if (arg.size() >= 2 && arg[0] == '\'')
648651
arg = arg.substr(1, arg.size() - 2);
@@ -654,7 +657,7 @@ namespace {
654657
return boolResult(startsWith(propertyValue,arg));
655658
throw std::runtime_error("Unhandled method '" + method + "'");
656659
}
657-
if (tok->str().size() >= 2 && tok->str()[0] == '\'')
660+
if (tok->str().size() >= 2 && tok->str()[0] == '\'') // String Literal
658661
return tok->str();
659662

660663
throw std::runtime_error("Unknown/unhandled operator/operand '" + tok->str() + "'");
@@ -1649,5 +1652,5 @@ bool cppcheck::testing::evaluateVcxprojCondition(const std::string& condition, c
16491652
p.configuration = configuration;
16501653
p.platformStr = platform;
16511654
std::vector<std::string> errors;
1652-
return ConditionalGroup::conditionIsTrue(condition, p, "file.vcxproj", errors) && errors.empty();
1655+
return ConditionalGroup::evalCondition(condition, p);
16531656
}

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)