Skip to content

Commit 4c4840f

Browse files
author
Joanna May
authored
Merge pull request #102 from chickensoft-games/fix/override-handler-diagrams
fix: correctly resolve overridden input handlers for diagram visualization
2 parents 972def3 + 9fd7d32 commit 4c4840f

File tree

5 files changed

+93
-10
lines changed

5 files changed

+93
-10
lines changed

.vscode/launch.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"type": "coreclr",
77
"request": "launch",
88
"preLaunchTask": "build",
9-
"program": "${workspaceFolder}/Chickensoft.LogicBlocks.Example/bin/Debug/net7.0/Chickensoft.LogicBlocks.Example.dll",
9+
"program": "${workspaceFolder}/Chickensoft.LogicBlocks.Example/bin/Debug/net8.0/Chickensoft.LogicBlocks.Example.dll",
1010
"args": [
1111
// "${input:args}"
1212
],
@@ -17,4 +17,4 @@
1717
"enableStepFiltering": false,
1818
},
1919
]
20-
}
20+
}

Chickensoft.LogicBlocks.CodeFixes/Chickensoft.LogicBlocks.CodeFixes.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,21 @@
2525
<PackageReleaseNotes>LogicBlocks CodeFixes release.</PackageReleaseNotes>
2626
<PackageIcon>icon.png</PackageIcon>
2727
<PackageTags>state management;bloc;godot;game;state machine</PackageTags>
28-
<PackageReadmeFile>README.md</PackageReadmeFile>
28+
<PackageReadmeFile>README.md</PackageReadmeFile>
2929
<PackageLicenseFile>LICENSE</PackageLicenseFile>
3030
<PackageProjectUrl>https://github.com/chickensoft-games/LogicBlocks</PackageProjectUrl>
3131
</PropertyGroup>
3232

3333
<ItemGroup>
3434
<!-- Has to be in its own item group -->
35-
<None Include="./README.md" Pack="true" PackagePath="\" />
35+
<None Include="./README.md" Pack="true" PackagePath="\" />
3636
<None Include="../LICENSE" Pack="true" PackagePath="\" />
3737
<None Include="../Chickensoft.LogicBlocks/icon.png" Pack="true" PackagePath="" />
3838
</ItemGroup>
3939

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

4545
<!-- This ensures the library will be packaged as an analyzer when we use `dotnet pack` -->
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
namespace Chickensoft.LogicBlocks.ScratchPad;
2+
3+
using Chickensoft.Introspection;
4+
5+
[Meta, LogicBlock(typeof(State), Diagram = true)]
6+
public partial class OverriddenHandlers : LogicBlock<OverriddenHandlers.State> {
7+
public override Transition GetInitialState() => To<State.Idle>();
8+
9+
public static class Input {
10+
public readonly record struct SomeInput();
11+
public readonly record struct SomeOtherInput();
12+
13+
}
14+
15+
public static class Output {
16+
public readonly record struct SomeOutput();
17+
public readonly record struct SomeOtherOutput();
18+
}
19+
20+
public abstract record State : StateLogic<State>,
21+
IGet<Input.SomeInput>, IGet<Input.SomeOtherInput> {
22+
23+
public virtual Transition On(in Input.SomeInput input) {
24+
Output(new Output.SomeOutput());
25+
26+
return ToSelf();
27+
}
28+
29+
public Transition On(in Input.SomeOtherInput input) {
30+
Output(new Output.SomeOtherOutput());
31+
32+
return ToSelf();
33+
}
34+
35+
public record Idle : State {
36+
public override Transition On(in Input.SomeInput input) {
37+
Output(new Output.SomeOtherOutput());
38+
39+
return ToSelf();
40+
}
41+
}
42+
}
43+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@startuml OverriddenHandlers
2+
state "OverriddenHandlers State" as Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State {
3+
state "Idle" as Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle
4+
}
5+
6+
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : SomeInput
7+
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : SomeOtherInput
8+
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle : SomeInput
9+
10+
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : OnSomeInputSomeOutput
11+
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State : OnSomeOtherInputSomeOtherOutput
12+
Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle : OnSomeInputSomeOtherOutput
13+
14+
[*] --> Chickensoft_LogicBlocks_ScratchPad_OverriddenHandlers_State_Idle
15+
@enduml

Chickensoft.LogicBlocks.DiagramGenerator/src/Diagrammer.cs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -499,14 +499,18 @@ INamedTypeSymbol stateBaseType
499499
// Get all of the handled inputs by looking at the implemented input
500500
// handler interfaces.
501501

502-
var handledInputInterfaces = type.Interfaces.Where(
502+
var handledInputInterfaces = type.AllInterfaces.Where(
503503
(interfaceType) => CodeService.GetNameFullyQualifiedWithoutGenerics(
504504
interfaceType, interfaceType.Name
505505
) is
506506
Constants.LOGIC_BLOCK_INPUT_INTERFACE_ID &&
507507
interfaceType.TypeArguments.Length == 1
508508
);
509509

510+
var interfaces = new HashSet<INamedTypeSymbol>(
511+
type.Interfaces, SymbolEqualityComparer.Default
512+
);
513+
510514
// Get all syntax nodes comprising this type declaration.
511515
var syntaxNodes = type.DeclaringSyntaxReferences
512516
.Select(syntaxRef => syntaxRef.GetSyntax(token));
@@ -542,16 +546,37 @@ INamedTypeSymbol stateBaseType
542546
continue;
543547
}
544548

549+
var onTypeItself = interfaces.Contains(handledInputInterface);
550+
551+
if (!onTypeItself) {
552+
// method is not on the current type (so it must be implemented on a
553+
// base type).
554+
//
555+
// we have to check for this case since Roslyn doesn't return
556+
// overridden methods on the derived type when asking for an interface's
557+
// member implementation method — we have to look up the overrides
558+
// ourselves :/
559+
560+
// find any equivalent, overridden method on the current derived type
561+
methodSymbol = type.GetMembers()
562+
.OfType<IMethodSymbol>()
563+
.FirstOrDefault(
564+
member => SymbolEqualityComparer.Default.Equals(
565+
member.OverriddenMethod, methodSymbol
566+
)
567+
);
568+
569+
if (methodSymbol is null) {
570+
continue;
571+
}
572+
}
573+
545574
var handlerMethodSyntaxes = methodSymbol
546575
.DeclaringSyntaxReferences
547576
.Select(syntaxRef => syntaxRef.GetSyntax(token))
548577
.OfType<MethodDeclarationSyntax>()
549578
.ToImmutableArray();
550579

551-
if (handlerMethodSyntaxes.Length == 0) {
552-
continue;
553-
}
554-
555580
foreach (var methodSyntax in handlerMethodSyntaxes) {
556581
inputHandlerMethods.Add(methodSyntax);
557582
var inputId = CodeService.GetNameFullyQualifiedWithoutGenerics(

0 commit comments

Comments
 (0)