dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.04k stars 4.03k forks source link

ForEachStatementInfo.ElementType Returns Nothing in VB #22352

Open paul1956 opened 7 years ago

paul1956 commented 7 years ago

Version Used: VS 15.3.5, VisualBasicCodeAalysis 2.3.2 Steps to Reproduce:

1 Set AnyString to any string for example "123abc"

  1. Get. ForEachStatementInfo for "For Each ch in AnyString
  2. Get ForEachStatementInfo .ElementType

Expected Behavior: It would contain the type of the elements Char in this case Actual Behavior: it returns Nothing There are many other cases were this happens, Is it better to list all here on one issue per type, right now I know about Class and Struct that implement IEnumbable(Of

paul1956 commented 7 years ago

@jcouv do you need a list of all the places I found where this doesn't work? In addition to the list above If forEachStatement.Expression.Type is an ArrayType you also get nothing, there are more.

jcouv commented 7 years ago

Let me start with those two and see if there is a common cause. If it feels like each scenario needs to be addressed separately, I'll ask you to list scenarios you ran into. Thanks

paul1956 commented 7 years ago

I have found workarounds for many of the cases where Nothing is returned but the case below (found in VisualBasicExtensions.vb) completely stumps me

Dim syntax As SyntaxToken
For Each diag In syntax.Errors
jcouv commented 6 years ago

@paul1956 I tried this with latest bits (15.5 bits) and didn't see a problem.

<Fact>
        Public Sub ForeachRepro()
            Dim comp = CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
    <file name="a.vb">
Module Module1
    Sub M(s As String)
        For Each c In s
        Next
    End Sub
End Module
    </file>
</compilation>)

            Dim tree = comp.SyntaxTrees(0)

            Dim model = comp.GetSemanticModel(tree)
            Dim nodes = tree.GetCompilationUnitRoot().DescendantNodes()
            Dim node = nodes.OfType(Of ForEachStatementSyntax)().Single()

            Dim foreachInfo = model.GetForEachStatementInfo(node)
            Assert.Equal("System.Char", foreachInfo.ElementType.ToTestDisplayString())
        End Sub
paul1956 commented 6 years ago

@jcouv I agree many of the cases I first reported are fixed in 2.6 but I am still seeing other cases where nothing is returned. How can I find out what was fixed? I am working on how to step through ElementType so I can report the path causing the issues. For Example from AbstractFlowPass.vb

      Private Sub ResolveBreaks(breakState As LocalState, breakLabel As LabelSymbol)
            Dim newPendingBranches As ArrayBuilder(Of PendingBranch) = ArrayBuilder(Of PendingBranch).GetInstance()
            For Each pending In Me.PendingBranches

I am also looking at using your example so I can produce simple tests that fail.

paul1956 commented 6 years ago

@jcouv where do I get CreateCompilationWithMscorlibAndVBRuntime the one in Roslyn Master uses all kinds of Internal stuff and is not easily isolated for use by VB.

jcouv commented 6 years ago

@paul1956 I wrote that test in context of Roslyn tests (for example in CodeGenTuples.vb as a random place) as it was expedient. You could either do the same, or set up your own compilation. The code for CreateCompilation... is in src\Compilers\Test\Utilities\VisualBasic\CompilationTestUtils.vb and basically does VisualBasicCompilation.Create with a source tree (parsed from the test input), some assembly references (typically mscorlib and a reference for VB types) and trivial options.

paul1956 commented 6 years ago

Found the source for CreateCompilationWithMscorlibAndVBRuntime but getting the references from VB has provide to be difficult.

paul1956 commented 6 years ago

@jcouv what do you need more information about, The original issue ForEachStatementInfo.ElementType Returns Nothing in VB is still not fixed in 2.6 in the majority of cases but some of my original test cases are fixed.

jcouv commented 6 years ago

@paul1956 Could you share a case that still not working? The case describe in OP and which I tried above was working:

For Each c In s
Next

Thanks

paul1956 commented 6 years ago

In Roslyn BasicCodeAnalysis the are 1123 places (out of 1208 For Each loops) that Nothing is returned most require other parts of Roslyn so I am having difficulty producing short examples. I would be happy to share the test that runs over the whole project and counts the number of times ElementType is Nothing's if that would help. I could also output the file name and line. For example from EmitStatement.VB line 142. I am normally doing this in the context of a CodeFix so I am not 100% sure these tests I faked are correct.

               For Each catchBlock In statement.CatchBlocks
                    EmitCatchBlock(catchBlock)
                Next

Also 2 tests I was able to put together that fail.

        <Fact>
        Public Sub ForeachRepro3()
            Dim comp As VisualBasicCompilation = CreateCompilationWithMscorlibAndVBRuntime(
"Imports Microsoft.CodeAnalysis
Imports System.Runime

Class Class1
    Sub Main()
            Dim triviaToMove As SyntaxTriviaList = Nothing
            For Each trivia In triviaToMove
            Next
    End Sub
End Class", "a.vb")

            Dim tree As SyntaxTree = comp.SyntaxTrees(0)

            Dim model As SemanticModel = comp.GetSemanticModel(tree)
            Dim nodes As IEnumerable(Of SyntaxNode) = tree.GetCompilationUnitRoot().DescendantNodes()
            Dim node As ForEachStatementSyntax = nodes.OfType(Of ForEachStatementSyntax)().Single()

            Dim foreachInfo As ForEachStatementInfo = model.GetForEachStatementInfo(node)
            Assert.NotNull(foreachInfo.ElementType)
        End Sub
        <Fact>
        Public Sub ForeachRepro4()
            Dim comp As VisualBasicCompilation = CreateCompilationWithMscorlibAndVBRuntime(
"Imports Microsoft.CodeAnalysis
Imports System.Runime

Class Class1
    Sub Main()
            Dim triviaToMove As SyntaxTriviaList = Nothing
            For Each trivia In triviaToMove
            Next
    End Sub
End Class", "a.vb")

            Dim tree As SyntaxTree = comp.SyntaxTrees(0)

            Dim model As SemanticModel = comp.GetSemanticModel(tree)
            Dim nodes As IEnumerable(Of SyntaxNode) = tree.GetCompilationUnitRoot().DescendantNodes()
            Dim node As ForEachStatementSyntax = nodes.OfType(Of ForEachStatementSyntax)().Single()

            Dim foreachInfo As ForEachStatementInfo = model.GetForEachStatementInfo(node)
            Assert.NotNull(foreachInfo.ElementType)
        End Sub
jcouv commented 6 years ago

Thanks a bunch @paul1956 I'll check on those examples.

jcouv commented 6 years ago

Those tests fail because the code is incomplete (SyntaxTriviaList is undefined). I tried to provide minimal implementation of those types, but then GetForEachSatementInfo returned a proper value.

I'll try your method of running an analyzer on the entire Roslyn codebase to repro.

paul1956 commented 6 years ago

I thought the test might be incomplete, I am not that familiar with writing them. But in real use 80% of the For Each statements in Roslyn return nothing. I have worked around some of it by using DetermineType but that only works 95% of the time. There are still a few that I can't figure out and way to get the Type.