Skip to content

Commit

Permalink
Merge pull request #102 from chickensoft-games/fix/override-handler-d…
Browse files Browse the repository at this point in the history
…iagrams

fix: correctly resolve overridden input handlers for diagram visualization
  • Loading branch information
jolexxa authored Oct 23, 2024
2 parents 972def3 + 9fd7d32 commit 4c4840f
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 10 deletions.
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/Chickensoft.LogicBlocks.Example/bin/Debug/net7.0/Chickensoft.LogicBlocks.Example.dll",
"program": "${workspaceFolder}/Chickensoft.LogicBlocks.Example/bin/Debug/net8.0/Chickensoft.LogicBlocks.Example.dll",
"args": [
// "${input:args}"
],
Expand All @@ -17,4 +17,4 @@
"enableStepFiltering": false,
},
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@
<PackageReleaseNotes>LogicBlocks CodeFixes release.</PackageReleaseNotes>
<PackageIcon>icon.png</PackageIcon>
<PackageTags>state management;bloc;godot;game;state machine</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageProjectUrl>https://github.com/chickensoft-games/LogicBlocks</PackageProjectUrl>
</PropertyGroup>

<ItemGroup>
<!-- Has to be in its own item group -->
<None Include="./README.md" Pack="true" PackagePath="\" />
<None Include="./README.md" Pack="true" PackagePath="\" />
<None Include="../LICENSE" Pack="true" PackagePath="\" />
<None Include="../Chickensoft.LogicBlocks/icon.png" Pack="true" PackagePath="" />
</ItemGroup>

<!-- The following libraries include the types we need -->
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.11.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" PrivateAssets="all" />
</ItemGroup>

<!-- This ensures the library will be packaged as an analyzer when we use `dotnet pack` -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
namespace Chickensoft.LogicBlocks.ScratchPad;

using Chickensoft.Introspection;

[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial class OverriddenHandlers : LogicBlock<OverriddenHandlers.State> {
public override Transition GetInitialState() => To<State.Idle>();

public static class Input {
public readonly record struct SomeInput();
public readonly record struct SomeOtherInput();

}

public static class Output {
public readonly record struct SomeOutput();
public readonly record struct SomeOtherOutput();
}

public abstract record State : StateLogic<State>,
IGet<Input.SomeInput>, IGet<Input.SomeOtherInput> {

public virtual Transition On(in Input.SomeInput input) {
Output(new Output.SomeOutput());

return ToSelf();
}

public Transition On(in Input.SomeOtherInput input) {
Output(new Output.SomeOtherOutput());

return ToSelf();
}

public record Idle : State {
public override Transition On(in Input.SomeInput input) {
Output(new Output.SomeOtherOutput());

return ToSelf();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@startuml OverriddenHandlers
state "OverriddenHandlers State" as Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State {
state "Idle" as Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle
}

Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : SomeInput
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : SomeOtherInput
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle : SomeInput

Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : OnSomeInputSomeOutput
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : OnSomeOtherInputSomeOtherOutput
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle : OnSomeInputSomeOtherOutput

[*] --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle
@enduml
35 changes: 30 additions & 5 deletions Chickensoft.LogicBlocks.DiagramGenerator/src/Diagrammer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,14 +499,18 @@ INamedTypeSymbol stateBaseType
// Get all of the handled inputs by looking at the implemented input
// handler interfaces.

var handledInputInterfaces = type.Interfaces.Where(
var handledInputInterfaces = type.AllInterfaces.Where(
(interfaceType) => CodeService.GetNameFullyQualifiedWithoutGenerics(
interfaceType, interfaceType.Name
) is
Constants.LOGIC_BLOCK_INPUT_INTERFACE_ID &&
interfaceType.TypeArguments.Length == 1
);

var interfaces = new HashSet<INamedTypeSymbol>(
type.Interfaces, SymbolEqualityComparer.Default
);

// Get all syntax nodes comprising this type declaration.
var syntaxNodes = type.DeclaringSyntaxReferences
.Select(syntaxRef => syntaxRef.GetSyntax(token));
Expand Down Expand Up @@ -542,16 +546,37 @@ INamedTypeSymbol stateBaseType
continue;
}

var onTypeItself = interfaces.Contains(handledInputInterface);

if (!onTypeItself) {
// method is not on the current type (so it must be implemented on a
// base type).
//
// we have to check for this case since Roslyn doesn't return
// overridden methods on the derived type when asking for an interface's
// member implementation method — we have to look up the overrides
// ourselves :/

// find any equivalent, overridden method on the current derived type
methodSymbol = type.GetMembers()
.OfType<IMethodSymbol>()
.FirstOrDefault(
member => SymbolEqualityComparer.Default.Equals(
member.OverriddenMethod, methodSymbol
)
);

if (methodSymbol is null) {
continue;
}
}

var handlerMethodSyntaxes = methodSymbol
.DeclaringSyntaxReferences
.Select(syntaxRef => syntaxRef.GetSyntax(token))
.OfType<MethodDeclarationSyntax>()
.ToImmutableArray();

if (handlerMethodSyntaxes.Length == 0) {
continue;
}

foreach (var methodSyntax in handlerMethodSyntaxes) {
inputHandlerMethods.Add(methodSyntax);
var inputId = CodeService.GetNameFullyQualifiedWithoutGenerics(
Expand Down

0 comments on commit 4c4840f

Please sign in to comment.