Skip to content

Commit

Permalink
AK1000: added failing test case for IIndirectActorProducer.Produce (#…
Browse files Browse the repository at this point in the history
…31)

* AK1000: added failing test case for `IIndirectActorProducer.Produce`

* resolved `IIndirectActorProducer` checks on AK1000
  • Loading branch information
Aaronontheweb committed Jan 3, 2024
1 parent d032681 commit 2c58781
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 1 deletion.
Expand Up @@ -167,6 +167,43 @@ class Test
return Method(() => new MyActor("foo", 1));
}
}
""",

// IIndirectActorProducer - won't often be found in user code, but should be supported
"""
using Akka.Actor;
using System;

public class TestProducer : IIndirectActorProducer
{
public TestProducer()
{
}

public ActorBase Produce()
{
return new PropsTestActor();
}

public Type ActorType
{
get { return typeof(PropsTestActor); }
}


public void Release(ActorBase actor)
{
actor = null;
}
}

public class PropsTestActor : ActorBase
{
protected override bool Receive(object message)
{
return true;
}
}
"""
};

Expand Down
Expand Up @@ -31,14 +31,32 @@ public override void AnalyzeCompilation(CompilationStartAnalysisContext context,
return;
// Check if it's within the context of Props.Create
if (IsInsidePropsCreate(objectCreation, ctx.SemanticModel, akkaContext))
if (IsInsidePropsCreate(objectCreation, ctx.SemanticModel, akkaContext) || IsWithinIndirectActorProducerProduce(objectCreation, ctx.SemanticModel, akkaContext))
return;
var diagnostic = Diagnostic.Create(RuleDescriptors.Ak1000DoNotNewActors, objectCreation.GetLocation(),
typeSymbol.Name);
ctx.ReportDiagnostic(diagnostic);
}, SyntaxKind.ObjectCreationExpression);
}

private static bool IsWithinIndirectActorProducerProduce(ObjectCreationExpressionSyntax objectCreation, SemanticModel semanticModel, AkkaContext akkaContext)
{
var enclosingMethod = objectCreation.Ancestors().OfType<MethodDeclarationSyntax>().FirstOrDefault();
if (enclosingMethod == null)
return false;

if (semanticModel.GetDeclaredSymbol(enclosingMethod) is not { Name: "Produce" } methodSymbol)
return false;

var containingType = methodSymbol.ContainingType;
if (containingType == null)
return false;

// Check if the containing type implements IIndirectActorProducer
return containingType.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, akkaContext.AkkaCore.IndirectActorProducerType));
}


private static bool IsInsidePropsCreate(ObjectCreationExpressionSyntax objectCreation, SemanticModel semanticModel, AkkaContext akkaContext)
{
Expand Down
16 changes: 16 additions & 0 deletions src/Akka.Analyzers/Utility/AkkaCoreContext.cs
Expand Up @@ -21,6 +21,10 @@ public interface IAkkaCoreContext
public INamedTypeSymbol? ActorBaseType { get; }
public INamedTypeSymbol? ActorRefType { get; }
public INamedTypeSymbol? PropsType { get; }

public INamedTypeSymbol? ActorContextType { get; }

public INamedTypeSymbol? IndirectActorProducerType { get; }
}

/// <summary>
Expand All @@ -38,6 +42,10 @@ private EmptyCoreContext()
public INamedTypeSymbol? ActorBaseType => null;
public INamedTypeSymbol? ActorRefType => null;
public INamedTypeSymbol? PropsType => null;

public INamedTypeSymbol? ActorContextType => null;

public INamedTypeSymbol? IndirectActorProducerType => null;
}

/// <summary>
Expand All @@ -52,13 +60,17 @@ public class AkkaCoreContext : IAkkaCoreContext
private readonly Lazy<INamedTypeSymbol?> _lazyActorBaseType;
private readonly Lazy<INamedTypeSymbol?> _lazyActorRefType;
private readonly Lazy<INamedTypeSymbol?> _lazyPropsType;
private readonly Lazy<INamedTypeSymbol?> _lazyActorContextType;
private readonly Lazy<INamedTypeSymbol?> _lazyIIndirectActorProducerType;

private AkkaCoreContext(Compilation compilation, Version version)
{
Version = version;
_lazyActorBaseType = new Lazy<INamedTypeSymbol?>(() => TypeSymbolFactory.ActorBase(compilation));
_lazyActorRefType = new Lazy<INamedTypeSymbol?>(() => TypeSymbolFactory.ActorReference(compilation));
_lazyPropsType = new Lazy<INamedTypeSymbol?>(() => TypeSymbolFactory.Props(compilation));
_lazyActorContextType = new Lazy<INamedTypeSymbol?>(() => TypeSymbolFactory.ActorContext(compilation));
_lazyIIndirectActorProducerType = new Lazy<INamedTypeSymbol?>(() => TypeSymbolFactory.IndirectActorProducer(compilation));
}

/// <inheritdoc />
Expand All @@ -67,6 +79,10 @@ private AkkaCoreContext(Compilation compilation, Version version)
public INamedTypeSymbol? ActorBaseType => _lazyActorBaseType.Value;
public INamedTypeSymbol? ActorRefType => _lazyActorRefType.Value;
public INamedTypeSymbol? PropsType => _lazyPropsType.Value;

public INamedTypeSymbol? ActorContextType => _lazyActorContextType.Value;

public INamedTypeSymbol? IndirectActorProducerType => _lazyIIndirectActorProducerType.Value;

public static AkkaCoreContext? Get(
Compilation compilation,
Expand Down
12 changes: 12 additions & 0 deletions src/Akka.Analyzers/Utility/TypeSymbolFactory.cs
Expand Up @@ -27,4 +27,16 @@ public static class TypeSymbolFactory
return Guard.AssertIsNotNull(compilation)
.GetTypeByMetadataName("Akka.Actor.Props");
}

public static INamedTypeSymbol? ActorContext(Compilation compilation)
{
return Guard.AssertIsNotNull(compilation)
.GetTypeByMetadataName("Akka.Actor.IActorContext");
}

public static INamedTypeSymbol? IndirectActorProducer(Compilation compilation)
{
return Guard.AssertIsNotNull(compilation)
.GetTypeByMetadataName("Akka.Actor.IIndirectActorProducer");
}
}

0 comments on commit 2c58781

Please sign in to comment.