/// <summary> /// Constructor /// </summary> /// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param> /// <param name="stateMachineKind">State machine kind</param> /// <param name="method">Method</param> /// <param name="kickoffMethod">Kickoff method or null</param> /// <param name="locals">Locals</param> /// <param name="parameters">Parameters or null</param> /// <param name="asyncInfo">Async method info or null</param> public MethodDebugInfoBuilder(int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef?kickoffMethod, SourceLocal[] locals, SourceParameter[]?parameters, AsyncMethodDebugInfo?asyncInfo) : this(decompilerSettingsVersion, stateMachineKind, method, kickoffMethod) { Scope.Locals.AddRange(locals); Parameters = parameters; AsyncInfo = asyncInfo; }
/// <summary> /// Constructor /// </summary> /// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param> /// <param name="stateMachineKind">State machine kind</param> /// <param name="method">Method</param> /// <param name="kickoffMethod">Kickoff method or null</param> public MethodDebugInfoBuilder(int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef?kickoffMethod) { this.decompilerSettingsVersion = decompilerSettingsVersion; this.stateMachineKind = stateMachineKind; this.method = method ?? throw new ArgumentNullException(nameof(method)); this.kickoffMethod = kickoffMethod; statements = new List <SourceStatement>(); Scope = new MethodDebugScopeBuilder(); Scope.Span = ILSpan.FromBounds(0, (uint)method.Body.GetCodeSize()); if (method == kickoffMethod) { throw new ArgumentException(); } }
internal static Match<SyntaxNode> GetMethodMatch(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var m1 = MakeMethodBody(src1, options, stateMachine); var m2 = MakeMethodBody(src2, options, stateMachine); var diagnostics = new List<RudeEditDiagnostic>(); bool needsSyntaxMap; var match = Analyzer.ComputeBodyMatch(m1, m2, new AbstractEditAndContinueAnalyzer.ActiveNode[0], diagnostics, out needsSyntaxMap); Assert.Equal(stateMachine != StateMachineKind.None, needsSyntaxMap); if (stateMachine == StateMachineKind.None) { Assert.Empty(diagnostics); } return match; }
/// <summary> /// Constructor /// </summary> /// <param name="compilerName">Compiler name (<see cref="PredefinedCompilerNames"/>) or null</param> /// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param> /// <param name="stateMachineKind">State machine kind</param> /// <param name="method">Method</param> /// <param name="kickoffMethod">Kickoff method or null</param> /// <param name="parameters">Parameters or null</param> /// <param name="statements">Statements</param> /// <param name="scope">Root scope</param> /// <param name="methodSpan">Method span or null to calculate it from <paramref name="statements"/></param> /// <param name="asyncMethodDebugInfo">Async info or null</param> public MethodDebugInfo(string?compilerName, int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef?kickoffMethod, SourceParameter[]?parameters, SourceStatement[] statements, MethodDebugScope scope, TextSpan?methodSpan, AsyncMethodDebugInfo?asyncMethodDebugInfo) { if (statements is null) { throw new ArgumentNullException(nameof(statements)); } CompilerName = compilerName; Method = method ?? throw new ArgumentNullException(nameof(method)); KickoffMethod = kickoffMethod; Parameters = parameters ?? Array.Empty <SourceParameter>(); if (statements.Length > 1) { Array.Sort(statements, SourceStatement.SpanStartComparer); } DecompilerSettingsVersion = decompilerSettingsVersion; Statements = statements; Scope = scope ?? throw new ArgumentNullException(nameof(scope)); Span = methodSpan ?? CalculateMethodSpan(statements) ?? new TextSpan(0, 0); AsyncInfo = asyncMethodDebugInfo; }
internal static BlockSyntax MakeMethodBody( string bodySource, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { string source; switch (stateMachine) { case StateMachineKind.Iterator: source = "class C { IEnumerable<int> F() { " + bodySource + " } }"; break; case StateMachineKind.Async: source = "class C { async Task<int> F() { " + bodySource + " } }"; break; default: source = "class C { void F() { " + bodySource + " } }"; break; } var tree = ParseSource(source, options: options); var root = tree.GetRoot(); tree.GetDiagnostics().Verify(); var declaration = (MethodDeclarationSyntax)((ClassDeclarationSyntax)((CompilationUnitSyntax)root).Members[0]).Members[0]; // We need to preserve the parent node to allow detection of state machine methods in the analyzer. // If we are not testing a state machine method we only use the body to avoid updating positions in all existing tests. if (stateMachine != StateMachineKind.None) { return(((MethodDeclarationSyntax)SyntaxFactory.SyntaxTree(declaration).GetRoot()).Body); } return((BlockSyntax)SyntaxFactory.SyntaxTree(declaration.Body).GetRoot()); }
protected override void GetStateMachineInfo(SyntaxNode body, out ImmutableArray<SyntaxNode> suspensionPoints, out StateMachineKind kind) { if (SyntaxUtilities.IsAsyncMethodOrLambda(body.Parent)) { suspensionPoints = SyntaxUtilities.GetAwaitExpressions(body); kind = StateMachineKind.Async; } else { suspensionPoints = SyntaxUtilities.GetYieldStatements(body); kind = suspensionPoints.IsEmpty ? StateMachineKind.None : StateMachineKind.Iterator; } }
internal static IEnumerable <KeyValuePair <SyntaxNode, SyntaxNode> > GetMethodMatches(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var methodMatch = GetMethodMatch(src1, src2, options, stateMachine); return(EditAndContinueTestHelpers.GetMethodMatches(Analyzer, methodMatch)); }
internal static Match <SyntaxNode> GetMethodMatch(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var m1 = MakeMethodBody(src1, options, stateMachine); var m2 = MakeMethodBody(src2, options, stateMachine); var diagnostics = new List <RudeEditDiagnostic>(); bool needsSyntaxMap; var match = Analyzer.ComputeBodyMatch(m1, m2, new AbstractEditAndContinueAnalyzer.ActiveNode[0], diagnostics, out needsSyntaxMap); Assert.Equal(stateMachine != StateMachineKind.None, needsSyntaxMap); if (stateMachine == StateMachineKind.None) { Assert.Empty(diagnostics); } return(match); }
internal static EditScript <SyntaxNode> GetMethodEdits(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var match = GetMethodMatch(src1, src2, options, stateMachine); return(match.GetTreeEdits()); }
internal static IEnumerable<Match<SyntaxNode>> GetMethodMatches(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var methodMatch = GetMethodMatch(src1, src2, options, stateMachine); var queue = new Queue<Match<SyntaxNode>>(); queue.Enqueue(methodMatch); while (queue.Count > 0) { var match = queue.Dequeue(); yield return match; foreach (var m in match.Matches) { if (m.Key == match.OldRoot) { Assert.Equal(match.NewRoot, m.Value); continue; } foreach (var body in GetLambdaBodies(m.Key, m.Value)) { var lambdaMatch = new StatementSyntaxComparer(body.Item1, body.Item2).ComputeMatch(m.Key, m.Value); queue.Enqueue(lambdaMatch); } } } }
internal static EditScript<SyntaxNode> GetMethodEdits(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var match = GetMethodMatch(src1, src2, options, stateMachine); return match.GetTreeEdits(); }
internal static BlockSyntax MakeMethodBody( string bodySource, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { string source; switch (stateMachine) { case StateMachineKind.Iterator: source = "class C { IEnumerable<int> F() { " + bodySource + " } }"; break; case StateMachineKind.Async: source = "class C { async Task<int> F() { " + bodySource + " } }"; break; default: source = "class C { void F() { " + bodySource + " } }"; break; } var tree = ParseSource(source, options: options); var root = tree.GetRoot(); tree.GetDiagnostics().Verify(); var declaration = (MethodDeclarationSyntax)((ClassDeclarationSyntax)((CompilationUnitSyntax)root).Members[0]).Members[0]; // We need to preserve the parent node to allow detection of state machine methods in the analyzer. // If we are not testing a state machine method we only use the body to avoid updating positions in all existing tests. if (stateMachine != StateMachineKind.None) { return ((MethodDeclarationSyntax)SyntaxFactory.SyntaxTree(declaration).GetRoot()).Body; } return (BlockSyntax)SyntaxFactory.SyntaxTree(declaration.Body).GetRoot(); }
internal static IEnumerable <Match <SyntaxNode> > GetMethodMatches(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var methodMatch = GetMethodMatch(src1, src2, options, stateMachine); var queue = new Queue <Match <SyntaxNode> >(); queue.Enqueue(methodMatch); while (queue.Count > 0) { var match = queue.Dequeue(); yield return(match); foreach (var m in match.Matches) { if (m.Key == match.OldRoot) { Assert.Equal(match.NewRoot, m.Value); continue; } foreach (var body in GetLambdaBodies(m.Key, m.Value)) { var lambdaMatch = new StatementSyntaxComparer(body.Item1, body.Item2).ComputeMatch(m.Key, m.Value); queue.Enqueue(lambdaMatch); } } } }
internal static IEnumerable <KeyValuePair <SyntaxNode, SyntaxNode> > GetMethodMatches(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var methodMatch = GetMethodMatch(src1, src2, options, stateMachine); Dictionary <SyntaxNode, AbstractEditAndContinueAnalyzer.LambdaInfo> lazyActiveOrMatchedLambdas = null; var map = Analyzer.ComputeMap(methodMatch, new AbstractEditAndContinueAnalyzer.ActiveNode[0], ref lazyActiveOrMatchedLambdas, new List <RudeEditDiagnostic>()); var result = new Dictionary <SyntaxNode, SyntaxNode>(); foreach (var pair in map.Forward) { if (pair.Value == methodMatch.NewRoot) { Assert.Same(pair.Key, methodMatch.OldRoot); continue; } result.Add(pair.Key, pair.Value); } return(result); }
internal static IEnumerable<KeyValuePair<SyntaxNode, SyntaxNode>> GetMethodMatches(string src1, string src2, ParseOptions options = null, StateMachineKind stateMachine = StateMachineKind.None) { var methodMatch = GetMethodMatch(src1, src2, options, stateMachine); return EditAndContinueTestHelpers.GetMethodMatches(Analyzer, methodMatch); }