Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,10 @@ private static bool TryMatchGenericSyntaxNodeWithGivenSymbol(GenericNameSyntax g
foreach (SyntaxReference? syntaxReference in typeSymbolDeclaringReferences)
{
SyntaxNode typeOrMethodDefinition = syntaxReference.GetSyntax();
if (typeOrMethodDefinition is ClassDeclarationSyntax classDeclaration)
if (typeOrMethodDefinition is TypeDeclarationSyntax typeDeclaration)
{
// For ex: class A<T> where T : IFoo, new() // where IFoo is preview
SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses = classDeclaration.ConstraintClauses;
SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses = typeDeclaration.ConstraintClauses;
if (TryGetConstraintClauseNode(constraintClauses, previewInterfaceConstraintSymbol, out SyntaxNode? ret))
{
return ret;
Expand Down Expand Up @@ -241,26 +241,9 @@ private static bool TryGetConstraintClauseNode(SyntaxList<TypeParameterConstrain
foreach (SyntaxReference? syntaxReference in typeSymbolDeclaringReferences)
{
SyntaxNode typeSymbolDefinition = syntaxReference.GetSyntax();
if (typeSymbolDefinition is ClassDeclarationSyntax classDeclaration)
if (typeSymbolDefinition is TypeDeclarationSyntax { BaseList.Types: var baseListTypes })
{
SeparatedSyntaxList<BaseTypeSyntax> baseListTypes = classDeclaration.BaseList.Types;
if (TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(baseListTypes, previewInterfaceSymbol, out ret))
{
return ret;
}
}
else if (typeSymbolDefinition is StructDeclarationSyntax structDeclaration)
{
SeparatedSyntaxList<BaseTypeSyntax> baseListTypes = structDeclaration.BaseList.Types;
if (TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(baseListTypes, previewInterfaceSymbol, out ret))
{
return ret;
}
}
else if (typeSymbolDefinition is InterfaceDeclarationSyntax interfaceDeclaration)
{
SeparatedSyntaxList<BaseTypeSyntax> baseListTypes = interfaceDeclaration.BaseList.Types;
if (TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(baseListTypes, previewInterfaceSymbol, out ret))
if (TryGetPreviewInterfaceNodeForTypeImplementingPreviewInterface(baseListTypes, previewInterfaceSymbol, out ret))
{
return ret;
}
Expand All @@ -270,11 +253,11 @@ private static bool TryGetConstraintClauseNode(SyntaxList<TypeParameterConstrain
return ret;
}

private static bool TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(SeparatedSyntaxList<BaseTypeSyntax> baseListTypes, ISymbol previewInterfaceSymbol, out SyntaxNode? previewInterfaceNode)
private static bool TryGetPreviewInterfaceNodeForTypeImplementingPreviewInterface(SeparatedSyntaxList<BaseTypeSyntax> baseListTypes, ISymbol previewInterfaceSymbol, out SyntaxNode? previewInterfaceNode)
{
foreach (BaseTypeSyntax baseTypeSyntax in baseListTypes)
{
if (baseTypeSyntax is SimpleBaseTypeSyntax simpleBaseTypeSyntax)
if (baseTypeSyntax is BaseTypeSyntax simpleBaseTypeSyntax)
{
TypeSyntax type = simpleBaseTypeSyntax.Type;
if (type is IdentifierNameSyntax identifier && IsSyntaxToken(identifier.Identifier, previewInterfaceSymbol))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ private static void ReportDiagnosticWithCustomMessageIfItExists(OperationAnalysi
{
if (!requiresPreviewFeaturesSymbols.TryGetValue(symbol, out (bool isPreview, string? message, string? url) existing))
{
Debug.Assert(true, $"Should never reach this line. This means the symbol {symbol.Name} was not processed in this analyzer");
Debug.Fail($"Should never reach this line. This means the symbol {symbol.Name} was not processed in this analyzer");
}
else
{
Expand All @@ -969,7 +969,7 @@ private static void ReportDiagnosticWithCustomMessageIfItExists(SymbolAnalysisCo
{
if (!requiresPreviewFeaturesSymbols.TryGetValue(previewSymbol, out (bool isPreview, string? message, string? url) existing))
{
Debug.Assert(true, $"Should never reach this line. This means the symbol {previewSymbol.Name} was not processed in this analyzer");
Debug.Fail($"Should never reach this line. This means the symbol {previewSymbol.Name} was not processed in this analyzer");
}
else
{
Expand All @@ -995,7 +995,7 @@ private static void ReportDiagnosticWithCustomMessageIfItExists(SymbolAnalysisCo
{
if (!requiresPreviewFeaturesSymbols.TryGetValue(previewSymbol, out (bool isPreview, string? message, string? url) existing))
{
Debug.Assert(true, $"Should never reach this line. This means the symbol {previewSymbol.Name} was not processed in this analyzer");
Debug.Fail($"Should never reach this line. This means the symbol {previewSymbol.Name} was not processed in this analyzer");
}
else
{
Expand All @@ -1022,7 +1022,7 @@ private static void ReportDiagnosticWithCustomMessageIfItExists(SymbolAnalysisCo
{
if (!requiresPreviewFeaturesSymbols.TryGetValue(previewSymbol, out (bool isPreview, string? message, string? url) existing))
{
Debug.Assert(true, $"Should never reach this line. This means the symbol {previewSymbol.Name} was not processed in this analyzer");
Debug.Fail($"Should never reach this line. This means the symbol {previewSymbol.Name} was not processed in this analyzer");
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Threading.Tasks;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpDetectPreviewFeatureAnalyzer,
Expand Down Expand Up @@ -110,39 +111,41 @@ static void Main(string[] args)
await test.RunAsync();
}

[Fact]
public async Task TestAbstractClass()
[Theory]
[InlineData("class")]
[InlineData("record")]
public async Task TestAbstractType(string type)
{
var csInput = @"
var csInput = $@"
using System.Runtime.Versioning; using System;
namespace Preview_Feature_Scratch
{
{{

class Program : {|#0:AbClass|}
{
{type} Program : {{|#0:AbClass|}}
{{
static void Main(string[] args)
{
{{
Program prog = new Program();
prog.Bar();
{|#1:prog.FooBar()|};
{|#2:prog.BarImplemented()|};
}
{{|#1:prog.FooBar()|}};
{{|#2:prog.BarImplemented()|}};
}}

public override void {|#3:Bar|}()
{
public override void {{|#3:Bar|}}()
{{
throw new NotImplementedException();
}
}}

[RequiresPreviewFeatures]
public override void FooBar()
{
{{
throw new NotImplementedException();
}
}
}}
}}

[RequiresPreviewFeatures]
public abstract class AbClass
{
public abstract {type} AbClass
{{
[RequiresPreviewFeatures]
public abstract void Bar();

Expand All @@ -151,8 +154,8 @@ public abstract class AbClass

[RequiresPreviewFeatures]
public void BarImplemented() => throw new NotImplementedException();
}
}";
}}
}}";

var test = TestCS(csInput);
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.DerivesFromPreviewClassRule).WithLocation(0).WithArguments("Program", "AbClass", DetectPreviewFeatureAnalyzer.DefaultURL));
Expand All @@ -162,6 +165,26 @@ public abstract class AbClass
await test.RunAsync();
}

[Fact, WorkItem(5802, "https://github.com/dotnet/roslyn-analyzers/issues/5802")]
public async Task TestPartialClassWithFirstDeclarationNotHavingBaseTypes()
{
var test = TestCS(@"
using System;
using System.Runtime.Versioning;

partial class Program { }

partial class Program : {|#0:AbClass|} { }

[RequiresPreviewFeatures]
public class AbClass
{
}
");
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.DerivesFromPreviewClassRule).WithLocation(0).WithArguments("Program", "AbClass", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();
}

[Theory]
[InlineData("class")]
[InlineData("struct")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,47 +126,15 @@ Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime

For Each syntaxReference In typeSymbolDeclaringReferences
Dim typeSymbolDefinition = syntaxReference.GetSyntax()
Dim classStatement = TryCast(typeSymbolDefinition, ClassStatementSyntax)
If classStatement IsNot Nothing Then
Dim classBlock = TryCast(classStatement.Parent, ClassBlockSyntax)
If classBlock IsNot Nothing Then
Dim typeStatement = TryCast(typeSymbolDefinition, TypeStatementSyntax)
If typeStatement IsNot Nothing Then
Dim typeBlock = TryCast(typeStatement.Parent, TypeBlockSyntax)
If typeBlock IsNot Nothing Then
Dim syntaxNode As SyntaxNode = Nothing
If TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(classBlock.Inherits, previewInterfaceSymbol, syntaxNode) Then
If TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(typeBlock.Inherits, previewInterfaceSymbol, syntaxNode) Then
Return syntaxNode
Else
If TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(classBlock.Implements, previewInterfaceSymbol, syntaxNode) Then
Return syntaxNode
End If
End If
End If
End If

Dim structStatement = TryCast(typeSymbolDefinition, StructureStatementSyntax)
If structStatement IsNot Nothing Then
Dim structBlock = TryCast(structStatement.Parent, StructureBlockSyntax)
If structBlock IsNot Nothing Then
Dim syntaxNode As SyntaxNode = Nothing
If TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(structBlock.Inherits, previewInterfaceSymbol, syntaxNode) Then
Return syntaxNode
Else
If TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(structBlock.Implements, previewInterfaceSymbol, syntaxNode) Then
Return syntaxNode
End If
End If
End If
End If

Dim interfaceStatement = TryCast(typeSymbolDefinition, InterfaceStatementSyntax)
If interfaceStatement IsNot Nothing Then
Dim interfaceBlock = TryCast(interfaceStatement.Parent, InterfaceBlockSyntax)
If interfaceBlock IsNot Nothing Then
Dim syntaxNode As SyntaxNode = Nothing
If TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(interfaceBlock.Implements, previewInterfaceSymbol, syntaxNode) Then
ElseIf TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(typeBlock.Implements, previewInterfaceSymbol, syntaxNode) Then
Return syntaxNode
Else
If TryGetPreviewInterfaceNodeForClassOrStructImplementingPreviewInterface(interfaceBlock.Inherits, previewInterfaceSymbol, syntaxNode) Then
Return syntaxNode
End If
End If
End If
End If
Expand Down