| File: Lowering\Diagnostics\DiagnosticsPass.vb | Web Access |
| Project: src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic) |
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports System Imports System.Collections.Generic Imports System.Diagnostics Imports System.Linq Imports System.Runtime.InteropServices Imports System.Text Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Utilities Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend NotInheritable Class DiagnosticsPass Inherits BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator Private ReadOnly _diagnostics As DiagnosticBag Private ReadOnly _compilation As VisualBasicCompilation Private _containingSymbol As MethodSymbol Private _withExpressionPlaceholderMap As Dictionary(Of BoundValuePlaceholderBase, BoundWithStatement) Private _expressionsBeingVisited As Stack(Of BoundExpression) Private _insideNameof As Boolean = False Private _inExpressionLambda As Boolean Public Shared Sub IssueDiagnostics(node As BoundNode, diagnostics As DiagnosticBag, containingSymbol As MethodSymbol) Debug.Assert(node IsNot Nothing) Debug.Assert(containingSymbol IsNot Nothing) Try Dim diagnosticPass As New DiagnosticsPass(containingSymbol.DeclaringCompilation, diagnostics, containingSymbol) diagnosticPass.Visit(node) Catch ex As CancelledByStackGuardException ex.AddAnError(diagnostics) End Try End Sub Private Sub New(compilation As VisualBasicCompilation, diagnostics As DiagnosticBag, containingSymbol As MethodSymbol) Me._compilation = compilation Me._diagnostics = diagnostics Me._containingSymbol = containingSymbol Me._inExpressionLambda = False End Sub Private ReadOnly Property IsInExpressionLambda As Boolean Get Return Me._inExpressionLambda End Get End Property Public Overrides Function VisitQueryLambda(node As BoundQueryLambda) As BoundNode Dim save_containingSymbol = Me._containingSymbol Me._containingSymbol = node.LambdaSymbol Me.Visit(node.Expression) Me._containingSymbol = save_containingSymbol Return Nothing End Function Public Overrides Function VisitParameter(node As BoundParameter) As BoundNode Dim parameterSymbol As ParameterSymbol = node.ParameterSymbol If parameterSymbol.IsByRef Then ' cannot access ByRef parameters in Lambdas Dim parameterSymbolContainingSymbol As Symbol = parameterSymbol.ContainingSymbol If _containingSymbol IsNot parameterSymbolContainingSymbol AndAlso Not _insideNameof Then ' Need to go up the chain of containers and see if the last lambda we see ' is a QueryLambda, before we reach parameter's container. If Binder.IsTopMostEnclosingLambdaAQueryLambda(_containingSymbol, parameterSymbolContainingSymbol) Then Binder.ReportDiagnostic(Me._diagnostics, node.Syntax, ERRID.ERR_CannotLiftByRefParamQuery1, parameterSymbol.Name) Else Binder.ReportDiagnostic(Me._diagnostics, node.Syntax, ERRID.ERR_CannotLiftByRefParamLambda1, parameterSymbol.Name) End If End If End If Return MyBase.VisitParameter(node) End Function Public Overrides Function VisitMeReference(node As BoundMeReference) As BoundNode Dim errorId As ERRID = GetMeAccessError() If errorId <> ERRID.ERR_None Then Binder.ReportDiagnostic(Me._diagnostics, node.Syntax, errorId) End If Return MyBase.VisitMeReference(node) End Function Public Overrides Function VisitMyClassReference(node As BoundMyClassReference) As BoundNode Dim errorId As ERRID = GetMeAccessError() If errorId <> ERRID.ERR_None Then Binder.ReportDiagnostic(Me._diagnostics, node.Syntax, errorId) End If Return MyBase.VisitMyClassReference(node) End Function Private Function GetMeAccessError() As ERRID Dim meParameter As ParameterSymbol = Me._containingSymbol.MeParameter If meParameter IsNot Nothing AndAlso meParameter.IsByRef Then If _containingSymbol.MethodKind = MethodKind.LambdaMethod Then ' Need to go up the chain of containers and see if the last lambda we see ' is a QueryLambda, before we reach a type member. If Binder.IsTopMostEnclosingLambdaAQueryLambda(_containingSymbol, Nothing) Then Return ERRID.ERR_CannotLiftStructureMeQuery Else Return ERRID.ERR_CannotLiftStructureMeLambda End If End If End If Return ERRID.ERR_None End Function Public Overrides Function VisitWithRValueExpressionPlaceholder(node As BoundWithRValueExpressionPlaceholder) As BoundNode CheckMeAccessInWithExpression(node) Return MyBase.VisitWithRValueExpressionPlaceholder(node) End Function Private Sub CheckMeAccessInWithExpression(node As BoundValuePlaceholderBase) Dim trackedWithStatement As BoundWithStatement = Nothing If _withExpressionPlaceholderMap IsNot Nothing AndAlso _withExpressionPlaceholderMap.TryGetValue(node, trackedWithStatement) Then Dim withBlockBinder As WithBlockBinder = trackedWithStatement.Binder If withBlockBinder.ContainingMember IsNot _containingSymbol Then ' If With statement expression is accessed from a different symbol, ' we need to check for value-typed Me reference being lifted If Not withBlockBinder.IsInLambda Then Debug.Assert(_containingSymbol.IsLambdaMethod) ' What else can it be? Dim containingType = withBlockBinder.ContainingType If containingType IsNot Nothing AndAlso containingType.IsValueType AndAlso withBlockBinder.Info.ExpressionHasByRefMeReference(RecursionDepth) Then Dim errorId As ERRID = GetMeAccessError() If errorId <> ERRID.ERR_None Then ' The placeholder node will actually use syntax from With statement and it might have some wrappers and conversions on top of it with the same syntax. ' Let's use syntax of parent node instead. Dim errorSyntax As SyntaxNode = node.Syntax For Each expr In _expressionsBeingVisited If expr.Syntax IsNot errorSyntax Then errorSyntax = expr.Syntax Exit For End If Next Binder.ReportDiagnostic(Me._diagnostics, errorSyntax, errorId) End If End If End If End If End If End Sub Public Overrides Function VisitWithStatement(node As BoundWithStatement) As BoundNode Me.Visit(node.OriginalExpression) Dim info As WithBlockBinder.WithBlockInfo = node.Binder.Info If info IsNot Nothing AndAlso info.ExpressionIsAccessedFromNestedLambda Then If _withExpressionPlaceholderMap Is Nothing Then _withExpressionPlaceholderMap = New Dictionary(Of BoundValuePlaceholderBase, BoundWithStatement)() _expressionsBeingVisited = New Stack(Of BoundExpression)() End If Debug.Assert(info.ExpressionPlaceholder IsNot Nothing) _withExpressionPlaceholderMap.Add(info.ExpressionPlaceholder, node) Else info = Nothing End If Me.Visit(node.Body) If info IsNot Nothing Then _withExpressionPlaceholderMap.Remove(info.ExpressionPlaceholder) End If Return Nothing End Function Public Overrides Function VisitNameOfOperator(node As BoundNameOfOperator) As BoundNode _insideNameof = True Dim r = MyBase.VisitNameOfOperator(node) _insideNameof = False Return r End Function Public Overrides Function Visit(node As BoundNode) As BoundNode Dim pop As Boolean = False If _withExpressionPlaceholderMap IsNot Nothing AndAlso _withExpressionPlaceholderMap.Count > 0 Then Dim expr = TryCast(node, BoundExpression) If expr IsNot Nothing Then _expressionsBeingVisited.Push(expr) pop = True End If End If Dim result = MyBase.Visit(node) If pop Then Debug.Assert(_expressionsBeingVisited.Peek Is node) _expressionsBeingVisited.Pop() End If Return result End Function End Class End Namespace