Skip to content

Commit

Permalink
Relax diagnostic analyzers for static members of grain interfaces (#8506
Browse files Browse the repository at this point in the history
)

* Fix: ORLEANS0009 - Skip Static Interface Methods even if virtual or abstract. There seems to be no valid reason why static methods shouldn't be allowed to return non-async types, just because they are abstract or virtual.

* Fix: ORLEANS0008 - Allow grain interfaces to have properties, if they are static.

* Fix: ORLEANS0002 - Allow grain interfaces methods to have out or ref params if those methods are static.

* SerializerConfigurationAnalyzer: Ignore static interface methods.

* Test: Add CodeGenTests for interfaces having static members.
  • Loading branch information
minichma authored Jul 5, 2023
1 parent f93d7d3 commit 005c27f
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)

if (symbol.ContainingType.TypeKind != TypeKind.Interface) return;

// allow static interface methods to return any type (excluding abstract / virtual)
if (symbol.IsStatic && !symbol.IsAbstract && !symbol.IsVirtual)
// allow static interface methods to return any type
if (symbol.IsStatic)
return;

var isIAddressableInterface = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)

if (symbol.ContainingType.TypeKind != TypeKind.Interface) return;

// ignore static members
if (symbol.IsStatic) return;

var isIAddressableInterface = false;
foreach (var implementedInterface in symbol.ContainingType.AllInterfaces)
{
Expand Down
3 changes: 3 additions & 0 deletions src/Orleans.Analyzers/NoRefParamsDiagnosticAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)

if (symbol.ContainingType.TypeKind != TypeKind.Interface) return;

// ignore static members
if (symbol.IsStatic) return;

var implementedInterfaces = symbol.ContainingType
.AllInterfaces
.Select(interfaceDef => interfaceDef.Name);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Orleans.Serialization.Configuration;
using Orleans.Serialization.Configuration;
using Orleans.Serialization.Serializers;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -29,7 +29,7 @@ public static Dictionary<Type, SerializerConfigurationComplaint> AnalyzeSerializ
var allComplaints = new Dictionary<Type, SerializerConfigurationComplaint>();
foreach (var @interface in options.Interfaces)
{
foreach (var method in @interface.GetMethods())
foreach (var method in @interface.GetMethods(BindingFlags.Instance | BindingFlags.Public))
{
if (typeof(Task).IsAssignableFrom(method.ReturnType))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public async Task StaticInterfaceMethodsWithRegularReturnsAreAllowed()
public interface I : Orleans.IGrain
{
public static int GetSomeOtherThing(int a) => 0;
public static virtual int GetSomeOtherThingVirtual(int a) => 0;
}
""";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,34 @@ public interface I : Orleans.IGrainObserver
Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);
Assert.Equal(MessageFormat, diagnostic.GetMessage());
}

[Fact]
public async Task StaticInterfacePropertiesAllowedInGrainInterface()
{
var code = """
public interface I : Orleans.IGrain
{
public static int MyProperty => 0;
public static virtual int MyVirtualProperty => 0;
}
""";

var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);
Assert.Empty(diagnostics);
}

[Fact]
public async Task StaticInterfacePropertiesAllowedInAddressableInterface()
{
var code = """
public interface I : Orleans.Runtime.IAddressable
{
public static int MyProperty => 0;
public static virtual int MyVirtualProperty => 0;
}
""";

var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);
Assert.Empty(diagnostics);
}
}
13 changes: 13 additions & 0 deletions test/Analyzers.Tests/NoRefParamsDiagnosticAnalyzerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,18 @@ public Task SomeNonInterfaceMethod(ref int value, out int value2, in int value3)

Assert.Empty(diagnostics);
}

[Fact]
public async Task OutAndRefParamsAllowedInStaticGrainInterfaceMethods()
{
var code = @"public interface I : IGrain
{
public static bool SomeStaticMethod(out int o, ref int v) { o = 0; return false; }
public static virtual bool SomeStaticVirtualMethod(out int o, ref int v) { o = 0; return false; }
}";

var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);
Assert.Empty(diagnostics);
}
}
}
13 changes: 13 additions & 0 deletions test/DefaultCluster.Tests/CodeGenTests/IRuntimeCodeGenGrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,4 +342,17 @@ public Task<int> Do(NestedConstructedGeneric value)
return Task.FromResult(value.Payload.Value);
}
}

public interface IGrainWithStaticMembers : IGrainWithGuidKey
{
public static int StaticMethodWithNonAsyncReturnType(int a) => 0;
public static virtual int StaticVirtualMethodWithNonAsyncReturnType(int a) => 0;
public static int StaticProperty => 0;
public static virtual int StaticVirtualProperty => 0;
public static int StaticMethodWithOutAndVarParams(out int a, ref int b) { a = 0; return 0; }
public static virtual int StaticVirtualMethodWithOutAndVarParams(out int a, ref int b) { a = 0; return 0; }
}

public class GrainWithStaticMembers : Grain, IGrainWithStaticMembers
{ }
}

0 comments on commit 005c27f

Please sign in to comment.