[xbuild] Parsing conditions with property references. Fixes #20634
authorMarek Safar <marek.safar@gmail.com>
Thu, 19 Jun 2014 15:27:27 +0000 (17:27 +0200)
committerMarek Safar <marek.safar@gmail.com>
Thu, 19 Jun 2014 15:28:52 +0000 (17:28 +0200)
mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConditionParser.cs
mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ConditionTokenizer.cs
mcs/class/Microsoft.Build.Engine/Test/various/Conditions.cs

index ec538abc29f3441d5927656608e29ecdb24ed11c..b5e2e809ae4347f07178b44ada2c6dff97bc0d2e 100644 (file)
@@ -182,7 +182,7 @@ namespace Microsoft.Build.BuildEngine {
                                e = new ConditionFactorExpression (token);
                        } else if (token.Type == TokenType.Item || token.Type == TokenType.Property
                                        || token.Type == TokenType.Metadata) {
-                               e = ParseReferenceExpression (token.Value);
+                               e = ParseReferenceExpression (token.Value [0]);
                        } else if (token.Type == TokenType.Not) {
                                e = ParseNotExpression ();
                        } else
@@ -224,21 +224,33 @@ namespace Microsoft.Build.BuildEngine {
                }
 
                //@prefix: @ or $
-               ConditionExpression ParseReferenceExpression (string prefix)
+               ConditionExpression ParseReferenceExpression (char prefix)
                {
-                       StringBuilder sb = new StringBuilder ();
-
-                       string ref_type = prefix [0] == '$' ? "a property" : "an item list";
                        int token_pos = tokenizer.Token.Position;
+                       string ref_type = prefix == '$' ? "a property" : "an item list";
                        IsAtToken (TokenType.LeftParen, String.Format (
                                                "Expected {0} at position {1} in condition \"{2}\". Missing opening parantheses after the '{3}'.",
                                                ref_type, token_pos, conditionStr, prefix));
-                       tokenizer.GetNextToken ();
 
+
+                       if (prefix == '$') {
+                               //
+                               // Tjhe scan should consider quoted parenthesis but it breaks on .net as well
+                               // we are bug compatible
+                               //
+                               tokenizer.ScanForClosingParens ();
+                       } else {
+                               tokenizer.GetNextToken ();
+                       }
+
+                       if (tokenizer.IsEOF ())
+                               throw new ExpressionParseException ("Missing closing parenthesis in condition " + conditionStr);
+
+                       StringBuilder sb = new StringBuilder ();
                        sb.AppendFormat ("{0}({1}", prefix, tokenizer.Token.Value);
 
                        tokenizer.GetNextToken ();
-                       if (prefix == "@" && tokenizer.Token.Type == TokenType.Transform) {
+                       if (prefix == '@' && tokenizer.Token.Type == TokenType.Transform) {
                                tokenizer.GetNextToken ();
                                sb.AppendFormat ("->'{0}'", tokenizer.Token.Value);
 
@@ -250,9 +262,7 @@ namespace Microsoft.Build.BuildEngine {
                                }
                        }
 
-                       IsAtToken (TokenType.RightParen, String.Format (
-                                               "Expected {0} at position {1} in condition \"{2}\". Missing closing parantheses'.",
-                                               ref_type, token_pos, conditionStr, prefix));
+                       IsAtToken (TokenType.RightParen, "Missing closing parenthesis in condition " + conditionStr);
                        tokenizer.GetNextToken ();
 
                        sb.Append (")");
index 29a4aba628af1765cad1851993be5fe6e4ec9d73..d9ee74475d6b79c919c3f660c01c180806a96bdd 100644 (file)
@@ -257,6 +257,29 @@ namespace Microsoft.Build.BuildEngine {
                        } else
                                throw new ExpressionParseException (String.Format ("Invalid token: {0}", ch));
                }
+
+               public void ScanForClosingParens (int parensCounter = 1)
+               {
+                       tokenPosition = position;
+                       int start = position;
+                       int ch;
+                       while ((ch = ReadChar ()) >= 0) {
+                               switch (ch) {
+                               case ')':
+                                       if (--parensCounter == 0) {
+                                               --position;
+                                               token = new Token (inputString.Substring (start, position - start), TokenType.String, tokenPosition);
+                                               return;
+                                       }
+                                       break;
+                               case '(':
+                                       ++parensCounter;
+                                       break;
+                               }
+                       }
+
+                       token = new Token (null, TokenType.EOF, tokenPosition);
+               }
                
                public int TokenPosition {
                        get { return tokenPosition; }
index 51c3da6cfbf3ff0f779d3b5d4facac81819f1574..c3c8dacabc5c4d3e19f5c2142195cffff4297174 100644 (file)
@@ -357,6 +357,24 @@ namespace MonoTests.Microsoft.Build.BuildEngine.Various {
                        Assert.IsNull (proj.EvaluatedProperties ["A"], "A1");
                }
 
+               [Test]
+               public void TestCondition_References ()
+               {
+                       Engine engine = new Engine (Consts.BinPath);
+                       Project proj = engine.CreateNewProject ();
+
+                       string documentString = @"
+                               <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+                                       <PropertyGroup>
+                                               <A Condition=""$([System.String]::new('test').StartsWith(`te`))"">valid</A>
+                                       </PropertyGroup>
+                               </Project>
+                       ";
+
+                       proj.LoadXml (documentString);
+
+                       Assert.AreEqual ("valid", proj.GetEvaluatedProperty ("A"), "#1");
+               }
 
                [Test]
                public void TestHasTrailingSlash1 ()