From a3f149c518e3b5e5fed3261c2d7875708a784fe0 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Mon, 2 Jul 2018 17:18:37 -0700 Subject: [PATCH 1/2] Track enclosing symbol in data flow analysis, which might be a field or property. Code used to assume it was (and typed it as) a method. Fixes #19845 Fixes #27969 --- .../DataFlowPass.LocalFunctions.cs | 10 +-- .../Portable/FlowAnalysis/DataFlowPass.cs | 45 ++++++----- .../Portable/FlowAnalysis/ReadWriteWalker.cs | 2 +- .../FlowAnalysis/RegionAnalysisTests.cs | 77 +++++++++++++++++++ 4 files changed, 105 insertions(+), 29 deletions(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs index ca0448d709434..4d4ac2496c6f9 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs @@ -118,9 +118,9 @@ private int RootSlot(int slot) public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc) { - var oldMethodOrLambda = this.currentMethodOrLambda; + var oldMember = this.currentMember; var localFuncSymbol = localFunc.Symbol; - this.currentMethodOrLambda = localFuncSymbol; + this.currentMember = localFuncSymbol; var oldPending = SavePending(); // we do not support branches into a lambda @@ -205,14 +205,14 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen } this.State = savedState; - this.currentMethodOrLambda = oldMethodOrLambda; + this.currentMember = oldMember; return null; } private void RecordReadInLocalFunction(int slot) { - var localFunc = GetNearestLocalFunctionOpt(currentMethodOrLambda); + var localFunc = GetNearestLocalFunctionOpt(currentMember); Debug.Assert(localFunc != null); @@ -294,7 +294,7 @@ private bool IsCapturedInLocalFunction(int slot) // A variable is captured in a local function iff its // container is higher in the tree than the nearest // local function - var nearestLocalFunc = GetNearestLocalFunctionOpt(currentMethodOrLambda); + var nearestLocalFunc = GetNearestLocalFunctionOpt(currentMember); return !(nearestLocalFunc is null) && IsCaptured(rootSymbol, nearestLocalFunc); } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs index e63e658cf7146..5179f15266f6b 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs @@ -114,9 +114,9 @@ internal partial class DataFlowPass : AbstractFlowPass private BitVector _alreadyReported; /// - /// Reflects the enclosing method or lambda at the current location (in the bound tree). + /// Reflects the enclosing member or lambda at the current location (in the bound tree). /// - protected MethodSymbol currentMethodOrLambda { get; private set; } + protected Symbol currentMember { get; private set; } /// /// A cache for remember which structs are empty. @@ -160,7 +160,7 @@ internal DataFlowPass( { this.initiallyAssignedVariables = null; _sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly; - this.currentMethodOrLambda = member as MethodSymbol; + this.currentMember = member; _unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes; bool strict = compilation.FeatureStrictEnabled; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility _emptyStructTypeCache = new EmptyStructTypeCache(compilation, !strict); @@ -179,7 +179,7 @@ internal DataFlowPass( { this.initiallyAssignedVariables = initiallyAssignedVariables; _sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly; - this.currentMethodOrLambda = member as MethodSymbol; + this.currentMember = member; _unassignedVariableAddressOfSyntaxes = null; bool strict = compilation.FeatureStrictEnabled; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility _emptyStructTypeCache = emptyStructs ?? new EmptyStructTypeCache(compilation, !strict); @@ -203,7 +203,7 @@ internal DataFlowPass( { this.initiallyAssignedVariables = initiallyAssignedVariables; _sourceAssembly = null; - this.currentMethodOrLambda = member as MethodSymbol; + this.currentMember = member; _unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes; _emptyStructTypeCache = new NeverEmptyStructTypeCache(); } @@ -262,17 +262,16 @@ protected override ImmutableArray RemoveReturns() { var result = base.RemoveReturns(); - if (currentMethodOrLambda?.IsAsync == true && - !currentMethodOrLambda.IsImplicitlyDeclared) + if (currentMember is MethodSymbol currentMethod && currentMethod.IsAsync && !currentMethod.IsImplicitlyDeclared) { var foundAwait = result.Any(pending => pending.Branch?.Kind == BoundKind.AwaitExpression); if (!foundAwait) { // If we're on a LambdaSymbol, then use its 'DiagnosticLocation'. That will be // much better than using its 'Location' (which is the entire span of the lambda). - var diagnosticLocation = currentMethodOrLambda is LambdaSymbol lambda + var diagnosticLocation = currentMember is LambdaSymbol lambda ? lambda.DiagnosticLocation - : currentMethodOrLambda.Locations[0]; + : currentMember.Locations[0]; Diagnostics.Add(ErrorCode.WRN_AsyncLacksAwaits, diagnosticLocation); } @@ -283,7 +282,7 @@ protected override ImmutableArray RemoveReturns() protected virtual void ReportUnassignedOutParameter(ParameterSymbol parameter, SyntaxNode node, Location location) { - if (!_requireOutParamsAssigned && topLevelMethod == currentMethodOrLambda) + if (!_requireOutParamsAssigned && topLevelMethod == (object)currentMember) { return; } @@ -399,13 +398,13 @@ protected void Analyze(ref bool badRegion, DiagnosticBag diagnostics) /// If variable.Kind is RangeVariable, its underlying lambda parameter. Else null. private void CheckCaptured(Symbol variable, ParameterSymbol rangeVariableUnderlyingParameter = null) { - if (IsCaptured(rangeVariableUnderlyingParameter ?? variable, currentMethodOrLambda)) + if (IsCaptured(rangeVariableUnderlyingParameter ?? variable, currentMember)) { NoteCaptured(variable); } } - private static bool IsCaptured(Symbol variable, MethodSymbol containingMethodOrLambda) + private static bool IsCaptured(Symbol variable, Symbol containingSymbol) { switch (variable.Kind) { @@ -439,7 +438,7 @@ private static bool IsCaptured(Symbol variable, MethodSymbol containingMethodOrL currentFunction != null; currentFunction = currentFunction.ContainingSymbol) { - if (currentFunction == containingMethodOrLambda) + if (currentFunction == (object)containingSymbol) { return false; } @@ -888,7 +887,7 @@ protected int MakeSlot(BoundExpression node) { var propAccess = (BoundPropertyAccess)node; - if (Binder.AccessingAutoPropertyFromConstructor(propAccess, this.currentMethodOrLambda)) + if (Binder.AccessingAutoPropertyFromConstructor(propAccess, this.currentMember)) { var propSymbol = propAccess.PropertySymbol; var backingField = (propSymbol as SourcePropertySymbol)?.BackingField; @@ -1090,7 +1089,7 @@ private bool IsAssigned(BoundExpression node, out int unassignedSlot) case BoundKind.PropertyAccess: { var propertyAccess = (BoundPropertyAccess)node; - if (Binder.AccessingAutoPropertyFromConstructor(propertyAccess, this.currentMethodOrLambda)) + if (Binder.AccessingAutoPropertyFromConstructor(propertyAccess, this.currentMember)) { var property = propertyAccess.PropertySymbol; var backingField = (property as SourcePropertySymbol)?.BackingField; @@ -1443,7 +1442,7 @@ private void EnterParameters(ImmutableArray parameters) protected virtual void EnterParameter(ParameterSymbol parameter) { - if (parameter.RefKind == RefKind.Out && !this.currentMethodOrLambda.IsAsync) // out parameters not allowed in async + if (parameter.RefKind == RefKind.Out && !(this.currentMember is MethodSymbol currentMethod && currentMethod.IsAsync)) // out parameters not allowed in async { int slot = GetOrCreateSlot(parameter); if (slot > 0) SetSlotState(slot, initiallyAssignedVariables?.Contains(parameter) == true); @@ -1750,9 +1749,9 @@ public override BoundNode VisitLocal(BoundLocal node) LocalSymbol localSymbol = node.LocalSymbol; CheckAssigned(localSymbol, node.Syntax); - if (localSymbol.IsFixed && - (this.currentMethodOrLambda.MethodKind == MethodKind.AnonymousFunction || - this.currentMethodOrLambda.MethodKind == MethodKind.LocalFunction) && + if (localSymbol.IsFixed && this.currentMember is MethodSymbol currentMethod && + (currentMethod.MethodKind == MethodKind.AnonymousFunction || + currentMethod.MethodKind == MethodKind.LocalFunction) && _capturedVariables.Contains(localSymbol)) { Diagnostics.Add(ErrorCode.ERR_FixedLocalInLambda, new SourceLocation(node.Syntax), localSymbol); @@ -1830,8 +1829,8 @@ public override BoundNode VisitMethodGroup(BoundMethodGroup node) public override BoundNode VisitLambda(BoundLambda node) { - var oldMethodOrLambda = this.currentMethodOrLambda; - this.currentMethodOrLambda = node.Symbol; + var oldMember = this.currentMember; + this.currentMember = node.Symbol; var oldPending = SavePending(); // we do not support branches into a lambda @@ -1866,7 +1865,7 @@ public override BoundNode VisitLambda(BoundLambda node) this.State = stateAfterLambda; - this.currentMethodOrLambda = oldMethodOrLambda; + this.currentMember = oldMember; return null; } @@ -2189,7 +2188,7 @@ public override BoundNode VisitFieldAccess(BoundFieldAccess node) public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { var result = base.VisitPropertyAccess(node); - if (Binder.AccessingAutoPropertyFromConstructor(node, this.currentMethodOrLambda)) + if (Binder.AccessingAutoPropertyFromConstructor(node, this.currentMember)) { var property = node.PropertySymbol; var backingField = (property as SourcePropertySymbol)?.BackingField; diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs index 5390469a10a1f..3f4144487ce9e 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs @@ -66,7 +66,7 @@ private ReadWriteWalker(CSharpCompilation compilation, Symbol member, BoundNode protected override void EnterRegion() { - for (MethodSymbol m = this.currentMethodOrLambda; (object)m != null; m = m.ContainingSymbol as MethodSymbol) + for (var m = this.currentMember as MethodSymbol; (object)m != null; m = m.ContainingSymbol as MethodSymbol) { foreach (var p in m.Parameters) { diff --git a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs index 8922fbd4f7f0f..75fa3796abeaf 100644 --- a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs @@ -6152,6 +6152,83 @@ event EventHandler MyEvent Assert.Equal("this, value", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); } + [Fact] + [WorkItem(27969, "https://github.com/dotnet/roslyn/issues/27969")] + public void CodeInInitializer01() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(@" +using System; +class C +{ + object P { get; } = Create(nameof(P), /**/x => true/**/); + + static object Create(string name, Func f) => throw null; +} +"); + var dataFlowAnalysisResults = analysisResults; + Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); + Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); + } + + [Fact] + [WorkItem(27969, "https://github.com/dotnet/roslyn/issues/27969")] + public void CodeInInitializer02() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(@" +using System; +class C +{ + object P { get; } = Create(P, /**/x => true/**/); + + static object Create(object name, Func f) => throw null; +} +"); + var dataFlowAnalysisResults = analysisResults; + Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); + Assert.Equal("x", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); + } + + [Fact] + [WorkItem(19845, "https://github.com/dotnet/roslyn/issues/19845")] + public void CodeInInitializer03() + { + var analysisResults = CompileAndAnalyzeDataFlowExpression(@" +class C { + static int X { get; set; } + int Y = /**/X/**/; +}"); + var dataFlowAnalysisResults = analysisResults; + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.AlwaysAssigned)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.Captured)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.CapturedOutside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); + Assert.Equal(null, GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); + } + #endregion } } From 9648253753f0fa07176065e21f1d8bbbc619c4ba Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Tue, 3 Jul 2018 12:48:01 -0700 Subject: [PATCH 2/2] Minor changes per code review. --- .../DataFlowPass.LocalFunctions.cs | 10 ++--- .../Portable/FlowAnalysis/DataFlowPass.cs | 38 +++++++++---------- .../Portable/FlowAnalysis/ReadWriteWalker.cs | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs index 4d4ac2496c6f9..e0fd98222dcca 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs @@ -118,9 +118,9 @@ private int RootSlot(int slot) public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc) { - var oldMember = this.currentMember; + var oldSymbol = this.currentSymbol; var localFuncSymbol = localFunc.Symbol; - this.currentMember = localFuncSymbol; + this.currentSymbol = localFuncSymbol; var oldPending = SavePending(); // we do not support branches into a lambda @@ -205,14 +205,14 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen } this.State = savedState; - this.currentMember = oldMember; + this.currentSymbol = oldSymbol; return null; } private void RecordReadInLocalFunction(int slot) { - var localFunc = GetNearestLocalFunctionOpt(currentMember); + var localFunc = GetNearestLocalFunctionOpt(currentSymbol); Debug.Assert(localFunc != null); @@ -294,7 +294,7 @@ private bool IsCapturedInLocalFunction(int slot) // A variable is captured in a local function iff its // container is higher in the tree than the nearest // local function - var nearestLocalFunc = GetNearestLocalFunctionOpt(currentMember); + var nearestLocalFunc = GetNearestLocalFunctionOpt(currentSymbol); return !(nearestLocalFunc is null) && IsCaptured(rootSymbol, nearestLocalFunc); } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs index 5179f15266f6b..c413fb66dfa3c 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs @@ -116,7 +116,7 @@ internal partial class DataFlowPass : AbstractFlowPass /// /// Reflects the enclosing member or lambda at the current location (in the bound tree). /// - protected Symbol currentMember { get; private set; } + protected Symbol currentSymbol { get; private set; } /// /// A cache for remember which structs are empty. @@ -160,7 +160,7 @@ internal DataFlowPass( { this.initiallyAssignedVariables = null; _sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly; - this.currentMember = member; + this.currentSymbol = member; _unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes; bool strict = compilation.FeatureStrictEnabled; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility _emptyStructTypeCache = new EmptyStructTypeCache(compilation, !strict); @@ -179,7 +179,7 @@ internal DataFlowPass( { this.initiallyAssignedVariables = initiallyAssignedVariables; _sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly; - this.currentMember = member; + this.currentSymbol = member; _unassignedVariableAddressOfSyntaxes = null; bool strict = compilation.FeatureStrictEnabled; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility _emptyStructTypeCache = emptyStructs ?? new EmptyStructTypeCache(compilation, !strict); @@ -203,7 +203,7 @@ internal DataFlowPass( { this.initiallyAssignedVariables = initiallyAssignedVariables; _sourceAssembly = null; - this.currentMember = member; + this.currentSymbol = member; _unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes; _emptyStructTypeCache = new NeverEmptyStructTypeCache(); } @@ -262,16 +262,16 @@ protected override ImmutableArray RemoveReturns() { var result = base.RemoveReturns(); - if (currentMember is MethodSymbol currentMethod && currentMethod.IsAsync && !currentMethod.IsImplicitlyDeclared) + if (currentSymbol is MethodSymbol currentMethod && currentMethod.IsAsync && !currentMethod.IsImplicitlyDeclared) { var foundAwait = result.Any(pending => pending.Branch?.Kind == BoundKind.AwaitExpression); if (!foundAwait) { // If we're on a LambdaSymbol, then use its 'DiagnosticLocation'. That will be // much better than using its 'Location' (which is the entire span of the lambda). - var diagnosticLocation = currentMember is LambdaSymbol lambda + var diagnosticLocation = currentSymbol is LambdaSymbol lambda ? lambda.DiagnosticLocation - : currentMember.Locations[0]; + : currentSymbol.Locations[0]; Diagnostics.Add(ErrorCode.WRN_AsyncLacksAwaits, diagnosticLocation); } @@ -282,7 +282,7 @@ protected override ImmutableArray RemoveReturns() protected virtual void ReportUnassignedOutParameter(ParameterSymbol parameter, SyntaxNode node, Location location) { - if (!_requireOutParamsAssigned && topLevelMethod == (object)currentMember) + if (!_requireOutParamsAssigned && ReferenceEquals(topLevelMethod, currentSymbol)) { return; } @@ -398,7 +398,7 @@ protected void Analyze(ref bool badRegion, DiagnosticBag diagnostics) /// If variable.Kind is RangeVariable, its underlying lambda parameter. Else null. private void CheckCaptured(Symbol variable, ParameterSymbol rangeVariableUnderlyingParameter = null) { - if (IsCaptured(rangeVariableUnderlyingParameter ?? variable, currentMember)) + if (IsCaptured(rangeVariableUnderlyingParameter ?? variable, currentSymbol)) { NoteCaptured(variable); } @@ -435,10 +435,10 @@ private static bool IsCaptured(Symbol variable, Symbol containingSymbol) // case the variable is not captured by the target function, or null, in which // case it is. for (var currentFunction = variable.ContainingSymbol; - currentFunction != null; + (object)currentFunction != null; currentFunction = currentFunction.ContainingSymbol) { - if (currentFunction == (object)containingSymbol) + if (ReferenceEquals(currentFunction, containingSymbol)) { return false; } @@ -887,7 +887,7 @@ protected int MakeSlot(BoundExpression node) { var propAccess = (BoundPropertyAccess)node; - if (Binder.AccessingAutoPropertyFromConstructor(propAccess, this.currentMember)) + if (Binder.AccessingAutoPropertyFromConstructor(propAccess, this.currentSymbol)) { var propSymbol = propAccess.PropertySymbol; var backingField = (propSymbol as SourcePropertySymbol)?.BackingField; @@ -1089,7 +1089,7 @@ private bool IsAssigned(BoundExpression node, out int unassignedSlot) case BoundKind.PropertyAccess: { var propertyAccess = (BoundPropertyAccess)node; - if (Binder.AccessingAutoPropertyFromConstructor(propertyAccess, this.currentMember)) + if (Binder.AccessingAutoPropertyFromConstructor(propertyAccess, this.currentSymbol)) { var property = propertyAccess.PropertySymbol; var backingField = (property as SourcePropertySymbol)?.BackingField; @@ -1442,7 +1442,7 @@ private void EnterParameters(ImmutableArray parameters) protected virtual void EnterParameter(ParameterSymbol parameter) { - if (parameter.RefKind == RefKind.Out && !(this.currentMember is MethodSymbol currentMethod && currentMethod.IsAsync)) // out parameters not allowed in async + if (parameter.RefKind == RefKind.Out && !(this.currentSymbol is MethodSymbol currentMethod && currentMethod.IsAsync)) // out parameters not allowed in async { int slot = GetOrCreateSlot(parameter); if (slot > 0) SetSlotState(slot, initiallyAssignedVariables?.Contains(parameter) == true); @@ -1749,7 +1749,7 @@ public override BoundNode VisitLocal(BoundLocal node) LocalSymbol localSymbol = node.LocalSymbol; CheckAssigned(localSymbol, node.Syntax); - if (localSymbol.IsFixed && this.currentMember is MethodSymbol currentMethod && + if (localSymbol.IsFixed && this.currentSymbol is MethodSymbol currentMethod && (currentMethod.MethodKind == MethodKind.AnonymousFunction || currentMethod.MethodKind == MethodKind.LocalFunction) && _capturedVariables.Contains(localSymbol)) @@ -1829,8 +1829,8 @@ public override BoundNode VisitMethodGroup(BoundMethodGroup node) public override BoundNode VisitLambda(BoundLambda node) { - var oldMember = this.currentMember; - this.currentMember = node.Symbol; + var oldSymbol = this.currentSymbol; + this.currentSymbol = node.Symbol; var oldPending = SavePending(); // we do not support branches into a lambda @@ -1865,7 +1865,7 @@ public override BoundNode VisitLambda(BoundLambda node) this.State = stateAfterLambda; - this.currentMember = oldMember; + this.currentSymbol = oldSymbol; return null; } @@ -2188,7 +2188,7 @@ public override BoundNode VisitFieldAccess(BoundFieldAccess node) public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { var result = base.VisitPropertyAccess(node); - if (Binder.AccessingAutoPropertyFromConstructor(node, this.currentMember)) + if (Binder.AccessingAutoPropertyFromConstructor(node, this.currentSymbol)) { var property = node.PropertySymbol; var backingField = (property as SourcePropertySymbol)?.BackingField; diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs index 3f4144487ce9e..1cd1d1516836d 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs @@ -66,7 +66,7 @@ private ReadWriteWalker(CSharpCompilation compilation, Symbol member, BoundNode protected override void EnterRegion() { - for (var m = this.currentMember as MethodSymbol; (object)m != null; m = m.ContainingSymbol as MethodSymbol) + for (var m = this.currentSymbol as MethodSymbol; (object)m != null; m = m.ContainingSymbol as MethodSymbol) { foreach (var p in m.Parameters) {