diff --git a/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs b/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs index 508c5e945f..4bf4e8bd72 100644 --- a/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs +++ b/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs @@ -21,9 +21,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; - using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; namespace ICSharpCode.NRefactory.CSharp.Analysis @@ -156,7 +157,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis } Statement rootStatement; - CSharpAstResolver resolver; + CSharpTypeResolveContext typeResolveContext; + Func resolver; List nodes; Dictionary labels; List gotoStatements; @@ -164,6 +166,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis public IList BuildControlFlowGraph(Statement statement, CancellationToken cancellationToken = default(CancellationToken)) { + if (statement == null) + throw new ArgumentNullException("statement"); CSharpResolver r = new CSharpResolver(MinimalCorlib.Instance.CreateCompilation()); return BuildControlFlowGraph(statement, new CSharpAstResolver(r, statement), cancellationToken); } @@ -174,7 +178,11 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis throw new ArgumentNullException("statement"); if (resolver == null) throw new ArgumentNullException("resolver"); - + return BuildControlFlowGraph(statement, resolver.Resolve, resolver.TypeResolveContext, cancellationToken); + } + + internal IList BuildControlFlowGraph(Statement statement, Func resolver, CSharpTypeResolveContext typeResolveContext, CancellationToken cancellationToken) + { NodeCreationVisitor nodeCreationVisitor = new NodeCreationVisitor(); nodeCreationVisitor.builder = this; try { @@ -183,6 +191,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis this.gotoStatements = new List(); this.rootStatement = statement; this.resolver = resolver; + this.typeResolveContext = typeResolveContext; this.cancellationToken = cancellationToken; ControlFlowNode entryPoint = CreateStartNode(statement); @@ -205,6 +214,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis this.gotoStatements = null; this.rootStatement = null; this.resolver = null; + this.typeResolveContext = null; this.cancellationToken = CancellationToken.None; } } @@ -288,7 +298,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis if (!(expr is PrimitiveExpression || expr is NullReferenceExpression)) return null; } - return resolver.Resolve(expr, cancellationToken); + return resolver(expr, cancellationToken); } /// @@ -308,7 +318,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis { if (c1 == null || c2 == null || !c1.IsCompileTimeConstant || !c2.IsCompileTimeConstant) return false; - CSharpResolver r = new CSharpResolver(resolver.TypeResolveContext); + CSharpResolver r = new CSharpResolver(typeResolveContext); ResolveResult c = r.ResolveBinaryOperator(BinaryOperatorType.Equality, c1, c2); return c.IsCompileTimeConstant && (c.ConstantValue as bool?) == true; } diff --git a/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs b/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs index e06c42490a..ebb8d419d3 100644 --- a/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs +++ b/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs @@ -20,6 +20,8 @@ using System; using System.Collections.Generic; using System.Threading; using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.CSharp.TypeSystem; +using ICSharpCode.NRefactory.Semantics; namespace ICSharpCode.NRefactory.CSharp.Analysis { @@ -42,6 +44,13 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis return Create(cfg, cancellationToken); } + internal static ReachabilityAnalysis Create(Statement statement, Func resolver, CSharpTypeResolveContext typeResolveContext, CancellationToken cancellationToken) + { + var cfgBuilder = new ControlFlowGraphBuilder(); + var cfg = cfgBuilder.BuildControlFlowGraph(statement, resolver, typeResolveContext, cancellationToken); + return Create(cfg, cancellationToken); + } + public static ReachabilityAnalysis Create(IList controlFlowGraph, CancellationToken cancellationToken = default(CancellationToken)) { if (controlFlowGraph == null) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs index 47525c3053..756d22ba6a 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs @@ -78,12 +78,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver this.resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile); } - internal CSharpAstResolver(ResolveVisitor resolveVisitor) - { - this.resolveVisitor = resolveVisitor; - this.resolverInitialized = true; - } - /// /// Gets the type resolve context for the root resolver. /// diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs index 31d441a07a..e469cd4e69 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs @@ -2319,7 +2319,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // Failure to infer a return type does not make the lambda invalid, // so we can ignore the 'tiSuccess' value if (isValidAsVoidMethod && returnExpressions.Count == 0 && body is Statement) { - var reachabilityAnalysis = ReachabilityAnalysis.Create((Statement)body, new CSharpAstResolver(this), cancellationToken); + var reachabilityAnalysis = ReachabilityAnalysis.Create( + (Statement)body, (node, _) => resolveResultCache[node], + resolver.CurrentTypeResolveContext, cancellationToken); isEndpointUnreachable = !reachabilityAnalysis.IsEndpointReachable((Statement)body); } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs index 6c5286cf67..aa41c7ca76 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs @@ -446,6 +446,20 @@ class Test { Assert.IsTrue(c.IsValid); } + [Test] + public void AnonymousMethodInNewEventHandler() + { + // The switch statement causes the control flow analysis to ask the resolver if it's a constant, + // which caused a bug. + string program = @"using System; +class Test { + static bool b; + object x = new EventHandler($delegate (object sender, AssemblyLoadEventArgs e) { switch (e.Action) {} }$); +}"; + var c = GetConversion(program); + Assert.IsTrue(c.IsValid); + } + [Test] public void ThrowingAnonymousMethodIsConvertibleToFunc() {