Skip to content

Commit

Permalink
VB support for the virtual methods in DetectPreviewFeatureAnalyzer (#…
Browse files Browse the repository at this point in the history
…5566)

* First cut of message and URL support. Needs to be cleaned up

* GeneralPreviewFeatureAttributeRule and unit test changes

* ImplementsPreviewInterfaceRule and unit test changes

* UsesPreviewTypeParameterRule and unit test changes

* Everything else

* Clean up

* Fix test failures in PCA

* Self review + unit tests

* Make method static

* First cut of addressing comments

* Before reordering args

* Checkpoint

* All unit tests pass

* MInor cleanup

* More cleanup

* Before unit test regex changes

* Bug fix and all unit tests pass

* sq

* sq

* Address comments

* sq

* pack

* Flush out VB implementation for the virtual methods

* Fix BC42030 warning

* Improve test coverage

* Add more test and fix a bug found

* Apply feedbacks

* Add seperate test for case sensitivity

Co-authored-by: Prashanth Govindarajan <prgovi@microsoft.com>
Co-authored-by: Buyaa Namnan <bunamnan@microsoft.com>
  • Loading branch information
3 people committed Oct 18, 2021
1 parent 23fab74 commit ab87232
Show file tree
Hide file tree
Showing 9 changed files with 802 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,14 @@ private static bool TryGetConstraintClauseNode(SyntaxList<TypeParameterConstrain
return ret;
}
}
else if (typeSymbolDefinition is InterfaceDeclarationSyntax interfaceDeclaration)
{
SeparatedSyntaxList<BaseTypeSyntax> baseListTypes = interfaceDeclaration.BaseList.Types;
if (TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(baseListTypes, previewInterfaceSymbol, out ret))
{
return ret;
}
}
}

return ret;
Expand Down Expand Up @@ -294,5 +302,10 @@ private static bool TryGetPreviewInterfaceNodeForClassOrStructImplementingPrevie

private static bool IsIdentifierNameSyntax(TypeSyntax identifier, ISymbol previewInterfaceSymbol) => identifier is IdentifierNameSyntax identifierName && IsSyntaxToken(identifierName.Identifier, previewInterfaceSymbol) ||
identifier is NullableTypeSyntax nullable && IsIdentifierNameSyntax(nullable.ElementType, previewInterfaceSymbol);

protected override SyntaxNode? GetPreviewImplementsClauseSyntaxNodeForMethodOrProperty(ISymbol methodSymbol, ISymbol previewSymbol)
{
throw new System.NotImplementedException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ public abstract class DetectPreviewFeatureAnalyzer : DiagnosticAnalyzer

protected abstract SyntaxNode? GetPreviewSyntaxNodeForFieldsOrEvents(ISymbol fieldOrEventSymbol, ISymbol previewSymbol);

protected abstract SyntaxNode? GetPreviewImplementsClauseSyntaxNodeForMethodOrProperty(ISymbol methodOrPropertySymbol, ISymbol previewSymbol);

public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
Expand Down Expand Up @@ -573,7 +575,23 @@ private void ProcessPropertyOrMethodAttributes(SymbolAnalysisContext context,
if (SymbolIsAnnotatedAsPreview(baseInterfaceMember, requiresPreviewFeaturesSymbols, previewFeatureAttributeSymbol))
{
string baseInterfaceMemberName = baseInterfaceMember.ContainingSymbol != null ? baseInterfaceMember.ContainingSymbol.Name + "." + baseInterfaceMember.Name : baseInterfaceMember.Name;
ReportDiagnosticWithCustomMessageIfItExists(context, baseInterfaceMember, propertyOrMethodSymbol, requiresPreviewFeaturesSymbols, ImplementsPreviewMethodRule, ImplementsPreviewMethodRuleWithCustomMessage, propertyOrMethodSymbol.Name, baseInterfaceMemberName);
SyntaxNode? previewImplementsClause = null;

if (propertyOrMethodSymbol.Language is LanguageNames.VisualBasic)
{
previewImplementsClause = GetPreviewImplementsClauseSyntaxNodeForMethodOrProperty(propertyOrMethodSymbol, baseInterfaceMember);
}

if (previewImplementsClause != null)
{
ReportDiagnosticWithCustomMessageIfItExists(context, previewImplementsClause, baseInterfaceMember, requiresPreviewFeaturesSymbols,
ImplementsPreviewMethodRule, ImplementsPreviewMethodRuleWithCustomMessage, propertyOrMethodSymbol.Name, baseInterfaceMemberName);
}
else
{
ReportDiagnosticWithCustomMessageIfItExists(context, baseInterfaceMember, propertyOrMethodSymbol, requiresPreviewFeaturesSymbols,
ImplementsPreviewMethodRule, ImplementsPreviewMethodRuleWithCustomMessage, propertyOrMethodSymbol.Name, baseInterfaceMemberName);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpDetectPreviewFeatureAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
Microsoft.NetCore.VisualBasic.Analyzers.Runtime.BasicDetectPreviewFeatureAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;

namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
Expand Down Expand Up @@ -37,7 +40,7 @@ public abstract class BAbstract : IZoo
{
}
interface {|#0:IZoo|} : IFoo
interface IZoo : {|#0:IFoo|}
{
bool Bar() { return true; }
}
Expand Down Expand Up @@ -319,6 +322,40 @@ public abstract class AbClass
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(1).WithArguments("Foo", "IFoo.Foo", DetectPreviewFeatureAnalyzer.DefaultURL));
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.DerivesFromPreviewClassRule).WithLocation(2).WithArguments("Zoo", "AbClass", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();

var vbInput = @"
Imports System.Runtime.Versioning
Imports System
Imports System.Collections.Generic
Namespace Preview_Feature_Scratch
Public Partial Class Zoo
Implements NonPreviewInterface, {|#0:PreviewInterface|}
Private _field As List(Of {|#1:PreviewType|})
End Class
Public Partial Class Zoo
Inherits {|#2:PreviewType|}
End Class
<RequiresPreviewFeatures>
Interface PreviewInterface
End Interface
Interface NonPreviewInterface
End Interface
<RequiresPreviewFeatures>
Public MustInherit Class PreviewType
End Class
End Namespace
";
var vbTest = TestVB(vbInput);
vbTest.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(0).WithArguments("Zoo", "PreviewInterface", DetectPreviewFeatureAnalyzer.DefaultURL));
vbTest.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(1).WithArguments("_field", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
vbTest.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.DerivesFromPreviewClassRule).WithLocation(2).WithArguments("Zoo", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
await vbTest.RunAsync();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpDetectPreviewFeatureAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
Microsoft.NetCore.VisualBasic.Analyzers.Runtime.BasicDetectPreviewFeatureAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;

namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
Expand Down Expand Up @@ -105,6 +108,32 @@ class AGenericClass<T>
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.GeneralPreviewFeatureAttributeRule).WithLocation(1).WithArguments("PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(2).WithArguments("_genericPreviewField", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();

var vbInput = @"
Imports System
Imports System.Runtime.Versioning
Imports System.Collections.Generic
Module Preview_Feature_Scratch
Public Class Program
Private _field As {|#0:PreviewType|}
Private _genericPreviewField As AGenericClass(Of {|#2:PreviewType|})
Private _noDiagnosticField As AGenericClass(Of Boolean)
End Class
<RequiresPreviewFeatures>
Public Class PreviewType
End Class
Public Class AGenericClass(Of T)
End Class
End Module
";

var testVb = TestVB(vbInput);
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(0).WithArguments("_field", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(2).WithArguments("_genericPreviewField", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
await testVb.RunAsync();
}

[Fact]
Expand Down Expand Up @@ -212,6 +241,39 @@ public class AGenericClass<T>
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(2).WithArguments("_genericPreviewField", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(3).WithArguments("_genericPreviewField", "AGenericClass", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();

var vbInput = @"
Imports System.Runtime.Versioning
Imports System
Namespace Preview_Feature_Scratch
Public Class Program
Private _field As {|#0:PreviewType|}
Private _genericPreviewField As {|#3:AGenericClass(Of {|#2:PreviewType|})|}()
Public Sub New()
_field = {|#1:New PreviewType()|}
End Sub
Private Shared Sub Main(ByVal args As String())
End Sub
End Class
<RequiresPreviewFeatures>
Public Class PreviewType
End Class
<RequiresPreviewFeatures>
Public Class AGenericClass(Of T As PreviewType)
End Class
End Namespace";

var vbTest = TestVB(vbInput);
vbTest.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(0).WithArguments("_field", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
vbTest.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.GeneralPreviewFeatureAttributeRule).WithLocation(1).WithArguments("PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
vbTest.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(2).WithArguments("_genericPreviewField", "PreviewType", DetectPreviewFeatureAnalyzer.DefaultURL));
vbTest.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.FieldOrEventIsPreviewTypeRule).WithLocation(3).WithArguments("_genericPreviewField", "AGenericClass", DetectPreviewFeatureAnalyzer.DefaultURL));
await vbTest.RunAsync();
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpDetectPreviewFeatureAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
Microsoft.NetCore.VisualBasic.Analyzers.Runtime.BasicDetectPreviewFeatureAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;

namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
Expand Down Expand Up @@ -37,12 +40,38 @@ public interface IProgram
void MarkedMethodInInterface();
}
}
";

var test = TestCS(csInput);
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(0).WithArguments("MarkedMethodInInterface", "IProgram.MarkedMethodInInterface", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();

var vbInput = @"
Imports System.Runtime.Versioning
Imports System
Namespace Preview_Feature_Scratch
Class Program
Implements IProgram
Private Shared Sub Main(ByVal args As String())
Dim prog = New Program()
End Sub
Public Sub MarkedMethodInInterface() Implements IProgram.{|#0:MarkedMethodInInterface|}
Throw New NotImplementedException()
End Sub
End Class
Interface IProgram
<RequiresPreviewFeatures>
Sub MarkedMethodInInterface()
End Interface
End Namespace";

var testVb = TestVB(vbInput);
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(0).WithArguments("MarkedMethodInInterface", "IProgram.MarkedMethodInInterface", DetectPreviewFeatureAnalyzer.DefaultURL));
await testVb.RunAsync();
}

[Fact]
Expand All @@ -61,7 +90,6 @@ static void Main(string[] args)
}
public void {|#0:UnmarkedMethodInMarkedInterface|}() { }
}
[RequiresPreviewFeatures]
Expand All @@ -70,13 +98,48 @@ public interface IProgram
public void UnmarkedMethodInMarkedInterface() { }
}
}
";

var test = TestCS(csInput);
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(0).WithArguments("UnmarkedMethodInMarkedInterface", "IProgram.UnmarkedMethodInMarkedInterface", DetectPreviewFeatureAnalyzer.DefaultURL));
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(1).WithArguments("Program", "IProgram", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();

var vbInput = @"
Imports System
Imports System.Runtime.Versioning
Module Preview_Feature_Scratch
Public Class Program
Implements {|#1:IProgram|}
Private Shared Sub Main(ByVal args As String())
Dim prog = New Program()
End Sub
Public Sub MarkedMethodInInterface() Implements IProgram.{|#0:MarkedMethodInInterface|}
Throw New NotImplementedException()
End Sub
Public ReadOnly Property Value As String Implements IProgram.{|#2:Value|}
{|#3:Get|}
Return """"
End Get
End Property
End Class
<RequiresPreviewFeatures>
Public Interface IProgram
Sub MarkedMethodInInterface()
ReadOnly Property Value() As String
End Interface
End Module
";

var testVb = TestVB(vbInput);
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(0).WithArguments("MarkedMethodInInterface", "IProgram.MarkedMethodInInterface", DetectPreviewFeatureAnalyzer.DefaultURL));
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(1).WithArguments("Program", "IProgram", DetectPreviewFeatureAnalyzer.DefaultURL));
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(2).WithArguments("Value", "IProgram.Value", DetectPreviewFeatureAnalyzer.DefaultURL));
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(3).WithArguments("get_Value", "IProgram.get_Value", DetectPreviewFeatureAnalyzer.DefaultURL));
await testVb.RunAsync();
}

[Fact]
Expand All @@ -100,12 +163,32 @@ public interface IProgram
{
}
}
";

var test = TestCS(csInput);
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(0).WithArguments("Program", "IProgram", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();

var vbInput = @"
Imports System
Imports System.Runtime.Versioning
Module Preview_Feature_Scratch
Public Class Program
Implements {|#1:IProgram|}
Private Shared Sub Main(ByVal args As String())
Dim prog = New Program()
End Sub
End Class
<RequiresPreviewFeatures>
Public Interface IProgram
End Interface
End Module
";

var testVb = TestVB(vbInput);
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(1).WithArguments("Program", "IProgram", DetectPreviewFeatureAnalyzer.DefaultURL));
await testVb.RunAsync();
}

[Fact]
Expand All @@ -116,7 +199,7 @@ public async Task TestDerivedInterface()
namespace Preview_Feature_Scratch
{
interface {|#0:IZoo|} : IFoo
interface IZoo : {|#0:IFoo|}
{
}
Expand All @@ -130,6 +213,25 @@ interface IFoo
var test = TestCS(csInput);
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(0).WithArguments("IZoo", "IFoo", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();

var vbInput = @"
Imports System
Imports System.Runtime.Versioning
Module Preview_Feature_Scratch
Public Interface IZoo
Inherits {|#0:IFoo|}
End Interface
<RequiresPreviewFeatures>
Public Interface IFoo
Sub Bar()
End Interface
End Module
";

var testVb = TestVB(vbInput);
testVb.ExpectedDiagnostics.Add(VerifyVB.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewInterfaceRule).WithLocation(0).WithArguments("IZoo", "IFoo", DetectPreviewFeatureAnalyzer.DefaultURL));
await testVb.RunAsync();
}
}
}
Loading

0 comments on commit ab87232

Please sign in to comment.