Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix analysis of IOperation descendants for BoundDelegateCreationExpre… #19307

Merged
merged 2 commits into from
May 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 5 additions & 29 deletions src/Compilers/CSharp/Portable/BoundTree/Expression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,44 +414,20 @@ public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, T
}
}

internal partial class BoundDelegateCreationExpression : IMethodBindingExpression
internal partial class BoundDelegateCreationExpression
{
IOperation IMemberReferenceExpression.Instance
{
get
{
BoundMethodGroup methodGroup = this.Argument as BoundMethodGroup;
if (methodGroup != null)
{
return methodGroup.InstanceOpt;
}

return null;
}
}

bool IMethodBindingExpression.IsVirtual =>
(object)this.MethodOpt != null &&
(this.MethodOpt.IsVirtual || this.MethodOpt.IsAbstract || this.MethodOpt.IsOverride) &&
!this.SuppressVirtualCalls;

ISymbol IMemberReferenceExpression.Member => this.MethodOpt;

IMethodSymbol IMethodBindingExpression.Method => this.MethodOpt;

protected override OperationKind ExpressionKind => OperationKind.MethodBindingExpression;
protected override OperationKind ExpressionKind => OperationKind.None;

// SyntaxNode for MethodBindingExpression is the argument of DelegateCreationExpression
SyntaxNode IOperation.Syntax => this.Argument.Syntax;
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Argument);

public override void Accept(OperationVisitor visitor)
{
visitor.VisitMethodBindingExpression(this);
visitor.VisitNoneOperation(this);
}

public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitMethodBindingExpression(this, argument);
return visitor.VisitNoneOperation(this, argument);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ public override void M1()
);
}

[Fact]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18839")]
public void EventAndMethodReferencesCSharp()
{
const string source = @"
Expand Down Expand Up @@ -1440,8 +1440,7 @@ public void OnMumble(System.EventArgs args)
Diagnostic(LambdaTestAnalyzer.LambdaExpressionDescriptor.Id, "input => input++").WithLocation(9, 31),
Diagnostic(LambdaTestAnalyzer.LambdaExpressionDescriptor.Id, "input => { input++; input++; if (input > 0) return true; return false; }").WithLocation(10, 32),
Diagnostic(LambdaTestAnalyzer.TooManyStatementsInLambdaExpressionDescriptor.Id, "input => { input++; input++; if (input > 0) return true; return false; }").WithLocation(10, 32),
// Bug: missing a Lambda expression in delegate creation https://github.com/dotnet/roslyn/issues/8347
//Diagnostic(LambdaTestAnalyzer.LambdaExpressionDescriptor.Id, "(s, e) => { }").WithLocation(22, 42),
Diagnostic(LambdaTestAnalyzer.LambdaExpressionDescriptor.Id, "(s, e) => { }").WithLocation(22, 42),
Diagnostic(LambdaTestAnalyzer.LambdaExpressionDescriptor.Id, "(s, e) => { int i = 0; i++; i++; i++; }").WithLocation(23, 19),
Diagnostic(LambdaTestAnalyzer.TooManyStatementsInLambdaExpressionDescriptor.Id, "(s, e) => { int i = 0; i++; i++; i++; }").WithLocation(23, 19));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,96 @@ public void M(int x, int y, int z)
VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}

[Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")]
public void ParameterReference_DelegateCreationExpressionWithLambdaArgument()
{
string source = @"
using System;

class Class
{
// Used parameter methods
public void UsedParameterMethod1(Action a)
{
Action a2 = /*<bind>*/new Action(() =>
{
a();
})/*</bind>*/;
}
}
";
string expectedOperationTree = @"
IOperation: (OperationKind.None) (Syntax: 'new Action( ... })')
Children(1): ILambdaExpression (Signature: lambda expression) (OperationKind.LambdaExpression, Type: System.Action) (Syntax: '() => ... }')
IBlockStatement (2 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }')
IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'a();')
IInvocationExpression (virtual void System.Action.Invoke()) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'a()')
Instance Receiver: IParameterReferenceExpression: a (OperationKind.ParameterReferenceExpression, Type: System.Action) (Syntax: 'a')
IReturnStatement (OperationKind.ReturnStatement) (Syntax: '{ ... }')
";
var expectedDiagnostics = DiagnosticDescription.None;

VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}

[Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")]
public void ParameterReference_DelegateCreationExpressionWithMethodArgument()
{
string source = @"
using System;

class Class
{
public delegate void Delegate(int x, int y);

public void Method(Delegate d)
{
var a = /*<bind>*/new Delegate(Method2)/*</bind>*/;
Copy link
Contributor

@AlekseyTs AlekseyTs May 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method2 [](start = 39, length = 7)

Please add a test with an explicit receiver (a parameter reference, for example). We should get it in the output. #Pending

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a note to #17588 about adding this unit test when implementing IOperation API for bound delegate creation expression.


In reply to: 115620033 [](ancestors = 115620033)

}

public void Method2(int x, int y)
{
}
}
";
string expectedOperationTree = @"
IOperation: (OperationKind.None) (Syntax: 'new Delegate(Method2)')
Children(1): IOperation: (OperationKind.None) (Syntax: 'Method2')
";
var expectedDiagnostics = DiagnosticDescription.None;

VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}

[Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")]
public void ParameterReference_DelegateCreationExpressionWithInvalidArgument()
{
string source = @"
using System;

class Class
{
public delegate void Delegate(int x, int y);

public void Method(int x)
{
var a = /*<bind>*/new Delegate(x)/*</bind>*/;
}
}
";
string expectedOperationTree = @"
IInvalidExpression (OperationKind.InvalidExpression, Type: Class.Delegate, IsInvalid) (Syntax: 'new Delegate(x)')
Children(1): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x')
";
var expectedDiagnostics = new DiagnosticDescription[] {
// CS0149: Method name expected
// var a = /*<bind>*/new Delegate(x)/*</bind>*/;
Diagnostic(ErrorCode.ERR_MethodNameExpected, "x").WithLocation(10, 40)
};

VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}

[Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")]
public void ParameterReference_DynamicCollectionInitializer()
{
Expand Down
37 changes: 7 additions & 30 deletions src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb
Original file line number Diff line number Diff line change
Expand Up @@ -1500,46 +1500,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Class

Friend Partial Class BoundDelegateCreationExpression
Implements IMethodBindingExpression

Private ReadOnly Property IMemberReferenceExpression_Instance As IOperation Implements IMemberReferenceExpression.Instance
Get
If Me.Method.IsShared Then
Return Nothing
Else
Return Me.ReceiverOpt
End If
End Get
End Property

Private ReadOnly Property IMethodBindingExpression_IsVirtual As Boolean Implements IMethodBindingExpression.IsVirtual
Get
Return Me.Method IsNot Nothing AndAlso (Me.Method.IsOverridable OrElse Me.Method.IsOverrides OrElse Me.Method.IsMustOverride) AndAlso Not Me.SuppressVirtualCalls
End Get
End Property

Private ReadOnly Property IMemberReferenceExpression_Member As ISymbol Implements IMemberReferenceExpression.Member
Get
Return Me.Method
End Get
End Property
Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function

Private ReadOnly Property IMethodBindingExpression_Method As IMethodSymbol Implements IMethodBindingExpression.Method
Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return Me.Method
Return ImmutableArray.Create(Of IOperation)(Me.ReceiverOpt)
End Get
End Property

Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.MethodBindingExpression
End Function

Public Overrides Sub Accept(visitor As OperationVisitor)
visitor.VisitMethodBindingExpression(Me)
visitor.VisitNoneOperation(Me)
End Sub

Public Overrides Function Accept(Of TArgument, TResult)(visitor As OperationVisitor(Of TArgument, TResult), argument As TArgument) As TResult
Return visitor.VisitMethodBindingExpression(Me, argument)
Return visitor.VisitNoneOperation(Me, argument)
End Function
End Class

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,7 @@ End Class
Diagnostic(ExplicitVsImplicitInstanceAnalyzer.ImplicitInstanceDescriptor.Id, "M2").WithLocation(15, 9))
End Sub

<Fact>
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/18839")>
Public Sub EventAndMethodReferencesVisualBasic()
Dim source = <compilation>
<file name="c.vb">
Expand Down Expand Up @@ -1411,7 +1411,7 @@ End Class
End Sub

<WorkItem(8385, "https://github.com/dotnet/roslyn/issues/8385")>
<Fact>
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/18839")>
Public Sub StaticMemberReferenceVisualBasic()
Dim source = <compilation>
<file name="c.vb">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,85 @@ IObjectCreationExpression (Constructor: Sub [Class]..ctor()) (OperationKind.Obje
VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub

<Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")>
Public Sub ParameterReference_DelegateCreationExpressionWithLambdaArgument()
Dim source = <![CDATA[
Option Strict Off
Imports System

Class Class1
Delegate Sub DelegateType()
Public Sub M(x As Object, y As EventArgs)
Dim eventHandler As New EventHandler(Function() x)'BIND:"New EventHandler(Function() x)"
End Sub
End Class]]>.Value

Dim expectedOperationTree = <![CDATA[
IConversionExpression (ConversionKind.Basic, Implicit) (OperationKind.ConversionExpression, Type: System.EventHandler) (Syntax: 'New EventHa ... nction() x)')
ILambdaExpression (Signature: Function () As System.Object) (OperationKind.LambdaExpression, Type: null) (Syntax: 'Function() x')
IBlockStatement (3 statements, 1 locals) (OperationKind.BlockStatement) (Syntax: 'Function() x')
Locals: Local_1: <anonymous local> As System.Object
IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'x')
IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Object) (Syntax: 'x')
ILabelStatement (Label: exit) (OperationKind.LabelStatement) (Syntax: 'Function() x')
IReturnStatement (OperationKind.ReturnStatement) (Syntax: 'Function() x')
ILocalReferenceExpression: (OperationKind.LocalReferenceExpression, Type: System.Object) (Syntax: 'Function() x')
]]>.Value

Dim expectedDiagnostics = String.Empty

VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub

<Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")>
Public Sub ParameterReference_DelegateCreationExpressionWithMethodArgument()
Dim source = <![CDATA[
Imports System

Class Class1
Public Sub M(x As Object, y As EventArgs)
Dim eventHandler As New EventHandler(AddressOf Me.M)'BIND:"New EventHandler(AddressOf Me.M)"
End Sub
End Class]]>.Value

Dim expectedOperationTree = <![CDATA[
IConversionExpression (ConversionKind.Basic, Explicit) (OperationKind.ConversionExpression, Type: System.EventHandler) (Syntax: 'New EventHa ... essOf Me.M)')
IOperation: (OperationKind.None) (Syntax: 'AddressOf Me.M')
Children(1): IInstanceReferenceExpression (InstanceReferenceKind.Explicit) (OperationKind.InstanceReferenceExpression, Type: Class1) (Syntax: 'Me')
]]>.Value

Dim expectedDiagnostics = String.Empty

VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub

<Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")>
Public Sub ParameterReference_DelegateCreationExpressionWithInvalidArgument()
Dim source = <![CDATA[
Option Strict Off
Imports System

Class Class1
Delegate Sub DelegateType()
Public Sub M(x As Object, y As EventArgs)
Dim eventHandler As New EventHandler(x)'BIND:"New EventHandler(x)"
End Sub
End Class]]>.Value

Dim expectedOperationTree = <![CDATA[
IInvalidExpression (OperationKind.InvalidExpression, Type: System.EventHandler, IsInvalid) (Syntax: 'New EventHandler(x)')
Children(1): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Object) (Syntax: 'x')
]]>.Value

Dim expectedDiagnostics = <![CDATA[
BC32008: Delegate 'EventHandler' requires an 'AddressOf' expression or lambda expression as the only argument to its constructor.
Dim eventHandler As New EventHandler(x)'BIND:"New EventHandler(x)"
~~~
]]>.Value

VerifyOperationTreeAndDiagnosticsForTest(Of ObjectCreationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub

<Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")>
Public Sub ParameterReference_NameOfExpression()
Dim source = <![CDATA[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,7 @@ void M()
}

[WorkItem(15325, "https://github.com/dotnet/roslyn/issues/15325")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsQualifyMemberAccess)]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18839"), Trait(Traits.Feature, Traits.Features.CodeActionsQualifyMemberAccess)]
public async Task QualifyInstanceMethodInDelegateCreation()
{
await TestAsyncWithOption(
Expand Down