提交 42097417 编写于 作者: T TomasMatousek

Implements EnC support for VB array-initialized fields (e.g. Dim a(10) As Integer).

     Fixes various issues around fields with shared initializers (e.g. Dim a,b As New C()) and auto-properties with AsNew clause (e.g. Property P As New C()).

     Makes breakpoint spans (IDE) consistent with sequence points (compiler) and makes sequence points for various forms of field and property initializers also more consistent with each other.
     Specifically:

     before:                                                                                  after:
     <A>Dim [|F As Integer = 1|]                                              <A>Dim [|F As Integer = 1|]                                         (no change)
     [|<A>Property P As Integer = 1 Implements I.P|]           <A>Property [|P As Integer = 1|] Implements I.P     (changed to match fields)

     Dim [|F|], [|G|] As Integer = 1                                              Dim [|F|], [|G|] As Integer = 1                                       (no change)
     Dim [|F(1), G(1) As Integer|]                                                Dim [|F(1)|], [|G(1)|] As Integer                                    (change to match fields with shared AsNew clause)
 (changeset 1210991)
上级 9c6d6537
......@@ -521,6 +521,16 @@ Public MustInherit Class BasicTestBaseBase
Return XElement.Parse(TestBase.GetPdbXml(compilation, methodName))
End Function
Public Shared Shadows Function GetSequencePoints(pdbXml As XElement) As XElement
Return <sequencePoints>
<%= From entry In pdbXml.<methods>.<method>.<sequencepoints>.<entry>
Select <entry start_row=<%= entry.@start_row %>
start_column=<%= entry.@start_column %>
end_row=<%= entry.@end_row %>
end_column=<%= entry.@end_column %>/> %>
</sequencePoints>
End Function
Public Shared ReadOnly ClassesWithReadWriteProperties As XCData = <![CDATA[
.class public auto ansi beforefieldinit B
extends [mscorlib]System.Object
......
......@@ -161,51 +161,46 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' declaration with "AsNew" and multiple variable names. The final rewriting will during local rewriting.
''' The statement list returned by this function can be copied into all constructors without reprocessing it.
''' </remarks>
Private Shared Function RewriteInitializersAsStatements(
constructor As MethodSymbol,
boundInitializers As ImmutableArray(Of BoundInitializer)
) As ImmutableArray(Of BoundStatement)
Private Shared Function RewriteInitializersAsStatements(constructor As MethodSymbol,
boundInitializers As ImmutableArray(Of BoundInitializer)) As ImmutableArray(Of BoundStatement)
Debug.Assert(Not boundInitializers.IsEmpty)
Dim boundStatements(boundInitializers.Length - 1) As BoundStatement
For i = 0 To boundStatements.Length - 1
Dim init = boundInitializers(i)
Dim boundStatements = ArrayBuilder(Of BoundStatement).GetInstance(boundInitializers.Length)
For Each init In boundInitializers
Select Case init.Kind
Case BoundKind.FieldOrPropertyInitializer
boundStatements(i) = init
boundStatements.Add(init)
Case BoundKind.GlobalStatementInitializer
Dim stmtInit = DirectCast(init, BoundGlobalStatementInitializer)
Dim syntax = init.Syntax
If constructor.IsSubmissionConstructor AndAlso i = boundStatements.Length - 1 AndAlso stmtInit.Statement.Kind = BoundKind.ExpressionStatement Then
If constructor.IsSubmissionConstructor AndAlso init Is boundInitializers.Last AndAlso stmtInit.Statement.Kind = BoundKind.ExpressionStatement Then
Dim submissionResultVariable = New BoundParameter(syntax, constructor.Parameters(1), constructor.Parameters(1).Type)
Dim expr = DirectCast(stmtInit.Statement, BoundExpressionStatement).Expression
Debug.Assert(expr.Type IsNot Nothing)
If expr.Type.SpecialType <> SpecialType.System_Void Then
boundStatements(i) = New BoundExpressionStatement(
boundStatements.Add(New BoundExpressionStatement(
syntax,
New BoundAssignmentOperator(
syntax,
submissionResultVariable,
expr,
False,
expr.Type))
expr.Type)))
Exit Select
End If
End If
boundStatements(i) = stmtInit.Statement
boundStatements.Add(stmtInit.Statement)
Case Else
Throw ExceptionUtilities.UnexpectedValue(init.Kind)
End Select
Next
Return boundStatements.AsImmutableOrNull()
Return boundStatements.ToImmutableAndFree()
End Function
''' <summary>
......
......@@ -249,8 +249,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim initializer = New BoundFieldOrPropertyInitializer(syntax,
ImmutableArray.Create(Of Symbol)(fieldSymbol),
boundFieldAccessExpression,
arrayCreation,
asNewSyntaxNodesOpt:=Nothing)
arrayCreation)
initializer.SetWasCompilerGenerated()
boundInitializers.Add(initializer)
......@@ -303,33 +302,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
asNewVariablePlaceholder,
diagnostics)
Dim asNewSyntaxNodes As ImmutableArray(Of SyntaxNode) = Nothing
Dim fieldSymbolCount = fieldSymbols.Length
Dim hasErrors = False
If fieldSymbolCount > 1 Then
Debug.Assert(fieldSymbolCount = DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names.Count)
Dim variableNames = DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names
Dim identifiers(fieldSymbolCount - 1) As SyntaxNode
For variableNameIndex = 0 To fieldSymbols.Length - 1
Dim name = variableNames(variableNameIndex)
If fieldSymbols.Length > 1 Then
Debug.Assert(fieldSymbols.Length = DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names.Count)
For Each name In DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names
If Not (name.ArrayRankSpecifiers.IsEmpty AndAlso name.ArrayBounds Is Nothing) Then
' Arrays cannot be declared with AsNew syntax
ReportDiagnostic(diagnostics, name, ERRID.ERR_AsNewArray)
hasErrors = True
End If
identifiers(variableNameIndex) = name
Next
asNewSyntaxNodes = identifiers.AsImmutableOrNull
End If
boundInitializers.Add(New BoundFieldOrPropertyInitializer(equalsValueOrAsNewSyntax,
fieldSymbols,
If(fieldSymbolCount = 1, fieldAccess, Nothing),
boundInitExpression,
asNewSyntaxNodes,
hasErrors))
boundInitializers.Add(New BoundFieldOrPropertyInitializer(
equalsValueOrAsNewSyntax,
fieldSymbols,
If(fieldSymbols.Length = 1, fieldAccess, Nothing),
boundInitExpression,
hasErrors))
End Sub
Friend Sub BindPropertyInitializer(
......@@ -380,8 +371,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
boundInitializers.Add(New BoundFieldOrPropertyInitializer(initValueOrAsNewNode,
ImmutableArray.Create(Of Symbol)(propertySymbol),
boundPropertyOrFieldAccess,
boundInitExpression,
asNewSyntaxNodesOpt:=Nothing))
boundInitExpression))
End Sub
......@@ -472,8 +462,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
boundInitializers.Add(New BoundFieldOrPropertyInitializer(equalsValueOrAsNewSyntax,
ImmutableArray.Create(Of Symbol)(fieldSymbol),
boundFieldAccessExpr,
boundInitValue,
asNewSyntaxNodesOpt:=Nothing))
boundInitValue))
End If
End Sub
......
......@@ -944,11 +944,6 @@
<!-- the expression representing the initial value -->
<Field Name="InitialValue" Type="BoundExpression" Null="disallow"/>
<!-- In case of multiple symbols in InitializedSymbols, this array contains a syntax node for each symbol to be used
e.g. in sequence points. This is needed because there is a different span for each variable of an AsNew
declaration. -->
<Field Name="AsNewSyntaxNodesOpt" Type="ImmutableArray(Of SyntaxNode)" Null="allow" />
</Node>
<!--
......
' Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.Text
......@@ -24,15 +25,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' rewriters because here we already have the infrastructure to replace placeholders.
''' </summary>
Public Overrides Function VisitFieldOrPropertyInitializer(node As BoundFieldOrPropertyInitializer) As BoundNode
Dim initializedSymbolsCount = node.InitializedSymbols.Length
Dim statements(initializedSymbolsCount - 1) As BoundStatement
Dim syntax = node.Syntax
Debug.Assert(
syntax.IsKind(SyntaxKind.AsNewClause) OrElse ' Dim a As New C(); Dim a,b As New C(); Property P As New C()
syntax.IsKind(SyntaxKind.ModifiedIdentifier) OrElse ' Dim a(1) As Integer
syntax.IsKind(SyntaxKind.EqualsValue)) ' Dim a = 1; Property P As Integer = 1
Dim initializedSymbols = node.InitializedSymbols
Dim rewrittenStatements = ArrayBuilder(Of BoundStatement).GetInstance(initializedSymbols.Length)
' it's enough to create one me reference if the symbols are not shared that gets reused for all following rewritings.
Dim meReferenceOpt As BoundExpression = Nothing
If Not node.InitializedSymbols.First.IsShared Then
If Not initializedSymbols.First.IsShared Then
' create me reference if needed
Debug.Assert(currentMethodOrLambda IsNot Nothing)
meReferenceOpt = New BoundMeReference(node.Syntax, currentMethodOrLambda.ContainingType)
meReferenceOpt = New BoundMeReference(syntax, currentMethodOrLambda.ContainingType)
meReferenceOpt.SetWasCompilerGenerated()
End If
......@@ -47,17 +55,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
End If
For symbolIndex = 0 To initializedSymbolsCount - 1
For symbolIndex = 0 To initializedSymbols.Length - 1
Dim symbol = node.InitializedSymbols(symbolIndex)
Debug.Assert(node.AsNewSyntaxNodesOpt.IsDefault OrElse initializedSymbolsCount > 1)
Dim syntaxForSequencePoint = If(initializedSymbolsCount > 1, node.AsNewSyntaxNodesOpt(symbolIndex), node.Syntax.Parent)
Dim accessExpression As BoundExpression
' if there are more than one symbol we need to create a field access for each of them
If initializedSymbolsCount > 1 Then
If initializedSymbols.Length > 1 Then
Dim fieldSymbol = DirectCast(symbol, FieldSymbol)
accessExpression = New BoundFieldAccess(node.Syntax, meReferenceOpt, fieldSymbol, True, fieldSymbol.Type)
accessExpression = New BoundFieldAccess(syntax, meReferenceOpt, fieldSymbol, True, fieldSymbol.Type)
Else
Debug.Assert(node.MemberAccessExpressionOpt IsNot Nothing)
......@@ -78,17 +83,56 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
RemovePlaceholderReplacement(objectInitializer.PlaceholderOpt)
Else
' in all other cases we want the initial value be assigned to the member (field or property)
rewrittenStatement = DirectCast(Visit(New BoundAssignmentOperator(DirectCast(syntaxForSequencePoint, VisualBasicSyntaxNode),
accessExpression,
node.InitialValue,
False).ToStatement), BoundStatement)
rewrittenStatement = VisitExpression(New BoundAssignmentOperator(syntax,
accessExpression,
node.InitialValue,
suppressObjectClone:=False)).ToStatement
rewrittenStatement = MarkInitializerSequencePoint(rewrittenStatement, syntax, symbolIndex)
End If
statements(symbolIndex) = rewrittenStatement
rewrittenStatements.Add(rewrittenStatement)
Next
Return New BoundStatementList(node.Syntax, statements.AsImmutableOrNull)
Return New BoundStatementList(node.Syntax, rewrittenStatements.ToImmutableAndFree())
End Function
Private Function MarkInitializerSequencePoint(rewrittenStatement As BoundStatement, syntax As VisualBasicSyntaxNode, nameIndex As Integer) As BoundStatement
If Not GenerateDebugInfo Then
Return rewrittenStatement
End If
If syntax.Parent.IsKind(SyntaxKind.PropertyStatement) Then
' Property [|P As Integer = 1|] Implements I.P
' Property [|P As New Integer|] Implements I.P
Dim propertyStatement = DirectCast(syntax.Parent, PropertyStatementSyntax)
Dim span = TextSpan.FromBounds(propertyStatement.Identifier.SpanStart,
If(propertyStatement.Initializer Is Nothing, propertyStatement.AsClause.Span.End, propertyStatement.Initializer.Span.End))
Return New BoundSequencePointWithSpan(syntax, rewrittenStatement, span)
End If
If syntax.IsKind(SyntaxKind.AsNewClause) Then
Dim declarator = DirectCast(syntax.Parent, VariableDeclaratorSyntax)
If declarator.Names.Count > 1 Then
' Dim [|a|], b As New C()
Return New BoundSequencePoint(declarator.Names(nameIndex), rewrittenStatement)
Else
' Dim [|a As New C()|]
Return New BoundSequencePoint(syntax.Parent, rewrittenStatement)
End If
End If
If syntax.IsKind(SyntaxKind.ModifiedIdentifier) Then
Debug.Assert(DirectCast(syntax, ModifiedIdentifierSyntax).ArrayBounds IsNot Nothing)
' Dim [|a(1)|] As Integer
Return New BoundSequencePoint(syntax, rewrittenStatement)
End If
' Dim [|a = 1|]
Debug.Assert(syntax.IsKind(SyntaxKind.EqualsValue))
Return New BoundSequencePoint(syntax.Parent, rewrittenStatement)
End Function
End Class
End Namespace
......@@ -172,6 +172,7 @@
<Compile Include="PDB\PDBCollectionInitializerTests.vb" />
<Compile Include="PDB\PDBConstLocalTests.vb" />
<Compile Include="PDB\PDBExternalSourceDirectiveTests.vb" />
<Compile Include="PDB\PDBFieldAndPropertyInitializerTests.vb" />
<Compile Include="PDB\PDBIteratorTests.vb" />
<Compile Include="PDB\PDBLoopStatementTests.vb" />
<Compile Include="PDB\PDBNamespaceScopes.vb" />
......
......@@ -3564,6 +3564,58 @@ End Module
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, method0, method1)))
End Sub
<WorkItem(849649)>
<Fact>
Public Sub Bug849649()
Dim source0 =
<compilation>
<file name="a.vb">
Module M
Sub F()
Dim x(5) As Integer
x(3) = 2
End Sub
End Module
</file>
</compilation>
Dim source1 =
<compilation>
<file name="a.vb">
Module M
Sub F()
Dim x(5) As Integer
x(3) = 3
End Sub
End Module
</file>
</compilation>
Dim compilation0 = CreateCompilationWithMscorlibAndVBRuntime(source0, UnoptimizedDll)
Dim compilation1 = CreateCompilationWithMscorlibAndVBRuntime(source1, UnoptimizedDll)
Dim bytes0 = compilation0.EmitToArray(debug:=True)
Dim method0 = compilation0.GetMember(Of MethodSymbol)("M.F")
Dim method1 = compilation1.GetMember(Of MethodSymbol)("M.F")
Dim generation0 = EmitBaseline.CreateInitialBaseline(ModuleMetadata.CreateFromImage(bytes0), Function(m) ImmutableArray(Of String).Empty)
Dim diff0 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, method0, method1, GetLocalMap(method1, method0), preserveLocalVariables:=True)))
diff0.VerifyIL("
{
// Code size 13 (0xd)
.maxstack 3
IL_0000: nop
IL_0001: ldc.i4.6
IL_0002: newarr 0x01000008
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.3
IL_000a: ldc.i4.3
IL_000b: stelem.i4
IL_000c: ret
}")
End Sub
#End Region
#Region "Helpers"
......
' Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.PDB
Public Class PDBFieldAndPropertyInitializerTests
Inherits BasicTestBase
<Fact>
Public Sub PartialClass()
Dim source =
<compilation>
<file name="a.vb">
Option strict on
imports system
partial Class C1
public f1 as integer = 23
public f3 As New C1()
public f4, f5 As New C1()
Public sub DumpFields()
Console.WriteLine(f1)
Console.WriteLine(f2)
End Sub
Public shared Sub Main(args() as string)
Dim c as new C1
c.DumpFields()
End sub
End Class
</file>
<file name="b.vb">
Option strict on
imports system
partial Class C1
' more lines to see a different span in the sequence points ...
public f2 as integer = 42
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlibAndVBRuntime(source, OptionsExe.WithOptimizations(False))
Dim actual = GetPdbXml(compilation, "C1..ctor")
Dim expected =
<symbols>
<files>
<file id="1" name="a.vb" language="3a12d0b8-c26c-11d0-b442-00a0244a1dd2" languageVendor="994b45c4-e6e9-11d2-903f-00c04fa302a1" documentType="5a869d0b-6611-11d3-bd2a-0000f80849bd"/>
<file id="2" name="b.vb" language="3a12d0b8-c26c-11d0-b442-00a0244a1dd2" languageVendor="994b45c4-e6e9-11d2-903f-00c04fa302a1" documentType="5a869d0b-6611-11d3-bd2a-0000f80849bd"/>
</files>
<entryPoint declaringType="C1" methodName="Main" parameterNames="args"/>
<methods>
<method containingType="C1" name=".ctor" parameterNames="">
<sequencepoints total="6">
<entry il_offset="0x0" hidden="true" start_row="16707566" start_column="0" end_row="16707566" end_column="0" file_ref="1"/>
<entry il_offset="0x6" start_row="6" start_column="12" end_row="6" end_column="30" file_ref="1"/>
<entry il_offset="0xe" start_row="7" start_column="12" end_row="7" end_column="26" file_ref="1"/>
<entry il_offset="0x19" start_row="8" start_column="12" end_row="8" end_column="14" file_ref="1"/>
<entry il_offset="0x24" start_row="8" start_column="16" end_row="8" end_column="18" file_ref="1"/>
<entry il_offset="0x2f" start_row="11" start_column="36" end_row="11" end_column="54" file_ref="2"/>
</sequencepoints>
<locals/>
<scope startOffset="0x0" endOffset="0x38">
<namespace name="System" importlevel="file"/>
<currentnamespace name=""/>
</scope>
</method>
</methods>
</symbols>
AssertXmlEqual(expected, actual)
End Sub
<Fact>
Public Sub AutoProperty1()
Dim source =
<compilation>
<file name="a.vb">
Interface I
Property P As Integer
End Interface
Class C
Implements I
Property P As Integer = 1 Implements I.P
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlib(source)
compilation.VerifyDiagnostics()
Dim actual = GetSequencePoints(GetPdbXml(compilation, "C..ctor"))
Dim expectedStart1 = " Property ".Length + 1
Dim expectedEnd1 = " Property P As Integer = 1".Length + 1
Dim expected =
<sequencePoints>
<entry start_row="16707566" start_column="0" end_row="16707566" end_column="0"/>
<entry start_row="8" start_column=<%= expectedStart1 %> end_row="8" end_column=<%= expectedEnd1 %>/>
</sequencePoints>
AssertXmlEqual(expected, actual)
End Sub
<Fact>
Public Sub AutoProperty2()
Dim source =
<compilation>
<file name="a.vb">
Interface I
Property P As Object
End Interface
Class C
Implements I
Property P = 1 Implements I.P
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlib(source)
compilation.VerifyDiagnostics()
Dim actual = GetSequencePoints(GetPdbXml(compilation, "C..ctor"))
Dim expectedStart1 = " Property ".Length + 1
Dim expectedEnd1 = " Property P = 1".Length + 1
Dim expected =
<sequencePoints>
<entry start_row="16707566" start_column="0" end_row="16707566" end_column="0"/>
<entry start_row="8" start_column=<%= expectedStart1 %> end_row="8" end_column=<%= expectedEnd1 %>/>
</sequencePoints>
AssertXmlEqual(expected, actual)
End Sub
<Fact>
Public Sub AutoPropertyAsNew()
Dim source =
<compilation>
<file name="a.vb">
Interface I
Property P As Integer
End Interface
Class C
Implements I
Property P As New Integer Implements I.P
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlib(source)
compilation.VerifyDiagnostics()
Dim actual = GetSequencePoints(GetPdbXml(compilation, "C..ctor"))
Dim expectedStart1 = " Property ".Length + 1
Dim expectedEnd1 = " Property P As New Integer".Length + 1
Dim expected =
<sequencePoints>
<entry start_row="16707566" start_column="0" end_row="16707566" end_column="0"/>
<entry start_row="8" start_column=<%= expectedStart1 %> end_row="8" end_column=<%= expectedEnd1 %>/>
</sequencePoints>
AssertXmlEqual(expected, actual)
End Sub
<Fact>
Public Sub ArrayInitializedField()
Dim source =
<compilation>
<file name="a.vb">
Class C
Dim F(1), G(2) As Integer
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlib(source)
compilation.VerifyDiagnostics()
Dim actual = GetSequencePoints(GetPdbXml(compilation, "C..ctor"))
Dim expectedStart1 = " Dim ".Length + 1
Dim expectedEnd1 = " Dim F(1)".Length + 1
Dim expectedStart2 = " Dim F(1), ".Length + 1
Dim expectedEnd2 = " Dim F(1), G(2)".Length + 1
Dim expected =
<sequencePoints>
<entry start_row="16707566" start_column="0" end_row="16707566" end_column="0"/>
<entry start_row="2" start_column=<%= expectedStart1 %> end_row="2" end_column=<%= expectedEnd1 %>/>
<entry start_row="2" start_column=<%= expectedStart2 %> end_row="2" end_column=<%= expectedEnd2 %>/>
</sequencePoints>
AssertXmlEqual(expected, actual)
End Sub
<Fact>
Public Sub FieldAsNewMultiInitializer()
Dim source =
<compilation>
<file name="a.vb">
Class C
Dim F, G As New C()
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlib(source)
compilation.VerifyDiagnostics()
Dim actual = GetSequencePoints(GetPdbXml(compilation, "C..ctor"))
Dim expectedStart1 = " Dim ".Length + 1
Dim expectedEnd1 = " Dim F".Length + 1
Dim expectedStart2 = " Dim F, ".Length + 1
Dim expectedEnd2 = " Dim F, G".Length + 1
Dim expected =
<sequencePoints>
<entry start_row="16707566" start_column="0" end_row="16707566" end_column="0"/>
<entry start_row="2" start_column=<%= expectedStart1 %> end_row="2" end_column=<%= expectedEnd1 %>/>
<entry start_row="2" start_column=<%= expectedStart2 %> end_row="2" end_column=<%= expectedEnd2 %>/>
</sequencePoints>
AssertXmlEqual(expected, actual)
End Sub
<Fact>
Public Sub FieldAsNewSingleInitializer()
Dim source =
<compilation>
<file name="a.vb">
Class C
Dim F As New C()
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlib(source)
compilation.VerifyDiagnostics()
Dim actual = GetSequencePoints(GetPdbXml(compilation, "C..ctor"))
Dim expectedStart1 = " Dim ".Length + 1
Dim expectedEnd1 = " Dim F As New C()".Length + 1
Dim expected =
<sequencePoints>
<entry start_row="16707566" start_column="0" end_row="16707566" end_column="0"/>
<entry start_row="2" start_column=<%= expectedStart1 %> end_row="2" end_column=<%= expectedEnd1 %>/>
</sequencePoints>
AssertXmlEqual(expected, actual)
End Sub
<Fact>
Public Sub FieldInitializer()
Dim source =
<compilation>
<file name="a.vb">
Class C
Dim F = 1
End Class
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlib(source)
compilation.VerifyDiagnostics()
Dim actual = GetSequencePoints(GetPdbXml(compilation, "C..ctor"))
Dim expectedStart1 = " Dim ".Length + 1
Dim expectedEnd1 = " Dim F = 1".Length + 1
Dim expected =
<sequencePoints>
<entry start_row="16707566" start_column="0" end_row="16707566" end_column="0"/>
<entry start_row="2" start_column=<%= expectedStart1 %> end_row="2" end_column=<%= expectedEnd1 %>/>
</sequencePoints>
AssertXmlEqual(expected, actual)
End Sub
End Class
End Namespace
\ No newline at end of file
......@@ -1449,84 +1449,6 @@ End Module
AssertXmlEqual(expected, actual)
End Sub
<Fact()>
Public Sub TestPartialClassFieldInitializers()
Dim source =
<compilation>
<file name="a.vb">
Option strict on
imports system
partial Class C1
public f1 as integer = 23
public f3 As New C1()
public f4, f5 As New C1()
Public sub DumpFields()
Console.WriteLine(f1)
Console.WriteLine(f2)
End Sub
Public shared Sub Main(args() as string)
Dim c as new C1
c.DumpFields()
End sub
End Class
</file>
<file name="b.vb">
Option strict on
imports system
partial Class C1
' more lines to see a different span in the sequence points ...
public f2 as integer = 42
End Class
</file>
</compilation>
Dim compilation = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(
source,
OptionsExe.WithOptimizations(False))
Dim actual = GetPdbXml(compilation, "C1..ctor")
Dim expected =
<symbols>
<files>
<file id="1" name="a.vb" language="3a12d0b8-c26c-11d0-b442-00a0244a1dd2" languageVendor="994b45c4-e6e9-11d2-903f-00c04fa302a1" documentType="5a869d0b-6611-11d3-bd2a-0000f80849bd"/>
<file id="2" name="b.vb" language="3a12d0b8-c26c-11d0-b442-00a0244a1dd2" languageVendor="994b45c4-e6e9-11d2-903f-00c04fa302a1" documentType="5a869d0b-6611-11d3-bd2a-0000f80849bd"/>
</files>
<entryPoint declaringType="C1" methodName="Main" parameterNames="args"/>
<methods>
<method containingType="C1" name=".ctor" parameterNames="">
<sequencepoints total="6">
<entry il_offset="0x0" hidden="true" start_row="16707566" start_column="0" end_row="16707566" end_column="0" file_ref="1"/>
<entry il_offset="0x6" start_row="6" start_column="12" end_row="6" end_column="30" file_ref="1"/>
<entry il_offset="0xe" start_row="7" start_column="12" end_row="7" end_column="26" file_ref="1"/>
<entry il_offset="0x19" start_row="8" start_column="12" end_row="8" end_column="14" file_ref="1"/>
<entry il_offset="0x24" start_row="8" start_column="16" end_row="8" end_column="18" file_ref="1"/>
<entry il_offset="0x2f" start_row="11" start_column="36" end_row="11" end_column="54" file_ref="2"/>
</sequencepoints>
<locals/>
<scope startOffset="0x0" endOffset="0x38">
<namespace name="System" importlevel="file"/>
<currentnamespace name=""/>
</scope>
</method>
</methods>
</symbols>
AssertXmlEqual(expected, actual)
End Sub
<Fact()>
Public Sub TestImplicitLocals()
Dim source =
......
......@@ -105,27 +105,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
SyntaxKind.CatchStatement,
SyntaxKind.FinallyStatement,
SyntaxKind.EndTryStatement,
SyntaxKind.SubStatement,
SyntaxKind.SubNewStatement,
SyntaxKind.EndSubStatement,
SyntaxKind.FunctionStatement,
SyntaxKind.EndFunctionStatement,
SyntaxKind.OperatorStatement,
SyntaxKind.EndOperatorStatement,
SyntaxKind.GetAccessorStatement,
SyntaxKind.EndGetStatement,
SyntaxKind.SetAccessorStatement,
SyntaxKind.EndSetStatement,
SyntaxKind.AddHandlerAccessorStatement,
SyntaxKind.EndAddHandlerStatement,
SyntaxKind.RemoveHandlerAccessorStatement,
SyntaxKind.EndRemoveHandlerStatement,
SyntaxKind.RaiseEventAccessorStatement,
SyntaxKind.EndRaiseEventStatement,
SyntaxKind.FunctionLambdaHeader,
SyntaxKind.SubLambdaHeader
Return CreateSpan(node)
Case SyntaxKind.SubStatement,
SyntaxKind.SubNewStatement,
SyntaxKind.FunctionStatement,
SyntaxKind.OperatorStatement,
SyntaxKind.GetAccessorStatement,
SyntaxKind.SetAccessorStatement,
SyntaxKind.AddHandlerAccessorStatement,
SyntaxKind.RemoveHandlerAccessorStatement,
SyntaxKind.RaiseEventAccessorStatement
Return CreateSpanForMethodBase(DirectCast(node, MethodBaseSyntax))
Case SyntaxKind.FunctionAggregation
Return TryCreateSpanForFunctionAggregation(DirectCast(node, FunctionAggregationSyntax))
......@@ -177,17 +179,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
End Select
End Function
Private Function CreateSpanForMethodBase(methodBase As MethodBaseSyntax) As TextSpan
If methodBase.Modifiers.Count = 0 Then
Return TextSpan.FromBounds(methodBase.Keyword.SpanStart, methodBase.Span.End)
End If
Return TextSpan.FromBounds(methodBase.Modifiers.First().SpanStart, methodBase.Span.End)
End Function
Private Function TryCreateSpanForPropertyStatement(node As PropertyStatementSyntax) As TextSpan?
If node.Parent.IsKind(SyntaxKind.PropertyBlock) Then
' not an auto-property:
Return Nothing
End If
If node.Initializer Is Nothing Then
Return Nothing
If node.Initializer IsNot Nothing Then
Return TextSpan.FromBounds(node.Identifier.Span.Start, node.Initializer.Span.End)
End If
If node.AsClause IsNot Nothing AndAlso node.AsClause.IsKind(SyntaxKind.AsNewClause) Then
Return TextSpan.FromBounds(node.Identifier.Span.Start, node.AsClause.Span.End)
End If
Return CreateSpan(node)
Return Nothing
End Function
Private Function TryCreateSpanForVariableDeclaration(modifiers As SyntaxTokenList, declarators As SeparatedSyntaxList(Of VariableDeclaratorSyntax), position As Integer) As TextSpan?
......@@ -199,37 +213,55 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
Return New TextSpan()
End If
Dim declarator = FindClosestDeclaratorWithInitializer(declarators, position)
If declarator Is Nothing Then
Dim name = FindClosestNameWithInitializer(declarators, position)
If name Is Nothing Then
Return New TextSpan()
End If
If declarator.Names.Count <= 1 Then
Return CreateSpan(declarator)
If name.ArrayBounds IsNot Nothing OrElse DirectCast(name.Parent, VariableDeclaratorSyntax).Names.Count > 1 Then
Return CreateSpan(name)
Else
Return CreateSpan(name.Parent)
End If
End Function
Dim name = declarator.Names(GetItemIndexByPosition(declarator.Names, position))
Return CreateSpan(name)
Private Function FindClosestNameWithInitializer(declarators As SeparatedSyntaxList(Of VariableDeclaratorSyntax), position As Integer) As ModifiedIdentifierSyntax
Return FindClosestNode(declarators, position,
Function(declarator)
If declarator.HasInitializer Then
Return declarator.Names(GetItemIndexByPosition(declarator.Names, position))
End If
Return FindClosestNode(declarator.Names, position, Function(idf)
Return If(idf.ArrayBounds IsNot Nothing, idf, Nothing)
End Function)
End Function)
End Function
Private Function FindClosestDeclaratorWithInitializer(declarators As SeparatedSyntaxList(Of VariableDeclaratorSyntax), position As Integer) As VariableDeclaratorSyntax
Dim d = GetItemIndexByPosition(declarators, position)
Private Function FindClosestNode(Of TListNode As SyntaxNode, TResult As SyntaxNode)(nodes As SeparatedSyntaxList(Of TListNode), position As Integer, predicate As Func(Of TListNode, TResult)) As TResult
Dim d = GetItemIndexByPosition(nodes, position)
Dim i = 0
Do
Dim left = d - i
Dim right = d + i
If left < 0 AndAlso right >= declarators.Count Then
If left < 0 AndAlso right >= nodes.Count Then
Return Nothing
End If
If left >= 0 AndAlso declarators(left).HasInitializer Then
Return declarators(left)
If left >= 0 Then
Dim result = predicate(nodes(left))
If result IsNot Nothing Then
Return result
End If
End If
If right < declarators.Count AndAlso declarators(right).HasInitializer Then
Return declarators(right)
If right < nodes.Count Then
Dim result = predicate(nodes(right))
If result IsNot Nothing Then
Return result
End If
End If
i += 1
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册