From 0ca43e5b82d81051882e63cced56eb8e24175bdc Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 13 Dec 2019 09:59:43 -0800 Subject: [PATCH] Reduce complexity of ParseStatementNoDeclaration (#40290) --- .../CSharp/Portable/Parser/LanguageParser.cs | 6 +- .../CSharp/Test/Emit/Emit/EndToEndTests.cs | 96 ++++++++++++++++++- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 1bd0a43354e61..bfcd7af5b21c9 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -6480,7 +6480,7 @@ private StatementSyntax ParseStatementNoDeclaration(bool allowAnyExpression) } else { - return this.ParseLocalDeclarationStatement(parseAwaitKeyword()); + return this.ParseLocalDeclarationStatement(parseAwaitKeyword(MessageID.None)); } } else if (this.IsPossibleLabeledStatement()) @@ -6523,11 +6523,11 @@ bool isPossibleAwaitUsing() this.PeekToken(1).Kind == SyntaxKind.UsingKeyword; } - SyntaxToken parseAwaitKeyword(MessageID? feature = null) + SyntaxToken parseAwaitKeyword(MessageID feature) { Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.AwaitKeyword); SyntaxToken awaitToken = this.EatContextualToken(SyntaxKind.AwaitKeyword); - return feature.HasValue ? CheckFeatureAvailability(awaitToken, feature.GetValueOrDefault()) : awaitToken; + return feature != MessageID.None ? CheckFeatureAvailability(awaitToken, feature) : awaitToken; } } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs index d0e731bc2b94b..c401d8926b7fd 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs @@ -2,10 +2,7 @@ using Roslyn.Test.Utilities; using System; -using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; using Xunit; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -43,6 +40,54 @@ private static void RunInThread(Action action) } } + private static void RunTest(int expectedDepth, Action runTest) + { + if (runTestAndCatch(expectedDepth)) + { + return; + } + + int minDepth = 0; + int maxDepth = expectedDepth; + int actualDepth; + while (true) + { + int depth = (maxDepth - minDepth) / 2 + minDepth; + if (depth <= minDepth) + { + actualDepth = minDepth; + break; + } + if (depth >= maxDepth) + { + actualDepth = maxDepth; + break; + } + if (runTestAndCatch(depth)) + { + minDepth = depth; + } + else + { + maxDepth = depth; + } + } + Assert.Equal(expectedDepth, actualDepth); + + bool runTestAndCatch(int depth) + { + try + { + runTest(depth); + return true; + } + catch (Exception) + { + return false; + } + } + } + // This test is a canary attempting to make sure that we don't regress the # of fluent calls that // the compiler can handle. [WorkItem(16669, "https://github.com/dotnet/roslyn/issues/16669")] @@ -175,5 +220,50 @@ public static void Main(string[] args) }); } } + + [ConditionalFact(typeof(WindowsOnly))] + public void NestedIfStatements() + { + int nestingLevel = (ExecutionConditionUtil.Architecture, ExecutionConditionUtil.Configuration) switch + { + (ExecutionArchitecture.x86, ExecutionConfiguration.Debug) => 310, + (ExecutionArchitecture.x86, ExecutionConfiguration.Release) => 1650, + (ExecutionArchitecture.x64, ExecutionConfiguration.Debug) => 200, + (ExecutionArchitecture.x64, ExecutionConfiguration.Release) => 780, + _ => throw new Exception($"Unexpected configuration {ExecutionConditionUtil.Architecture} {ExecutionConditionUtil.Configuration}") + }; + + RunTest(nestingLevel, runTest); + + static void runTest(int nestingLevel) + { + var builder = new StringBuilder(); + builder.AppendLine( +@"class Program +{ + static bool F(int i) => true; + static void Main() + {"); + for (int i = 0; i < nestingLevel; i++) + { + builder.AppendLine( +$@" if (F({i})) + {{"); + } + for (int i = 0; i < nestingLevel; i++) + { + builder.AppendLine(" }"); + } + builder.AppendLine( +@" } +}"); + var source = builder.ToString(); + RunInThread(() => + { + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + }); + } + } } }