提交 8578512a 编写于 作者: M Manish Vasani

Ensure that we return the root IBlockOperation as the primary operation block for VB method bodies

Previously, we used to return two different operation blocks for the statements node within the body and the end block statement. This was incorrect, and was exposed when we recently started marking the implicit return statement in the sub as IsImplicit, and ended up with no explicit operations for an empty method body.
上级 7dfc2fa4
......@@ -8,6 +8,7 @@
using Roslyn.Test.Utilities;
using Xunit;
using Microsoft.CodeAnalysis.UnitTests.Diagnostics;
using static Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
......@@ -1949,5 +1950,33 @@ public void M()
.VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new SemanticModelInternalAnalyzer() }, null, null, true,
Diagnostic(SemanticModelInternalAnalyzer.GetOperationInternalDescriptor.Id, "1").WithLocation(6, 17));
}
[Fact]
public void TestOperationBlockAnalyzer_EmptyMethodBody()
{
const string source = @"
class C
{
public void M()
{
}
public void M2(int i)
{
}
public void M3(int i = 0)
{
}
}
";
CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularWithIOperationFeature)
.VerifyDiagnostics()
.VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new OperationBlockAnalyzer() }, null, null, false,
Diagnostic("ID", "M2").WithArguments("M2", "Block").WithLocation(8, 17),
Diagnostic("ID", "M").WithArguments("M", "Block").WithLocation(4, 17),
Diagnostic("ID", "M3").WithArguments("M3", "ParameterInitializer").WithLocation(12, 17),
Diagnostic("ID", "M3").WithArguments("M3", "Block").WithLocation(12, 17));
}
}
}
......@@ -132,7 +132,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim methodBlock = TryCast(node, MethodBlockBaseSyntax)
If methodBlock IsNot Nothing Then
Dim paramInitializers = GetParameterInitializers(methodBlock.BlockStatement.ParameterList)
Dim codeBlocks = paramInitializers.Concat(methodBlock.Statements).Concat(methodBlock.EndBlockStatement)
Dim codeBlocks = paramInitializers.Concat(methodBlock)
builder.Add(GetDeclarationInfo(model, node, getSymbol, codeBlocks, cancellationToken))
Return
End If
......
......@@ -1178,7 +1178,8 @@ Namespace Microsoft.CodeAnalysis.Operations
Function(tuple)
Return tuple.s.Kind <> OperationKind.None OrElse
tuple.bound.Kind = BoundKind.WithStatement OrElse tuple.bound.Kind = BoundKind.StopStatement OrElse
tuple.bound.Kind = BoundKind.EndStatement
tuple.bound.Kind = BoundKind.EndStatement OrElse tuple.bound.Kind = BoundKind.UnstructuredExceptionHandlingStatement OrElse
tuple.bound.Kind = BoundKind.ResumeStatement
End Function).Select(Function(tuple) tuple.s).ToImmutableArray()
End Function)
Dim locals As ImmutableArray(Of ILocalSymbol) = boundBlock.Locals.As(Of ILocalSymbol)()
......
' Copyright (c) Microsoft. 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 Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.UnitTests.Diagnostics
......@@ -1313,9 +1314,15 @@ End Class
</file>
</compilation>
' We have 2 OperationKind.None operations in the operation tree:
' (1) BoundUnstructedExceptionHandlingStatement for the method block with Resume statement
' (2) BoundResumeStatement for Resume statement
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=TestOptions.RegularWithIOperationFeature)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New NoneOperationTestAnalyzer}, Nothing, Nothing, False,
Diagnostic(NoneOperationTestAnalyzer.NoneOperationDescriptor.Id, <![CDATA[Public Sub Barney
Resume
End Sub]]>).WithLocation(22, 5),
Diagnostic(NoneOperationTestAnalyzer.NoneOperationDescriptor.Id, "Resume").WithLocation(23, 9))
End Sub
......@@ -2162,5 +2169,33 @@ End Class
comp.VerifyAnalyzerDiagnostics({New SemanticModelInternalAnalyzer}, Nothing, Nothing, False,
Diagnostic(SemanticModelInternalAnalyzer.GetOperationInternalDescriptor.Id, "1").WithLocation(3, 17))
End Sub
<Fact>
Public Sub TestOperationBlockAnalyzer_EmptyMethodBody()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Public Sub M()
End Sub
Public Sub M2(i as Integer)
End Sub
Public Sub M3(Optional i as Integer = 0)
End Sub
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=TestOptions.RegularWithIOperationFeature)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New OperationBlockAnalyzer}, Nothing, Nothing, False,
Diagnostic("ID", "M").WithArguments("M", "Block").WithLocation(2, 16),
Diagnostic("ID", "M2").WithArguments("M2", "Block").WithLocation(5, 16),
Diagnostic("ID", "M3").WithArguments("M3", "ParameterInitializer").WithLocation(8, 16),
Diagnostic("ID", "M3").WithArguments("M3", "Block").WithLocation(8, 16))
End Sub
End Class
End Namespace
......@@ -792,54 +792,27 @@ private void ReportDiagnosticIfActionInvokedConcurrently(SemaphoreSlim gate, Sym
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class OperationAnalyzer : DiagnosticAnalyzer
public sealed class OperationBlockAnalyzer : DiagnosticAnalyzer
{
private readonly ActionKind _actionKind;
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
"ID",
"Title1",
"{0} diagnostic",
"OperationBlock for {0}: {1}",
"Category1",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public enum ActionKind
{
Operation,
OperationBlock,
OperationBlockEnd
}
public OperationAnalyzer(ActionKind actionKind)
{
_actionKind = actionKind;
}
private void ReportDiagnostic(Action<Diagnostic> addDiagnostic, Location location)
{
var diagnostic = Diagnostic.Create(Descriptor, location, _actionKind);
addDiagnostic(diagnostic);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Descriptor);
public override void Initialize(AnalysisContext context)
{
if (_actionKind == ActionKind.OperationBlockEnd)
context.RegisterOperationBlockAction(c =>
{
context.RegisterOperationBlockStartAction(oc =>
foreach (var operationRoot in c.OperationBlocks)
{
oc.RegisterOperationBlockEndAction(c => ReportDiagnostic(c.ReportDiagnostic, c.OwningSymbol.Locations[0]));
});
}
else if (_actionKind == ActionKind.Operation)
{
context.RegisterOperationAction(c => ReportDiagnostic(c.ReportDiagnostic, c.Operation.Syntax.GetLocation()), OperationKind.VariableDeclarations);
}
else
{
context.RegisterOperationBlockAction(c => ReportDiagnostic(c.ReportDiagnostic, c.OwningSymbol.Locations[0]));
}
var diagnostic = Diagnostic.Create(Descriptor, c.OwningSymbol.Locations[0], c.OwningSymbol.Name, operationRoot.Kind);
c.ReportDiagnostic(diagnostic);
}
});
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册