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