@@ -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}
0 commit comments