com.wallstop-studios.dxmessaging 2.2.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +315 -67
- package/CHANGELOG.md.meta +7 -7
- package/Editor/Analyzers/BaseCallIlInspector.cs +277 -0
- package/Editor/Analyzers/BaseCallIlInspector.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallLogMessageParser.cs +295 -0
- package/Editor/Analyzers/BaseCallLogMessageParser.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallReportAggregator.cs +308 -0
- package/Editor/Analyzers/BaseCallReportAggregator.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallTypeScanner.cs +110 -0
- package/Editor/Analyzers/BaseCallTypeScanner.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallTypeScannerCore.cs +562 -0
- package/Editor/Analyzers/BaseCallTypeScannerCore.cs.meta +11 -0
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs +1129 -0
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs.meta +11 -0
- package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +44 -44
- package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +44 -44
- package/Editor/Analyzers/System.Collections.Immutable.dll.meta +44 -44
- package/Editor/Analyzers/System.Reflection.Metadata.dll.meta +44 -44
- package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +44 -44
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll +0 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll.meta +46 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +72 -72
- package/Editor/Analyzers.meta +8 -8
- package/Editor/AssemblyInfo.cs.meta +11 -3
- package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs +81 -0
- package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs.meta +11 -0
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs +429 -0
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs.meta +11 -0
- package/Editor/CustomEditors/MessagingComponentEditor.cs +1 -1
- package/Editor/CustomEditors/MessagingComponentEditor.cs.meta +11 -3
- package/Editor/CustomEditors.meta +2 -2
- package/Editor/DxMessagingEditorIdle.cs +62 -0
- package/Editor/DxMessagingEditorIdle.cs.meta +11 -0
- package/Editor/DxMessagingEditorInitializer.cs +112 -15
- package/Editor/DxMessagingEditorInitializer.cs.meta +11 -3
- package/Editor/DxMessagingEditorLog.cs +32 -0
- package/Editor/DxMessagingEditorLog.cs.meta +11 -0
- package/Editor/DxMessagingMenu.cs.meta +11 -11
- package/Editor/DxMessagingSceneBuildProcessor.cs.meta +11 -11
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs +313 -0
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs.meta +11 -0
- package/Editor/Settings/DxMessagingSettings.cs +261 -11
- package/Editor/Settings/DxMessagingSettings.cs.meta +11 -3
- package/Editor/Settings/DxMessagingSettingsProvider.cs +50 -33
- package/Editor/Settings/DxMessagingSettingsProvider.cs.meta +11 -3
- package/Editor/Settings.meta +2 -2
- package/Editor/SetupCscRsp.cs +406 -39
- package/Editor/SetupCscRsp.cs.meta +11 -3
- package/Editor/Testing/MessagingComponentEditorHarness.cs +2 -2
- package/Editor/Testing/MessagingComponentEditorHarness.cs.meta +11 -3
- package/Editor/Testing.meta +3 -3
- package/Editor/WallstopStudios.DxMessaging.Editor.asmdef +14 -14
- package/Editor/WallstopStudios.DxMessaging.Editor.asmdef.meta +7 -7
- package/Editor.meta +8 -8
- package/LICENSE.md +9 -9
- package/LICENSE.md.meta +7 -7
- package/README.md +940 -900
- package/README.md.meta +7 -7
- package/Runtime/AssemblyInfo.cs +4 -0
- package/Runtime/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxIgnoreMissingBaseCallAttribute.cs +26 -0
- package/Runtime/Core/Attributes/DxIgnoreMissingBaseCallAttribute.cs.meta +11 -0
- package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +2 -4
- package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/Il2CppSetOptionAttribute.cs +56 -0
- package/Runtime/Core/Attributes/Il2CppSetOptionAttribute.cs.meta +11 -0
- package/Runtime/Core/Attributes.meta +2 -2
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettings.cs +195 -0
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettings.cs.meta +11 -0
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettingsProvider.cs +179 -0
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettingsProvider.cs.meta +11 -0
- package/Runtime/Core/Configuration.meta +9 -0
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +46 -28
- package/Runtime/Core/DataStructure/CyclicBuffer.cs.meta +11 -3
- package/Runtime/Core/DataStructure.meta +2 -2
- package/Runtime/Core/Diagnostics/MessageEmissionData.cs.meta +11 -3
- package/Runtime/Core/Diagnostics/MessageRegistrationData.cs.meta +11 -3
- package/Runtime/Core/Diagnostics/MessageRegistrationType.cs.meta +11 -3
- package/Runtime/Core/Diagnostics.meta +2 -2
- package/Runtime/Core/DxMessagingStaticState.cs +19 -0
- package/Runtime/Core/DxMessagingStaticState.cs.meta +11 -11
- package/Runtime/Core/Extensions/EnumExtensions.cs +6 -5
- package/Runtime/Core/Extensions/EnumExtensions.cs.meta +11 -3
- package/Runtime/Core/Extensions/IListExtensions.cs.meta +11 -3
- package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -12
- package/Runtime/Core/Extensions/MessageExtensions.cs +0 -60
- package/Runtime/Core/Extensions/MessageExtensions.cs.meta +11 -11
- package/Runtime/Core/Extensions.meta +8 -8
- package/Runtime/Core/Helper/MessageCache.cs +32 -0
- package/Runtime/Core/Helper/MessageCache.cs.meta +11 -3
- package/Runtime/Core/Helper/MessageHelperIndexer.cs.meta +11 -3
- package/Runtime/Core/Helper.meta +2 -2
- package/Runtime/Core/IMessage.cs +3 -3
- package/Runtime/Core/IMessage.cs.meta +11 -11
- package/Runtime/Core/InstanceId.cs +25 -1
- package/Runtime/Core/InstanceId.cs.meta +11 -11
- package/Runtime/Core/Internal/DxUnsafe.cs +60 -0
- package/Runtime/Core/Internal/DxUnsafe.cs.meta +11 -0
- package/Runtime/Core/Internal/FlatDispatch.cs +198 -0
- package/Runtime/Core/Internal/FlatDispatch.cs.meta +11 -0
- package/Runtime/Core/Internal/TypedGlobalSlotIndex.cs +38 -0
- package/Runtime/Core/Internal/TypedGlobalSlotIndex.cs.meta +11 -0
- package/Runtime/Core/Internal/TypedSlotIndex.cs +81 -0
- package/Runtime/Core/Internal/TypedSlotIndex.cs.meta +11 -0
- package/Runtime/Core/Internal/TypedSlots.cs +597 -0
- package/Runtime/Core/Internal/TypedSlots.cs.meta +11 -0
- package/Runtime/Core/Internal.meta +9 -0
- package/Runtime/Core/MessageBus/DiagnosticsTarget.cs.meta +11 -11
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -11
- package/Runtime/Core/MessageBus/IMessageBus.cs +189 -15
- package/Runtime/Core/MessageBus/IMessageBus.cs.meta +11 -11
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -11
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +1 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -11
- package/Runtime/Core/MessageBus/Internal/BusContextIndex.cs +16 -0
- package/Runtime/Core/MessageBus/Internal/BusContextIndex.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/BusSinkIndex.cs +40 -0
- package/Runtime/Core/MessageBus/Internal/BusSinkIndex.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/BusSlots.cs +719 -0
- package/Runtime/Core/MessageBus/Internal/BusSlots.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/DispatchKind.cs +38 -0
- package/Runtime/Core/MessageBus/Internal/DispatchKind.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/DispatchPhase.cs +20 -0
- package/Runtime/Core/MessageBus/Internal/DispatchPhase.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/DispatchVariant.cs +28 -0
- package/Runtime/Core/MessageBus/Internal/DispatchVariant.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/IEvictableSlot.cs +48 -0
- package/Runtime/Core/MessageBus/Internal/IEvictableSlot.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/ISweepable.cs +15 -0
- package/Runtime/Core/MessageBus/Internal/ISweepable.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/RegistrationMethodAxes.cs +222 -0
- package/Runtime/Core/MessageBus/Internal/RegistrationMethodAxes.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/SlotKey.cs +192 -0
- package/Runtime/Core/MessageBus/Internal/SlotKey.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal.meta +9 -0
- package/Runtime/Core/MessageBus/MessageBus.cs +5366 -3838
- package/Runtime/Core/MessageBus/MessageBus.cs.meta +11 -11
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -11
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +187 -14
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -11
- package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +11 -11
- package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +11 -11
- package/Runtime/Core/MessageBus.meta +8 -8
- package/Runtime/Core/MessageHandler.cs +2399 -1042
- package/Runtime/Core/MessageHandler.cs.meta +11 -11
- package/Runtime/Core/MessageRegistrationHandle.cs.meta +11 -11
- package/Runtime/Core/MessageRegistrationToken.cs +429 -44
- package/Runtime/Core/MessageRegistrationToken.cs.meta +11 -11
- package/Runtime/Core/Messages/GlobalStringMessage.cs.meta +11 -3
- package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/ITargetedMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/ReflexiveMessage.cs.meta +11 -3
- package/Runtime/Core/Messages/SourcedStringMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/StringMessage.cs.meta +11 -3
- package/Runtime/Core/Messages.meta +8 -8
- package/Runtime/Core/MessagingDebug.cs.meta +11 -11
- package/Runtime/Core/Pooling/CollectionPool.cs +266 -0
- package/Runtime/Core/Pooling/CollectionPool.cs.meta +11 -0
- package/Runtime/Core/Pooling/CollectionPoolDiagnostics.cs +30 -0
- package/Runtime/Core/Pooling/CollectionPoolDiagnostics.cs.meta +11 -0
- package/Runtime/Core/Pooling/DxPools.cs +157 -0
- package/Runtime/Core/Pooling/DxPools.cs.meta +11 -0
- package/Runtime/Core/Pooling/EvictionPlayerLoopHook.cs +106 -0
- package/Runtime/Core/Pooling/EvictionPlayerLoopHook.cs.meta +11 -0
- package/Runtime/Core/Pooling/IDxMessagingClock.cs +18 -0
- package/Runtime/Core/Pooling/IDxMessagingClock.cs.meta +11 -0
- package/Runtime/Core/Pooling/PoolDiagnosticsSnapshot.cs +55 -0
- package/Runtime/Core/Pooling/PoolDiagnosticsSnapshot.cs.meta +11 -0
- package/Runtime/Core/Pooling/StopwatchClock.cs +27 -0
- package/Runtime/Core/Pooling/StopwatchClock.cs.meta +11 -0
- package/Runtime/Core/Pooling/UnityRealtimeClock.cs +31 -0
- package/Runtime/Core/Pooling/UnityRealtimeClock.cs.meta +11 -0
- package/Runtime/Core/Pooling.meta +9 -0
- package/Runtime/Core.meta +8 -8
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -12
- package/Runtime/Unity/DxMessagingRuntimeInitializer.cs.meta +11 -11
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -12
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -11
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -20
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -7
- package/Runtime/Unity/Integrations/Reflex.meta +8 -8
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +109 -1
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -11
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -30
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -7
- package/Runtime/Unity/Integrations/VContainer.meta +8 -8
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -30
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -7
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +79 -1
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -11
- package/Runtime/Unity/Integrations/Zenject.meta +8 -8
- package/Runtime/Unity/Integrations.meta +8 -8
- package/Runtime/Unity/MessageAwareComponent.cs +74 -0
- package/Runtime/Unity/MessageAwareComponent.cs.meta +11 -11
- package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -12
- package/Runtime/Unity/MessagingComponent.cs +43 -10
- package/Runtime/Unity/MessagingComponent.cs.meta +11 -11
- package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -12
- package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -12
- package/Runtime/Unity.meta +8 -8
- package/Runtime/WallstopStudios.DxMessaging.asmdef +14 -14
- package/Runtime/WallstopStudios.DxMessaging.asmdef.meta +7 -7
- package/Runtime.meta +8 -8
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -98
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -7
- package/Samples~/DI/Prefabs.meta +8 -8
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -14
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -8
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -14
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -8
- package/Samples~/DI/Providers.meta +8 -8
- package/Samples~/DI/README.md +51 -51
- package/Samples~/DI/README.md.meta +7 -7
- package/Samples~/DI/Reflex/SampleInstaller.cs +7 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -11
- package/Samples~/DI/Reflex.meta +8 -8
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs +6 -1
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -11
- package/Samples~/DI/VContainer.meta +8 -8
- package/Samples~/DI/Zenject/SampleInstaller.cs +8 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -11
- package/Samples~/DI/Zenject.meta +8 -8
- package/Samples~/DI.meta +8 -8
- package/Samples~/Mini Combat/Boot.cs.meta +11 -11
- package/Samples~/Mini Combat/Enemy.cs.meta +11 -11
- package/Samples~/Mini Combat/Messages.cs.meta +11 -11
- package/Samples~/Mini Combat/Player.cs.meta +11 -11
- package/Samples~/Mini Combat/README.md +324 -323
- package/Samples~/Mini Combat/README.md.meta +7 -7
- package/Samples~/Mini Combat/UIOverlay.cs.meta +11 -11
- package/Samples~/Mini Combat/Walkthrough.md +430 -430
- package/Samples~/Mini Combat/Walkthrough.md.meta +7 -7
- package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef +13 -13
- package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef.meta +7 -7
- package/Samples~/Mini Combat.meta +8 -8
- package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/Messages.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/MessagingObserver.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/README.md +210 -209
- package/Samples~/UI Buttons + Inspector/README.md.meta +7 -7
- package/Samples~/UI Buttons + Inspector/UIButtonEmitter.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef +13 -13
- package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef.meta +7 -7
- package/Samples~/UI Buttons + Inspector.meta +8 -8
- package/SourceGenerators/Directory.Build.props +50 -3
- package/SourceGenerators/Directory.Build.props.meta +7 -7
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +96 -63
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs.meta +11 -11
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +745 -87
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs.meta +11 -3
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +39 -46
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj.meta +7 -7
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.meta +8 -8
- package/SourceGenerators/global.json +7 -0
- package/SourceGenerators/global.json.meta +7 -0
- package/SourceGenerators.meta +8 -8
- package/Third Party Notices.md +3 -3
- package/Third Party Notices.md.meta +7 -7
- package/package.json +102 -92
- package/package.json.meta +7 -7
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
// The Unity Editor assembly that hosts this file does not enable nullable annotations; the
|
|
2
|
+
// dotnet-test project that compiles a linked copy DOES (`<Nullable>enable</Nullable>`). Pin the
|
|
3
|
+
// nullable state per-file so behavior is identical in both compilation contexts.
|
|
4
|
+
#nullable disable
|
|
5
|
+
namespace DxMessaging.Editor.Analyzers
|
|
6
|
+
{
|
|
7
|
+
using System;
|
|
8
|
+
using System.Collections.Generic;
|
|
9
|
+
using System.Reflection;
|
|
10
|
+
|
|
11
|
+
/// <summary>
|
|
12
|
+
/// Pure (Unity-API-free) classification core for the IL-reflection scanner. Takes a
|
|
13
|
+
/// pre-supplied set of candidate <see cref="MessageAwareComponent"/>-derived types and
|
|
14
|
+
/// produces the per-FQN snapshot that the inspector overlay consumes.
|
|
15
|
+
/// </summary>
|
|
16
|
+
/// <remarks>
|
|
17
|
+
/// <para>
|
|
18
|
+
/// Extracted from <see cref="BaseCallTypeScanner"/> so the dotnet-test project can cover the
|
|
19
|
+
/// classification logic (chain walk, opt-out paths, master-toggle gating, FQN normalisation,
|
|
20
|
+
/// abstract / generic-definition skipping) without depending on Unity's <c>TypeCache</c> API.
|
|
21
|
+
/// The Unity-only wrapper <see cref="BaseCallTypeScanner.Scan"/> simply forwards
|
|
22
|
+
/// <c>TypeCache.GetTypesDerivedFrom<MessageAwareComponent>()</c> as the candidate set
|
|
23
|
+
/// and reads the project's ignore list off <c>DxMessagingSettings</c>.
|
|
24
|
+
/// </para>
|
|
25
|
+
/// <para>
|
|
26
|
+
/// All inputs are pure-BCL: tests compile small Roslyn fixtures, load the resulting
|
|
27
|
+
/// assemblies, enumerate <c>assembly.GetTypes().Where(t => ...)</c> as the candidate set,
|
|
28
|
+
/// and assert against the returned snapshot.
|
|
29
|
+
/// </para>
|
|
30
|
+
/// <para>
|
|
31
|
+
/// Diagnostic IDs produced match what the inspector overlay reads from the Unity-facing entry:
|
|
32
|
+
/// <c>DXMSG006</c> (override missing base call), <c>DXMSG007</c> (hides via <c>new</c>; also
|
|
33
|
+
/// covers DXMSG009 since IL alone can't distinguish the two -- see remarks on
|
|
34
|
+
/// <see cref="BaseCallIlInspector"/>), and <c>DXMSG010</c> (override calls base but a chain
|
|
35
|
+
/// link does not).
|
|
36
|
+
/// </para>
|
|
37
|
+
/// </remarks>
|
|
38
|
+
public static class BaseCallTypeScannerCore
|
|
39
|
+
{
|
|
40
|
+
/// <summary>
|
|
41
|
+
/// The guarded lifecycle methods on <c>MessageAwareComponent</c>. Method names are
|
|
42
|
+
/// matched ordinally. Most are zero-parameter, void-returning instance methods;
|
|
43
|
+
/// <c>OnApplicationFocus</c> and <c>OnApplicationPause</c> are guarded prospectively
|
|
44
|
+
/// for their canonical Unity <c>(bool)</c> signature even though the base class does
|
|
45
|
+
/// not currently declare them. See
|
|
46
|
+
/// <c>MessageAwareComponentBaseCallAnalyzer.GuardedMethodNames</c> /
|
|
47
|
+
/// <c>GuardedMethodsWithBoolSignature</c>; the two sets MUST stay in sync (a meta-test
|
|
48
|
+
/// in the dotnet-test project asserts set-equality).
|
|
49
|
+
/// </summary>
|
|
50
|
+
public static readonly string[] GuardedMethodNames =
|
|
51
|
+
{
|
|
52
|
+
"Awake",
|
|
53
|
+
"OnEnable",
|
|
54
|
+
"OnDisable",
|
|
55
|
+
"OnDestroy",
|
|
56
|
+
"OnApplicationFocus",
|
|
57
|
+
"OnApplicationPause",
|
|
58
|
+
"RegisterMessageHandlers",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/// <summary>
|
|
62
|
+
/// Guarded methods whose canonical Unity signature takes a single <c>bool</c>
|
|
63
|
+
/// (<c>OnApplicationFocus(bool focused)</c>, <c>OnApplicationPause(bool paused)</c>).
|
|
64
|
+
/// All other guarded methods are zero-argument.
|
|
65
|
+
/// </summary>
|
|
66
|
+
public static readonly HashSet<string> GuardedMethodsWithBoolSignature = new(
|
|
67
|
+
StringComparer.Ordinal
|
|
68
|
+
)
|
|
69
|
+
{
|
|
70
|
+
"OnApplicationFocus",
|
|
71
|
+
"OnApplicationPause",
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/// <summary>
|
|
75
|
+
/// Per-method consequence text shown by the inspector overlay HelpBox when an override
|
|
76
|
+
/// is missing its base call. Mirrors
|
|
77
|
+
/// <c>MessageAwareComponentBaseCallAnalyzer.MissingBaseCallMessageFormatsByMethod</c>
|
|
78
|
+
/// keyed by method name. The two dictionaries MUST stay in sync; the inspector overlay
|
|
79
|
+
/// already calls <see cref="GetMissingBaseConsequenceLine"/> per missing-method row, and
|
|
80
|
+
/// the meta-test on the analyzer side keeps the analyzer's dictionary populated for every
|
|
81
|
+
/// guarded method, but a future contributor adding a new guarded method MUST update both.
|
|
82
|
+
/// ASCII-only by policy.
|
|
83
|
+
/// </summary>
|
|
84
|
+
public static readonly IReadOnlyDictionary<
|
|
85
|
+
string,
|
|
86
|
+
string
|
|
87
|
+
> MissingBaseCallMessageFormatsByMethod = new Dictionary<string, string>(
|
|
88
|
+
StringComparer.Ordinal
|
|
89
|
+
)
|
|
90
|
+
{
|
|
91
|
+
{
|
|
92
|
+
"Awake",
|
|
93
|
+
"'{0}' overrides MessageAwareComponent.Awake but does not call base.Awake(); the message registration token will never be created and handlers cannot register."
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"OnEnable",
|
|
97
|
+
"'{0}' overrides MessageAwareComponent.OnEnable but does not call base.OnEnable(); handlers will not be re-enabled when this component is enabled."
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"OnDisable",
|
|
101
|
+
"'{0}' overrides MessageAwareComponent.OnDisable but does not call base.OnDisable(); handlers will not be disabled when this component is disabled, causing unwanted message processing."
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"OnDestroy",
|
|
105
|
+
"'{0}' overrides MessageAwareComponent.OnDestroy but does not call base.OnDestroy(); handlers will not be deregistered and the registration token will not be released, causing a memory leak."
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"RegisterMessageHandlers",
|
|
109
|
+
"'{0}' overrides MessageAwareComponent.RegisterMessageHandlers but does not call base.RegisterMessageHandlers(); default string-message handlers will not be registered (override RegisterForStringMessages to suppress this warning)."
|
|
110
|
+
},
|
|
111
|
+
// Prospective entries. MessageAwareComponent does not currently declare these
|
|
112
|
+
// methods; entries exist so future changes immediately surface actionable
|
|
113
|
+
// consequence text. Keep aligned with the analyzer's dictionary.
|
|
114
|
+
{
|
|
115
|
+
"OnApplicationFocus",
|
|
116
|
+
"'{0}' overrides MessageAwareComponent.OnApplicationFocus but does not call base.OnApplicationFocus(); the messaging system may not function correctly on this component when focus changes."
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"OnApplicationPause",
|
|
120
|
+
"'{0}' overrides MessageAwareComponent.OnApplicationPause but does not call base.OnApplicationPause(); the messaging system may not function correctly on this component when the application pauses."
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
private const string GenericMissingBaseCallMessageFormat =
|
|
125
|
+
"'{0}' overrides MessageAwareComponent.{1} but does not call base.{1}(); the messaging system may not function correctly on this component.";
|
|
126
|
+
|
|
127
|
+
/// <summary>
|
|
128
|
+
/// Returns the per-method consequence sentence for a given guarded method name, formatted
|
|
129
|
+
/// against the supplied type display string. Falls back to the generic format if the
|
|
130
|
+
/// method is unknown so that inserting a new guarded method does not blank the overlay.
|
|
131
|
+
/// </summary>
|
|
132
|
+
public static string GetMissingBaseConsequenceLine(string methodName, string typeDisplay)
|
|
133
|
+
{
|
|
134
|
+
string format = MissingBaseCallMessageFormatsByMethod.TryGetValue(
|
|
135
|
+
methodName ?? string.Empty,
|
|
136
|
+
out string perMethodFormat
|
|
137
|
+
)
|
|
138
|
+
? perMethodFormat
|
|
139
|
+
: GenericMissingBaseCallMessageFormat;
|
|
140
|
+
return string.Format(
|
|
141
|
+
System.Globalization.CultureInfo.InvariantCulture,
|
|
142
|
+
format,
|
|
143
|
+
typeDisplay ?? string.Empty,
|
|
144
|
+
methodName ?? string.Empty
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private const string IgnoreAttributeFullName =
|
|
149
|
+
"DxMessaging.Core.Attributes.DxIgnoreMissingBaseCallAttribute";
|
|
150
|
+
|
|
151
|
+
private const string MessageAwareComponentFullName =
|
|
152
|
+
"DxMessaging.Unity.MessageAwareComponent";
|
|
153
|
+
|
|
154
|
+
private static readonly Type[] BoolParameterTypes = { typeof(bool) };
|
|
155
|
+
|
|
156
|
+
/// <summary>
|
|
157
|
+
/// Result row produced by <see cref="Scan"/>. Mirrors the Unity-facing
|
|
158
|
+
/// <c>BaseCallReportEntry</c> shape but uses pure BCL collections so the helper is
|
|
159
|
+
/// callable from <c>dotnet test</c>.
|
|
160
|
+
/// </summary>
|
|
161
|
+
public sealed class ScanEntry
|
|
162
|
+
{
|
|
163
|
+
/// <summary>Fully-qualified name of the offending type (dot-form for nested types).</summary>
|
|
164
|
+
public string TypeName;
|
|
165
|
+
|
|
166
|
+
/// <summary>Method names whose overrides are missing the corresponding <c>base.*()</c> call.</summary>
|
|
167
|
+
public SortedSet<string> MissingBaseFor = new(StringComparer.Ordinal);
|
|
168
|
+
|
|
169
|
+
/// <summary>Diagnostic IDs that contributed to this entry (DXMSG006 / DXMSG007 / DXMSG010).</summary>
|
|
170
|
+
public HashSet<string> DiagnosticIds = new(StringComparer.Ordinal);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// <summary>
|
|
174
|
+
/// Classify every <paramref name="candidates"/> type and return a per-FQN snapshot keyed
|
|
175
|
+
/// by fully-qualified type name (dot-form for nested types). Types opted out via
|
|
176
|
+
/// class-level <c>[DxIgnoreMissingBaseCall]</c> or via
|
|
177
|
+
/// <paramref name="ignoredTypeNames"/> are
|
|
178
|
+
/// intentionally NOT included in the returned dictionary -- the inspector overlay reads
|
|
179
|
+
/// the project ignore list directly to render its "Stop ignoring" HelpBox, and the
|
|
180
|
+
/// snapshot semantics here match the bridge path (DXMSG008-equivalent rows were never
|
|
181
|
+
/// present in the snapshot's <c>missingBaseFor</c> either). Method-level
|
|
182
|
+
/// <c>[DxIgnoreMissingBaseCall]</c> is applied per guarded method only.
|
|
183
|
+
/// </summary>
|
|
184
|
+
/// <param name="candidates">
|
|
185
|
+
/// Strict subclasses of <c>MessageAwareComponent</c>. Abstract types and generic-type
|
|
186
|
+
/// definitions are skipped; the <c>MessageAwareComponent</c> type itself is also skipped.
|
|
187
|
+
/// May contain <c>null</c> entries (defensively skipped).
|
|
188
|
+
/// </param>
|
|
189
|
+
/// <param name="ignoredTypeNames">
|
|
190
|
+
/// Project-level ignore list (typically the parsed contents of
|
|
191
|
+
/// <c>Assets/Editor/DxMessaging.BaseCallIgnore.txt</c>, surfaced through
|
|
192
|
+
/// <c>DxMessagingSettings._baseCallIgnoredTypes</c>). May be <c>null</c>.
|
|
193
|
+
/// </param>
|
|
194
|
+
public static Dictionary<string, ScanEntry> Scan(
|
|
195
|
+
IEnumerable<Type> candidates,
|
|
196
|
+
IEnumerable<string> ignoredTypeNames
|
|
197
|
+
)
|
|
198
|
+
{
|
|
199
|
+
Dictionary<string, ScanEntry> result = new(StringComparer.Ordinal);
|
|
200
|
+
if (candidates is null)
|
|
201
|
+
{
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
HashSet<string> projectIgnore = ignoredTypeNames is null
|
|
206
|
+
? new HashSet<string>(StringComparer.Ordinal)
|
|
207
|
+
: new HashSet<string>(ignoredTypeNames, StringComparer.Ordinal);
|
|
208
|
+
|
|
209
|
+
foreach (Type concrete in candidates)
|
|
210
|
+
{
|
|
211
|
+
if (concrete == null)
|
|
212
|
+
{
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (concrete.IsAbstract)
|
|
216
|
+
{
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (concrete.IsGenericTypeDefinition)
|
|
220
|
+
{
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
string fullName = concrete.FullName ?? string.Empty;
|
|
225
|
+
if (string.IsNullOrEmpty(fullName))
|
|
226
|
+
{
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (
|
|
230
|
+
string.Equals(fullName, MessageAwareComponentFullName, StringComparison.Ordinal)
|
|
231
|
+
)
|
|
232
|
+
{
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
// FullName for nested types uses '+'; the analyzer (and the inspector overlay's
|
|
236
|
+
// lookup) emits the dotted form. Normalise here so the scanner-produced snapshot
|
|
237
|
+
// is keyed identically to the analyzer's identifiers.
|
|
238
|
+
fullName = fullName.Replace('+', '.');
|
|
239
|
+
|
|
240
|
+
bool optedOutByAttribute = TypeHasIgnoreAttribute(concrete);
|
|
241
|
+
bool optedOutByList = projectIgnore.Contains(fullName);
|
|
242
|
+
|
|
243
|
+
if (optedOutByAttribute || optedOutByList)
|
|
244
|
+
{
|
|
245
|
+
// Suppression makes the entry an audit-marker (DXMSG008-equivalent). The
|
|
246
|
+
// overlay's "ignored" branch handles this via the ignored-types list directly,
|
|
247
|
+
// so we don't add it to the snapshot at all; the overlay reads the project
|
|
248
|
+
// list to render the "Stop ignoring" HelpBox. This matches the bridge path's
|
|
249
|
+
// snapshot semantics (DXMSG008 was never in MissingBaseFor either).
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
HashSet<string> methodLevelIgnore = GetGuardedMethodsWithIgnoreAttribute(concrete);
|
|
254
|
+
|
|
255
|
+
ScanEntry entry = ScanOne(concrete, fullName, methodLevelIgnore);
|
|
256
|
+
if (entry == null || entry.MissingBaseFor.Count == 0)
|
|
257
|
+
{
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
result[fullName] = entry;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private static bool TypeHasIgnoreAttribute(Type type)
|
|
268
|
+
{
|
|
269
|
+
// [DxIgnoreMissingBaseCall] applies with Inherited=false (matches the analyzer's
|
|
270
|
+
// attribute declaration), so we inspect only the type itself.
|
|
271
|
+
foreach (object attr in type.GetCustomAttributes(inherit: false))
|
|
272
|
+
{
|
|
273
|
+
if (attr.GetType().FullName == IgnoreAttributeFullName)
|
|
274
|
+
{
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private static HashSet<string> GetGuardedMethodsWithIgnoreAttribute(Type type)
|
|
282
|
+
{
|
|
283
|
+
HashSet<string> ignoredMethods = new(StringComparer.Ordinal);
|
|
284
|
+
foreach (string methodName in GuardedMethodNames)
|
|
285
|
+
{
|
|
286
|
+
MethodInfo m = GetDeclaredInstance(type, methodName);
|
|
287
|
+
if (m == null)
|
|
288
|
+
{
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
foreach (object attr in m.GetCustomAttributes(inherit: false))
|
|
292
|
+
{
|
|
293
|
+
if (attr.GetType().FullName == IgnoreAttributeFullName)
|
|
294
|
+
{
|
|
295
|
+
ignoredMethods.Add(methodName);
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return ignoredMethods;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
private static ScanEntry ScanOne(
|
|
304
|
+
Type concrete,
|
|
305
|
+
string fullName,
|
|
306
|
+
HashSet<string> methodLevelIgnore
|
|
307
|
+
)
|
|
308
|
+
{
|
|
309
|
+
ScanEntry entry = new()
|
|
310
|
+
{
|
|
311
|
+
TypeName = fullName,
|
|
312
|
+
MissingBaseFor = new SortedSet<string>(StringComparer.Ordinal),
|
|
313
|
+
DiagnosticIds = new HashSet<string>(StringComparer.Ordinal),
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
foreach (string methodName in GuardedMethodNames)
|
|
317
|
+
{
|
|
318
|
+
ClassifyMethod(concrete, methodName, entry, methodLevelIgnore);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return entry;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
private static void ClassifyMethod(
|
|
325
|
+
Type concrete,
|
|
326
|
+
string methodName,
|
|
327
|
+
ScanEntry entry,
|
|
328
|
+
HashSet<string> methodLevelIgnore
|
|
329
|
+
)
|
|
330
|
+
{
|
|
331
|
+
if (methodLevelIgnore.Contains(methodName))
|
|
332
|
+
{
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Walk the type chain: first the leaf (concrete), then ancestors via BaseType until we
|
|
337
|
+
// leave the MessageAwareComponent inheritance subtree. For the leaf we determine which
|
|
338
|
+
// of DXMSG006/007/009 fires (if any). If the leaf overrides correctly, we walk
|
|
339
|
+
// ancestor links to detect DXMSG010 (a broken intermediate). Each link's diagnosis is
|
|
340
|
+
// independent; we only record the FIRST classification for the leaf in
|
|
341
|
+
// entry.MissingBaseFor since the overlay HelpBox shows one row per method per type.
|
|
342
|
+
|
|
343
|
+
MethodInfo declared = GetDeclaredInstance(concrete, methodName);
|
|
344
|
+
if (declared == null)
|
|
345
|
+
{
|
|
346
|
+
// Type does not declare this method at all; nothing to flag at this level.
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (declared.ReturnType != typeof(void))
|
|
350
|
+
{
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (declared.IsStatic)
|
|
354
|
+
{
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (declared.IsGenericMethodDefinition)
|
|
358
|
+
{
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// DXMSG009 vs DXMSG007: declares without override (or with `new`); hides the base.
|
|
363
|
+
// In IL/reflection terms: the method does NOT have the override slot binding
|
|
364
|
+
// (GetBaseDefinition() returns the method itself) AND the base type has a same-named
|
|
365
|
+
// virtual we are hiding. The C# compiler emits the same IL for `new void X()` and
|
|
366
|
+
// `void X()`-with-CS0114, so we cannot perfectly distinguish DXMSG007 from DXMSG009
|
|
367
|
+
// from IL alone. The compile-time analyzer is authoritative for the precise ID;
|
|
368
|
+
// here we conservatively classify the case as DXMSG007; both produce the same
|
|
369
|
+
// overlay outcome (method listed in HelpBox).
|
|
370
|
+
bool isOverride = declared.GetBaseDefinition() != declared;
|
|
371
|
+
bool hasNewKeyword =
|
|
372
|
+
!isOverride && BaseHasSameNamedVirtual(concrete.BaseType, methodName);
|
|
373
|
+
|
|
374
|
+
if (!isOverride)
|
|
375
|
+
{
|
|
376
|
+
if (hasNewKeyword)
|
|
377
|
+
{
|
|
378
|
+
AddIfMissing(entry, methodName, "DXMSG007");
|
|
379
|
+
}
|
|
380
|
+
// else: not an override, no base virtual to hide; not our concern.
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// It IS an override. Check IL for base call.
|
|
385
|
+
bool callsBase = BaseCallIlInspector.MethodIlContainsBaseCall(declared, methodName);
|
|
386
|
+
if (!callsBase)
|
|
387
|
+
{
|
|
388
|
+
AddIfMissing(entry, methodName, "DXMSG006");
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Leaf calls base. Walk the inheritance chain to look for a broken intermediate
|
|
393
|
+
// (DXMSG010). Each link's IL is inspected independently; the first broken link found
|
|
394
|
+
// produces DXMSG010 on the leaf and we stop. Cross-assembly ancestors with no IL body
|
|
395
|
+
// are trusted (assume-clean); the alternative would be unactionable warnings against
|
|
396
|
+
// closed-source code.
|
|
397
|
+
MethodInfo cursorOverridden = GetOverriddenMethod(declared);
|
|
398
|
+
HashSet<MethodInfo> visited = new();
|
|
399
|
+
while (cursorOverridden != null && visited.Add(cursorOverridden))
|
|
400
|
+
{
|
|
401
|
+
// Chain reached MessageAwareComponent itself; clean. We compare by full type
|
|
402
|
+
// name so the helper does not need a hard reference to the Unity-only type.
|
|
403
|
+
Type cursorDeclaring = cursorOverridden.DeclaringType;
|
|
404
|
+
if (
|
|
405
|
+
cursorDeclaring != null
|
|
406
|
+
&& cursorDeclaring.FullName == "DxMessaging.Unity.MessageAwareComponent"
|
|
407
|
+
)
|
|
408
|
+
{
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (cursorOverridden.GetMethodBody() == null)
|
|
412
|
+
{
|
|
413
|
+
// Cross-assembly / abstract; assume clean (cannot inspect).
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
bool ancestorCallsBase = BaseCallIlInspector.MethodIlContainsBaseCall(
|
|
417
|
+
cursorOverridden,
|
|
418
|
+
methodName
|
|
419
|
+
);
|
|
420
|
+
if (!ancestorCallsBase)
|
|
421
|
+
{
|
|
422
|
+
AddIfMissing(entry, methodName, "DXMSG010");
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
cursorOverridden = GetOverriddenMethod(cursorOverridden);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
private static MethodInfo GetDeclaredZeroArgInstance(Type type, string methodName)
|
|
430
|
+
{
|
|
431
|
+
return type.GetMethod(
|
|
432
|
+
methodName,
|
|
433
|
+
BindingFlags.Public
|
|
434
|
+
| BindingFlags.NonPublic
|
|
435
|
+
| BindingFlags.Instance
|
|
436
|
+
| BindingFlags.DeclaredOnly,
|
|
437
|
+
null,
|
|
438
|
+
Type.EmptyTypes,
|
|
439
|
+
null
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
private static MethodInfo GetDeclaredBoolArgInstance(Type type, string methodName)
|
|
444
|
+
{
|
|
445
|
+
return type.GetMethod(
|
|
446
|
+
methodName,
|
|
447
|
+
BindingFlags.Public
|
|
448
|
+
| BindingFlags.NonPublic
|
|
449
|
+
| BindingFlags.Instance
|
|
450
|
+
| BindingFlags.DeclaredOnly,
|
|
451
|
+
null,
|
|
452
|
+
BoolParameterTypes,
|
|
453
|
+
null
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/// <summary>
|
|
458
|
+
/// Resolves the declared instance method for a guarded name. Most guarded methods are
|
|
459
|
+
/// zero-arg (and we look up via <see cref="GetDeclaredZeroArgInstance"/>), but the
|
|
460
|
+
/// canonical Unity signature for <c>OnApplicationFocus</c> / <c>OnApplicationPause</c>
|
|
461
|
+
/// takes a single <c>bool</c>; for those names we try the zero-arg lookup first
|
|
462
|
+
/// (defensive against an unusual subclass that declared a zero-arg variant) and fall
|
|
463
|
+
/// back to the bool variant.
|
|
464
|
+
/// </summary>
|
|
465
|
+
private static MethodInfo GetDeclaredInstance(Type type, string methodName)
|
|
466
|
+
{
|
|
467
|
+
MethodInfo zeroArg = GetDeclaredZeroArgInstance(type, methodName);
|
|
468
|
+
if (zeroArg != null)
|
|
469
|
+
{
|
|
470
|
+
return zeroArg;
|
|
471
|
+
}
|
|
472
|
+
if (!GuardedMethodsWithBoolSignature.Contains(methodName))
|
|
473
|
+
{
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
return GetDeclaredBoolArgInstance(type, methodName);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
private static IEnumerable<Type[]> GetGuardedMethodSignatures(string methodName)
|
|
480
|
+
{
|
|
481
|
+
yield return Type.EmptyTypes;
|
|
482
|
+
if (GuardedMethodsWithBoolSignature.Contains(methodName))
|
|
483
|
+
{
|
|
484
|
+
yield return BoolParameterTypes;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
private static bool BaseHasSameNamedVirtual(Type baseType, string methodName)
|
|
489
|
+
{
|
|
490
|
+
while (baseType != null && baseType != typeof(object))
|
|
491
|
+
{
|
|
492
|
+
foreach (Type[] parameterTypes in GetGuardedMethodSignatures(methodName))
|
|
493
|
+
{
|
|
494
|
+
MethodInfo m = baseType.GetMethod(
|
|
495
|
+
methodName,
|
|
496
|
+
BindingFlags.Public
|
|
497
|
+
| BindingFlags.NonPublic
|
|
498
|
+
| BindingFlags.Instance
|
|
499
|
+
| BindingFlags.DeclaredOnly,
|
|
500
|
+
null,
|
|
501
|
+
parameterTypes,
|
|
502
|
+
null
|
|
503
|
+
);
|
|
504
|
+
if (m != null && (m.IsVirtual || m.IsAbstract))
|
|
505
|
+
{
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
baseType = baseType.BaseType;
|
|
510
|
+
}
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
private static Type[] GetParameterTypes(MethodInfo method)
|
|
515
|
+
{
|
|
516
|
+
ParameterInfo[] parameters = method.GetParameters();
|
|
517
|
+
Type[] parameterTypes = new Type[parameters.Length];
|
|
518
|
+
for (int i = 0; i < parameters.Length; i++)
|
|
519
|
+
{
|
|
520
|
+
parameterTypes[i] = parameters[i].ParameterType;
|
|
521
|
+
}
|
|
522
|
+
return parameterTypes;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
private static MethodInfo GetOverriddenMethod(MethodInfo derivedOverride)
|
|
526
|
+
{
|
|
527
|
+
// For an override, GetBaseDefinition() returns the most-base virtual (the originating
|
|
528
|
+
// declaration). To walk the chain link-by-link we need the closest ancestor that
|
|
529
|
+
// declares the same-named method directly; we look up each BaseType in turn and
|
|
530
|
+
// return the first match. This skips intermediate types that don't override the slot
|
|
531
|
+
// (e.g. a generic intermediate that just passes through), which is exactly what the
|
|
532
|
+
// chain walk needs to detect DXMSG010 at the broken link rather than the pass-through.
|
|
533
|
+
Type baseType = derivedOverride.DeclaringType?.BaseType;
|
|
534
|
+
Type[] signature = GetParameterTypes(derivedOverride);
|
|
535
|
+
while (baseType != null && baseType != typeof(object))
|
|
536
|
+
{
|
|
537
|
+
MethodInfo m = baseType.GetMethod(
|
|
538
|
+
derivedOverride.Name,
|
|
539
|
+
BindingFlags.Public
|
|
540
|
+
| BindingFlags.NonPublic
|
|
541
|
+
| BindingFlags.Instance
|
|
542
|
+
| BindingFlags.DeclaredOnly,
|
|
543
|
+
null,
|
|
544
|
+
signature,
|
|
545
|
+
null
|
|
546
|
+
);
|
|
547
|
+
if (m != null)
|
|
548
|
+
{
|
|
549
|
+
return m;
|
|
550
|
+
}
|
|
551
|
+
baseType = baseType.BaseType;
|
|
552
|
+
}
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
private static void AddIfMissing(ScanEntry entry, string methodName, string diagnosticId)
|
|
557
|
+
{
|
|
558
|
+
entry.MissingBaseFor.Add(methodName);
|
|
559
|
+
entry.DiagnosticIds.Add(diagnosticId);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|