Skip to content

Commit

Permalink
[GH-71] - preventing traversing class and struct declaration when det…
Browse files Browse the repository at this point in the history
…ecting reentrant calls
  • Loading branch information
tpodolak committed Feb 19, 2019
1 parent 178235b commit dfd9db7
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ public override void VisitInvocationExpression(InvocationExpressionSyntax node)
base.VisitInvocationExpression(node);
}

public override void VisitClassDeclaration(ClassDeclarationSyntax node)
{
}

public override void VisitStructDeclaration(StructDeclarationSyntax node)
{
}

public override void DefaultVisit(SyntaxNode node)
{
VisitRelatedSymbols(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ public override void VisitInvocationExpression(InvocationExpressionSyntax node)
base.VisitInvocationExpression(node);
}

public override void VisitClassBlock(ClassBlockSyntax node)
{
}

public override void VisitStructureBlock(StructureBlockSyntax node)
{
}

public override void DefaultVisit(SyntaxNode node)
{
VisitRelatedSymbols(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ public abstract class ReEntrantReturnsSetupDiagnosticVerifier : CSharpDiagnostic
[InlineData]
public abstract Task ReportsDiagnostic_WhenUsingReEntrantReturns_AcrossMultipleFiles(string method);

[CombinatoryTheory]
[InlineData("Foo")]
[InlineData("FooBar")]
public abstract Task ReportsNoDiagnostic_WhenUsed_WithTypeofExpression(string method, string type);

protected override DiagnosticAnalyzer GetDiagnosticAnalyzer()
{
return new ReEntrantSetupAnalyzer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,5 +530,49 @@ public static int ReturnThis()

await VerifyDiagnostics(new[] { source, secondSource }, Descriptor, $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => FooBar.ReturnThis()).");
}

[CombinatoryData("Returns", "Returns<object>", "ReturnsForAnyArgs", "ReturnsForAnyArgs<object>")]
public override async Task ReportsNoDiagnostic_WhenUsed_WithTypeofExpression(string method, string type)
{
var source = $@"using NSubstitute;
namespace MyNamespace
{{
public class Foo
{{
public object FooBar()
{{
return null;
}}
public object Bar()
{{
var sub = Substitute.For<Foo>();
sub.FooBar().Returns(1);
return null;
}}
}}
public struct FooBar
{{
public object Bar()
{{
var sub = Substitute.For<Foo>();
sub.FooBar().Returns(1);
return null;
}}
}}
public class FooTests
{{
public void Test()
{{
var substitute = NSubstitute.Substitute.For<Foo>();
substitute.FooBar().{method}(typeof({type}));
}}
}}
}}";
await VerifyNoDiagnostic(source);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -529,5 +529,49 @@ public static int ReturnThis()

await VerifyDiagnostics(new[] { source, secondSource }, Descriptor, $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => FooBar.ReturnThis()).");
}

[CombinatoryData("SubstituteExtensions.Returns", "SubstituteExtensions.Returns<object>", "SubstituteExtensions.ReturnsForAnyArgs", "SubstituteExtensions.ReturnsForAnyArgs<object>")]
public override async Task ReportsNoDiagnostic_WhenUsed_WithTypeofExpression(string method, string type)
{
var source = $@"using NSubstitute;
namespace MyNamespace
{{
public class Foo
{{
public object FooBar()
{{
return null;
}}
public object Bar()
{{
var sub = Substitute.For<Foo>();
sub.FooBar().Returns(1);
return null;
}}
}}
public struct FooBar
{{
public object Bar()
{{
var sub = Substitute.For<Foo>();
sub.FooBar().Returns(1);
return null;
}}
}}
public class FooTests
{{
public void Test()
{{
var substitute = NSubstitute.Substitute.For<Foo>();
{method}(substitute.FooBar(), typeof({type}));
}}
}}
}}";
await VerifyNoDiagnostic(source);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ public interface IReEntrantReturnsSetupDiagnosticVerifier
Task ReportsNoDiagnostic_WhenReEntrantSubstituteNotUsed(string method, string firstReturn, string secondReturn);

Task ReportsDiagnostic_WhenUsingReEntrantReturns_AcrossMultipleFiles(string method);

Task ReportsNoDiagnostic_WhenUsed_WithTypeofExpression(string method, string type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ public abstract class ReEntrantReturnsSetupDiagnosticVerifier : VisualBasicDiagn
[InlineData]
public abstract Task ReportsDiagnostic_WhenUsingReEntrantReturns_AcrossMultipleFiles(string method);

[CombinatoryTheory]
[InlineData("Foo")]
[InlineData("FooBar")]
public abstract Task ReportsNoDiagnostic_WhenUsed_WithTypeofExpression(string method, string type);

protected override DiagnosticAnalyzer GetDiagnosticAnalyzer()
{
return new ReEntrantSetupAnalyzer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,5 +450,41 @@ End Namespace

await VerifyDiagnostics(new[] { source, secondSource }, Descriptor, $"{method}() is set with a method that itself calls {method}. This can cause problems with NSubstitute. Consider replacing with a lambda: {method}(Function(x) FooBar.ReturnThis()).");
}

public override async Task ReportsNoDiagnostic_WhenUsed_WithTypeofExpression(string method, string type)
{
var source = $@"Imports NSubstitute
Imports System
Namespace MyNamespace
Public Class Foo
Public Function FooBar() As Type
Return Nothing
End Function
Public Function Bar() As Type
Dim [sub] = Substitute.[For](Of Foo)()
[sub].FooBar().Returns(GetType(Object))
Return Nothing
End Function
End Class
Public Structure FooBar
Public Function Bar() As Type
Dim [sub] = Substitute.[For](Of Foo)()
[sub].FooBar().Returns(GetType(Object))
Return Nothing
End Function
End Structure
Public Class FooTests
Public Sub Test()
Dim substitute = NSubstitute.Substitute.[For](Of Foo)()
substitute.FooBar().{method}(GetType([{type}]))
End Sub
End Class
End Namespace";

await VerifyNoDiagnostic(source);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -458,5 +458,42 @@ End Namespace

await VerifyDiagnostics(new[] { source, secondSource }, Descriptor, $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) FooBar.ReturnThis()).");
}

[CombinatoryData("SubstituteExtensions.Returns", "SubstituteExtensions.Returns(Of Object)", "SubstituteExtensions.ReturnsForAnyArgs", "SubstituteExtensions.ReturnsForAnyArgs(Of Object)")]
public override async Task ReportsNoDiagnostic_WhenUsed_WithTypeofExpression(string method, string type)
{
var source = $@"Imports NSubstitute
Imports System
Namespace MyNamespace
Public Class Foo
Public Function FooBar() As Type
Return Nothing
End Function
Public Function Bar() As Type
Dim [sub] = Substitute.[For](Of Foo)()
[sub].FooBar().Returns(GetType(Object))
Return Nothing
End Function
End Class
Public Structure FooBar
Public Function Bar() As Type
Dim [sub] = Substitute.[For](Of Foo)()
[sub].FooBar().Returns(GetType(Object))
Return Nothing
End Function
End Structure
Public Class FooTests
Public Sub Test()
Dim substitute = NSubstitute.Substitute.[For](Of Foo)()
{method}(substitute.FooBar(), GetType([{type}]))
End Sub
End Class
End Namespace";

await VerifyNoDiagnostic(source);
}
}
}

0 comments on commit dfd9db7

Please sign in to comment.