From 9d21e449662897fc9fcbd777e90a928ab6e845a7 Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 18:57:10 -0400 Subject: [PATCH] [3.0] Rework naming system (#2565) * Update OpenAL name overrides to match the 2 character acronym threshold used by other bindings The default acronym threshold was changed during https://github.com/Exanite/Silk.NET/pull/29, which was merged as part of https://github.com/dotnet/Silk.NET/pull/2503. * Start of feature/nested-struct-name-affixes branch * Cleanup leftover return statement * Split TransformHandles into two mods * Rename UseDSL to UseDsl Considering we decided to follow Microsoft's Framework Design Guidelines (acronym threshold of 2) for the bindings and rest of the API, might as well be consistent here. * Cleanup unused property in TransformHandles * Cleanup usages of redundant collections expressions in TransformHandles * Add NameAffixer.AddResolvedNameAffix() for handling compound names * Use AddResolvedNameAffix for extracted function pointer delegate types * Use AddResolvedNameAffix for extracted nested structs and remove name separation hack (no longer necessary) * Rename resolved affix to referenced affix and add parsing code for referenced affixes * Add extra ConsecutiveNumbers test case documenting that Xs between numbers are normalized * Fix incorrect declarationOrder implementation * Change Prettify to not prefix identifiers starting with numbers This lets us handle prefixing and prettification separately, which notably is important if we add prefixes after prettification. We want to prefix the final name, not the intermediate name in this case. * Change the list and order of INameTrimmers used to be statically configured (cherry picked from commit bc94260c4b22344a1cc4eceb29a26711e2ade531) * Replace now outdated comment * Move PrettifyNamesTrimmer higher up in the class to make it more obvious that it is not the last trimmer * Remove INameTrimmer.Version This no longer makes sense to keep and enabling features by baseline version seems fiddly. If we need to toggle features for newer versions, we can explicitly add a boolean config option. * Add PrefixIfStartsWithNumberTrimmer * Remove TrimmerBaseline config option * Rename INameTrimmer to INameProcessor and update rest of codebase * Simplify name affixer name processor names to be StripAffixesNameProcessor and ReapplyAffixesNameProcessor * Shorten names a bit more for readability * Decide to only support references within the same scope depth Kinda a cop out decision, but it keeps thing simple (and thus maintainable) and implementing it fully seems overkill for what we need. * Restrict feature set of AddReferencedNameAffix even more for simplicity * Implement referenced affixes and change how -Delegate types generated for function pointer types are named * Update OpenAL name overrides in generator.json This is because we no longer output the separating underscore in ExtractNestedTyping * Update doc comment in ServiceCollectionExtensions to indicate removal of INameTrimmer registrations * Update name overrides for OpenAL to match new Delegate type naming convention Note that the goal is to eventually remove the name overrides for the `EFXEAXREVERBPROPERTIESflLateReverbPan` and `-Delegate` cases entirely. This is because these are theoretically possible to handle automatically and the reason it doesn't work is due to an edge case interaction with the name override system. See the "Tasks" section here for more info: https://github.com/dotnet/Silk.NET/pull/2555 * Optimize comparison by hoisting the calculation * Add topological sort to ReapplyAffixesProcessor This covers cases where there are multiple levels of nested structs, such as in SDL: GamepadBinding contains GamepadBindingInput which contains GamepadBindingInputAxis * Improve error handling by checking for case where dependencies are not fully fulfilled * Edit error message * Add test: PrettifyNamesTests.SuccessfullyUsesReferencedAffixes * Use "SDL.gen.cs" for test document name This is just to hint that these structs come from SDL * Add tests for referenced affix behavior MissingReferencedAffix_Throws currently fails, but seems to be an unrelated issue. * Alphabetically sort the mod names * Add start of IdentifySharedPrefixes mod * Work on IdentifySharedPrefixes * Remove ApplyPrettifyOnlyPipeline * Rename BreakIntoWords as SplitIntoWords * Remove the double legacy NameTrimmers * Fix compile errors * Temporary: Disable all mods after PrettifyNames * Add SharedPrefix affix config to Vulkan job * Remove unused isContainer param from GetTrimmingName * Work on IdentifySharedPrefixes * Replace regex based NameUtils.LenientUnderscore() with NameSplitter.Underscore() * Fix compile errors due to changes * Remove NonDeterminant/Transformed attribute handling from PrettifyNames * Slightly simplify NameTrimmer * Remove NameTrimmer usage from ExtractNestedTyping and slightly optimize the foreach loops * Slightly cleanup NameTrimmer * Annotate the param names for NameTrimmer's GetPrefix call for readability * Implement visitor for IdentifySharedPrefixes * Properly store scopes * Handle filtering of non C-prefixed names * Work on migrating the NameTrimmer code over to IdentifySharedPrefixes * Cleanup * Add affix handling to IdentifySharedPrefixes * Implement shared prefix identification output to name affixes * Fix incorrect Rewriter implementation * Simplify code * Add missing ModConfiguration attribute * Fix incorrect method call * Fix incorrect member name output for identified prefixes * Fix duplicate key exception caused by functions being able to have duplicate names * Revert "Temporary: Disable all mods after PrettifyNames" This reverts commit 3ec90a74be085119a4272a2f7912e96dfb96b38e. * Update generator config for OpenAL, OpenGL, and SDL to use IdentifySharedPrefixes * Add another test case as an example of how "2D" is split * Add another prefix override for SeparableTargetEXT This is because 2D isn't trimmed properly by my new name splitter, but I decided that this case was not worth handling in favor of keeping the trimming code simple. See my thoughts here: https://discord.com/channels/521092042781229087/1485943448069738608/1489457083857506336 * Migrate over most prefix trimming/identification tests from PrettifyNamesTests to IdentifySharedPrefixesTests * Update PrettifyNamesTests now that prefix identification is done separately * Migrate over the NameTrimmerTests * Remove IdentifiesSharedPrefix_WhenPrefixesDeclared See https://github.com/dotnet/Silk.NET/pull/2557 for full reasoning, but the short is that this edge case is purely theoretical and can be handled later on when actually necessary. * Also remove the snapshot for IdentifiesSharedPrefix_WhenPrefixesDeclared * Change INameProcessor to be private to PrettifyNames * Change nPasses to be a class constant to allow usage of doc comments * Rename _forbiddenTrimmings to _forbiddenPrefixes and adjust docs * Change GetPrefix to use a non-null scope parameter for consistency * Add comment explaining why the topological sort exists * Begin replacing the "container" terminology with "scope" * Fix failing tests since the global scope is now represented with an empty string instead of null * Cleanup IdentifySharedPrefixes * Combine EnumInProgress with TypeInProgress * Simplify affix data storage and retrieval * Update docs for Visitor.AffixData * Edit docs for IdentifySharedPrefixes * Swap parameter order on ReportName in IdentifySharedPrefixes * Rewrite PrettifyNames.Visitor to match IdentifySharedPrefixes.Visitor This reduces the amount of code by ~100 lines (1331 -> 1227 lines), which is pretty significant. * Reorder PrettifyNames.Configuration members to improve scannability * Begin rewriting the name processing part of PrettifyNames.ExecuteAsync * Adjust error message for cycle detection * Fix missing method declaration data * Fix missing name data * Add todos and work on updating docs * Change code and comments to refer to trimming names as original names (and some other cleanup) * Move CandidateNames into PrettifyNames * Fix typo * Rename DiscrimStr to GetMethodDiscriminator * Cleanup naming * Use if statements instead of ternaries for populating dictionaries If statements are generally easier to read and debug for this. That said, I do find the original ternary approach better for the method discriminator tuple case, but I decided to use it for all 3 cases for consistency. * Update name conflict resolution code to account for non-method and method names being mixed together now * Add another todo * Change NameProcessorContext to be a class * Begin exposing the entire set of names to name processors and rewriting the rest of the pipeline as INameProcessors * Roughly outline the final implementation and move code to where it roughly belongs * Define name processor inputs * Also provide affix config to ReapplyAffixesProcessor * Implement HandleOverridesProcessor * Cleanup NameProcessorContext * Remove helper data retrieval methods from ScrapedNameData since it can lead to inefficient data access * Remove ScrapedNameData since it's now just an empty wrapper class * Reimplement StripAffixesProcessor * Reimplement PrettifyProcessor * Reimplement ReapplyAffixesProcessor * Reimplement PrefixIfStartsWithNumberProcessor * Edit documentation and add RemoveUnmodifiedFinalNamesProcessor * Add docs for PrefixIfStartsWithNumberProcessor * Implement ResolveConflictsProcessor using adapted name conflict resolution code * Add remark doc comment on ResolveConflictsProcessor about it copying names from the final to working set * Add NameSymbolVisitor for gathering symbols to rename * Add remark comment on nested type support in PrettifyNames * Fix constructors not getting renamed * Add PrettifyNamesTests.ConflictsAreResolved_ForMethodsAndConstants (currently fails) * Work on non-method/method conflict resolution * Also add test case: ConflictsAreResolved_ForMethodsAndConstants_WithAdditionalDiscriminatorAffixes * Ensure conflicts are iterated deterministically This wasn't an actual observed issue, but is a possible edge case I noticed when I was reading the code. The underlying data collection is a hashset or dictionary, both of which have non-deterministic iteration order. This commit adds a tie-breaker to prevent this issue from possibly happening. * Add ConflictsAreResolved_ForMethodsAndConstants_WithAdditionalDiscriminatorAffixes_ReversedPriority and add more comments on why the tests exist * Implement non-method/method conflict resolution and fix secondaries not getting chosen properly * Ensure that the temporary data collections are allocated once and edit comments/variable names to be clearer * Implement "-Value" suffixing for non-methods conflicting with methods and update test cases to reflect expected behavior * Decide it's not worth implementing cross-scope name referencing for affixes yet * Remove unused RenamedType struct and unused MemberData.Name property * Fix -Value suffixing not working properly I expected this to be an issue *eventually*, but apparently it also affects the SDL output already. This is probably because SDL has multiple overloads of the SDL_main method, which my test case does not test for. * Update test snapshot This new snapshot matches the expected output that I wrote in the comments earlier. I just forgot to update the snapshot. * Also resolve referenced affixes from the final set of names and the OpenAL overrides that are now unnecessary * Add ReapplyAffixesProcessor.TryResolveName method (refactor) * Change ReapplyAffixesProcessor to use one global topological sort and update test to indicate that one level of scoping is now supported * Fix issue where overrides break the topological sort * Reorder tests in file * Add test case: SuccessfullyUsesReferencedAffixes_WhenOverridden * Rename NameProcessorContext/NameDataVisitor.Scopes to Names * Work on refactoring name affix processors * Add local OutputName function * Implement the option to prettify individual affixes * Update generator config now that affixes are prettified by default * Don't prettify referenced affixes by default since we usually want the verbatim value of the referenced name * Change affixes to not be prettified by default since it simplifies the code and config * Empty commit * Update snapshot to match expected stated by comment * Adjust doc comment wording for IdentifySharedPrefixes._passCount --- .silktouch/openal-clangsharp.stout | Bin 40930 -> 40930 bytes .silktouch/vulkan-clangsharp.stout | Bin 1974639 -> 1974639 bytes generator.json | 64 +- .../OpenAL/al/BufferCallbackSOFT.gen.cs | 2 +- ...n.cs => BufferCallbackSOFTDelegate.gen.cs} | 2 +- .../OpenAL/al/ContextEventProcSOFT.gen.cs | 2 +- ...cs => ContextEventProcSOFTDelegate.gen.cs} | 2 +- sources/OpenAL/OpenAL/al/DebugProcEXT.gen.cs | 2 +- ...EXT.gen.cs => DebugProcEXTDelegate.gen.cs} | 2 +- sources/OpenAL/OpenAL/al/EventProcSOFT.gen.cs | 2 +- ...FT.gen.cs => EventProcSOFTDelegate.gen.cs} | 2 +- .../SilkTouch/Mods/BakeSourceSets.cs | 16 +- .../SilkTouch/Mods/Common/ModLoader.cs | 22 +- .../SilkTouch/Mods/Common/ModUtils.cs | 22 +- .../SilkTouch/Mods/ExtractHandles.cs | 324 +++ .../SilkTouch/Mods/ExtractNestedTyping.cs | 32 +- .../SilkTouch/Mods/IdentifySharedPrefixes.cs | 726 ++++++ .../SilkTouch/Mods/MixKhronosData.cs | 3 +- .../SilkTouch/SilkTouch/Mods/PrettifyNames.cs | 2307 +++++++++-------- .../SilkTouch/Mods/TransformHandles.cs | 338 +-- .../Transformation/FunctionTransformer.cs | 10 +- .../SilkTouch/Naming/CandidateNames.cs | 18 - .../SilkTouch/Naming/INameTrimmer.cs | 29 - .../SilkTouch/SilkTouch/Naming/NameAffix.cs | 7 +- .../SilkTouch/SilkTouch/Naming/NameAffixer.cs | 127 +- .../SilkTouch/Naming/NamePrettifier.cs | 27 +- .../SilkTouch/Naming/NameSplitter.cs | 8 +- .../SilkTouch/SilkTouch/Naming/NameTrimmer.cs | 407 --- .../SilkTouch/Naming/NameTrimmer217.cs | 40 - .../SilkTouch/Naming/NameTrimmer218.cs | 22 - .../SilkTouch/Naming/NameTrimmerContext.cs | 41 - .../SilkTouch/SilkTouch/Naming/NameUtils.cs | 57 +- .../SilkTouch/Naming/TrimmerOrder.cs | 20 - .../SilkTouch/ServiceCollectionExtensions.cs | 5 - .../Vulkan/DebugMarkerMarkerInfoEXT.gen.cs | 2 +- ...s => DebugMarkerMarkerInfoEXTColor.gen.cs} | 2 +- .../Vulkan/DebugReportCallbackEXT.gen.cs | 2 +- ... => DebugReportCallbackEXTDelegate.gen.cs} | 2 +- .../Vulkan/Vulkan/DebugUtilsLabelEXT.gen.cs | 2 +- ....gen.cs => DebugUtilsLabelEXTColor.gen.cs} | 2 +- .../DebugUtilsMessengerCallbackEXT.gen.cs | 2 +- ...gUtilsMessengerCallbackEXTDelegate.gen.cs} | 2 +- .../Vulkan/Vulkan/DeviceFaultInfoEXT.gen.cs | 2 +- ...s => DeviceFaultInfoEXTDescription.gen.cs} | 2 +- ...aultVendorBinaryHeaderVersionOneEXT.gen.cs | 2 +- ...aderVersionOneEXTPipelineCacheUuid.gen.cs} | 2 +- .../Vulkan/DeviceFaultVendorInfoEXT.gen.cs | 2 +- ...eviceFaultVendorInfoEXTDescription.gen.cs} | 2 +- .../DeviceGroupPresentCapabilitiesKHR.gen.cs | 2 +- ...pPresentCapabilitiesKHRPresentMask.gen.cs} | 2 +- .../DeviceMemoryReportCallbackEXT.gen.cs | 2 +- ...iceMemoryReportCallbackEXTDelegate.gen.cs} | 2 +- .../Vulkan/GetInstanceProcAddrLUNARG.gen.cs | 2 +- ... GetInstanceProcAddrLUNARGDelegate.gen.cs} | 2 +- .../PerformanceCounterDescriptionARM.gen.cs | 2 +- ...rformanceCounterDescriptionARMName.gen.cs} | 2 +- .../PerformanceCounterDescriptionKHR.gen.cs | 6 +- ...manceCounterDescriptionKHRCategory.gen.cs} | 2 +- ...ceCounterDescriptionKHRDescription.gen.cs} | 2 +- ...rformanceCounterDescriptionKHRName.gen.cs} | 2 +- .../Vulkan/PerformanceCounterKHR.gen.cs | 2 +- ...en.cs => PerformanceCounterKHRUuid.gen.cs} | 2 +- ...lusterCullingShaderPropertiesHUAWEI.gen.cs | 4 +- ...rPropertiesHUAWEIMaxWorkGroupCount.gen.cs} | 2 +- ...erPropertiesHUAWEIMaxWorkGroupSize.gen.cs} | 2 +- ...lDeviceDataGraphOperationSupportARM.gen.cs | 2 +- ...ceDataGraphOperationSupportARMName.gen.cs} | 2 +- ...ysicalDeviceLayeredApiPropertiesKHR.gen.cs | 2 +- ...eLayeredApiPropertiesKHRDeviceName.gen.cs} | 2 +- ...icalDeviceMemoryBudgetPropertiesEXT.gen.cs | 4 +- ...emoryBudgetPropertiesEXTHeapBudget.gen.cs} | 2 +- ...MemoryBudgetPropertiesEXTHeapUsage.gen.cs} | 2 +- ...ysicalDeviceMeshShaderPropertiesEXT.gen.cs | 8 +- ...PropertiesEXTMaxMeshWorkGroupCount.gen.cs} | 2 +- ...rPropertiesEXTMaxMeshWorkGroupSize.gen.cs} | 2 +- ...PropertiesEXTMaxTaskWorkGroupCount.gen.cs} | 2 +- ...rPropertiesEXTMaxTaskWorkGroupSize.gen.cs} | 2 +- ...lDeviceSampleLocationsPropertiesEXT.gen.cs | 2 +- ...esEXTSampleLocationCoordinateRange.gen.cs} | 2 +- ...ShaderModuleIdentifierPropertiesEXT.gen.cs | 2 +- ...haderModuleIdentifierAlgorithmUuid.gen.cs} | 2 +- ...icalDeviceShaderObjectPropertiesEXT.gen.cs | 2 +- ...bjectPropertiesEXTShaderBinaryUuid.gen.cs} | 2 +- .../Vulkan/Vulkan/PipelineBinaryKeyKHR.gen.cs | 2 +- ....gen.cs => PipelineBinaryKeyKHRKey.gen.cs} | 2 +- ...lineCacheHeaderVersionDataGraphQCOM.gen.cs | 2 +- ...rsionDataGraphQCOMToolchainVersion.gen.cs} | 2 +- ...ExecutableInternalRepresentationKHR.gen.cs | 4 +- ...ternalRepresentationKHRDescription.gen.cs} | 2 +- ...tableInternalRepresentationKHRName.gen.cs} | 2 +- .../PipelineExecutablePropertiesKHR.gen.cs | 4 +- ...ExecutablePropertiesKHRDescription.gen.cs} | 2 +- ...ipelineExecutablePropertiesKHRName.gen.cs} | 2 +- .../PipelineExecutableStatisticKHR.gen.cs | 4 +- ...eExecutableStatisticKHRDescription.gen.cs} | 2 +- ...PipelineExecutableStatisticKHRName.gen.cs} | 2 +- ...agmentShadingRateStateCreateInfoKHR.gen.cs | 2 +- ...gRateStateCreateInfoKHRCombinerOps.gen.cs} | 2 +- .../PipelinePropertiesIdentifierEXT.gen.cs | 2 +- ...iesIdentifierEXTPipelineIdentifier.gen.cs} | 2 +- .../RenderPassSubpassFeedbackInfoEXT.gen.cs | 2 +- ...sSubpassFeedbackInfoEXTDescription.gen.cs} | 2 +- .../Vulkan/ShaderModuleIdentifierEXT.gen.cs | 2 +- ...haderModuleIdentifierEXTIdentifier.gen.cs} | 2 +- .../Vulkan/ShaderStatisticsInfoAMD.gen.cs | 2 +- ...tisticsInfoAMDComputeWorkGroupSize.gen.cs} | 2 +- .../Vulkan/Vulkan/TransformMatrixKHR.gen.cs | 2 +- ...gen.cs => TransformMatrixKHRMatrix.gen.cs} | 2 +- .../VideoDecodeAv1PictureInfoKHR.gen.cs | 2 +- ...ureInfoKHRReferenceNameSlotIndices.gen.cs} | 2 +- .../VideoDecodeVp9PictureInfoKHR.gen.cs | 2 +- ...ureInfoKHRReferenceNameSlotIndices.gen.cs} | 2 +- .../VideoEncodeAv1PictureInfoKHR.gen.cs | 2 +- ...ureInfoKHRReferenceNameSlotIndices.gen.cs} | 2 +- ...fix_WhenSingleName_WithNoHint.verified.txt | 3 + ...ngleName_WithNonMatchingHint.verified.txt} | 0 ...tifiesPrefix_WhenMatchingHint.verified.txt | 4 + ...sTests.IdentifiesSharedPrefix.verified.txt | 7 + ...Tests.IdentifiesSharedPrefix2.verified.txt | 9 + ...iesSharedPrefixGlfw_hint=glfw.verified.txt | 17 + ...iesSharedPrefixGlfw_hint=null.verified.txt | 17 + ...entifiesSharedPrefix_ForTypes.verified.txt | 9 + ...ndNamesWithoutAffixesConflict.verified.txt | 10 + ...edPrefix_WhenSuffixesDeclared.verified.txt | 9 + ...sts.MultipleGlobalPrefixHints.verified.txt | 5 + ...veKhronosNamespaceEnumPrefix.verified.txt} | 0 ...sTests.RegressionEvalTargetNV.verified.txt | 7 + ...FragmentShaderColorModMaskATI.verified.txt | 11 + ...emberEnumUsesGlobalPrefixHint.verified.txt | 5 + .../Naming/IdentifySharedPrefixesTests.cs | 610 +++++ .../SilkTouch/Naming/NamePrettifierTests.cs | 26 +- .../SilkTouch/Naming/NameSplitterTests.cs | 29 +- .../SilkTouch/Naming/NameTrimmerTests.cs | 159 -- ...solved_ForMethodsAndConstants.verified.txt | 7 + ...ts.FallbackIsChosenCorrectly.verified.txt} | 8 +- ...senCorrectly_ReversedPriority.verified.txt | 17 + ...ngNumbers_WhenAffixesDeclared.verified.txt | 4 + ...tedCasingChangesInFormatEnums.verified.txt | 2 + ...essfullyUsesReferencedAffixes.verified.txt | 14 + ...rencedAffixes_FromParentScope.verified.txt | 6 + ...erencedAffixes_WhenOverridden.verified.txt | 4 + ....TrimsPrefix_WhenMatchingHint.verified.txt | 3 - ...yNamesTests.TrimsSharedPrefix.verified.txt | 5 - ...NamesTests.TrimsSharedPrefix2.verified.txt | 6 - ...ts.TrimsSharedPrefix_ForTypes.verified.txt | 7 - ...redPrefix_WhenAffixesDeclared.verified.txt | 7 - ...ndNamesWithoutAffixesConflict.verified.txt | 8 - .../SilkTouch/Naming/PrettifyNamesTests.cs | 570 ++-- 148 files changed, 3696 insertions(+), 2777 deletions(-) rename sources/OpenAL/OpenAL/al/{BufferCallbackDelegateSOFT.gen.cs => BufferCallbackSOFTDelegate.gen.cs} (90%) rename sources/OpenAL/OpenAL/al/{ContextEventProcDelegateSOFT.gen.cs => ContextEventProcSOFTDelegate.gen.cs} (92%) rename sources/OpenAL/OpenAL/al/{DebugProcDelegateEXT.gen.cs => DebugProcEXTDelegate.gen.cs} (93%) rename sources/OpenAL/OpenAL/al/{EventProcDelegateSOFT.gen.cs => EventProcSOFTDelegate.gen.cs} (93%) create mode 100644 sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs create mode 100644 sources/SilkTouch/SilkTouch/Mods/IdentifySharedPrefixes.cs delete mode 100644 sources/SilkTouch/SilkTouch/Naming/CandidateNames.cs delete mode 100644 sources/SilkTouch/SilkTouch/Naming/INameTrimmer.cs delete mode 100644 sources/SilkTouch/SilkTouch/Naming/NameTrimmer.cs delete mode 100644 sources/SilkTouch/SilkTouch/Naming/NameTrimmer217.cs delete mode 100644 sources/SilkTouch/SilkTouch/Naming/NameTrimmer218.cs delete mode 100644 sources/SilkTouch/SilkTouch/Naming/NameTrimmerContext.cs delete mode 100644 sources/SilkTouch/SilkTouch/Naming/TrimmerOrder.cs rename sources/Vulkan/Vulkan/Vulkan/{DebugMarkerMarkerInfoExtColor.gen.cs => DebugMarkerMarkerInfoEXTColor.gen.cs} (91%) rename sources/Vulkan/Vulkan/Vulkan/{DebugReportCallbackDelegateEXT.gen.cs => DebugReportCallbackEXTDelegate.gen.cs} (91%) rename sources/Vulkan/Vulkan/Vulkan/{DebugUtilsLabelExtColor.gen.cs => DebugUtilsLabelEXTColor.gen.cs} (92%) rename sources/Vulkan/Vulkan/Vulkan/{DebugUtilsMessengerCallbackDelegateEXT.gen.cs => DebugUtilsMessengerCallbackEXTDelegate.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{DeviceFaultInfoExtDescription.gen.cs => DeviceFaultInfoEXTDescription.gen.cs} (92%) rename sources/Vulkan/Vulkan/Vulkan/{DeviceFaultVendorBinaryHeaderVersionOneExtPipelineCacheUuid.gen.cs => DeviceFaultVendorBinaryHeaderVersionOneEXTPipelineCacheUuid.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{DeviceFaultVendorInfoExtDescription.gen.cs => DeviceFaultVendorInfoEXTDescription.gen.cs} (91%) rename sources/Vulkan/Vulkan/Vulkan/{DeviceGroupPresentCapabilitiesKhrPresentMask.gen.cs => DeviceGroupPresentCapabilitiesKHRPresentMask.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{DeviceMemoryReportCallbackDelegateEXT.gen.cs => DeviceMemoryReportCallbackEXTDelegate.gen.cs} (89%) rename sources/Vulkan/Vulkan/Vulkan/{GetInstanceProcAddrDelegateLUNARG.gen.cs => GetInstanceProcAddrLUNARGDelegate.gen.cs} (96%) rename sources/Vulkan/Vulkan/Vulkan/{PerformanceCounterDescriptionArmName.gen.cs => PerformanceCounterDescriptionARMName.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PerformanceCounterDescriptionKhrCategory.gen.cs => PerformanceCounterDescriptionKHRCategory.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{RenderPassSubpassFeedbackInfoExtDescription.gen.cs => PerformanceCounterDescriptionKHRDescription.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PerformanceCounterDescriptionKhrName.gen.cs => PerformanceCounterDescriptionKHRName.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PerformanceCounterKhrUuid.gen.cs => PerformanceCounterKHRUuid.gen.cs} (92%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupCount.gen.cs => PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupCount.gen.cs} (96%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupSize.gen.cs => PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupSize.gen.cs} (96%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceDataGraphOperationSupportArmName.gen.cs => PhysicalDeviceDataGraphOperationSupportARMName.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceLayeredApiPropertiesKhrDeviceName.gen.cs => PhysicalDeviceLayeredApiPropertiesKHRDeviceName.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceMemoryBudgetPropertiesExtHeapBudget.gen.cs => PhysicalDeviceMemoryBudgetPropertiesEXTHeapBudget.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceMemoryBudgetPropertiesExtHeapUsage.gen.cs => PhysicalDeviceMemoryBudgetPropertiesEXTHeapUsage.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupCount.gen.cs => PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupCount.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupSize.gen.cs => PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupSize.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupCount.gen.cs => PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupCount.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupSize.gen.cs => PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupSize.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceSampleLocationsPropertiesExtSampleLocationCoordinateRange.gen.cs => PhysicalDeviceSampleLocationsPropertiesEXTSampleLocationCoordinateRange.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceShaderModuleIdentifierPropertiesExtShaderModuleIdentifierAlgorithmUuid.gen.cs => PhysicalDeviceShaderModuleIdentifierPropertiesEXTShaderModuleIdentifierAlgorithmUuid.gen.cs} (94%) rename sources/Vulkan/Vulkan/Vulkan/{PhysicalDeviceShaderObjectPropertiesExtShaderBinaryUuid.gen.cs => PhysicalDeviceShaderObjectPropertiesEXTShaderBinaryUuid.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineBinaryKeyKhrKey.gen.cs => PipelineBinaryKeyKHRKey.gen.cs} (92%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineCacheHeaderVersionDataGraphQcomToolchainVersion.gen.cs => PipelineCacheHeaderVersionDataGraphQCOMToolchainVersion.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineExecutableInternalRepresentationKhrDescription.gen.cs => PipelineExecutableInternalRepresentationKHRDescription.gen.cs} (88%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineExecutableInternalRepresentationKhrName.gen.cs => PipelineExecutableInternalRepresentationKHRName.gen.cs} (89%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineExecutablePropertiesKhrDescription.gen.cs => PipelineExecutablePropertiesKHRDescription.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineExecutablePropertiesKhrName.gen.cs => PipelineExecutablePropertiesKHRName.gen.cs} (91%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineExecutableStatisticKhrDescription.gen.cs => PipelineExecutableStatisticKHRDescription.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineExecutableStatisticKhrName.gen.cs => PipelineExecutableStatisticKHRName.gen.cs} (91%) rename sources/Vulkan/Vulkan/Vulkan/{PipelineFragmentShadingRateStateCreateInfoKhrCombinerOps.gen.cs => PipelineFragmentShadingRateStateCreateInfoKHRCombinerOps.gen.cs} (97%) rename sources/Vulkan/Vulkan/Vulkan/{PipelinePropertiesIdentifierExtPipelineIdentifier.gen.cs => PipelinePropertiesIdentifierEXTPipelineIdentifier.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{PerformanceCounterDescriptionKhrDescription.gen.cs => RenderPassSubpassFeedbackInfoEXTDescription.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{ShaderModuleIdentifierExtIdentifier.gen.cs => ShaderModuleIdentifierEXTIdentifier.gen.cs} (91%) rename sources/Vulkan/Vulkan/Vulkan/{ShaderStatisticsInfoAmdComputeWorkGroupSize.gen.cs => ShaderStatisticsInfoAMDComputeWorkGroupSize.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{TransformMatrixKhrMatrix.gen.cs => TransformMatrixKHRMatrix.gen.cs} (92%) rename sources/Vulkan/Vulkan/Vulkan/{VideoDecodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs => VideoDecodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{VideoDecodeVp9PictureInfoKhrReferenceNameSlotIndices.gen.cs => VideoDecodeVp9PictureInfoKHRReferenceNameSlotIndices.gen.cs} (90%) rename sources/Vulkan/Vulkan/Vulkan/{VideoEncodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs => VideoEncodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs} (90%) create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.DoesNotIdentifyPrefix_WhenSingleName_WithNoHint.verified.txt rename tests/SilkTouch/SilkTouch/Naming/{PrettifyNamesTests.DoesNotTrimTypeName_WhenNotMatchingHint_AndOnlyOneType.verified.txt => IdentifySharedPrefixesTests.DoesNotIdentifyPrefix_WhenSingleName_WithNonMatchingHint.verified.txt} (100%) create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesPrefix_WhenMatchingHint.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix2.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=glfw.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=null.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_ForTypes.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenSuffixesDeclared.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.MultipleGlobalPrefixHints.verified.txt rename tests/SilkTouch/SilkTouch/Naming/{PrettifyNamesTests.PreserveKhronosNamespaceEnumPrefix.verified.txt => IdentifySharedPrefixesTests.PreserveKhronosNamespaceEnumPrefix.verified.txt} (100%) create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionEvalTargetNV.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionFragmentShaderColorModMaskATI.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionSingleMemberEnumUsesGlobalPrefixHint.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.cs delete mode 100644 tests/SilkTouch/SilkTouch/Naming/NameTrimmerTests.cs create mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.ConflictsAreResolved_ForMethodsAndConstants.verified.txt rename tests/SilkTouch/SilkTouch/Naming/{PrettifyNamesTests.Regression_IncorrectSecondary_ChosenAsFallback.verified.txt => PrettifyNamesTests.FallbackIsChosenCorrectly.verified.txt} (70%) create mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.FallbackIsChosenCorrectly_ReversedPriority.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_FromParentScope.verified.txt create mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_WhenOverridden.verified.txt delete mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsPrefix_WhenMatchingHint.verified.txt delete mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix.verified.txt delete mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix2.verified.txt delete mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_ForTypes.verified.txt delete mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared.verified.txt delete mode 100644 tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt diff --git a/.silktouch/openal-clangsharp.stout b/.silktouch/openal-clangsharp.stout index c00c2aa9e0f1c3c73c6201b020f40b5d4199cb19..fe7129046ae063b28f06579eaaab3f60fe925b22 100644 GIT binary patch delta 83 zcmaE~pXt$lCf)#VW)=|!CJqjU>`8SSd3|G;f%N9smRxGhLz^3r+s TVEXyIU@&bvKMYJyo9_bv;-(-~ delta 83 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 Ojk*ecF)CS45&S>5oMwao delta 88835 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≈OIoR31 zAE^F&_MEp!@Q(2Ztd~Xh*hDb3*B^RilI~Q=#7$b+(k+0eidN46K1h^;kHzc$5X&0^ zFl^`Ey`vEi&kKaMo*DHuk7C7pfru5;*1kJRO(sEb4&#C#b~3>*Z%cz={i}odrQ(Eg zf3!YPE_T5(Ja%>&6tG7K=;a@RmfIl+a0ZRV49()ruPu*4m z=Vz?sDT`IL66&hE3S-Bt0x%D#GT1{2T$R-z*^zMEEJC4z>7hJ*`9U=d_H1()zgE3ffCVC@UFi^A=Vid5FF%6u6Mvjo@&guytIs?l=SC~u#RS%czR{x$Gr`KLaP1_p&Jl{OF zq%C*36&sS-hExid5vW8iVdOS=%y+jz`OQiSPLNmS9Sym0+}{5*DMfiSq+2}(yAbZn z7!p=w#9)CfF+3f`N9q2j4G`E63lOM|1@t<{LFCKh5P+M+V`I7T@Nwo@>h*=SFi$|> z+9mT^F4^c)32@8*CE&rp?FbMH-UO1aKFiNZGy1VR;Z&YDnLCyeJaS3cp?eY*@y2WY0z@*kN${IY z1b&ssv;XA&Sb{c{0-hY63~}C*%+t%3Pj^N?1!r}3!GY1AJkyeLk?Ff&;@nI7e5M?$ z+-|t|`}TKng;5RI4bdyvjg70OKpEGhV8)Ma7qe4A%ZgNV9=Zost=cthiHTSTmbr(g zA_&zHj@l-obC8q<-=I)SL(W!+WZ6$)P8$4@ab?N-VO`790Lbl@zX(M1YOxp5>mzAHt27OS~l1<%&NLOYd()aQ7 zqE|h;DcZrA83-csE=xiwifzb%ra5N2V0;p0K%d2*SHNhv23>eU=ZRrI#q2FTg%kukBSvWuM0{ zK%>4~fV?B@{?!bkSc!%A5vN zB6FHkiMbW4czOx9bJC%Y^k8fiBHe2yZ)zxz{!|5!QL1HyPvV*Bl!uV5)Q2Ev%R~6e z`_vb-0_nmYLHNra!IX3_-R3FC%w`&H{}{n-%3~m~(h~%QzViM(;PfRvLBRgu2_mi; z)%ec#9k+Y-E)**jJ_klfUbOiM%jd}0PD;SC6nbn4b|Ic1Q&iC)~%eSLlS-wWD zDLG4Fu`5}qyw@;HN^cMWu6@HtipIoEIDC!FB>xtQ6!qxVP>5^XTZn7pTjX5w_MZ=h zR}l6N-hJW_t4t~rZg_`uef{~CF>n-J-b1VxtWG`+MhHlfl7oCeo! ziQYn|Rly%%KJNG8f07K|{{R`(_z06{^(VOwxRdb_xYJMG_bGC3%AdgH1)m@twu{iO@Iwz9_N_xyqTGa;{hBb+(;35IU?iB-z{f{_dOg#ns=@oUAAmi^`nB}Uq(C8G+}=+P3>PkN*rR0QqNLny1A}}r?=r2Px+mN zd|_(~By{#apy%Cx@cJjWf@oXx>mEU$>RKUskr)5H6LUB_T_jXE5O?zEZqbF>c}YSi z^?sf0c3D#`rjCq+4*S>2Na!G{NsnKJn=NfO?PMi%W}hu9q4VZ`?QpTF?c!TI2_2hw zw#Tiq_7bY>SnvA4(u|V)_Hq(>S8JV%x4?dEFZEDQ$w}x;HNw2N^8{*B?;xQ=&A<*4 z%K1I*AffY%yF((gNc6orN~jRxL`Ml_BPLk|RZ<8!vXg`k(IPuZ$k|CqdUyaHN{`MG z`c%OU3%l*)ImLFygteU|bap%Cu}7;51tfXH>OWsw1iVH)RPOm|Do{JE3qeKm}X6 zsUo3IDXiN9f26-vX!K!Q3hn~|DefboPu;ILu<)c6 z9kV+0g@mN_l~6T>Qa=eLER?5LHbDvW@v_ c5-K(twkvWW3IWX3v6}7b60tBUNkiiQKbyyA_y7O^ diff --git a/generator.json b/generator.json index 2c4d20f02e..1d08ab7d61 100644 --- a/generator.json +++ b/generator.json @@ -42,10 +42,12 @@ "AddIncludes", "ClangScraper", "MarkNativeNames", + "ExtractHandles", "ExtractNestedTyping", "TransformHandles", "TransformFunctions", "TransformProperties", + "IdentifySharedPrefixes", "PrettifyNames", "TransformEnums", "AddVTables", @@ -59,17 +61,23 @@ "InputTestRoot": "tests/SDL" }, "TransformHandles": { - "AssumeMissingTypesOpaque": true, - "UseDSL": true + "UseDsl": true }, "TransformFunctions": { "BoolTypes": { "SDL_bool": null } }, - "PrettifyNames": { + "IdentifySharedPrefixes": { "GlobalPrefixHints": ["SDL"] }, + "PrettifyNames": { + "Affixes": { + "SharedPrefix": { + "Remove": true + } + } + }, "TransformEnums": { "AddNoneMemberToFlags": true, "RewriteMemberValues": true @@ -95,6 +103,7 @@ "MixKhronosData", "AddOpaqueStructs", "TransformFunctions", + "IdentifySharedPrefixes", "PrettifyNames", "TransformEnums", "AddVTables", @@ -171,14 +180,17 @@ } ] }, - "PrettifyNames": { + "IdentifySharedPrefixes": { "GlobalPrefixHints": ["gl"], "PrefixOverrides": { "SyncObjectMask": "GL_SYNC", "OcclusionQueryParameterNameNV": "GL", "TexStorageAttribs": "GL", - "ContainerType": "GL" - }, + "ContainerType": "GL", + "SeparableTargetEXT": "GL" + } + }, + "PrettifyNames": { "Affixes": { "HandleType": { "Order": 1 @@ -197,6 +209,9 @@ }, "KhronosNonExclusiveVendor": { "Remove": true + }, + "SharedPrefix": { + "Remove": true } } }, @@ -228,10 +243,12 @@ "ChangeNativeClass", "AddApiProfiles", "MixKhronosData", + "ExtractHandles", "ExtractNestedTyping", "TransformHandles", "InterceptNativeFunctions", "TransformFunctions", + "IdentifySharedPrefixes", "PrettifyNames", "TransformEnums", "AddVTables", @@ -294,25 +311,20 @@ } ] }, + "IdentifySharedPrefixes": { + "GlobalPrefixHints": ["alc", "al"] + }, "PrettifyNames": { - "GlobalPrefixHints": ["alc", "al"], "NameOverrides": { "ALContext": "ALContext", "EFXEAXREVERBPROPERTIES": "EfxEaxReverbProperties", - "EFXEAXREVERBPROPERTIES_flReflectionsPan": "EfxEaxReverbPropertiesFlReflectionsPan", - "EFXEAXREVERBPROPERTIES_flLateReverbPan": "EfxEaxReverbPropertiesFlLateReverbPan", "ALCcontextHandle": "ContextHandle", "ALCdeviceHandle": "DeviceHandle", "ALBUFFERCALLBACKTYPESOFT": "BufferCallbackSOFT", - "ALBUFFERCALLBACKTYPESOFTDelegate": "BufferCallbackDelegateSOFT", "ALCEVENTPROCTYPESOFT": "ContextEventProcSOFT", - "ALCEVENTPROCTYPESOFTDelegate": "ContextEventProcDelegateSOFT", "ALEVENTPROCSOFT": "EventProcSOFT", - "ALEVENTPROCSOFTDelegate": "EventProcDelegateSOFT", "ALDEBUGPROCEXT": "DebugProcEXT", - "ALDEBUGPROCEXTDelegate": "DebugProcDelegateEXT", - "LPALFOLDBACKCALLBACK": "FoldbackCallback", - "LPALFOLDBACKCALLBACKDelegate": "FoldbackCallbackDelegate" + "LPALFOLDBACKCALLBACK": "FoldbackCallback" }, "Affixes": { "HandleType": { @@ -332,6 +344,9 @@ }, "KhronosNonExclusiveVendor": { "Remove": true + }, + "SharedPrefix": { + "Remove": true } } }, @@ -347,8 +362,7 @@ "BenefitOfTheDoubtArrayTransformation": true }, "TransformHandles": { - "AssumeMissingTypesOpaque": true, - "UseDSL": true + "UseDsl": true }, "StripAttributes": { "Remove": [ @@ -366,6 +380,7 @@ "AddIncludes", "ClangScraper", "MarkNativeNames", + "ExtractHandles", "ExtractNestedTyping", "TransformHandles", "MixKhronosData", @@ -373,6 +388,7 @@ "InterceptNativeFunctions", "TransformFunctions", "TransformProperties", + "IdentifySharedPrefixes", "PrettifyNames", "TransformEnums", "AddVTables", @@ -419,15 +435,16 @@ } }, "TransformHandles": { - "AssumeMissingTypesOpaque": true, - "UseDSL": true + "UseDsl": true }, - "PrettifyNames": { - "GlobalPrefixHints": ["PFN_vk","vk"], + "IdentifySharedPrefixes": { + "GlobalPrefixHints": ["PFN_vk", "vk"], "PrefixOverrides": { "VkPipelineCreateFlags2": "VK_PIPELINE_CREATE_2", "VkMemoryDecompressionMethodFlagsEXT": "VK_MEMORY_DECOMPRESSION_METHOD" - }, + } + }, + "PrettifyNames": { "NameOverrides": { "numAABBs": "NumAabbs" }, @@ -446,6 +463,9 @@ }, "KhronosHandleType": { "Remove": true + }, + "SharedPrefix": { + "Remove": true } } }, diff --git a/sources/OpenAL/OpenAL/al/BufferCallbackSOFT.gen.cs b/sources/OpenAL/OpenAL/al/BufferCallbackSOFT.gen.cs index 821cb1670f..d28a908f9a 100644 --- a/sources/OpenAL/OpenAL/al/BufferCallbackSOFT.gen.cs +++ b/sources/OpenAL/OpenAL/al/BufferCallbackSOFT.gen.cs @@ -19,7 +19,7 @@ namespace Silk.NET.OpenAL; public BufferCallbackSOFT(delegate* unmanaged ptr) => Pointer = ptr; - public BufferCallbackSOFT(BufferCallbackDelegateSOFT proc) => + public BufferCallbackSOFT(BufferCallbackSOFTDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); public void Dispose() => SilkMarshal.Free(Pointer); diff --git a/sources/OpenAL/OpenAL/al/BufferCallbackDelegateSOFT.gen.cs b/sources/OpenAL/OpenAL/al/BufferCallbackSOFTDelegate.gen.cs similarity index 90% rename from sources/OpenAL/OpenAL/al/BufferCallbackDelegateSOFT.gen.cs rename to sources/OpenAL/OpenAL/al/BufferCallbackSOFTDelegate.gen.cs index 9304622154..00ceea77e9 100644 --- a/sources/OpenAL/OpenAL/al/BufferCallbackDelegateSOFT.gen.cs +++ b/sources/OpenAL/OpenAL/al/BufferCallbackSOFTDelegate.gen.cs @@ -11,4 +11,4 @@ namespace Silk.NET.OpenAL; [NativeName("ALBUFFERCALLBACKTYPESOFT")] -public unsafe delegate int BufferCallbackDelegateSOFT(void* arg0, void* arg1, int arg2); +public unsafe delegate int BufferCallbackSOFTDelegate(void* arg0, void* arg1, int arg2); diff --git a/sources/OpenAL/OpenAL/al/ContextEventProcSOFT.gen.cs b/sources/OpenAL/OpenAL/al/ContextEventProcSOFT.gen.cs index 36ccd70272..cc8b15a5c4 100644 --- a/sources/OpenAL/OpenAL/al/ContextEventProcSOFT.gen.cs +++ b/sources/OpenAL/OpenAL/al/ContextEventProcSOFT.gen.cs @@ -21,7 +21,7 @@ public ContextEventProcSOFT( delegate* unmanaged ptr ) => Pointer = ptr; - public ContextEventProcSOFT(ContextEventProcDelegateSOFT proc) => + public ContextEventProcSOFT(ContextEventProcSOFTDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); public void Dispose() => SilkMarshal.Free(Pointer); diff --git a/sources/OpenAL/OpenAL/al/ContextEventProcDelegateSOFT.gen.cs b/sources/OpenAL/OpenAL/al/ContextEventProcSOFTDelegate.gen.cs similarity index 92% rename from sources/OpenAL/OpenAL/al/ContextEventProcDelegateSOFT.gen.cs rename to sources/OpenAL/OpenAL/al/ContextEventProcSOFTDelegate.gen.cs index 8bf39a4158..298338bc3a 100644 --- a/sources/OpenAL/OpenAL/al/ContextEventProcDelegateSOFT.gen.cs +++ b/sources/OpenAL/OpenAL/al/ContextEventProcSOFTDelegate.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.OpenAL; [NativeName("ALCEVENTPROCTYPESOFT")] -public unsafe delegate void ContextEventProcDelegateSOFT( +public unsafe delegate void ContextEventProcSOFTDelegate( int arg0, int arg1, DeviceHandle arg2, diff --git a/sources/OpenAL/OpenAL/al/DebugProcEXT.gen.cs b/sources/OpenAL/OpenAL/al/DebugProcEXT.gen.cs index 1c7f5c2f40..2e70e56727 100644 --- a/sources/OpenAL/OpenAL/al/DebugProcEXT.gen.cs +++ b/sources/OpenAL/OpenAL/al/DebugProcEXT.gen.cs @@ -20,7 +20,7 @@ namespace Silk.NET.OpenAL; public DebugProcEXT(delegate* unmanaged ptr) => Pointer = ptr; - public DebugProcEXT(DebugProcDelegateEXT proc) => Pointer = SilkMarshal.DelegateToPtr(proc); + public DebugProcEXT(DebugProcEXTDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); public void Dispose() => SilkMarshal.Free(Pointer); diff --git a/sources/OpenAL/OpenAL/al/DebugProcDelegateEXT.gen.cs b/sources/OpenAL/OpenAL/al/DebugProcEXTDelegate.gen.cs similarity index 93% rename from sources/OpenAL/OpenAL/al/DebugProcDelegateEXT.gen.cs rename to sources/OpenAL/OpenAL/al/DebugProcEXTDelegate.gen.cs index 55d0dbf77f..2731ebb85e 100644 --- a/sources/OpenAL/OpenAL/al/DebugProcDelegateEXT.gen.cs +++ b/sources/OpenAL/OpenAL/al/DebugProcEXTDelegate.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.OpenAL; [NativeName("ALDEBUGPROCEXT")] -public unsafe delegate void DebugProcDelegateEXT( +public unsafe delegate void DebugProcEXTDelegate( int arg0, int arg1, uint arg2, diff --git a/sources/OpenAL/OpenAL/al/EventProcSOFT.gen.cs b/sources/OpenAL/OpenAL/al/EventProcSOFT.gen.cs index a9c1b55168..9bfa68cf4e 100644 --- a/sources/OpenAL/OpenAL/al/EventProcSOFT.gen.cs +++ b/sources/OpenAL/OpenAL/al/EventProcSOFT.gen.cs @@ -20,7 +20,7 @@ namespace Silk.NET.OpenAL; public EventProcSOFT(delegate* unmanaged ptr) => Pointer = ptr; - public EventProcSOFT(EventProcDelegateSOFT proc) => Pointer = SilkMarshal.DelegateToPtr(proc); + public EventProcSOFT(EventProcSOFTDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); public void Dispose() => SilkMarshal.Free(Pointer); diff --git a/sources/OpenAL/OpenAL/al/EventProcDelegateSOFT.gen.cs b/sources/OpenAL/OpenAL/al/EventProcSOFTDelegate.gen.cs similarity index 93% rename from sources/OpenAL/OpenAL/al/EventProcDelegateSOFT.gen.cs rename to sources/OpenAL/OpenAL/al/EventProcSOFTDelegate.gen.cs index 78284252ae..aeb235dd90 100644 --- a/sources/OpenAL/OpenAL/al/EventProcDelegateSOFT.gen.cs +++ b/sources/OpenAL/OpenAL/al/EventProcSOFTDelegate.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.OpenAL; [NativeName("ALEVENTPROCSOFT")] -public unsafe delegate void EventProcDelegateSOFT( +public unsafe delegate void EventProcSOFTDelegate( int arg0, uint arg1, uint arg2, diff --git a/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs b/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs index 0f1fd372ab..16885d4a3a 100644 --- a/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs +++ b/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs @@ -98,7 +98,7 @@ class Rewriter(IBakeStrategy strategy, ILogger logger) : ModCSha public override SyntaxNode? VisitIndexerDeclaration(IndexerDeclarationSyntax node) => Visit( node, - $"this[{string.Join(", ", node.ParameterList.Parameters.Select(ModUtils.DiscrimStr))}]", + $"this[{string.Join(", ", node.ParameterList.Parameters.Select(ModUtils.GetMethodDiscriminator))}]", base.VisitIndexerDeclaration ); @@ -122,7 +122,13 @@ ConstructorDeclarationSyntax node ) => Visit( node, - ModUtils.DiscrimStr(node.Modifiers, null, string.Empty, node.ParameterList, null), + ModUtils.GetMethodDiscriminator( + node.Modifiers, + null, + string.Empty, + node.ParameterList, + null + ), base.VisitConstructorDeclaration ); @@ -132,7 +138,7 @@ ConstructorDeclarationSyntax node public override SyntaxNode? VisitOperatorDeclaration(OperatorDeclarationSyntax node) => Visit( node, - ModUtils.DiscrimStr( + ModUtils.GetMethodDiscriminator( node.Modifiers, null, $"op_{node.OperatorToken.Kind()}", @@ -147,7 +153,7 @@ ConversionOperatorDeclarationSyntax node ) => Visit( node, - ModUtils.DiscrimStr( + ModUtils.GetMethodDiscriminator( node.Modifiers, null, $"op_{node.ImplicitOrExplicitKeyword.Kind()}", @@ -160,7 +166,7 @@ ConversionOperatorDeclarationSyntax node public override SyntaxNode? VisitMethodDeclaration(MethodDeclarationSyntax node) => Visit( node, - ModUtils.DiscrimStr( + ModUtils.GetMethodDiscriminator( node.Modifiers, node.TypeParameterList, node.Identifier.ToString(), diff --git a/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs b/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs index 8556bd7539..5ad3bb237d 100644 --- a/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs +++ b/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs @@ -16,24 +16,26 @@ public class ModLoader public static Type? LoadModByName(string name) => name switch { - nameof(ChangeNamespace) => typeof(ChangeNamespace), + nameof(AddApiProfiles) => typeof(AddApiProfiles), nameof(AddIncludes) => typeof(AddIncludes), - nameof(TransformFunctions) => typeof(TransformFunctions), - nameof(PrettifyNames) => typeof(PrettifyNames), nameof(AddOpaqueStructs) => typeof(AddOpaqueStructs), nameof(AddVTables) => typeof(AddVTables), nameof(BakeSourceSets) => typeof(BakeSourceSets), - nameof(AddApiProfiles) => typeof(AddApiProfiles), - nameof(MixKhronosData) => typeof(MixKhronosData), - nameof(TransformHandles) => typeof(TransformHandles), - nameof(TransformEnums) => typeof(TransformEnums), - nameof(ExtractNestedTyping) => typeof(ExtractNestedTyping), - nameof(TransformProperties) => typeof(TransformProperties), - nameof(ClangScraper) => typeof(ClangScraper), + nameof(ChangeNamespace) => typeof(ChangeNamespace), nameof(ChangeNativeClass) => typeof(ChangeNativeClass), + nameof(ClangScraper) => typeof(ClangScraper), + nameof(ExtractHandles) => typeof(ExtractHandles), + nameof(ExtractNestedTyping) => typeof(ExtractNestedTyping), + nameof(IdentifySharedPrefixes) => typeof(IdentifySharedPrefixes), nameof(InterceptNativeFunctions) => typeof(InterceptNativeFunctions), nameof(MarkNativeNames) => typeof(MarkNativeNames), + nameof(MixKhronosData) => typeof(MixKhronosData), + nameof(PrettifyNames) => typeof(PrettifyNames), nameof(StripAttributes) => typeof(StripAttributes), + nameof(TransformEnums) => typeof(TransformEnums), + nameof(TransformFunctions) => typeof(TransformFunctions), + nameof(TransformHandles) => typeof(TransformHandles), + nameof(TransformProperties) => typeof(TransformProperties), _ => null, }; } diff --git a/sources/SilkTouch/SilkTouch/Mods/Common/ModUtils.cs b/sources/SilkTouch/SilkTouch/Mods/Common/ModUtils.cs index a0a8133a80..91dcf7c06b 100644 --- a/sources/SilkTouch/SilkTouch/Mods/Common/ModUtils.cs +++ b/sources/SilkTouch/SilkTouch/Mods/Common/ModUtils.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using ClangSharp; using Microsoft.CodeAnalysis; @@ -13,6 +14,11 @@ namespace Silk.NET.SilkTouch.Mods; /// public static class ModUtils { + /// + /// Returns the specified list as a span. + /// + public static Span AsSpan(this List list) => CollectionsMarshal.AsSpan(list); + /// /// Converts a namespace string into an . /// @@ -101,7 +107,7 @@ string candidate /// Tokens e.g. ref, in, out. /// The type syntax. /// The discriminator string. - public static string DiscrimStr(SyntaxTokenList? toks, TypeSyntax? type) => + public static string GetMethodDiscriminator(SyntaxTokenList? toks, TypeSyntax? type) => toks?.Any(x => x.Kind() is SyntaxKind.RefKeyword or SyntaxKind.InKeyword or SyntaxKind.OutKeyword ) ?? false @@ -117,7 +123,7 @@ public static string DiscrimStr(SyntaxTokenList? toks, TypeSyntax? type) => /// The parameters of the function. /// The return type of the function. /// The discriminator string. - public static string DiscrimStr( + public static string GetMethodDiscriminator( SyntaxTokenList? modifiers, TypeParameterListSyntax? tParams, ReadOnlySpan identifier, @@ -125,8 +131,8 @@ public static string DiscrimStr( TypeSyntax? returnType ) => (modifiers?.Any(SyntaxKind.StaticKeyword) ?? false ? "static " : string.Empty) - + $"{DiscrimStr(modifiers, returnType)} {identifier}{tParams}" - + $"({string.Join(", ", @params?.Select(DiscrimStr) ?? [])})"; + + $"{GetMethodDiscriminator(modifiers, returnType)} {identifier}{tParams}" + + $"({string.Join(", ", @params?.Select(GetMethodDiscriminator) ?? [])})"; /// /// Gets a string that can be used to discriminate a function-like element for baking purposes. @@ -137,21 +143,21 @@ public static string DiscrimStr( /// The parameters of the function. /// The return type of the function. /// The discriminator string. - public static string DiscrimStr( + public static string GetMethodDiscriminator( SyntaxTokenList? modifiers, TypeParameterListSyntax? tParams, ReadOnlySpan identifier, BaseParameterListSyntax? @params, TypeSyntax? returnType - ) => DiscrimStr(modifiers, tParams, identifier, @params?.Parameters, returnType); + ) => GetMethodDiscriminator(modifiers, tParams, identifier, @params?.Parameters, returnType); /// /// Gets a string that can be used to discriminate a single parameter. /// /// The parameter. /// The discriminator string. - public static string DiscrimStr(BaseParameterSyntax param) => - DiscrimStr(param.Modifiers, param.Type); + public static string GetMethodDiscriminator(BaseParameterSyntax param) => + GetMethodDiscriminator(param.Modifiers, param.Type); /// /// Gets the relative path for this document. diff --git a/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs b/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs new file mode 100644 index 0000000000..d1018b9caf --- /dev/null +++ b/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs @@ -0,0 +1,324 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Extensions.Logging; +using Silk.NET.SilkTouch.Naming; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Silk.NET.SilkTouch.Mods; + +/// +/// Adds empty handle structs by searching for missing types referenced through pointers. +/// If all references to the missing type are through a pointer, +/// that missing type is then added as an empty struct. +/// +/// See for applying further transformations. +/// +public class ExtractHandles(ILogger logger) : Mod +{ + /// + public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) + { + await base.ExecuteAsync(ctx, ct); + + var project = ctx.SourceProject; + if (project == null) + { + return; + } + + var compilation = await project.GetCompilationAsync(ct); + if (compilation == null) + { + throw new InvalidOperationException("Failed to get compilation"); + } + + // Find missing handle types + var handleDiscoverer = new MissingHandleTypeDiscoverer(logger, compilation, ct); + var missingHandleTypes = handleDiscoverer.GetMissingHandleTypes(); + + // Generate syntax nodes containing empty structs to represent the missing handle types + var structGenerator = new EmptyStructGenerator(); + var syntaxNodes = structGenerator.GenerateSyntaxNodes(missingHandleTypes); + + // Add syntax nodes to the project as new documents + foreach (var (fullyQualifiedName, node) in syntaxNodes) + { + var relativePath = $"Handles/{PathForFullyQualified(fullyQualifiedName)}"; + project = project + .AddDocument( + Path.GetFileName(relativePath), + node.NormalizeWhitespace(), + filePath: project.FullPath(relativePath) + ) + .Project; + } + + ctx.SourceProject = project; + } + + private class MissingHandleTypeDiscoverer( + ILogger logger, + Compilation compilation, + CancellationToken ct + ) : SymbolVisitor + { + private readonly HashSet _nonHandleTypes = + new(SymbolEqualityComparer.Default); + private readonly Dictionary _missingTypes = + new(SymbolEqualityComparer.Default); + + private string? _currentNamespace = null; + private int _pointerTypeDepth = 0; + + /// + /// Gets all missing handle types that are found and the namespace that they should be created in. + /// + public Dictionary GetMissingHandleTypes() + { + // We need to find and generate all missing handle types + // Handle types are types that are only referenced through a pointer + // We do this by parsing through the list of type errors + var typeErrors = compilation + .GetDiagnostics(ct) + .Where(d => d.Id == "CS0246") // Type errors + .ToList(); + + // Find symbols that contain ITypeErrorSymbols + // These symbols are not necessarily ITypeErrorSymbols + var symbolsFound = new HashSet(SymbolEqualityComparer.Default); + foreach (var typeError in typeErrors) + { + var syntaxTree = typeError.Location.SourceTree; + if (syntaxTree == null) + { + continue; + } + + var semanticModel = compilation.GetSemanticModel(syntaxTree); + + // Get the syntax node the type error corresponds to + var currentSyntax = syntaxTree.GetRoot().FindNode(typeError.Location.SourceSpan); + + // Search upwards to find a syntax node that we can call GetDeclaredSymbol on + // This is because calling GetDeclaredSymbol on the starting node will just return null + var isSuccess = false; + while (currentSyntax != null && currentSyntax is not TypeDeclarationSyntax) + { + switch (currentSyntax) + { + case VariableDeclarationSyntax variableDeclarationSyntax: + { + foreach (var declaratorSyntax in variableDeclarationSyntax.Variables) + { + var symbol = semanticModel.GetDeclaredSymbol(declaratorSyntax, ct); + if (symbol != null) + { + symbolsFound.Add(symbol); + isSuccess = true; + + // All of the declarators will have the same type, so getting the first symbol is enough + break; + } + } + + break; + } + case MemberDeclarationSyntax memberDeclarationSyntax: + { + var symbol = semanticModel.GetDeclaredSymbol( + memberDeclarationSyntax, + ct + ); + if (symbol != null) + { + symbolsFound.Add(symbol); + isSuccess = true; + } + + break; + } + // Skip syntaxes that will never contain handle types + case BaseTypeSyntax: + case AttributeSyntax: + { + isSuccess = true; + break; + } + } + + currentSyntax = currentSyntax.Parent; + } + + if (!isSuccess) + { + // This is to warn of unhandled cases + logger.LogWarning( + "Failed to find corresponding symbol for type error. There may be an unhandled case in the code" + ); + } + } + + // These symbols contain at least one IErrorTypeSymbol, we need to search downwards for them + foreach (var symbol in symbolsFound) + { + Visit(symbol); + } + + return new Dictionary( + _missingTypes.Where(kvp => !_nonHandleTypes.Contains(kvp.Key)), + SymbolEqualityComparer.Default + ); + } + + public override void VisitMethod(IMethodSymbol symbol) + { + base.VisitMethod(symbol); + + _currentNamespace = symbol.NamespaceFromSymbol(); + foreach (var parameterSymbol in symbol.Parameters) + { + Visit(parameterSymbol); + } + _currentNamespace = null; + } + + public override void VisitParameter(IParameterSymbol symbol) + { + base.VisitParameter(symbol); + + _currentNamespace = symbol.NamespaceFromSymbol(); + Visit(symbol.Type); + _currentNamespace = null; + } + + public override void VisitProperty(IPropertySymbol symbol) + { + base.VisitProperty(symbol); + + _currentNamespace = symbol.NamespaceFromSymbol(); + Visit(symbol.Type); + _currentNamespace = null; + } + + public override void VisitField(IFieldSymbol symbol) + { + base.VisitField(symbol); + + _currentNamespace = symbol.NamespaceFromSymbol(); + Visit(symbol.Type); + _currentNamespace = null; + } + + public override void VisitLocal(ILocalSymbol symbol) + { + base.VisitLocal(symbol); + + _currentNamespace = symbol.NamespaceFromSymbol(); + Visit(symbol.Type); + _currentNamespace = null; + } + + public override void VisitPointerType(IPointerTypeSymbol symbol) + { + base.VisitPointerType(symbol); + + _pointerTypeDepth++; + Visit(symbol.PointedAtType); + _pointerTypeDepth--; + } + + public override void VisitNamedType(INamedTypeSymbol symbol) + { + base.VisitNamedType(symbol); + + if (symbol is IErrorTypeSymbol errorTypeSymbol) + { + if (_currentNamespace == null) + { + throw new InvalidOperationException( + $"{nameof(_currentNamespace)} should not be null" + ); + } + + if (_pointerTypeDepth == 0) + { + _nonHandleTypes.Add(errorTypeSymbol); + } + + if (_missingTypes.TryGetValue(errorTypeSymbol, out var sharedNamespace)) + { + _missingTypes[errorTypeSymbol] = NameUtils + .FindCommonPrefix([sharedNamespace, _currentNamespace], true, false, true) + .Trim('.'); + } + else + { + _missingTypes[errorTypeSymbol] = _currentNamespace; + } + } + } + } + + private class EmptyStructGenerator + { + /// + /// Generates a syntax node for each specified type. + /// + /// Map from error type symbol to the namespace the type should be created in. + /// Map from the fully qualified name of the generated type to the syntax node containing code for that type. + public Dictionary GenerateSyntaxNodes( + Dictionary typesToGenerate + ) => + GenerateSyntaxNodes( + typesToGenerate + .Select(kvp => new KeyValuePair(kvp.Key.Name, kvp.Value)) + .ToDictionary() + ); + + /// + /// Generates a syntax node for each specified type. + /// + /// Map from type name to the namespace the type should be created in. + /// Map from the fully qualified name of the generated type to the syntax node containing code for that type. + public Dictionary GenerateSyntaxNodes( + Dictionary missingHandleTypes + ) + { + var results = new Dictionary(); + foreach (var (name, ns) in missingHandleTypes) + { + var fullyQualifiedName = string.IsNullOrWhiteSpace(ns) ? name : $"{ns}.{name}"; + var structDeclarationSyntax = StructDeclaration(name) + .WithModifiers( + TokenList( + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.UnsafeKeyword), + Token(SyntaxKind.PartialKeyword) + ) + ); + + results[fullyQualifiedName] = CompilationUnit() + .WithMembers( + SingletonList( + string.IsNullOrWhiteSpace(ns) + ? structDeclarationSyntax + : FileScopedNamespaceDeclaration( + ModUtils.NamespaceIntoIdentifierName(ns) + ) + .WithMembers( + SingletonList( + structDeclarationSyntax + ) + ) + ) + ); + } + + return results; + } + } +} diff --git a/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs b/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs index fd53e3a615..e5073907e0 100644 --- a/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs +++ b/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs @@ -322,11 +322,20 @@ mem is not StructDeclarationSyntax struc continue; } - var iden = $"{node.Identifier}_{match.Groups[1].Value}"; + var iden = $"{node.Identifier}{match.Groups[1].Value}"; _typeRenames[struc.Identifier.ToString()] = iden; struc = - VisitStructDeclaration(struc.WithIdentifier(Identifier(iden))) - as StructDeclarationSyntax + VisitStructDeclaration( + struc + .WithIdentifier(Identifier(iden)) + .WithAttributeLists( + struc.AttributeLists.AddReferencedNameAffix( + NameAffixType.Prefix, + "NestedStructParent", + node.Identifier.ToString() + ) + ) + ) as StructDeclarationSyntax ?? struc; ExtractedNestedStructs.Add(struc); members = members.RemoveAt(i--); @@ -529,6 +538,11 @@ _fallbackFromOuterFunctionPointer is not null : default ) .WithNativeName(currentNativeTypeName) + .AddReferencedNameAffix( + NameAffixType.Prefix, + "FunctionPointerParent", + currentNativeTypeName + ) .AddNameAffix( NameAffixType.Suffix, "FunctionPointerDelegateType", @@ -618,8 +632,6 @@ or SyntaxKind.ULongKeyword return base.VisitPredefinedType(node); } - private readonly NameTrimmer _nameTrimmer = new(); - // This code can probably be better. public ( Dictionary< @@ -643,7 +655,7 @@ HashSet ExtractedConstants var (enumName, enumType) in _numericTypeNames.OrderByDescending(x => x.Key.Length) ) { - var enumTrimmingName = _nameTrimmer.GetTrimmingName(null, enumName, true); + var enumTrimmingName = NameSplitter.Underscore(enumName); (EnumDeclarationSyntax, HashSet, HashSet)? extractedEnum = enumType is { } theType ? ( @@ -663,11 +675,13 @@ HashSet ExtractedConstants // taking casing into account). It is possible that this could be expanded, but this should be done // carefully to ensure we don't light up prematurely. var nextConst = false; - var trimmingName = _nameTrimmer.GetTrimmingName(null, constant, false); - foreach (var enumCandidate in (IEnumerable)[enumName, enumTrimmingName]) + var trimmingName = NameSplitter.Underscore(constant); + foreach ( + var enumCandidate in (ReadOnlySpan)[enumName, enumTrimmingName] + ) { foreach ( - var constCandidate in (IEnumerable)[constant, trimmingName] + var constCandidate in (ReadOnlySpan)[constant, trimmingName] ) { // Make sure the constant name starts with the enum name, and that there is clearly a word diff --git a/sources/SilkTouch/SilkTouch/Mods/IdentifySharedPrefixes.cs b/sources/SilkTouch/SilkTouch/Mods/IdentifySharedPrefixes.cs new file mode 100644 index 0000000000..34ba8ae567 --- /dev/null +++ b/sources/SilkTouch/SilkTouch/Mods/IdentifySharedPrefixes.cs @@ -0,0 +1,726 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Extensions.Options; +using Silk.NET.SilkTouch.Naming; + +namespace Silk.NET.SilkTouch.Mods; + +/// +/// Identifies shared prefixes, +/// such as namespace prefixes (eg: vk, gl) +/// and enum constant prefixes (eg: VK_ACCESS). +/// +/// These are identified as [NameAffix] attributes that +/// and other mods can then process further. +/// +[ModConfiguration] +public class IdentifySharedPrefixes(IOptionsSnapshot config) + : Mod +{ + /// + /// This was from the original NameTrimmer code + /// Referencing the original documentation: + /// The second pass does not use . + /// The third pass uses naive prefix detection for . + /// + /// + /// This documentation should be expanded to explain the reasoning for each pass. + /// + private const int _passCount = 3; + + /// + /// Strings that are not allowed to be part of the final prefix. + /// + private static readonly HashSet _forbiddenPrefixes = new() { "unsigned", "per" }; + + /// + /// The configuration for the mod. + /// + public record Configuration + { + /// + /// Corrections to the automatic prefix determination. + /// + public Dictionary PrefixOverrides { get; init; } = []; + + /// + /// A list of known prefixes that are commonly used by names in the native API. + /// These are preferred when identifying shared prefixes. + /// + public List GlobalPrefixHints { get; init; } = []; + } + + /// + public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) + { + var configuration = config.Get(ctx.JobKey); + var project = ctx.SourceProject; + if (project is null) + { + return; + } + + // Sort the hints from large to small + // This makes it so that we prefer longer prefixes + var hints = configuration.GlobalPrefixHints.ToList(); + hints.Sort((x, y) => -x.Length.CompareTo(y.Length)); + configuration = configuration with { GlobalPrefixHints = hints }; + + // Gather all the names + var visitor = new Visitor(); + foreach (var doc in project.Documents) + { + visitor.Visit(await doc.GetSyntaxRootAsync(ct)); + } + + // Identify shared prefixes + var results = new Dictionary>(); + foreach (var (scope, members) in visitor.Scopes) + { + var prefixes = IdentifyPrefixes(scope, members, visitor.NonDeterminant, configuration); + if (prefixes == null) + { + continue; + } + + results.Add(scope, prefixes); + } + + // Output results as NameAffix attributes + var rewriter = new Rewriter(results); + foreach (var documentId in project.DocumentIds) + { + var document = project.GetDocument(documentId); + if (document == null) + { + continue; + } + + var syntaxRoot = await document.GetSyntaxRootAsync(ct); + if (syntaxRoot == null) + { + continue; + } + + project = document.WithSyntaxRoot(rewriter.Visit(syntaxRoot)).Project; + } + + ctx.SourceProject = project; + } + + /// + /// Identifies shared prefixes and returns a dictionary mapping the member name to the identified prefix for that member. + /// + private Dictionary? IdentifyPrefixes( + string scope, + List members, + HashSet nonDeterminant, + Configuration configuration + ) + { + List? localNames = null; + string? identifiedPrefix = null; + var naive = false; + { + for (var i = 0; i < _passCount; i++) // try with both trimming name and non trimming name + { + // Attempt to identify the hint being used. + string? hint = null; + foreach (var candidateHint in configuration.GlobalPrefixHints) + { + var match = true; + foreach (var member in members) + { + if ( + !member.UnaffixedName.StartsWith( + candidateHint, + StringComparison.OrdinalIgnoreCase + ) + ) + { + match = false; + break; + } + } + + if (match) + { + hint = candidateHint; + break; + } + } + + var result = GetPrefix( + scope, + members, + configuration.PrefixOverrides, + nonDeterminant, + hint, + useTrimmingName: i == 0, + naive: naive = i == 2 + ); + + if (result is null) + { + // skip outright. + return null; + } + + (identifiedPrefix, localNames) = result.Value; + + // If we have found a prefix, + if ( + identifiedPrefix.Length > 0 + && identifiedPrefix.Length < localNames.Min(x => x.TrimmingName.Length) + ) + { + // break and use it for trimming! + break; + } + + // If not, do most of them at least start with the hint? + if ( + hint is null + || localNames.Count(x => + x.TrimmingName.StartsWith(hint, StringComparison.OrdinalIgnoreCase) + ) + >= localNames.Count / 2 + ) + { + // Nope, nothing we can do it seems, we've already tried both trimming name and non trimming name... + continue; + } + + // The prefix is the hint! + identifiedPrefix = hint; + naive = true; + break; + } + } + + // If identifiedPrefix is null, we fall back to the hints. + // I know we've checked above whether this is the obvious answer for a given pass, + // but if we've still got no possible prefix after all the passes, then this is better than nothing. + // If the name doesn't start with the prefix, we simply won't use the prefix. + if ( + string.IsNullOrWhiteSpace(identifiedPrefix) + && configuration.GlobalPrefixHints is not { Count: > 0 } + ) + { + return null; + } + + var results = new Dictionary(); + + identifiedPrefix = identifiedPrefix?.Trim('_'); + foreach (var (originalName, unaffixedName, trimmingName) in localNames!) + { + ReadOnlySpan candidatePrefixes = !string.IsNullOrWhiteSpace(identifiedPrefix) + ? [identifiedPrefix] // Otherwise we fall back to the hints + : configuration.GlobalPrefixHints.AsSpan(); + + foreach (var candidatePrefix in candidatePrefixes) + { + if ( + naive + && ( + candidatePrefix.Length >= trimmingName.Length + || !trimmingName.StartsWith( + candidatePrefix, + StringComparison.OrdinalIgnoreCase + ) + ) + ) + { + continue; + } + + var unaffixedNameI = 0; + var isPrefixTooLong = false; + foreach (var c in candidatePrefix) + { + if (unaffixedNameI >= unaffixedName.Length) + { + isPrefixTooLong = true; + break; + } + + if (char.ToLower(c) == char.ToLower(unaffixedName[unaffixedNameI])) + { + unaffixedNameI++; + continue; + } + + if (c == '_') + { + unaffixedNameI++; + } + } + + if (isPrefixTooLong) + { + continue; + } + + // Output prefix to results + results[originalName] = unaffixedName[..unaffixedNameI]; + break; + } + } + + if (results.Count == 0) + { + return null; + } + + return results; + } + + /// + /// Gets the prefix for the given constituents of the given scope. + /// + /// The scope name if applicable. + /// The names to get a prefix for. + /// Prefix overrides. + /// List of names that should not be used for prefix determination. + /// The global prefix hint if applicable. + /// + /// Whether to use or to use the native name as-is. + /// + /// + /// Just match the start of the strings; don't bother checking for obvious name separation gaps. + /// + /// + /// Null to skip this scope outright, empty if no prefix was found, or the prefix otherwise. + /// + /// A local names list is also returned. + /// This is the list of names to be used for the remainder of the trimming process. + /// + private (string Prefix, List)? GetPrefix( + string scope, + List members, + Dictionary prefixOverrides, + HashSet? nonDeterminant, + string? hint, + bool useTrimmingName, + bool naive + ) + { + // If the type has no members, + if (members.Count == 0) + { + // skip it + return null; + } + + // Get the trimming names + var rawScopeTrimmingName = + (string.IsNullOrWhiteSpace(scope) ? null : scope) ?? hint ?? string.Empty; + var scopeTrimmingName = useTrimmingName + ? GetTrimmingName(prefixOverrides, rawScopeTrimmingName, hint) + : rawScopeTrimmingName; + + var localNames = members + .Select(member => new TrimmingNames( + member.OriginalName, + member.UnaffixedName, + useTrimmingName + ? GetTrimmingName(prefixOverrides, member.UnaffixedName, hint) + : member.UnaffixedName + )) + .ToList(); + + // Set the prefix to the prefix override for this scope, if it exists. + // This is to allow us to handle poorly/inconsistently named scopes, + // without putting special cases elsewhere in the logic + // ex: For the enum: + // enum Things { + // ThingsRGB + // ThingRGB + // } + // If we specify a prefix override of "Thing", + // then it will trim ThingsRGB to sRGB and ThingRGB to RGB + // a case like this is simple to add a special case for in the generator to handle sRGB specially, + // but see ImageChannelOrder from spirv.h for a more problematic occurrence. + string prefix; + if (prefixOverrides.TryGetValue(scope, out var @override)) + { + // Use the override + prefix = @override; + } + else + { + if (members.Count == 1) + { + if (!string.IsNullOrWhiteSpace(scopeTrimmingName)) + { + // Use the member name and its scope. + prefix = NameUtils.FindCommonPrefix( + [ + members + .First(member => + !(nonDeterminant?.Contains(member.UnaffixedName) ?? false) + ) + .UnaffixedName, + scopeTrimmingName, + ], + true, + false, + naive + ); + } + else + { + // One name. Can't determine prefix. + prefix = ""; + } + } + else + { + // Common case - Find the prefix based on the scope's members + prefix = NameUtils.FindCommonPrefix( + localNames + .Where(x => !(nonDeterminant?.Contains(x.UnaffixedName) ?? false)) + .Select(x => x.TrimmingName) + .ToList(), + // If naive mode is on and we're trimming type names, allow full matches (method class is + // probably the prefix) + naive && scope == "", + false, + naive + ); + } + } + + // If any of the children's trimming name is shorter than the prefix length, + if ( + localNames.Any(x => + x.TrimmingName.Length <= prefix.Length + && !(nonDeterminant?.Contains(x.UnaffixedName) ?? false) + ) && !string.IsNullOrWhiteSpace(scopeTrimmingName) + ) + { + // Do a second pass, but put the scope name in the loop to see if it makes a difference + prefix = NameUtils.FindCommonPrefix( + localNames.Select(x => x.TrimmingName).Append(scopeTrimmingName).ToList(), + // If naive mode is on and we're trimming type names, allow full matches (method class is probably the + // prefix) + naive && scope == "", + false, + naive + ); + } + + // Prevent certain strings from being part of the final prefix + foreach (var word in _forbiddenPrefixes) + { + // If the prefix starts with a forbidden prefix + if (prefix.StartsWith($"{word}_")) + { + // Clear the prefix + prefix = string.Empty; + } + + // If the prefix contains the forbidden trimming surrounded by underscores + var idx = prefix.IndexOf($"_{word}_", StringComparison.OrdinalIgnoreCase); + if (idx != -1) + { + // Trim the end of the prefix to the start of the forbidden prefix + // ex: + // input prefix = THIS_GL_ + // forbidden prefix = GL + // + // resulting prefix = THIS + prefix = prefix[..idx]; + } + } + + return (prefix, localNames); + } + + /// + /// Gets the name to feed into . + /// + /// The prefix overrides. + /// The name to get a trimming name for. + /// The global prefix hint. + /// The trimming name. + private string GetTrimmingName( + Dictionary prefixOverrides, + string name, + string? hint = null + ) + { + // If there's a prefix override for this enum, + if (prefixOverrides.ContainsKey(name)) + { + // Use the raw native name as the trimming name + return name; + } + + if (hint is not null && name.StartsWith(hint, StringComparison.OrdinalIgnoreCase)) + { + return NameSplitter.Underscore($"{hint}_{name[hint.Length..]}"); + } + + return NameSplitter.Underscore(name); + } + + /// The name as it exists in source code. + /// The original name with affixes stripped. + private readonly record struct MemberName(string OriginalName, string UnaffixedName); + + /// The name as it exists in source code. + /// The original name with affixes stripped. + /// The unaffixed name as a trimming name. See . + private readonly record struct TrimmingNames( + string OriginalName, + string UnaffixedName, + string TrimmingName + ) + { + public override string ToString() => + $"(Unaffixed={UnaffixedName}, Trimming={TrimmingName})"; + } + + private class Visitor : CSharpSyntaxWalker + { + /// + /// A mapping from scope names to their member names. + /// These only represent names that need to have their prefixes determined. + /// + public Dictionary> Scopes { get; } = new(); + + /// + /// A set of type names marked with the [Transformed] attribute. + /// + /// + /// These are not used for prefix determination since they can contain identifiers that + /// are not part of the original source code. + /// + public HashSet NonDeterminant { get; } = []; + + private BaseTypeDeclarationSyntax? _scope = null; + + private void ReportName( + SyntaxToken memberIdentifier, + SyntaxList memberAttributeLists + ) + { + var scopeName = _scope?.Identifier.ToString() ?? ""; + var memberName = memberIdentifier.ToString(); + + if (memberAttributeLists.ContainsAttribute("Silk.NET.Core.Transformed")) + { + NonDeterminant.Add(memberName); + } + + if (!Scopes.TryGetValue(scopeName, out var members)) + { + Scopes[scopeName] = members = []; + } + + var nameAffixes = memberAttributeLists.GetNameAffixes(); + var unaffixedMemberName = NameAffixer.StripAffixes(memberName, nameAffixes); + members.Add(new MemberName(memberName, unaffixedMemberName)); + } + + // ----- Types ----- + + public override void VisitClassDeclaration(ClassDeclarationSyntax node) + { + ReportName(node.Identifier, node.AttributeLists); + + var previousScope = _scope; + _scope = node; + foreach (var member in node.Members) + { + Visit(member); + } + _scope = previousScope; + } + + public override void VisitStructDeclaration(StructDeclarationSyntax node) + { + ReportName(node.Identifier, node.AttributeLists); + + var previousScope = _scope; + _scope = node; + foreach (var member in node.Members) + { + Visit(member); + } + _scope = previousScope; + } + + public override void VisitEnumDeclaration(EnumDeclarationSyntax node) + { + ReportName(node.Identifier, node.AttributeLists); + + var previousScope = _scope; + _scope = node; + foreach (var member in node.Members) + { + Visit(member); + } + _scope = previousScope; + } + + public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) => + ReportName(node.Identifier, node.AttributeLists); + + // ----- Members ----- + + public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => + ReportName(node.Identifier, node.AttributeLists); + + // Only supports single variable fields + public override void VisitFieldDeclaration(FieldDeclarationSyntax node) + { + // If the node is not a constant, skip it + // Otherwise, it's likely a C constant + if ( + !node.Modifiers.Any(SyntaxKind.ConstKeyword) + && !node.Modifiers.Any(SyntaxKind.StaticKeyword) + ) + { + return; + } + + var firstVariable = node.Declaration.Variables.First(); + ReportName(firstVariable.Identifier, node.AttributeLists); + } + + public override void VisitMethodDeclaration(MethodDeclarationSyntax node) + { + // Struct methods are introduced by the generator so we skip them + // Otherwise, it's likely a C function + if (_scope.IsKind(SyntaxKind.StructDeclaration)) + { + return; + } + + ReportName(node.Identifier, node.AttributeLists); + } + + public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) + { + // If the node is not a constant, skip it + // Otherwise, it's likely a C constant (often strings) + var hasSetter = + node.AccessorList?.Accessors.Any(a => + a.IsKind(SyntaxKind.SetAccessorDeclaration) + || a.IsKind(SyntaxKind.InitAccessorDeclaration) + ) ?? false; + + if (hasSetter) + { + return; + } + + ReportName(node.Identifier, node.AttributeLists); + } + } + + /// ScopeName -> (MemberName -> MemberPrefix) + private class Rewriter(Dictionary> results) + : CSharpSyntaxRewriter + { + private BaseTypeDeclarationSyntax? _scope = null; + + private SyntaxList RewriteAttributes( + SyntaxToken memberIdentifier, + SyntaxList memberAttributeLists + ) + { + var scopeName = _scope?.Identifier.ToString() ?? ""; + if (!results.TryGetValue(scopeName, out var scopePrefixes)) + { + return memberAttributeLists; + } + + if (!scopePrefixes.TryGetValue(memberIdentifier.ToString(), out var prefix)) + { + return memberAttributeLists; + } + + return memberAttributeLists.AddNameAffix( + NameAffixType.Prefix, + "SharedPrefix", + prefix, + true + ); + } + + // ----- Types ----- + + public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) + { + node = node.WithAttributeLists(RewriteAttributes(node.Identifier, node.AttributeLists)); + + var previousScope = _scope; + _scope = node; + node = node.WithMembers( + [.. node.Members.Select(member => (MemberDeclarationSyntax)Visit(member))] + ); + _scope = previousScope; + + return node; + } + + public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) + { + node = node.WithAttributeLists(RewriteAttributes(node.Identifier, node.AttributeLists)); + + var previousScope = _scope; + _scope = node; + node = node.WithMembers( + [.. node.Members.Select(member => (MemberDeclarationSyntax)Visit(member))] + ); + _scope = previousScope; + + return node; + } + + public override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node) + { + node = node.WithAttributeLists(RewriteAttributes(node.Identifier, node.AttributeLists)); + + var previousScope = _scope; + _scope = node; + node = node.WithMembers( + [.. node.Members.Select(member => (EnumMemberDeclarationSyntax)Visit(member))] + ); + _scope = previousScope; + + return node; + } + + public override SyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyntax node) => + node.WithAttributeLists(RewriteAttributes(node.Identifier, node.AttributeLists)); + + // ----- Members ----- + + public override SyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => + node.WithAttributeLists(RewriteAttributes(node.Identifier, node.AttributeLists)); + + // Only supports single variable fields + public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node) => + node.WithAttributeLists( + RewriteAttributes( + node.Declaration.Variables.First().Identifier, + node.AttributeLists + ) + ); + + public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) => + node.WithAttributeLists(RewriteAttributes(node.Identifier, node.AttributeLists)); + + public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) => + node.WithAttributeLists(RewriteAttributes(node.Identifier, node.AttributeLists)); + } +} diff --git a/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs b/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs index e7bb381c84..98395e7517 100644 --- a/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs +++ b/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs @@ -1915,9 +1915,8 @@ private SyntaxList ProcessAndGetNewAttributes( MethodDeclarationSyntax? methodDeclaration = null ) { - // Get the name of the identifier, preferring the native one if available // This name will be modified by the code below as different suffixes are identified - var trimmedName = attributeLists.GetNativeNameOrDefault(identifier); + var trimmedName = identifier.ToString(); if (trimHandleSuffix) { diff --git a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs index a803b7ab6b..100f43ad25 100644 --- a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs +++ b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -12,36 +14,21 @@ namespace Silk.NET.SilkTouch.Mods; /// /// A mod that will convert other naming conventions to the PascalCase nomenclature typically used in C#. /// -/// The logger. -/// Configuration snapshot. -/// Name trimmer providers. +/// +/// Does not support nested types. Please use before this mod. +/// Note that despite this, some initial work has been done to add nested type support so that it can be added when necessary. +/// [ModConfiguration] public class PrettifyNames( ILogger logger, - IOptionsSnapshot config, - IEnumerable> trimmerProviders + IOptionsSnapshot config ) : IMod, IResponseFileMod { /// - /// The configuration for the prettify names mod. + /// The configuration for the mod. /// - public record Configuration // DON'T USE CONSTRUCTOR-STYLE RECORDS! Needs a default ctor. + public record Configuration { - /// - /// Corrections to the automatic prefix determination. - /// - public Dictionary PrefixOverrides { get; init; } = []; - - /// - /// Manually renamed native names. - /// - public Dictionary NameOverrides { get; init; } = []; - - /// - /// The base trimmer version. If null, trimming is disabled. - /// - public Version? TrimmerBaseline { get; init; } = new(3, 0); - /// /// The maximum length of an all capitals string to be treated as a single acronym, rather than as an all /// capitals word. @@ -53,9 +40,9 @@ IEnumerable> trimmerProviders public int LongAcronymThreshold { get; init; } = 2; /// - /// Multiple candidate name prefixes that may apply across all of the bindings generated. + /// Manually renamed native names. /// - public IReadOnlyList? GlobalPrefixHints { get; init; } + public Dictionary NameOverrides { get; init; } = []; /// /// The configuration for each category of name affixes. @@ -71,9 +58,16 @@ public record NameAffixConfiguration { /// /// Whether the affix should be removed. + /// Defaults to false. /// public bool Remove { get; init; } = false; + /// + /// Whether the affix should be prettified. + /// Defaults to false. + /// + public bool Prettify { get; init; } = false; + /// /// The order with which the affix is applied. /// @@ -106,212 +100,53 @@ public record NameAffixConfiguration /// public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) { - // First pass to scan the sources and create a dictionary of type/member names. var cfg = config.Get(ctx.JobKey); - - // Sort the hints from large to small (longest prefix match) - var hints = cfg.GlobalPrefixHints?.ToList(); - hints?.Sort((x, y) => -x.Length.CompareTo(y.Length)); - cfg = cfg with { GlobalPrefixHints = hints }; - - var visitor = new Visitor(); if (ctx.SourceProject is null) { return; } + // Scan sources to gather names + var visitor = new NameDataVisitor(); foreach (var doc in ctx.SourceProject.Documents) { visitor.Visit(await doc.GetSyntaxRootAsync(ct)); } - // The dictionary containing mappings from the original type names to the new names of the type and its members - var newNames = new Dictionary(); - - var nameAffixer = new PrettifyNamesAffixer(visitor.AffixTypes, cfg.Affixes); - var namePrettifier = new NamePrettifier(cfg.LongAcronymThreshold); - - // Trim the trimmable names if the trimmer baseline is set - // Otherwise, we just prettify the trimmable names - if (cfg.TrimmerBaseline is null) - { - // Only prettify the trimmable names - foreach (var (name, (nonFunctions, functions)) in visitor.TrimmableTypes) - { - newNames[name] = new RenamedType( - ApplyPrettifyOnlyPipeline( - null, - name, - cfg.NameOverrides, - nameAffixer, - namePrettifier - ), - nonFunctions.ToDictionary( - x => x, - x => - ApplyPrettifyOnlyPipeline( - name, - x, - cfg.NameOverrides, - nameAffixer, - namePrettifier - ) - ), - functions.ToDictionary( - x => x.Name, - x => - ApplyPrettifyOnlyPipeline( - name, - x.Name, - cfg.NameOverrides, - nameAffixer, - namePrettifier - ) - ) - ); - } - } - else + // Process the names + var nameProcessorContext = new NameProcessorContext(visitor); { - // Trim and prettify the trimmable names - - // Get all the trimmers that are above this baseline. We also sort by the version. Why? Because someone - // couldn't be bothered to introduce a weight property. It is also unclear what effect this has on 2.17/2.18 - // but to be honest those trimmers aren't used and are only included for posterity and understanding of the - // old logic. - var trimmers = trimmerProviders - .SelectMany(x => x.Get(ctx.JobKey)) - .Append(new NameAffixerEarlyTrimmer(nameAffixer)) - .Append(new NameAffixerLateTrimmer(nameAffixer)) - .Append(new PrettifyNamesTrimmer(namePrettifier)) - .OrderBy(x => x.Order) - .ToArray(); - - // Create a type name dictionary to trim the type names. - var typeNames = visitor.TrimmableTypes.ToDictionary( - x => x.Key, - x => new CandidateNames(x.Key, []) - ); - - // If we don't have a prefix hint and don't have more than one type, we can't determine a prefix so don't - // trim. - if (typeNames.Count > 1 || cfg.GlobalPrefixHints is not null) - { - Trim( - new NameTrimmerContext - { - Container = null, - Names = typeNames, - Configuration = cfg, - JobKey = ctx.JobKey, - NonDeterminant = visitor.NonDeterminant, - }, - trimmers - ); - } - - // Now rename everything within each type. - foreach (var (typeName, (newTypeName, _)) in typeNames) - { - var (_, (consts, functions)) = visitor.TrimmableTypes.First(x => x.Key == typeName); - - // Rename the "constants" i.e. all the consts/static readonlys in this type. These are treated - // individually because everything that isn't a constant or a function is only prettified instead of prettified & trimmed. - var constNames = consts.ToDictionary(x => x, x => new CandidateNames(x, [])); - - // Trim the constants. - Trim( - new NameTrimmerContext - { - Container = typeName, - Names = constNames, - Configuration = cfg, - JobKey = ctx.JobKey, - NonDeterminant = visitor.NonDeterminant, - }, - trimmers - ); - - // Rename the functions. More often that not functions have different nomenclature to constants, so we - // treat them separately. - var functionNames = functions - .DistinctBy(x => x.Name) - .ToDictionary(x => x.Name, x => new CandidateNames(x.Name, [])); - - // Collect the syntax as this is used for conflict resolution in the Trim function. - var functionSyntax = functionNames.Keys.ToDictionary( - x => x, - x => functions.Where(y => y.Name == x).Select(y => y.Syntax) - ); - - // Trim the functions. - Trim( - new NameTrimmerContext - { - Container = typeName, - Names = functionNames, - Configuration = cfg, - JobKey = ctx.JobKey, - NonDeterminant = visitor.NonDeterminant, - }, - trimmers, - functionSyntax - ); - - // Add it to the rewriter's list of names to... rewrite... - newNames[typeName] = new RenamedType( - newTypeName, - constNames.ToDictionary(x => x.Key, x => x.Value.Primary), - functionNames.ToDictionary(x => x.Key, x => x.Value.Primary) - ); - } - } + var namePrettifier = new NamePrettifier(cfg.LongAcronymThreshold); - // Prettify the prettify only names - foreach (var (typeName, memberNames) in visitor.PrettifyOnlyTypes) - { - if (!newNames.TryGetValue(typeName, out var renamedType)) + // Define name processors + var nameProcessors = new INameProcessor[] { - renamedType = new RenamedType( - ApplyPrettifyOnlyPipeline( - null, - typeName, - cfg.NameOverrides, - nameAffixer, - namePrettifier - ), - [], - [] - ); - } + new HandleOverridesProcessor(cfg.NameOverrides), + new StripAffixesProcessor(visitor), + new PrettifyProcessor(namePrettifier), + new ReapplyAffixesProcessor(visitor, namePrettifier, cfg.Affixes), + new PrefixIfStartsWithNumberProcessor(), + new ResolveConflictsProcessor(visitor, logger), + new OutputFinalNamesProcessor(), + new RemoveUnmodifiedFinalNamesProcessor(), + }; - foreach (var memberName in memberNames) + foreach (var nameProcessor in nameProcessors) { - renamedType.NonFunctions[memberName] = ApplyPrettifyOnlyPipeline( - typeName, - memberName, - cfg.NameOverrides, - nameAffixer, - namePrettifier - ); + nameProcessor.ProcessNames(nameProcessorContext); } - - newNames[typeName] = renamedType; } + var newNames = nameProcessorContext.FinalNames; if (logger.IsEnabled(LogLevel.Debug)) { - foreach (var (name, (newName, nonFunctions, functions)) in newNames) + logger.LogDebug("Prettified names by scope:"); + foreach (var (scope, members) in newNames) { - logger.LogDebug("{} = {}", name, newName); - foreach (var (old, @new) in nonFunctions) - { - logger.LogDebug("{}.{} = {}.{}", name, old, newName, @new); - } - - foreach (var (old, @new) in functions) + logger.LogDebug("Scope: {}", scope); + foreach (var (oldMemberName, newMemberName) in members) { - logger.LogDebug("{}.{} = {}.{}", name, old, newName, @new); + logger.LogDebug(" {} = {}", oldMemberName, newMemberName); } } } @@ -341,53 +176,16 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) logger.LogDebug("Discovering references to symbols to rename for {}...", ctx.JobKey); ctx.SourceProject = proj; - var comp = + var compilation = await proj.GetCompilationAsync(ct) ?? throw new InvalidOperationException( "Failed to obtain compilation for source project!" ); - await NameUtils.RenameAllAsync( - ctx, - newNames.SelectMany(x => - { - var nonFunctionConflicts = x - .Value.NonFunctions.Values.Where(y => x.Value.Functions.ContainsValue(y)) - .ToHashSet(); - return comp.GetSymbolsWithName(x.Key, SymbolFilter.Type, ct) - .OfType() - .SelectMany(y => - [ - .. Enumerable.SelectMany( - [ - .. x.Value.NonFunctions.Select(z => - nonFunctionConflicts.Contains(z.Value) - ? new KeyValuePair( - z.Key, - $"{z.Value}Value" - ) - : z - ), - .. x.Value.Functions, - ], - z => - { - return y.GetMembers(z.Key).Select(w => (w, z.Value)); - } - ), - .. y.GetMembers() - .OfType() - .Where(z => - z.MethodKind is MethodKind.Constructor or MethodKind.Destructor - ) - .Select(z => (z, x.Value.NewName)), - (y, x.Value.NewName), - ] - ); - }), - logger, - ct - ); + // Gather symbols and rename + var symbolVisitor = new NameSymbolVisitor(newNames); + symbolVisitor.Visit(compilation.Assembly); + await NameUtils.RenameAllAsync(ctx, symbolVisitor.ToRename, logger, ct); logger.LogDebug( "Reference renaming took {} seconds for {}.", @@ -397,16 +195,21 @@ z.MethodKind is MethodKind.Constructor or MethodKind.Destructor // Change the filenames where appropriate. proj = ctx.SourceProject; + var typeNames = newNames.GetValueOrDefault("", []); + var typeNamesLongestFirst = typeNames.OrderByDescending(x => x.Key.Length).ToArray(); + foreach (var docId in proj.DocumentIds) { var doc = proj.GetDocument(docId); - if ( - doc is not { FilePath: not null } - || newNames - .OrderByDescending(x => x.Key.Length) - .FirstOrDefault(x => doc.FilePath.Contains(x.Key) || doc.Name.Contains(x.Key)) - is not { Key: { } oldName, Value.NewName: { } newName } - ) + if (doc?.FilePath == null) + { + continue; + } + + var firstMatch = typeNamesLongestFirst.FirstOrDefault(x => + doc.FilePath.Contains(x.Key) || doc.Name.Contains(x.Key) + ); + if (firstMatch is not { Key: { } oldName, Value: { } newName }) { continue; } @@ -453,856 +256,551 @@ z.MethodKind is MethodKind.Constructor or MethodKind.Destructor ctx.SourceProject = proj; } - /// - /// Applies the prettify only pipeline. - /// This currently consists of checking for name overrides first. - /// Then if no override is found, then the name's affixes are removed, - /// the name is prettified, and the name's affixes are added back. - /// - private string ApplyPrettifyOnlyPipeline( - string? container, - string name, - Dictionary nameOverrides, - PrettifyNamesAffixer nameAffixer, - NamePrettifier namePrettifier - ) + /// + public Task> BeforeScrapeAsync(string key, List rsps) { - // Check for overrides - foreach (var (nativeName, overriddenName) in nameOverrides) + foreach (var responseFile in rsps) { - if (nativeName.Contains('.')) + if (!responseFile.GeneratorConfiguration.DontUseUsingStaticsForEnums) { - // We're processing a type dictionary, so don't add a member thing. - if (container is null) - { - continue; - } - - // Check whether the override is for this type. - var span = nativeName.AsSpan(); - var containerSpan = span[..span.IndexOf('.')]; - if ( - !containerSpan.Equals("*", StringComparison.Ordinal) - && !containerSpan.Equals(container, StringComparison.Ordinal) - ) - { - continue; - } - - var nameToAdd = span[(span.IndexOf('.') + 1)..].ToString(); - if (nameToAdd == name) - { - return overriddenName; - } + logger.LogWarning( + "{} (for {}) should use exclude-using-statics-for-enums as PrettifyNames does not resolve " + + "conflicts with members of other types.", + responseFile.FilePath, + key + ); } - else if (nativeName == name) + if (!responseFile.GeneratorConfiguration.DontUseUsingStaticsForGuidMember) { - return overriddenName; + logger.LogWarning( + "{} (for {}) should use exclude-using-statics-for-guid-members as PrettifyNames does not resolve " + + "conflicts with members of other types.", + responseFile.FilePath, + key + ); } } - // Be lenient about caps for type names (e.g. GL) - var allowAllCaps = container == null; - - var result = name; - result = nameAffixer.RemoveAffixes(result, container, name, null); - result = namePrettifier.Prettify(result, allowAllCaps); - result = nameAffixer.ApplyAffixes(result, container, name, null); - - return result; + return Task.FromResult(rsps); } - private void Trim( - NameTrimmerContext context, - IEnumerable trimmers, - Dictionary>? functionSyntax = null - ) + /// + /// Stores additional data for each scope member. + /// + /// The affixes declared for the name. + /// The declaration syntaxes for the member. + private record struct MemberData( + NameAffix[] Affixes, + List Declarations + ); + + private class NameDataVisitor : CSharpSyntaxWalker { - // Ensure the trimmers don't see names that have been manually overridden, as we don't want them to influence - // automatic prefix determination for example - var namesToTrim = context.Names; - foreach (var (nativeName, overriddenName) in context.Configuration.NameOverrides) - { - var nameToAdd = nativeName; - if (nativeName.Contains('.')) - { - // We're processing a type dictionary, so don't add a member thing. - if (context.Container is null) - { - continue; - } + /// + /// Represents a mapping: ScopeName -> (MemberName -> MemberData). + /// This data is used by name processors to transform and prettify the names. + /// + public Dictionary> Names { get; } = []; - // Check whether the override is for this type. - var span = nativeName.AsSpan(); - var containerSpan = span[..span.IndexOf('.')]; - if ( - containerSpan.Equals("*", StringComparison.Ordinal) - || containerSpan.Equals(context.Container, StringComparison.Ordinal) - ) - { - nameToAdd = span[(span.IndexOf('.') + 1)..].ToString(); - } - else - { - continue; - } - } + private BaseTypeDeclarationSyntax? _scope; - if (!namesToTrim.TryGetValue(nameToAdd, out var v)) + private void ReportName( + SyntaxToken memberIdentifier, + SyntaxList memberAttributeLists, + MemberDeclarationSyntax memberDeclaration + ) + { + var scopeName = _scope?.Identifier.ToString() ?? ""; + var memberName = memberIdentifier.ToString(); + var affixes = memberAttributeLists.GetNameAffixes(); + + if (!Names.TryGetValue(scopeName, out var members)) { - continue; + Names[scopeName] = members = []; } - // If we haven't created the differentiated dictionary yet, then do so now. We do want to keep the original - // dictionary so we can actually apply the renames; if we have created two different branching dictionaries - // they are recombined following trimming. - if (namesToTrim == context.Names) + if (!members.TryGetValue(memberName, out var memberData)) { - namesToTrim = namesToTrim.ToDictionary(); + // Note that we only store affix data for the first encountered version of the name + // This is fine because if two members have the same name, they should have the same affixes + memberData = new MemberData(affixes, []); } - // Don't let the trimmers see the overridden native name. - namesToTrim.Remove(nameToAdd); - - // Apply the name override to the dictionary we actually use. - context.Names[nameToAdd] = new CandidateNames( - overriddenName, - [.. v.Secondary, nameToAdd] - ); + memberData.Declarations.Add(memberDeclaration); + members[memberName] = memberData; } - // Run each trimmer - foreach (var trimmer in trimmers) + // ----- Types ----- + + public override void VisitClassDeclaration(ClassDeclarationSyntax node) { - trimmer.Trim(context with { Names = namesToTrim }); + ReportName(node.Identifier, node.AttributeLists, node); + + var previousScope = _scope; + _scope = node; + foreach (var member in node.Members) + { + Visit(member); + } + _scope = previousScope; } - // Apply changes - if (namesToTrim != context.Names) + public override void VisitStructDeclaration(StructDeclarationSyntax node) { - foreach (var (evalName, result) in namesToTrim) + ReportName(node.Identifier, node.AttributeLists, node); + + var previousScope = _scope; + _scope = node; + foreach (var member in node.Members) { - context.Names[evalName] = result; + Visit(member); } + _scope = previousScope; } - // Prefer shorter names - foreach (var (_, (_, secondary)) in context.Names) + public override void VisitEnumDeclaration(EnumDeclarationSyntax node) { - secondary.Sort((a, b) => -a.Length.CompareTo(b.Length)); + ReportName(node.Identifier, node.AttributeLists, node); + + var previousScope = _scope; + _scope = node; + foreach (var member in node.Members) + { + Visit(member); + } + _scope = previousScope; } - // Create a map from primaries to trimming names, to account for multiple overloads with the same primary and - // same trimming name (i.e. it is a generated/transformed overload) but differing discriminators. - var primaries = new Dictionary>(); - foreach (var (trimmingName, (primary, _)) in context.Names) + public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) => + ReportName(node.Identifier, node.AttributeLists, node); + + // ----- Members ----- + + public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => + ReportName(node.Identifier, node.AttributeLists, node); + + public override void VisitFieldDeclaration(FieldDeclarationSyntax node) { - var trimmingNamesForPrimary = primaries.TryGetValue(primary, out var tnfp) - ? tnfp - : primaries[primary] = []; - trimmingNamesForPrimary.Add(trimmingName); + var firstVariable = node.Declaration.Variables.First(); + ReportName(firstVariable.Identifier, node.AttributeLists, node); } - // Unwind some names back to their secondary names if the primaries would duplicate - // We'll use a hash set to determine whether or not we need to check a primary for conflicts. - var namesToEval = primaries.Keys.ToHashSet(); - - // Keep track of the method discriminators to determine whether we have incompatible overloads that need to be - // renamed. We keep track of the first trimming name so that we can add it to conflictingTrimmingNames when we - // do discover a conflict (along with the trimming name of the actual conflict). - var methDiscrims = - new Dictionary< - string, - (string? FirstTrimmingName, List Methods) - >(); - var conflictingTrimmingNames = new HashSet(); - while (namesToEval.GetEnumerator() is var e && e.MoveNext() && e.Current is var primary) + public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) => + ReportName(node.Identifier, node.AttributeLists, node); + + public override void VisitMethodDeclaration(MethodDeclarationSyntax node) => + ReportName(node.Identifier, node.AttributeLists, node); + } + + /// + /// Discovers and stores symbol to new name mappings to be used by . + /// + /// The new names in the format defined by . + private class NameSymbolVisitor(Dictionary> newNames) + : SymbolVisitor + { + public readonly List<(ISymbol Symbol, string NewName)> ToRename = []; + + private INamedTypeSymbol? _scope; + + private void ReportSymbol(ISymbol symbol) { - // ^-- We can't use a foreach loop because we're mutating below. We're also using GetEnumerator instead of - // First to avoid allocations. - - // First, let's check whether we have any conflicting discriminators. If we don't, we can mark this as all - // good right away. - methDiscrims.Clear(); - conflictingTrimmingNames.Clear(); - var trimmingNamesForOldPrimary = primaries[primary]; - - // Function-specific logic where some conflicts are okay, so we have to evaluate each signature to see if - // we can discriminate each one such that there are no conflicts. - // - // An example of where this is the case is e.g. alGetBufferf/alGetBufferfv - signatures are identical. - var nMethConflicts = 0; - var nMethods = 0; - var nNoSecondaries = 0; // <-- at least all but one needs to have a secondary to resolve conflicts - string? noSecondaryTrimmingName = null; - foreach (var trimmingNameToEval in trimmingNamesForOldPrimary) - { - // Do we even have a secondary to fall back on if there is a conflict? - if (context.Names[trimmingNameToEval].Secondary.Count == 0) - { - noSecondaryTrimmingName ??= trimmingNameToEval; - nNoSecondaries++; - } + var scopeName = _scope?.Name ?? ""; + var memberName = symbol.Name; - if (functionSyntax is not null) - { - foreach (var meth in functionSyntax[trimmingNameToEval]) - { - var discrim = ModUtils.DiscrimStr( - meth.Modifiers, - meth.TypeParameterList, - primary, - meth.ParameterList, - returnType: null - ); - var (ogTrimmingName, discrimMatches) = methDiscrims.TryGetValue( - discrim, - out var dte - ) - ? dte - : methDiscrims[discrim] = (trimmingNameToEval, []); - discrimMatches.Add(meth); - nMethods++; - - // NOTE: The number of conflicts influences how we go about conflict resolution. See the - // logic below all of these loops just in case this comment is out of date, but at time of - // writing if 50% or more of the methods with this primary name are conflicting then we - // rename all of them, otherwise we rename only the conflicting overloads. - nMethConflicts += discrimMatches.Count switch - { - 2 => 2, // The original needs to be counted as a conflict in addition to this conflict - > 2 => 1, // Just mark this conflict, original is already counted. - _ => 0, // No conflict to see here (not yet anyway, call it Schrodinger's Conflict) - }; + if ( + symbol is IMethodSymbol methodSymbol + && methodSymbol.MethodKind is MethodKind.Constructor or MethodKind.Destructor + ) + { + // Constructors/destructors use the name of their containing types + memberName = scopeName; + scopeName = ""; + } - if (discrimMatches.Count == 2 && ogTrimmingName is not null) - { - conflictingTrimmingNames.Add(ogTrimmingName); - } + if (!newNames.TryGetValue(scopeName, out var memberNewNames)) + { + return; + } - if (discrimMatches.Count > 1) - { - conflictingTrimmingNames.Add(trimmingNameToEval); - } - } - } + if (!memberNewNames.TryGetValue(memberName, out var memberNewName)) + { + return; } - // If we're checking methods for conflicts and in our travels we've discovered that there are in fact - // no conflicts, we can bail out early here. - if (nMethods > 0 && (methDiscrims.Count == 0 || nMethConflicts == 0)) + ToRename.Add((symbol, memberNewName)); + } + + // ----- Entry ----- + + public override void VisitAssembly(IAssemblySymbol symbol) => Visit(symbol.GlobalNamespace); + + public override void VisitNamespace(INamespaceSymbol symbol) + { + foreach (var member in symbol.GetMembers()) { - namesToEval.Remove(primary); - continue; + Visit(member); } + } + + // ----- Types ----- - // We need to determine if we even have alternative names. If one doesn't that's fine because as long - // as we unwind all the others that one still won't conflict. - if (nNoSecondaries > 1) + public override void VisitNamedType(INamedTypeSymbol symbol) + { + ReportSymbol(symbol); + + var previousScope = _scope; + _scope = symbol; + foreach (var member in symbol.GetMembers()) { - logger.LogError( - "Couldn't resolve conflict for \"{}\" because {} of the APIs with that primary name did not have any secondary names.", - primary, - nNoSecondaries - ); - namesToEval.Remove(primary); - continue; + Visit(member); } + _scope = previousScope; + } - var renameOnlyConflicts = nMethConflicts <= nMethods / 2.0; - - // We can afford to leave one API alone. If that place isn't already filled by a method without a secondary - // name then we should fill it with whatever has the shortest trimming name. The logic being that the more - // characters (i.e. longer suffix) a name has, the more discriminatory/important that name is ergo the - // reverse (the shorter the name, the less discriminatory/important it is) is also true. - string? first = null; - var primaryClaimed = noSecondaryTrimmingName is not null; - namesToEval.Remove(primary); // <-- just in case the below loop somehow produces the same primary again. - foreach ( - var conflictingTrimmingName in ( - renameOnlyConflicts ? conflictingTrimmingNames : primaries[primary] - ).OrderBy(x => x.Length) - ) + // ----- Members ----- + + public override void VisitField(IFieldSymbol symbol) => ReportSymbol(symbol); + + public override void VisitProperty(IPropertySymbol symbol) => ReportSymbol(symbol); + + public override void VisitMethod(IMethodSymbol symbol) => ReportSymbol(symbol); + } + + private class RenameSafeAttributeListsRewriter : CSharpSyntaxRewriter + { + public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) => + ( + (MethodDeclarationSyntax)base.VisitMethodDeclaration(node)! + ).WithRenameSafeAttributeLists(); + } + + /// + /// Applies name overrides and moves overridden names to the final set of names. + /// Overridden names are removed from the working set to prevent later processors from directly seeing them. + /// + private class HandleOverridesProcessor(Dictionary nameOverrides) + : INameProcessor + { + public void ProcessNames(NameProcessorContext context) + { + var overriddenNames = new List<(string Scope, string Member, string OverriddenName)>(); + foreach (var (overrideTargetName, overriddenName) in nameOverrides) { - // Do not rename if this is the trimming name that does not have a secondary. - if (noSecondaryTrimmingName == conflictingTrimmingName) + // Target format can either be "Member" or "Scope.Member" + // Split into the two parts here + var overrideTargetScopeEnd = overrideTargetName.IndexOf('.'); + var overrideTargetScope = + overrideTargetScopeEnd >= 0 + ? overrideTargetName[..overrideTargetScopeEnd] + : null; + var overrideTargetMember = overrideTargetName[(overrideTargetScopeEnd + 1)..]; + + // Wildcard scope is the same as not specifying a scope + if ( + overrideTargetScope != null + && overrideTargetScope.Equals("*", StringComparison.Ordinal) + ) { - continue; + overrideTargetScope = null; } - // If the current primary hasn't been "claimed" by a trimming name without a secondary, we only want - // to let the shortest name claim it (per the logic described in the last comment) if it is actually - // the absolute shortest name and not joint-1st for that title. Therefore, the first trimming name - // is saved for the second iteration where we'll make that judgement call and handle both at the - // same time. - if (first is null) + if (overrideTargetScope == null) { - first = conflictingTrimmingName; - if (!primaryClaimed) + // Apply unscoped override + foreach (var (scope, members) in context.Names) { - continue; + if (members.ContainsKey(overrideTargetMember)) + { + overriddenNames.Add((scope, overrideTargetMember, overriddenName)); + } } } - - // Now we're going to make the above judgement call. If the first item has the same length as the - // second item, the first item has no right to claim the primary name therefore both items will be - // demoted to use their secondary name. - if (!primaryClaimed) + else { - if (first.Length == conflictingTrimmingName.Length) + // Apply scoped override + if ( + context.Names.TryGetValue(overrideTargetScope, out var members) + && members.ContainsKey(overrideTargetMember) + ) { - // Update the output name. - var firstSecondary = - context.Names[first].Secondary - ?? throw new InvalidOperationException( - "More than one trimming name without secondary names." - ); - var firstNextPrimary = firstSecondary[^1]; - firstSecondary.RemoveAt(firstSecondary.Count - 1); - context.Names[first] = new CandidateNames(firstNextPrimary, firstSecondary); - - // Update our primary to trimming name map - var trimmingNamesForFirst = primaries.TryGetValue( - firstNextPrimary, - out var tnff - ) - ? tnff - : primaries[firstNextPrimary] = []; - trimmingNamesForFirst.Add(first); - trimmingNamesForOldPrimary.Remove(first); - if (trimmingNamesForOldPrimary.Count == 0) - { - primaries.Remove(primary); - } - - // Make sure we do a pass over the new primary just in case we already have APIs with that - // primary - namesToEval.Add(firstNextPrimary); - if (logger.IsEnabled(LogLevel.Trace)) // <-- prevent needless string.Join - { - logger.LogTrace( - "{}: {} -> {} (remaining secondaries: {})", - first, - primary, - firstNextPrimary, - string.Join(", ", firstNextPrimary) - ); - } + overriddenNames.Add( + (overrideTargetScope, overrideTargetMember, overriddenName) + ); } - - primaryClaimed = true; } + } - // Conflict resolution! Update the output name. - var secondary = - context.Names[conflictingTrimmingName].Secondary - ?? throw new InvalidOperationException( - "More than one trimming name without secondary names." - ); - var nextPrimary = secondary[^1]; - secondary.RemoveAt(secondary.Count - 1); - context.Names[conflictingTrimmingName] = new CandidateNames(nextPrimary, secondary); - - // Update our primary to trimming name map - var trimmingNamesForNewPrimary = primaries.TryGetValue(nextPrimary, out var tnfp) - ? tnfp - : primaries[nextPrimary] = []; - trimmingNamesForNewPrimary.Add(conflictingTrimmingName); - trimmingNamesForOldPrimary.Remove(conflictingTrimmingName); - if (trimmingNamesForOldPrimary.Count == 0) - { - primaries.Remove(primary); - } + // Move overridden names to final output + foreach (var overriddenName in overriddenNames) + { + // Remove from working set + // This is to prevent later processors from modifying overrides + context.Names[overriddenName.Scope].Remove(overriddenName.Member); - // Make sure we do a pass over the new primary just in case we already have APIs with that primary - namesToEval.Add(nextPrimary); - if (logger.IsEnabled(LogLevel.Trace)) // <-- prevent needless string.Join + // Add to final names + if (!context.FinalNames.TryGetValue(overriddenName.Scope, out var members)) { - logger.LogTrace( - "{}: {} -> {} (remaining secondaries: {})", - conflictingTrimmingName, - primary, - nextPrimary, - string.Join(", ", secondary) - ); + context.FinalNames[overriddenName.Scope] = members = []; } + + members[overriddenName.Member] = overriddenName.OverriddenName; } } } - /// - public Task> BeforeScrapeAsync(string key, List rsps) + /// + /// Removes identified affixes so that other name processors can process the base name separately. + /// These affixes should be reapplied by . + /// + private class StripAffixesProcessor(NameDataVisitor nameData) : INameProcessor { - foreach (var responseFile in rsps) + public void ProcessNames(NameProcessorContext context) { - if (!responseFile.GeneratorConfiguration.DontUseUsingStaticsForEnums) + foreach (var (scope, members) in context.Names) { - logger.LogWarning( - "{} (for {}) should use exclude-using-statics-for-enums as PrettifyNames does not resolve " - + "conflicts with members of other types.", - responseFile.FilePath, - key - ); - } - if (!responseFile.GeneratorConfiguration.DontUseUsingStaticsForGuidMember) - { - logger.LogWarning( - "{} (for {}) should use exclude-using-statics-for-guid-members as PrettifyNames does not resolve " - + "conflicts with members of other types.", - responseFile.FilePath, - key - ); - } - } - - return Task.FromResult(rsps); - } - - /// - /// Contains the new name of a type and mappings between original names and new names of its members. - /// - /// The new name of the type. - /// The mappings from original names to new names of the type's non-function members. - /// The mappings from original names to new names of the type's function members. - private record struct RenamedType( - string NewName, - Dictionary NonFunctions, - Dictionary Functions - ); - - private record struct TypeData(List NonFunctions, List Functions); - - private record struct FunctionData(string Name, MethodDeclarationSyntax Syntax); - - private record struct TypeAffixData( - NameAffix[] TypeAffixes, - Dictionary? MemberAffixes - ); - - private class Visitor : CSharpSyntaxWalker - { - /// - /// A mapping from type names to their member names (along with some additional info). - /// These names are first trimmed, then prettified. - /// - public Dictionary TrimmableTypes { get; } = new(); - - /// - /// A mapping from type names to their member names. - /// These names do not participate in trimming and are only prettified. - /// - public Dictionary> PrettifyOnlyTypes { get; } = new(); - - /// - /// A mapping from type names to the type's affix data, which contains mappings from member names to each member's affix data. - /// This is used at the start of trimming to remove declared affixes and at the end to restore declared affixes. - /// Declared affixes are defined by the [NamePrefix] and [NameSuffix] attributes and don't contribute towards the usual trimming processes. - /// - public Dictionary AffixTypes { get; } = new(); - - /// - /// A set of type names marked with the [Transformed] attribute. - /// - /// - /// These are not used for prefix determination since they can contain identifiers that - /// are not part of the original source code. - /// - public HashSet NonDeterminant { get; } = new(); - - /// - /// Tracks the type that we currently are visiting. - /// - private TypeInProgress? _typeInProgress; - - /// - /// Tracks the enum that we currently are visiting. - /// - private EnumInProgress? _enumInProgress; - - /// - /// While this is called a "type" in progress, this represents either a class or a struct. - /// - /// The class or struct's declaration syntax node. - /// The names of the non-function members directly contained by the type. - /// The names of the function members directly contained by the type. - private record struct TypeInProgress( - TypeDeclarationSyntax Type, - List NonFunctions, - List Functions - ); - - /// - /// Represents an enum. - /// - /// The enum's declaration syntax node. - /// The names of the members directly contained by the enum. - private record struct EnumInProgress(EnumDeclarationSyntax Enum, List EnumMembers); + if (!nameData.Names.TryGetValue(scope, out var scopeData)) + { + continue; + } - /// - /// Returns whether we are currently inside of a type. - /// - /// - /// Note that we currently do not handle nested types. - /// If we encounter a type while we are already in a type, we ignore that type. - /// If we encounter a non-type (i.e., a type member), we add the member to the type we are already in. - /// - private bool IsCurrentlyInType(SyntaxNode node) => - _typeInProgress is not null - || _enumInProgress is not null - || node.Ancestors().OfType().Any(); - - private void ReportTypeAffixData( - string typeIdentifier, - SyntaxList attributeLists - ) - { - var affixes = attributeLists.GetNameAffixes(); - if (affixes.Length == 0) - { - return; - } + foreach (var (original, candidateNames) in members) + { + if (!scopeData.TryGetValue(original, out var memberData)) + { + continue; + } - if (!AffixTypes.TryGetValue(typeIdentifier, out var typeAffixData)) - { - typeAffixData = new TypeAffixData([], null); + members[original] = StripAffixes(candidateNames, memberData.Affixes); + } } - - AffixTypes[typeIdentifier] = typeAffixData with - { - TypeAffixes = [.. typeAffixData.TypeAffixes, .. affixes], - }; } - private void ReportMemberAffixData( - string typeIdentifier, - string memberIdentifier, - SyntaxList attributeLists - ) + /// + /// Removes affixes from the primary name and adds the original primary to the secondary list. + /// + /// The current candidate names. + /// The affixes declared for the original name. + private CandidateNames StripAffixes(CandidateNames candidateNames, NameAffix[] affixes) { - var affixes = attributeLists.GetNameAffixes(); if (affixes.Length == 0) { - return; + return candidateNames; } - if (!AffixTypes.TryGetValue(typeIdentifier, out var typeAffixData)) + var stripped = NameAffixer.StripAffixes(candidateNames.Primary, affixes); + if (stripped != candidateNames.Primary) { - typeAffixData = new TypeAffixData([], null); + candidateNames.Secondary.Add(candidateNames.Primary); } - // Note that TryAdd will lead to affixes for later members being silently dropped. - // This is to handle methods which have the same name and affixes. It is fine to drop the affixes in this case. - (typeAffixData.MemberAffixes ??= []).TryAdd(memberIdentifier, affixes); - AffixTypes[typeIdentifier] = typeAffixData; + return new CandidateNames(stripped, candidateNames.Secondary); } + } - // ----- Types ----- - - public override void VisitClassDeclaration(ClassDeclarationSyntax node) + /// + /// Prettifies the primary and secondary candidate names. + /// Also see . + /// + private class PrettifyProcessor(NamePrettifier namePrettifier) : INameProcessor + { + public void ProcessNames(NameProcessorContext context) { - if (IsCurrentlyInType(node)) - { - return; - } - - var identifier = node.Identifier.ToString(); - if (node.AttributeLists.ContainsAttribute("Silk.NET.Core.Transformed")) + foreach (var (scope, members) in context.Names) { - NonDeterminant.Add(identifier); - } - - ReportTypeAffixData(identifier, node.AttributeLists); + // Be lenient about caps for type names (e.g. GL) + var allowAllCaps = scope == ""; - // Recurse into members. - _typeInProgress = new TypeInProgress(node, [], []); - base.VisitClassDeclaration(node); + foreach (var (original, (primary, secondary)) in members) + { + for (var i = 0; i < secondary.Count; i++) + { + secondary[i] = namePrettifier.Prettify(secondary[i], allowAllCaps); + } - // Merge with existing data in case of partials - if (!TrimmableTypes.TryGetValue(identifier, out var typeData)) - { - typeData = new TypeData([], []); - TrimmableTypes.Add(identifier, typeData); + members[original] = new CandidateNames( + namePrettifier.Prettify(primary, allowAllCaps), + secondary + ); + } } - - typeData.NonFunctions.AddRange( - _typeInProgress.Value.NonFunctions.Where(nonFunction => - !typeData.NonFunctions.Contains(nonFunction) - ) - ); - typeData.Functions.AddRange(_typeInProgress.Value.Functions); - - _typeInProgress = null; } + } - public override void VisitStructDeclaration(StructDeclarationSyntax node) - { - if (IsCurrentlyInType(node)) - { - return; - } - - var identifier = node.Identifier.ToString(); - if (node.AttributeLists.ContainsAttribute("Silk.NET.Core.Transformed")) - { - NonDeterminant.Add(identifier); - } - - ReportTypeAffixData(identifier, node.AttributeLists); - - // Recurse into members - _typeInProgress = new TypeInProgress(node, [], []); - base.VisitStructDeclaration(node); - - // Merge with existing data in case of partials - if (!TrimmableTypes.TryGetValue(identifier, out var typeData)) - { - typeData = new TypeData([], []); - TrimmableTypes.Add(identifier, typeData); - } + /// + /// Reapplies and transforms identified affixes based on . + /// + private class ReapplyAffixesProcessor( + NameDataVisitor nameData, + NamePrettifier namePrettifier, + Dictionary config + ) : INameProcessor + { + private readonly record struct MemberKey(string Scope, string Member); - typeData.NonFunctions.AddRange( - _typeInProgress.Value.NonFunctions.Where(nonFunction => - !typeData.NonFunctions.Contains(nonFunction) - ) - ); - typeData.Functions.AddRange(_typeInProgress.Value.Functions); + private readonly record struct NameFragment(string Value, bool Prettify); - _typeInProgress = null; - } + private static readonly NameAffixConfiguration _defaultConfig = new(); - public override void VisitEnumDeclaration(EnumDeclarationSyntax node) + public void ProcessNames(NameProcessorContext context) { - if (IsCurrentlyInType(node)) - { - return; - } - - var identifier = node.Identifier.ToString(); - if (node.AttributeLists.ContainsAttribute("Silk.NET.Core.Transformed")) - { - NonDeterminant.Add(identifier); - } - - ReportTypeAffixData(identifier, node.AttributeLists); - - // Recurse into members - _enumInProgress = new EnumInProgress(node, []); - base.VisitEnumDeclaration(node); + // Calculate processing order using topological sort + // Name affixes can reference other names + // We want names that don't reference other names to be processed first + var processingOrderByKey = new List(); - // Merge with existing data in case of partials - if (!TrimmableTypes.TryGetValue(identifier, out var typeData)) - { - typeData = new TypeData([], []); - TrimmableTypes.Add(identifier, typeData); - } - - typeData.NonFunctions.AddRange(_enumInProgress.Value.EnumMembers); - _enumInProgress = null; - } + var ready = new Queue(); + var dependencyCountByKey = new Dictionary(); + var notifyDependantByKey = new Dictionary>(); - public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) - { - var identifier = node.Identifier.ToString(); - if (IsCurrentlyInType(node)) + foreach (var (scope, members) in context.Names) { - if (node.Parent == _typeInProgress?.Type) + if (!nameData.Names.TryGetValue(scope, out var scopeData)) { - _typeInProgress!.Value.NonFunctions.Add(identifier); + continue; } - return; - } - - if (node.AttributeLists.ContainsAttribute("Silk.NET.Core.Transformed")) - { - NonDeterminant.Add(identifier); - } - - ReportTypeAffixData(identifier, node.AttributeLists); - TrimmableTypes.Add(identifier, new TypeData([], [])); - } - - // ----- Members ----- - - public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) - { - if (node.Parent == _enumInProgress?.Enum) - { - var typeIdentifier = _enumInProgress!.Value.Enum.Identifier.ToString(); - var memberIdentifier = node.Identifier.ToString(); - ReportMemberAffixData(typeIdentifier, memberIdentifier, node.AttributeLists); - - _enumInProgress!.Value.EnumMembers.Add(memberIdentifier); - } - } - - public override void VisitFieldDeclaration(FieldDeclarationSyntax node) - { - // If it's not a constant then we only prettify - // C constants are globally scoped and typically prefixed, so we trim in addition to prettifying - var prettifyOnly = - !node.Modifiers.Any(SyntaxKind.ConstKeyword) - && !node.Modifiers.Any(SyntaxKind.StaticKeyword); - - if (node.Parent == _typeInProgress?.Type) - { - var typeIdentifier = _typeInProgress!.Value.Type.Identifier.ToString(); - foreach (var variable in node.Declaration.Variables) + // Build dependency graph + foreach (var (member, _) in members) { - var memberIdentifier = variable.Identifier.ToString(); - ReportMemberAffixData(typeIdentifier, memberIdentifier, node.AttributeLists); + if (!scopeData.TryGetValue(member, out var memberData)) + { + continue; + } - if (prettifyOnly) + var dependencyCount = 0; + var affixes = memberData.Affixes; + foreach (var affix in affixes) { - if (!PrettifyOnlyTypes.TryGetValue(typeIdentifier, out var typeData)) + if (!affix.IsReference) { - typeData = []; - PrettifyOnlyTypes.Add(typeIdentifier, typeData); + continue; } - typeData.Add(memberIdentifier); - } - else - { - _typeInProgress.Value.NonFunctions.Add(memberIdentifier); - } - } - } - } + var referencedMemberOriginalName = affix.Affix; + if ( + TryResolveName( + context, + scope, + referencedMemberOriginalName, + out var referencedMemberScope, + out _, + out var isInFinalSet + ) + ) + { + // Add as dependency only if not in final set + // This is because this processor does not process names from the final set + // Names from the final set should therefore not affect the processing order + if (!isInFinalSet) + { + var referencedMemberkey = new MemberKey( + referencedMemberScope, + referencedMemberOriginalName + ); + if ( + !notifyDependantByKey.TryGetValue( + referencedMemberkey, + out var dependants + ) + ) + { + notifyDependantByKey[referencedMemberkey] = dependants = []; + } - public override void VisitMethodDeclaration(MethodDeclarationSyntax node) - { - if (node.Parent == _typeInProgress?.Type) - { - var typeIdentifier = _typeInProgress!.Value.Type.Identifier.ToString(); - var memberIdentifier = node.Identifier.ToString(); + dependants.Add(new MemberKey(scope, member)); + dependencyCount++; + } + } + else + { + // Failed to resolve reference + throw new InvalidOperationException( + $"Failed to resolve a name affix reference '{affix.Affix}' defined for member '{member}'" + ); + } + } - if (_typeInProgress!.Value.Type.IsKind(SyntaxKind.StructDeclaration)) - { - // Prettify only - // Struct methods are introduced by the generator so they are not prefixed - if (!PrettifyOnlyTypes.TryGetValue(typeIdentifier, out var typeData)) + if (dependencyCount == 0) { - typeData = []; - PrettifyOnlyTypes.Add(typeIdentifier, typeData); + // No dependencies + ready.Enqueue(new MemberKey(scope, member)); + continue; } - typeData.Add(memberIdentifier); - } - else - { - // Trim + Prettify - ReportMemberAffixData(typeIdentifier, memberIdentifier, node.AttributeLists); - - _typeInProgress!.Value.Functions.Add(new FunctionData(memberIdentifier, node)); + // Store dependency count + dependencyCountByKey.Add(new MemberKey(scope, member), dependencyCount); } } - } - public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) - { - if (node.Parent == _typeInProgress?.Type) + // Output final order + while (ready.TryDequeue(out var key)) { - var typeIdentifier = _typeInProgress!.Value.Type.Identifier.ToString(); - var memberIdentifier = node.Identifier.ToString(); - ReportMemberAffixData(typeIdentifier, memberIdentifier, node.AttributeLists); - - // If it's not a constant then we only prettify. - var hasSetter = - node.AccessorList?.Accessors.Any(a => - a.IsKind(SyntaxKind.SetAccessorDeclaration) - || a.IsKind(SyntaxKind.InitAccessorDeclaration) - ) ?? false; - if (hasSetter) + processingOrderByKey.Add(key); + if (notifyDependantByKey.TryGetValue(key, out var dependants)) { - if (!PrettifyOnlyTypes.TryGetValue(typeIdentifier, out var typeData)) + foreach (var dependant in dependants) { - typeData = []; - PrettifyOnlyTypes.Add(typeIdentifier, typeData); + if (dependencyCountByKey.TryGetValue(dependant, out var dependencyCount)) + { + dependencyCount--; + if (dependencyCount == 0) + { + ready.Enqueue(dependant); + dependencyCountByKey.Remove(dependant); + continue; + } + + dependencyCountByKey[dependant] = dependencyCount; + } } - - typeData.Add(memberIdentifier); - } - else - { - _typeInProgress!.Value.NonFunctions.Add(memberIdentifier); } } - } - } - - private class RenameSafeAttributeListsRewriter : CSharpSyntaxRewriter - { - public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) => - ( - (MethodDeclarationSyntax)base.VisitMethodDeclaration(node)! - ).WithRenameSafeAttributeLists(); - } - - /// The affix data retrieved by the . - /// The configuration from . - private class PrettifyNamesAffixer( - Dictionary affixTypes, - Dictionary config - ) - { - private static readonly NameAffixConfiguration _defaultConfig = new(); - /// - /// Removes affixes from the specified primary name and adds the original specified primary to the secondary list if provided. - /// - /// - /// Designed to be used by either or . - /// - /// The current primary name. - /// The container name. Either null or the containing type. - /// The original name of the identifier. Either the type name or the member name. - /// The list of secondary names. This should be null if used by . - /// The new primary name. - public string RemoveAffixes( - string primary, - string? container, - string originalName, - List? secondary - ) - { - var affixes = GetAffixes(container, originalName); - if (affixes.Length == 0) + // Check for cycles + if (dependencyCountByKey.Count != 0) { - return primary; + throw new InvalidOperationException( + $"Detected cycle in referenced affixes. Names that are part of the cycle: {string.Join(", ", dependencyCountByKey.Keys)}" + ); } - var stripped = NameAffixer.StripAffixes(primary, affixes); - if (stripped != primary) + foreach (var key in processingOrderByKey) { - secondary?.Add(primary); - } + var scopeData = nameData.Names[key.Scope]; + var scopeMembers = context.Names[key.Scope]; + if (!scopeData.TryGetValue(key.Member, out var memberData)) + { + continue; + } - return stripped; + scopeMembers[key.Member] = ApplyAffixes( + key.Scope, + scopeMembers[key.Member], + memberData.Affixes, + context + ); + } } /// - /// Applies affixes to the specified primary name and adds fallbacks to the secondary list if provided. + /// Applies affixes to the primary name and adds fallbacks to the secondary list. /// - /// - /// Designed to be used by either or . - /// - /// The current primary name. - /// The container name. Either null or the containing type. - /// The original name of the identifier. Either the type name or the member name. - /// The list of secondary names. This should be null if used by . + /// The scope of the original name. Used for resolving referenced affixes. + /// The current candidate names. + /// The affixes declared for the original name. /// The new primary name. - public string ApplyAffixes( - string primary, - string? container, - string originalName, - List? secondary + /// The current . Used for resolving referenced affixes. + private CandidateNames ApplyAffixes( + string scope, + CandidateNames candidateNames, + NameAffix[] affixes, + NameProcessorContext context ) { - var affixes = GetAffixes(container, originalName); if (affixes.Length == 0) { - return primary; + return candidateNames; } // Sort affixes by priority @@ -1331,6 +829,9 @@ public string ApplyAffixes( // This is guaranteed to be non-null when this method returns if there is at least one affix string? newPrimary = null; + // Used to track the number of secondaries added + var originalSecondaryCount = candidateNames.Secondary.Count; + // Process each group of affixes var hasProcessedNonDiscriminator = false; var currentPriority = int.MaxValue; @@ -1350,94 +851,223 @@ public string ApplyAffixes( { hasProcessedNonDiscriminator = true; currentPriority = GetConfiguration(affix).DiscriminatorPriority; - CreateName(primary, affixes.AsSpan()[..affixI]); - if (secondary == null) - { - return newPrimary!; - } + OutputName( + CreateName( + scope, + candidateNames.Primary, + affixes.AsSpan()[..affixI], + context + ) + ); } } // Process final group since the loop above skips the final group - CreateName(primary, affixes); - - return newPrimary!; - - void CreateName(string name, Span currentAffixes) - { - // Sort affixes so that the inner affixes are first - currentAffixes.Sort( - (a, b) => - { - // Sort by descending order - // Higher order means the affix is closer to the inside of the name - if (GetConfiguration(a).Order != GetConfiguration(b).Order) - { - return -GetConfiguration(a).Order.CompareTo(GetConfiguration(b).Order); - } + OutputName(CreateName(scope, candidateNames.Primary, affixes, context)); - // Then by ascending declaration order - // Lower declaration order means the affix is closer to the inside of the name - return a.DeclarationOrder.CompareTo(b.DeclarationOrder); - } - ); + // Reverse the secondaries added since secondaries later in the list have higher priority + // The original code above assumed that earlier had higher priority so this fixes that + var secondaryNamesAdded = candidateNames.Secondary.Count - originalSecondaryCount; + candidateNames.Secondary.AsSpan()[^secondaryNamesAdded..].Reverse(); - foreach (var affix in currentAffixes) - { - if (!GetConfiguration(affix).Remove) - { - if (affix.Type == NameAffixType.Prefix) - { - name = affix.Affix + name; - } - else - { - name += affix.Affix; - } - } - } + return new CandidateNames(newPrimary!, candidateNames.Secondary); + void OutputName(string name) + { if (newPrimary == null) { newPrimary = name; } else { - secondary?.Add(name); + candidateNames.Secondary.Add(name); } } } /// - /// Gets affix data for the specified container and original name of the identifier. + /// Creates a new name using the provided information. + /// See the docs for what each individual parameter does. /// - /// The container name. Either null or the containing type. - /// The original name of the identifier. Either the type name or the member name. - /// The name affixes for the specified identifier. - private NameAffix[] GetAffixes(string? container, string originalName) + /// The scope the original name is in. Used for referenced affix resolution. + /// The base name that affixes will be applied to. + /// The affixes to be applied to the base name. + /// The context from which referenced affixes will be resolved from. + private string CreateName( + string scope, + string baseName, + Span affixes, + NameProcessorContext context + ) { - TypeAffixData typeAffixData; - if (container == null) - { - if (!affixTypes.TryGetValue(originalName, out typeAffixData)) + // Sort affixes so that the inner affixes are first + affixes.Sort( + (a, b) => { - return []; + var configA = GetConfiguration(a); + var configB = GetConfiguration(b); + + // Sort by descending order + // Higher order means the affix is closer to the inside of the name + if (configA.Order != configB.Order) + { + return -configA.Order.CompareTo(configB.Order); + } + + // Then by ascending declaration order + // Lower declaration order means the affix is closer to the inside of the name + return a.DeclarationOrder.CompareTo(b.DeclarationOrder); } + ); + + var nameFragments = new List { new(baseName, false) }; + foreach (var affix in affixes) + { + var affixValue = affix.Affix; + if (affix.IsReference) + { + if ( + TryResolveName( + context, + scope, + affixValue, + out _, + out var referencedMemberValue, + out _ + ) + ) + { + affixValue = referencedMemberValue; + } + } + + var affixConfig = GetConfiguration(affix); + if (!affixConfig.Remove) + { + var fragment = new NameFragment(affixValue, affixConfig.Prettify); - return typeAffixData.TypeAffixes; + if (affix.Type == NameAffixType.Prefix) + { + nameFragments.Insert(0, fragment); + } + else + { + nameFragments.Add(fragment); + } + } } - if (affixTypes.TryGetValue(container, out typeAffixData)) + // Build result by merging fragments + var result = ""; + var previousFragment = new NameFragment("", false); + foreach (var nameFragment in nameFragments) { + switch (previousFragment.Prettify, nameFragment.Prettify) + { + case (true, true): + { + previousFragment = new NameFragment( + $"{previousFragment.Value}_{nameFragment.Value}", + true + ); + break; + } + case (false, false): + { + previousFragment = new NameFragment( + $"{previousFragment.Value}{nameFragment.Value}", + false + ); + break; + } + default: + { + OutputFragment(previousFragment); + previousFragment = nameFragment; + break; + } + } + } + + OutputFragment(previousFragment); + + return result; + + void OutputFragment(NameFragment fragment) + { + var fragmentValue = fragment.Value; + if (previousFragment.Prettify) + { + fragmentValue = namePrettifier.Prettify(fragmentValue, true); + } + + result += fragmentValue; + } + } + + /// + /// Tries the resolve the current output name of the referenced member from the current scope. + /// + /// The name processor context. Used during the name resolution process. + /// The scope from which the reference was made. The reference scope and its parent scopes will be used during the resolution process. + /// The original name of the member being referenced. + /// The scope in which the referenced member was found. + /// The current output name of the member being referenced. + /// Whether the referenced member was found in the final set. + private bool TryResolveName( + NameProcessorContext context, + string referenceScope, + string referencedMember, + [NotNullWhen(true)] out string? referencedMemberScope, + [NotNullWhen(true)] out string? referencedMemberValue, + out bool isInFinalSet + ) + { + var currentScope = referenceScope; + while (true) + { + // Try resolve from working set + if ( + context.Names.TryGetValue(currentScope, out var workingScopeMembers) + && workingScopeMembers.TryGetValue( + referencedMember, + out var referencedCandidateNames + ) + ) + { + referencedMemberScope = currentScope; + referencedMemberValue = referencedCandidateNames.Primary; + isInFinalSet = false; + return true; + } + + // Try resolve from final set if ( - typeAffixData.MemberAffixes?.TryGetValue(originalName, out var affixes) ?? false + context.FinalNames.TryGetValue(currentScope, out var finalScopeMembers) + && finalScopeMembers.TryGetValue(referencedMember, out var referencedFinalName) ) { - return affixes; + referencedMemberScope = currentScope; + referencedMemberValue = referencedFinalName; + isInFinalSet = true; + return true; + } + + // Try to go up a scope + // This currently does not handle nested scopes + if (currentScope != "") + { + currentScope = ""; + continue; } + + break; } - return []; + referencedMemberScope = null; + referencedMemberValue = null; + isInFinalSet = false; + return false; } private NameAffixConfiguration GetConfiguration(NameAffix affix) => @@ -1448,109 +1078,604 @@ private NameAffixConfiguration GetConfiguration(string category) => } /// - /// Removes identified affixes so that other trimmers can process the base name separately. - /// These affixes should be reapplied by . + /// Prefixes candidate names that start with a number. + /// This is required because C# identifiers cannot start with a number. /// - private class NameAffixerEarlyTrimmer(PrettifyNamesAffixer affixer) : INameTrimmer + private class PrefixIfStartsWithNumberProcessor : INameProcessor { - /// - public Version Version => new(0, 0, 0); + public void ProcessNames(NameProcessorContext context) + { + foreach (var (_, members) in context.Names) + { + foreach (var (original, (primary, secondary)) in members) + { + for (var i = 0; i < secondary.Count; i++) + { + secondary[i] = NameUtils.PrefixIfStartsWithNumber(secondary[i]); + } - /// - public int Order => (int)TrimmerOrder.NameAffixerEarlyTrimmer; + members[original] = new CandidateNames( + NameUtils.PrefixIfStartsWithNumber(primary), + secondary + ); + } + } + } + } - public void Trim(NameTrimmerContext context) + /// + /// Resolves conflicts where multiple names have been transformed into the same output name. + /// This also considers cases where the methods with the same name are compatible because of method overloading rules. + /// + /// + /// This also copies the names from the final set back into the working set. + /// This is to ensure that all names are considered by the conflict resolution algorithm. + /// + private class ResolveConflictsProcessor(NameDataVisitor nameData, ILogger logger) + : INameProcessor + { + public void ProcessNames(NameProcessorContext context) { - if (context.Container == null) + // Add the names from the final set to the working set + // This is so that conflicts are resolved with all names available + foreach (var (scope, finalMembers) in context.FinalNames) { - foreach (var (original, (primary, secondary)) in context.Names) + if (!context.Names.TryGetValue(scope, out var workingMembers)) { - var secondaries = secondary; - var newPrimary = affixer.RemoveAffixes(primary, null, original, secondaries); - context.Names[original] = new CandidateNames(newPrimary, secondaries); + context.Names[scope] = workingMembers = []; } - return; + // Naively overwrite working set names + foreach (var (member, newMemberName) in finalMembers) + { + workingMembers[member] = new CandidateNames(newMemberName, []); + } } - foreach (var (original, (primary, secondary)) in context.Names) + // These collections are used later. + // These keep track of method discriminators to determine whether we have incompatible overloads. + // We keep track of the first original name so that we can add it to conflictingOriginalNames when we + // do discover a conflict (along with the original name of the actual conflict). + var methodDiscriminators = + new Dictionary< + string, + (string? FirstOriginalName, List Methods) + >(); + var conflictingOriginalNames = new HashSet(); + + // This loop cannot be part of the loop below because it modifies the primaries + foreach (var (scope, members) in context.Names) { - var secondaries = secondary; - var newPrimary = affixer.RemoveAffixes( - primary, - context.Container, - original, - secondaries - ); - context.Names[original] = new CandidateNames(newPrimary, secondaries); + if (!nameData.Names.TryGetValue(scope, out var scopeData)) + { + continue; + } + + var originalNamesByPrimary = GetOriginalNamesByPrimary(members); + foreach (var (_, originalNames) in originalNamesByPrimary) + { + // Count the number of original members that share this primary name + var nNonMethods = 0; + var nMethods = 0; + foreach (var originalName in originalNames) + { + if (scopeData.TryGetValue(originalName, out var memberData)) + { + foreach (var declaration in memberData.Declarations) + { + if (declaration is MethodDeclarationSyntax) + { + nMethods++; + continue; + } + + nNonMethods++; + } + } + } + + // If there are both non-methods and methods sharing the primary name, + // suffix the non-methods with "-Value" + // + // Main case: Non-method and method share the same name, but with different casing/underscoring + // GL_PROGRAM_STRING_ARB (constant) and glProgramStringARB (method) + // Both usually result in primaries of ProgramStringARB + // Prefixing the non-member with "-Value" works here + // + // Another way to handle this is to restore the namespace prefix for one of the members + // This works here, but is not always the case + // Suffixing with "-Value" should almost always work + if (nNonMethods != 0 && nMethods != 0) + { + foreach (var originalName in originalNames) + { + if ( + scopeData.TryGetValue(originalName, out var memberData) + && memberData.Declarations.Any(d => + d is not MethodDeclarationSyntax + ) + ) + { + var candidateNames = members[originalName]; + candidateNames.Secondary.Add(candidateNames.Primary); + members[originalName] = new CandidateNames( + $"{candidateNames.Primary}Value", + candidateNames.Secondary + ); + } + } + } + } + } + + foreach (var (scope, members) in context.Names) + { + nameData.Names.TryGetValue(scope, out var scopeData); + var originalNamesByPrimary = GetOriginalNamesByPrimary(members); + + // Unwind some names back to their secondary names if the primaries would duplicate + // We'll use a hash set to determine whether we need to check a primary for conflicts. + var primariesToEval = originalNamesByPrimary.Keys.ToHashSet(); + + while ( + primariesToEval.GetEnumerator() is var e + && e.MoveNext() + && e.Current is var primary + ) + { + // ^-- We can't use a foreach loop because we're mutating below. + // We're also using GetEnumerator instead of First to avoid allocations. + + // Clear temporary collections + methodDiscriminators.Clear(); + conflictingOriginalNames.Clear(); + + // We map the primary name to the original names so we can fetch information about the original members + var originalNamesForPrimary = originalNamesByPrimary[primary]; + + // Count the number of original members that share this primary name + var nNonMethods = 0; + var nMethods = 0; + if (scopeData != null) + { + foreach (var originalName in originalNamesForPrimary) + { + if (scopeData.TryGetValue(originalName, out var memberData)) + { + foreach (var declaration in memberData.Declarations) + { + if (declaration is MethodDeclarationSyntax) + { + nMethods++; + continue; + } + + nNonMethods++; + } + } + } + } + + // Methods can have the same names assuming their overloads are compatible + // We need to evaluate each signature to see + // if we can discriminate each one such that there are no conflicts. + // + // Example: alGetBufferf/alGetBufferfv (signatures are identical) + // In this case, we have to use secondary names to prevent the methods from conflicting + var nMethodConflicts = 0; + var nNoSecondaries = 0; // <-- at least all but one needs to have a secondary to resolve conflicts + string? noSecondaryOriginalName = null; + foreach (var originalName in originalNamesForPrimary) + { + // Do we even have a secondary to fall back on if there is a conflict? + if (members[originalName].Secondary.Count == 0) + { + noSecondaryOriginalName ??= originalName; + nNoSecondaries++; + } + + if ( + scopeData != null + && scopeData.TryGetValue(originalName, out var memberData) + ) + { + foreach (var declaration in memberData.Declarations) + { + if (declaration is not MethodDeclarationSyntax methodDeclaration) + { + continue; + } + + var discriminator = ModUtils.GetMethodDiscriminator( + methodDeclaration.Modifiers, + methodDeclaration.TypeParameterList, + primary, + methodDeclaration.ParameterList, + returnType: null + ); + + if ( + !methodDiscriminators.TryGetValue( + discriminator, + out var methodDiscriminator + ) + ) + { + methodDiscriminators[discriminator] = methodDiscriminator = ( + originalName, + [] + ); + } + + var (firstOriginalName, discriminatorMatches) = methodDiscriminator; + + discriminatorMatches.Add(methodDeclaration); + + // NOTE: The number of conflicts influences how we go about conflict resolution. See the + // logic below all of these loops just in case this comment is out of date, but at time of + // writing if 50% or more of the methods with this primary name are conflicting then we + // rename all of them, otherwise we rename only the conflicting overloads. + nMethodConflicts += discriminatorMatches.Count switch + { + 2 => 2, // The original needs to be counted as a conflict in addition to this conflict + > 2 => 1, // Just mark this conflict, original is already counted. + _ => 0, // No conflict to see here (not yet anyway, call it Schrodinger's Conflict) + }; + + if ( + discriminatorMatches.Count == 2 + && firstOriginalName is not null + ) + { + conflictingOriginalNames.Add(firstOriginalName); + } + + if (discriminatorMatches.Count > 1) + { + conflictingOriginalNames.Add(originalName); + } + } + } + } + + // If there are methods, check for two conditions: + // 1. That there are no non-methods (these always conflict) + // 2. That there are no conflicting method signatures + // If these conditions are satisfied, we can bail out early + if ( + nMethods > 0 + && nNonMethods == 0 + && (methodDiscriminators.Count == 0 || nMethodConflicts == 0) + ) + { + primariesToEval.Remove(primary); + continue; + } + + // We need to determine if we even have alternative names. If one doesn't that's fine because as long + // as we unwind all the others that one still won't conflict. + if (nNoSecondaries > 1) + { + logger.LogError( + "Couldn't resolve conflict for \"{}\" because {} of the APIs with that primary name did not have any secondary names.", + primary, + nNoSecondaries + ); + primariesToEval.Remove(primary); + continue; + } + + // Only rename the conflicts if most of the methods do not conflict + // Exception to this rule: If we have both non-methods and methods + var renameOnlyConflicts = + nMethodConflicts <= (nMethods / 2.0) && !(nNonMethods > 0 && nMethods > 0); + + // We can afford to leave one API alone. If that place isn't already filled by a method without a secondary + // name then we should fill it with whatever has the shortest original name. The logic being that the more + // characters (i.e. longer suffix) a name has, the more discriminatory/important that name is ergo the + // reverse (the shorter the name, the less discriminatory/important it is) is also true. + string? first = null; + var primaryClaimed = noSecondaryOriginalName is not null; + primariesToEval.Remove(primary); // <-- just in case the below loop somehow produces the same primary again. + foreach ( + var conflictingOriginalName in ( + renameOnlyConflicts + ? conflictingOriginalNames + : originalNamesByPrimary[primary] + ) + .OrderBy(x => x.Length) // Short names have priority + .ThenBy(x => x) // Tie-breaker + ) + { + // Do not rename if this is the original name that does not have a secondary. + if (noSecondaryOriginalName == conflictingOriginalName) + { + continue; + } + + // If the current primary hasn't been "claimed" by an original name without a secondary, we only want + // to let the shortest name claim it (per the logic described in the last comment) if it is actually + // the absolute shortest name and not joint-1st for that title. Therefore, the first original name + // is saved for the second iteration where we'll make that judgement call and handle both at the + // same time. + if (first is null) + { + first = conflictingOriginalName; + if (!primaryClaimed) + { + continue; + } + } + + // Now we're going to make the above judgement call. If the first item has the same length as the + // second item, the first item has no right to claim the primary name therefore both items will be + // demoted to use their secondary name. + if (!primaryClaimed) + { + if (first.Length == conflictingOriginalName.Length) + { + // Update the output name. + var firstSecondary = + members[first].Secondary + ?? throw new InvalidOperationException( + "More than one original member name without secondary names." + ); + var firstNextPrimary = firstSecondary[^1]; + firstSecondary.RemoveAt(firstSecondary.Count - 1); + members[first] = new CandidateNames( + firstNextPrimary, + firstSecondary + ); + + // Update our primary to original name map + if ( + !originalNamesByPrimary.TryGetValue( + firstNextPrimary, + out var originalNamesForFirst + ) + ) + { + originalNamesByPrimary[firstNextPrimary] = + originalNamesForFirst = []; + } + + originalNamesForFirst.Add(first); + originalNamesForPrimary.Remove(first); + if (originalNamesForPrimary.Count == 0) + { + originalNamesByPrimary.Remove(primary); + } + + // Make sure we do a pass over the new primary just in case we already have APIs with that + // primary + primariesToEval.Add(firstNextPrimary); + if (logger.IsEnabled(LogLevel.Trace)) // <-- prevent needless string.Join + { + logger.LogTrace( + "{}: {} -> {} (remaining secondaries: {})", + first, + primary, + firstNextPrimary, + string.Join(", ", firstNextPrimary) + ); + } + } + + primaryClaimed = true; + } + + // Conflict resolution! Update the output name. + var secondary = + members[conflictingOriginalName].Secondary + ?? throw new InvalidOperationException( + "More than one original member name without secondary names." + ); + var nextPrimary = secondary[^1]; + secondary.RemoveAt(secondary.Count - 1); + members[conflictingOriginalName] = new CandidateNames( + nextPrimary, + secondary + ); + + // Update our primary to original name map + if ( + !originalNamesByPrimary.TryGetValue( + nextPrimary, + out var originalNamesForNewPrimary + ) + ) + { + originalNamesByPrimary[nextPrimary] = originalNamesForNewPrimary = []; + } + + originalNamesForNewPrimary.Add(conflictingOriginalName); + originalNamesForPrimary.Remove(conflictingOriginalName); + if (originalNamesForPrimary.Count == 0) + { + originalNamesByPrimary.Remove(primary); + } + + // Make sure we do a pass over the new primary just in case we already have APIs with that primary + primariesToEval.Add(nextPrimary); + if (logger.IsEnabled(LogLevel.Trace)) // <-- prevent needless string.Join + { + logger.LogTrace( + "{}: {} -> {} (remaining secondaries: {})", + conflictingOriginalName, + primary, + nextPrimary, + string.Join(", ", secondary) + ); + } + } + } + } + + return; + + Dictionary> GetOriginalNamesByPrimary( + Dictionary members + ) + { + // Create a mapping: Primary name -> Original name + // Primary name refers to the primary candidate name + // Original name refers to the original name of the member as seen in source code + // + // This is to account for method overloads that have the + // same primary candidate name and original name, but different discriminators + // + // This usually happens with generated/transformed overloads + var originalNamesByPrimary = new Dictionary>(); + foreach (var (originalName, (primary, _)) in members) + { + if ( + !originalNamesByPrimary.TryGetValue( + primary, + out var originalNamesForPrimary + ) + ) + { + originalNamesByPrimary[primary] = originalNamesForPrimary = []; + } + + originalNamesForPrimary.Add(originalName); + } + + return originalNamesByPrimary; } } } /// - /// Reapplies and transforms identified affixes based on . + /// Outputs all primary names to the final set of names. /// - private class NameAffixerLateTrimmer(PrettifyNamesAffixer affixer) : INameTrimmer + /// + /// This is intentionally implemented in a naive manner. + /// The working set of names is not cleared and existing data in the final set can be overwritten. + /// + private class OutputFinalNamesProcessor : INameProcessor { - /// - public Version Version => new(0, 0, 0); + public void ProcessNames(NameProcessorContext context) + { + foreach (var (scope, members) in context.Names) + { + if (!context.FinalNames.TryGetValue(scope, out var outputScope)) + { + context.FinalNames[scope] = outputScope = []; + } - /// - public int Order => (int)TrimmerOrder.NameAffixerLateTrimmer; + foreach (var (member, (primary, _)) in members) + { + outputScope[member] = primary; + } + } + } + } - public void Trim(NameTrimmerContext context) + /// + /// Removes all unmodified names from the final set of names. + /// + private class RemoveUnmodifiedFinalNamesProcessor : INameProcessor + { + public void ProcessNames(NameProcessorContext context) { - if (context.Container == null) + var unmodified = new List(); + + // Remove unmodified members + foreach (var (_, members) in context.FinalNames) { - foreach (var (original, (primary, secondary)) in context.Names) + unmodified.Clear(); + foreach (var (originalName, newName) in members) { - var secondaries = secondary; - var newPrimary = affixer.ApplyAffixes(primary, null, original, secondaries); - context.Names[original] = new CandidateNames(newPrimary, secondaries); + if (originalName == newName) + { + unmodified.Add(originalName); + } } - return; + foreach (var unmodifiedMember in unmodified) + { + members.Remove(unmodifiedMember); + } } - foreach (var (original, (primary, secondary)) in context.Names) + // Remove unmodified scopes + foreach (var (scope, members) in context.FinalNames) { - var secondaries = secondary; - var newPrimary = affixer.ApplyAffixes( - primary, - context.Container, - original, - secondaries - ); - context.Names[original] = new CandidateNames(newPrimary, secondaries); + if (members.Count == 0) + { + unmodified.Add(scope); + } + } + + foreach (var unmodifiedScope in unmodified) + { + context.FinalNames.Remove(unmodifiedScope); } } } - private class PrettifyNamesTrimmer(NamePrettifier namePrettifier) : INameTrimmer + /// + /// Represents a name processor. + /// + private interface INameProcessor { - /// - public Version Version => new(0, 0, 0); + /// + /// Process and transform the names within the given scope. + /// + public void ProcessNames(NameProcessorContext context); + } - /// - public int Order => (int)TrimmerOrder.PrettifyNamesTrimmer; + /// + /// State made available to implementations. + /// + private class NameProcessorContext + { + /// + /// Represents a mapping: ScopeName -> (MemberName -> MemberCandidateNames). + /// This stores the candidates for the final prettified name for each name organized by scope. + /// Also known as the working set of names. + /// + public Dictionary> Names { get; } - public void Trim(NameTrimmerContext context) - { - foreach (var (original, (primary, secondary)) in context.Names) - { - // Be lenient about caps for type names (e.g. GL) - var allowAllCaps = context.Container == null; + /// + /// Represents a mapping: ScopeName -> (MemberName -> NewMemberName). + /// This stores the final names for each member. + /// + /// + /// Processors are allowed to modify these, but should have a good reason in doing so. + /// + public Dictionary> FinalNames { get; } = []; - for (var i = 0; i < secondary.Count; i++) - { - secondary[i] = namePrettifier.Prettify(secondary[i], allowAllCaps); - } + /// + /// Creates a new context from the scraped name data. + /// + public NameProcessorContext(NameDataVisitor nameData) => + Names = nameData.Names.ToDictionary( + // Scope + x => x.Key, + x => + x.Value.ToDictionary( + // Member name + y => y.Key, + // Member candidate names + y => new CandidateNames(y.Key, []) + ) + ); + } - context.Names[original] = new CandidateNames( - namePrettifier.Prettify(primary, allowAllCaps), - secondary - ); - } - } + /// + /// Represents the set of primary and secondary candidates for the prettified version of a name. + /// + /// The preferred version of the output name. + /// + /// The fallback versions of the output name. + /// Used in the case the primary causes conflicts. + /// Names later in the list have higher priority. + /// + private readonly record struct CandidateNames(string Primary, List Secondary) + { + public override string ToString() => + $"(Primary={Primary}, Secondary=[{string.Join(", ", Secondary)}])"; } } diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs index 5e958705c6..04feaa8cd0 100644 --- a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs +++ b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs @@ -25,11 +25,6 @@ namespace Silk.NET.SilkTouch.Mods; /// VkBuffer*, usages of that pointer will be replaced by VkBufferHandle. For a 2-dimensional pointer, /// VkBuffer**, the resulting replacement is VkBufferHandle*. /// -/// -/// It is assumed that all handle types in the generated syntax do not require a using directive in order to be -/// in scope. That is, if a file with the namespace Silk.NET.OpenGL is encountered and it is referencing -/// Program, Program must be declared in Silk.NET.OpenGL, Silk.NET, or Silk. -/// [ModConfiguration] public class TransformHandles( IOptionsSnapshot config, @@ -41,16 +36,10 @@ ILogger logger /// public class Config { - /// - /// Whether it should be assumed that missing types are likely opaque if they are only used as a pointer type - /// and therefore should be subjected to handle transformations. - /// - public bool AssumeMissingTypesOpaque { get; init; } - /// /// Whether the DSL (i.e. nullptr) should be usable with handle types. /// - public bool UseDSL { get; init; } + public bool UseDsl { get; init; } } /// @@ -58,6 +47,7 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = { await base.ExecuteAsync(ctx, ct); + var cfg = config.Get(ctx.JobKey); var project = ctx.SourceProject; if (project == null) { @@ -70,45 +60,13 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = throw new InvalidOperationException("Failed to get compilation"); } - var cfg = config.Get(ctx.JobKey); - if (cfg.AssumeMissingTypesOpaque) - { - // Find missing handle types - var handleDiscoverer = new MissingHandleTypeDiscoverer(logger, compilation, ct); - var missingHandleTypes = handleDiscoverer.GetMissingHandleTypes(); - - // Generate syntax nodes containing empty structs to represent the missing handle types - var structGenerator = new EmptyStructGenerator(); - var syntaxNodes = structGenerator.GenerateSyntaxNodes(missingHandleTypes); - - // Add syntax nodes to the project as new documents - foreach (var (fullyQualifiedName, node) in syntaxNodes) - { - var relativePath = $"Handles/{PathForFullyQualified(fullyQualifiedName)}"; - project = project - .AddDocument( - Path.GetFileName(relativePath), - node.NormalizeWhitespace(), - filePath: project.FullPath(relativePath) - ) - .Project; - } - - // Update compilation - compilation = await project.GetCompilationAsync(ct); - if (compilation == null) - { - throw new InvalidOperationException("Failed to get compilation"); - } - } - // Find handle documents var handleTypeDiscoverer = new HandleTypeDiscoverer(project, compilation, ct); var handleTypes = await handleTypeDiscoverer.GetHandleTypesAsync(); // Store handle document IDs for later // We will use these IDs to know which documents to rewrite and rename - var handleTypeDocumentIds = new List<(string OriginalName, DocumentId DocumentId)>(); + var handleTypeDocumentIds = new List(); foreach (var handleTypeSymbol in handleTypes) { if (handleTypeSymbol.DeclaringSyntaxReferences.Length > 1) @@ -124,7 +82,7 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = var documentId = project.GetDocumentId(declaringSyntaxReference.SyntaxTree); if (documentId != null) { - handleTypeDocumentIds.Add((handleTypeSymbol.Name, documentId)); + handleTypeDocumentIds.Add(documentId); } } @@ -141,8 +99,8 @@ [new PointerDimensionReductionTransformer()], project = ctx.SourceProject; // Use document IDs from earlier - var handleTypeRewriter = new HandleTypeRewriter(cfg.UseDSL); - foreach (var (originalName, documentId) in handleTypeDocumentIds) + var handleTypeRewriter = new HandleTypeRewriter(cfg.UseDsl); + foreach (var documentId in handleTypeDocumentIds) { var document = project.GetDocument(documentId) @@ -165,270 +123,6 @@ [new PointerDimensionReductionTransformer()], } ctx.SourceProject = project; - - return; - } - - private class MissingHandleTypeDiscoverer( - ILogger logger, - Compilation compilation, - CancellationToken ct - ) : SymbolVisitor - { - private readonly HashSet _nonHandleTypes = - new(SymbolEqualityComparer.Default); - private readonly Dictionary _missingTypes = - new(SymbolEqualityComparer.Default); - - private string? _currentNamespace = null; - private int _pointerTypeDepth = 0; - - /// - /// Gets all missing handle types that are found and the namespace that they should be created in. - /// - public Dictionary GetMissingHandleTypes() - { - // We need to find and generate all missing handle types - // Handle types are types that are only referenced through a pointer - // We do this by parsing through the list of type errors - var typeErrors = compilation - .GetDiagnostics(ct) - .Where(d => d.Id == "CS0246") // Type errors - .ToList(); - - // Find symbols that contain ITypeErrorSymbols - // These symbols are not necessarily ITypeErrorSymbols - var symbolsFound = new HashSet(SymbolEqualityComparer.Default); - foreach (var typeError in typeErrors) - { - var syntaxTree = typeError.Location.SourceTree; - if (syntaxTree == null) - { - continue; - } - - var semanticModel = compilation.GetSemanticModel(syntaxTree); - - // Get the syntax node the type error corresponds to - var currentSyntax = syntaxTree.GetRoot().FindNode(typeError.Location.SourceSpan); - - // Search upwards to find a syntax node that we can call GetDeclaredSymbol on - // This is because calling GetDeclaredSymbol on the starting node will just return null - var isSuccess = false; - while (currentSyntax != null && currentSyntax is not TypeDeclarationSyntax) - { - switch (currentSyntax) - { - case VariableDeclarationSyntax variableDeclarationSyntax: - { - foreach (var declaratorSyntax in variableDeclarationSyntax.Variables) - { - var symbol = semanticModel.GetDeclaredSymbol(declaratorSyntax, ct); - if (symbol != null) - { - symbolsFound.Add(symbol); - isSuccess = true; - - // All of the declarators will have the same type, so getting the first symbol is enough - break; - } - } - - break; - } - case MemberDeclarationSyntax memberDeclarationSyntax: - { - var symbol = semanticModel.GetDeclaredSymbol( - memberDeclarationSyntax, - ct - ); - if (symbol != null) - { - symbolsFound.Add(symbol); - isSuccess = true; - } - - break; - } - // Skip syntaxes that will never contain handle types - case BaseTypeSyntax: - case AttributeSyntax: - { - isSuccess = true; - break; - } - } - - currentSyntax = currentSyntax.Parent; - } - - if (!isSuccess) - { - // This is to warn of unhandled cases - logger.LogWarning( - "Failed to find corresponding symbol for type error. There may be an unhandled case in the code" - ); - } - } - - // These symbols contain at least one IErrorTypeSymbol, we need to search downwards for them - foreach (var symbol in symbolsFound) - { - Visit(symbol); - } - - return new Dictionary( - _missingTypes.Where(kvp => !_nonHandleTypes.Contains(kvp.Key)), - SymbolEqualityComparer.Default - ); - } - - public override void VisitMethod(IMethodSymbol symbol) - { - base.VisitMethod(symbol); - - _currentNamespace = symbol.NamespaceFromSymbol(); - foreach (var parameterSymbol in symbol.Parameters) - { - Visit(parameterSymbol); - } - _currentNamespace = null; - } - - public override void VisitParameter(IParameterSymbol symbol) - { - base.VisitParameter(symbol); - - _currentNamespace = symbol.NamespaceFromSymbol(); - Visit(symbol.Type); - _currentNamespace = null; - } - - public override void VisitProperty(IPropertySymbol symbol) - { - base.VisitProperty(symbol); - - _currentNamespace = symbol.NamespaceFromSymbol(); - Visit(symbol.Type); - _currentNamespace = null; - } - - public override void VisitField(IFieldSymbol symbol) - { - base.VisitField(symbol); - - _currentNamespace = symbol.NamespaceFromSymbol(); - Visit(symbol.Type); - _currentNamespace = null; - } - - public override void VisitLocal(ILocalSymbol symbol) - { - base.VisitLocal(symbol); - - _currentNamespace = symbol.NamespaceFromSymbol(); - Visit(symbol.Type); - _currentNamespace = null; - } - - public override void VisitPointerType(IPointerTypeSymbol symbol) - { - base.VisitPointerType(symbol); - - _pointerTypeDepth++; - Visit(symbol.PointedAtType); - _pointerTypeDepth--; - } - - public override void VisitNamedType(INamedTypeSymbol symbol) - { - base.VisitNamedType(symbol); - - if (symbol is IErrorTypeSymbol errorTypeSymbol) - { - if (_currentNamespace == null) - { - throw new InvalidOperationException( - $"{nameof(_currentNamespace)} should not be null" - ); - } - - if (_pointerTypeDepth == 0) - { - _nonHandleTypes.Add(errorTypeSymbol); - } - - if (_missingTypes.TryGetValue(errorTypeSymbol, out var sharedNamespace)) - { - _missingTypes[errorTypeSymbol] = NameUtils - .FindCommonPrefix([sharedNamespace, _currentNamespace], true, false, true) - .Trim('.'); - } - else - { - _missingTypes[errorTypeSymbol] = _currentNamespace; - } - } - } - } - - private class EmptyStructGenerator - { - /// - /// Generates a syntax node for each specified type. - /// - /// Map from error type symbol to the namespace the type should be created in. - /// Map from the fully qualified name of the generated type to the syntax node containing code for that type. - public Dictionary GenerateSyntaxNodes( - Dictionary typesToGenerate - ) => - GenerateSyntaxNodes( - typesToGenerate - .Select(kvp => new KeyValuePair(kvp.Key.Name, kvp.Value)) - .ToDictionary() - ); - - /// - /// Generates a syntax node for each specified type. - /// - /// Map from type name to the namespace the type should be created in. - /// Map from the fully qualified name of the generated type to the syntax node containing code for that type. - public Dictionary GenerateSyntaxNodes( - Dictionary missingHandleTypes - ) - { - var results = new Dictionary(); - foreach (var (name, ns) in missingHandleTypes) - { - var fullyQualifiedName = string.IsNullOrWhiteSpace(ns) ? name : $"{ns}.{name}"; - var structDeclarationSyntax = StructDeclaration(name) - .WithModifiers( - TokenList( - Token(SyntaxKind.PublicKeyword), - Token(SyntaxKind.UnsafeKeyword), - Token(SyntaxKind.PartialKeyword) - ) - ); - - results[fullyQualifiedName] = CompilationUnit() - .WithMembers( - SingletonList( - string.IsNullOrWhiteSpace(ns) - ? structDeclarationSyntax - : FileScopedNamespaceDeclaration( - ModUtils.NamespaceIntoIdentifierName(ns) - ) - .WithMembers( - SingletonList( - structDeclarationSyntax - ) - ) - ) - ); - } - - return results; - } } private class HandleTypeDiscoverer( @@ -533,7 +227,7 @@ public override void VisitNamedType(INamedTypeSymbol symbol) } } - private class HandleTypeRewriter(bool useDSL) : CSharpSyntaxRewriter + private class HandleTypeRewriter(bool useDsl) : CSharpSyntaxRewriter { public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) { @@ -547,7 +241,7 @@ public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) .WithMembers( List( GetDefaultHandleMembers(structName) - .Concat(useDSL ? GetDSLHandleMembers(structName) : []) + .Concat(useDsl ? GetDslHandleMembers(structName) : []) ) ) .WithModifiers( @@ -629,7 +323,7 @@ string structName Identifier("Equals") ) .WithModifiers( - TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)]) + TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)) ) .WithParameterList( ParameterList( @@ -668,7 +362,7 @@ string structName Identifier("GetHashCode") ) .WithModifiers( - TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)]) + TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)) ) .WithExpressionBody( ArrowExpressionClause( @@ -700,7 +394,7 @@ string structName Token(SyntaxKind.EqualsEqualsToken) ) .WithModifiers( - TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)]) + TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)) ) .WithParameterList( ParameterList( @@ -737,7 +431,7 @@ string structName Token(SyntaxKind.ExclamationEqualsToken) ) .WithModifiers( - TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)]) + TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)) ) .WithParameterList( ParameterList( @@ -771,7 +465,7 @@ string structName .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); } - private static IEnumerable GetDSLHandleMembers(string structName) + private static IEnumerable GetDslHandleMembers(string structName) { yield return MethodDeclaration( PredefinedType(Token(SyntaxKind.BoolKeyword)), @@ -800,7 +494,7 @@ private static IEnumerable GetDSLHandleMembers(string s Token(SyntaxKind.EqualsEqualsToken) ) .WithModifiers( - TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)]) + TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)) ) .WithParameterList( ParameterList( @@ -837,7 +531,7 @@ private static IEnumerable GetDSLHandleMembers(string s Token(SyntaxKind.ExclamationEqualsToken) ) .WithModifiers( - TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)]) + TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)) ) .WithParameterList( ParameterList( @@ -875,7 +569,7 @@ private static IEnumerable GetDSLHandleMembers(string s IdentifierName(structName) ) .WithModifiers( - TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)]) + TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)) ) .WithParameterList( ParameterList( diff --git a/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs b/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs index cc221c4561..ba663df169 100644 --- a/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs +++ b/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs @@ -56,14 +56,14 @@ public IEnumerable GetTransformedFunctions( // to null as overloads that differ only by return type aren't acceptable. However, we do need a // discriminator that does include the return type so we can determine whether the function has gone // through the transformation pipeline completely unmodified. - var discrim = ModUtils.DiscrimStr( + var discrim = ModUtils.GetMethodDiscriminator( meth.Modifiers, meth.TypeParameterList, meth.Identifier.ToString(), meth.ParameterList, returnType: null ); - var discrimWithRet = ModUtils.DiscrimStr( + var discrimWithRet = ModUtils.GetMethodDiscriminator( meth.Modifiers, meth.TypeParameterList, meth.Identifier.ToString(), @@ -127,14 +127,14 @@ meth.Body.Statements[0] as ExpressionStatementSyntax // to null as overloads that differ only by return type aren't acceptable. However, we do need a // discriminator that does include the return type so we can determine whether the function has gone // through the transformation pipeline completely unmodified. - var discrim = ModUtils.DiscrimStr( + var discrim = ModUtils.GetMethodDiscriminator( function.Modifiers, function.TypeParameterList, function.Identifier.ToString(), function.ParameterList, returnType: null ); - var discrimWithRet = ModUtils.DiscrimStr( + var discrimWithRet = ModUtils.GetMethodDiscriminator( function.Modifiers, function.TypeParameterList, function.Identifier.ToString(), @@ -190,7 +190,7 @@ meth.Body.Statements[0] as ExpressionStatementSyntax ) ); - discrim = ModUtils.DiscrimStr( + discrim = ModUtils.GetMethodDiscriminator( function.Modifiers, function.TypeParameterList, newIden, diff --git a/sources/SilkTouch/SilkTouch/Naming/CandidateNames.cs b/sources/SilkTouch/SilkTouch/Naming/CandidateNames.cs deleted file mode 100644 index 101122c6c8..0000000000 --- a/sources/SilkTouch/SilkTouch/Naming/CandidateNames.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Silk.NET.SilkTouch.Naming; - -/// -/// Represents the set of primary and secondary options for the trimmed version of a name. -/// -/// The preferred version of the trimmed name. -/// The fallback versions of the trimmed name in case the primary does not work. -public record struct CandidateNames(string Primary, List Secondary) -{ - /// - /// Formats this instance as a string. - /// - public override string ToString() => - $"(Primary={Primary}, Secondary=[{string.Join(", ", Secondary)}])"; -} diff --git a/sources/SilkTouch/SilkTouch/Naming/INameTrimmer.cs b/sources/SilkTouch/SilkTouch/Naming/INameTrimmer.cs deleted file mode 100644 index ec77fef58e..0000000000 --- a/sources/SilkTouch/SilkTouch/Naming/INameTrimmer.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Silk.NET.SilkTouch.Naming; - -/// -/// Represents a name trimmer. -/// -public interface INameTrimmer -{ - /// - /// Gets the name trimmer version i.e. the Silk.NET version that introduced this name trimming method. This is so - /// new bindings released with or after this version don't have to have older trimming methods executed (the name - /// version can be specified in the mod configuration) - /// - Version Version { get; } - - /// - /// Used to define the order that the trimmers will run in. - /// Higher values indicate that the trimmer should run later. - /// - int Order { get; } - - /// - /// Trims prefixes from the given constituent names within the given container. - /// - /// The arguments. - void Trim(NameTrimmerContext context); -} diff --git a/sources/SilkTouch/SilkTouch/Naming/NameAffix.cs b/sources/SilkTouch/SilkTouch/Naming/NameAffix.cs index c5c132a9fc..90be238ffa 100644 --- a/sources/SilkTouch/SilkTouch/Naming/NameAffix.cs +++ b/sources/SilkTouch/SilkTouch/Naming/NameAffix.cs @@ -13,9 +13,14 @@ namespace Silk.NET.SilkTouch.Naming; /// The order that the attribute was declared in. /// 0 is the first and indicates that the affix is on the inside of the name. /// +/// +/// Whether the affix uses the name of a referenced symbol. +/// See . +/// public record struct NameAffix( NameAffixType Type, string Category, string Affix, - int DeclarationOrder + int DeclarationOrder, + bool IsReference = false ); diff --git a/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs b/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs index a778a7d2dc..22fcfdd1f7 100644 --- a/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs +++ b/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs @@ -32,13 +32,21 @@ public static NameAffix[] GetNameAffixes(this SyntaxList at var argumentList = attribute.ArgumentList; if ( - argumentList != null - && argumentList.Arguments[0].Expression - is LiteralExpressionSyntax { Token.Value: string type } - && argumentList.Arguments[1].Expression - is LiteralExpressionSyntax { Token.Value: string category } - && argumentList.Arguments[2].Expression - is LiteralExpressionSyntax { Token.Value: string affix } + argumentList == null + || argumentList.Arguments[0].Expression + is not LiteralExpressionSyntax { Token.Value: string type } + || argumentList.Arguments[1].Expression + is not LiteralExpressionSyntax { Token.Value: string category } + ) + { + continue; + } + + if ( + argumentList.Arguments[2].Expression is LiteralExpressionSyntax + { + Token.Value: string affix + } ) { affixes = @@ -51,6 +59,36 @@ public static NameAffix[] GetNameAffixes(this SyntaxList at declarationOrder ), ]; + + declarationOrder++; + } + else if ( + argumentList.Arguments[2].Expression is InvocationExpressionSyntax + { + Expression: IdentifierNameSyntax { Identifier.ValueText: "nameof" }, + ArgumentList.Arguments: [ + { + Expression: IdentifierNameSyntax + { + Identifier.ValueText: var referencedAffix, + }, + }, + ], + } + ) + { + affixes = + [ + .. affixes, + new NameAffix( + type == "Prefix" ? NameAffixType.Prefix : NameAffixType.Suffix, + category, + referencedAffix, + declarationOrder, + true + ), + ]; + declarationOrder++; } } @@ -92,17 +130,92 @@ public static SyntaxList AddNameAffix( Literal($"\"{affixType}\"", affixType) ) ); + var categoryArgument = AttributeArgument( LiteralExpression( SyntaxKind.StringLiteralExpression, Literal($"\"{category}\"", category) ) ); + var affixArgument = AttributeArgument( LiteralExpression(SyntaxKind.StringLiteralExpression, Literal($"\"{affix}\"", affix)) ); + var argumentList = AttributeArgumentList([typeArgument, categoryArgument, affixArgument]); + var attribute = AttributeList([Attribute(IdentifierName("NameAffix"), argumentList)]); + + return addToInner ? [attribute, .. attributeLists] : [.. attributeLists, attribute]; + } + + /// + /// This is similar to + /// but allows the name of another symbol to be referenced. + /// + /// This ensures transformations applied to the referenced symbol's name + /// are also applied to this affix. + /// + /// + /// This allows compound names to be handled more cleanly. + /// + /// For simplicity, only names within the same name container are currently supported. + /// This lets us skip sorting across different containers. + /// This should cover most real world use cases since if something is nested and + /// has the parent name as a prefix, then the prefix is likely unnecessary. + /// + /// + /// For example, PerformanceCounterDescriptionARM can be used as a referenced prefix for PerformanceCounterDescriptionARMName. + /// If PerformanceCounterDescriptionARM becomes ARMPerformanceCounterDescription, + /// then PerformanceCounterDescriptionARMName will also be output as ARMPerformanceCounterDescriptionName. + /// + public static SyntaxList AddReferencedNameAffix( + this IEnumerable attributeLists, + NameAffixType type, + string category, + string referencedAffix, + bool addToInner = false + ) + { + var affixType = type switch + { + NameAffixType.Prefix => "Prefix", + NameAffixType.Suffix => "Suffix", + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + + var typeArgument = AttributeArgument( + LiteralExpression( + SyntaxKind.StringLiteralExpression, + Literal($"\"{affixType}\"", affixType) + ) + ); + var categoryArgument = AttributeArgument( + LiteralExpression( + SyntaxKind.StringLiteralExpression, + Literal($"\"{category}\"", category) + ) + ); + + // nameof(referencedAffix) + var affixArgument = AttributeArgument( + InvocationExpression( + IdentifierName( + Identifier( + TriviaList(), + SyntaxKind.NameOfKeyword, + "nameof", + "nameof", + TriviaList() + ) + ) + ) + .WithArgumentList( + ArgumentList(SingletonSeparatedList(Argument(IdentifierName(referencedAffix)))) + ) + ); + + var argumentList = AttributeArgumentList([typeArgument, categoryArgument, affixArgument]); var attribute = AttributeList([Attribute(IdentifierName("NameAffix"), argumentList)]); return addToInner ? [attribute, .. attributeLists] : [.. attributeLists, attribute]; diff --git a/sources/SilkTouch/SilkTouch/Naming/NamePrettifier.cs b/sources/SilkTouch/SilkTouch/Naming/NamePrettifier.cs index 1e9f5387ea..0b6cbce8e5 100644 --- a/sources/SilkTouch/SilkTouch/Naming/NamePrettifier.cs +++ b/sources/SilkTouch/SilkTouch/Naming/NamePrettifier.cs @@ -21,6 +21,7 @@ public class NamePrettifier(int longAcronymThreshold) { /// /// Prettifies the given C# identifier. + /// This involves transformation steps such as removing underscores and pascal casing the identifier. /// /// /// See the test cases for this method to see examples on how this method behaves. @@ -31,12 +32,7 @@ public class NamePrettifier(int longAcronymThreshold) /// Thrown when the input or output is an empty identifier. public string Prettify(string identifier, bool allowAllCaps = false) { - if (identifier.Length == 0) - { - throw new InvalidOperationException("Cannot prettify an empty identifier"); - } - - var words = NameSplitter.BreakIntoWords(identifier); + var words = NameSplitter.SplitIntoWords(identifier); // Add "X" to separate out numbers for (var i = words.Count - 1; i >= 1; i--) @@ -50,15 +46,6 @@ public string Prettify(string identifier, bool allowAllCaps = false) } } - // Add "X" if first word is a number - if (words.Count > 0) - { - if (NameUtils.GetCharType(words[0][0]) is CharType.Number) - { - words.Insert(0, "X"); - } - } - // Pretend there is an underscore between each word // This is used as a heuristic for determining whether we can treat short, all uppercase words as acronyms // @@ -179,17 +166,11 @@ public string Prettify(string identifier, bool allowAllCaps = false) } } - var result = string.Join("", words); - if (result.Length == 0) - { - throw new InvalidOperationException( - $"Prettification for '{identifier}' led to an empty identifier" - ); - } + var result = string.Join(null, words); // Disallow all capitals var resultSpan = result.AsSpan(); - if (!allowAllCaps && IsAllCaps(result)) + if (result.Length > 0 && !allowAllCaps && IsAllCaps(result)) { Span caps = stackalloc char[resultSpan.Length - 1]; resultSpan[1..].ToLower(caps, CultureInfo.InvariantCulture); diff --git a/sources/SilkTouch/SilkTouch/Naming/NameSplitter.cs b/sources/SilkTouch/SilkTouch/Naming/NameSplitter.cs index abf8c0af12..4b67b5dac8 100644 --- a/sources/SilkTouch/SilkTouch/Naming/NameSplitter.cs +++ b/sources/SilkTouch/SilkTouch/Naming/NameSplitter.cs @@ -10,6 +10,12 @@ namespace Silk.NET.SilkTouch.Naming; /// public static class NameSplitter { + /// + /// Splits the given C# identifier into separate words and rejoins them using an underscore as a separator. + /// + public static string Underscore(string identifier) => + string.Join("_", SplitIntoWords(identifier)); + /// /// Splits the given C# identifier into separate words. /// @@ -17,7 +23,7 @@ public static class NameSplitter /// See the test cases for this method to see examples on how this method behaves. /// /// A string that contains only valid C# identifier characters. - public static List BreakIntoWords(string identifier) + public static List SplitIntoWords(string identifier) { var words = new List(); var currentWord = new StringBuilder(); diff --git a/sources/SilkTouch/SilkTouch/Naming/NameTrimmer.cs b/sources/SilkTouch/SilkTouch/Naming/NameTrimmer.cs deleted file mode 100644 index 3bc9c92deb..0000000000 --- a/sources/SilkTouch/SilkTouch/Naming/NameTrimmer.cs +++ /dev/null @@ -1,407 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text.Json; - -namespace Silk.NET.SilkTouch.Naming; - -/// -/// The default name trimmer ported from Silk.NET 2.18 with modifications for 3.0. -/// -public class NameTrimmer : INameTrimmer -{ - /// - public virtual Version Version => new(3, 0); - - /// - public virtual int Order => (int)TrimmerOrder.NameTrimmer; - - /// - /// Determines whether a second pass without using is warranted. - /// - protected virtual bool HasRawPass => true; - - /// - /// Determines whether a third pass using "naive" prefix detection is warranted. Only applicable if - /// is true. - /// - /// - protected virtual bool HasNaivePass => true; - - private static readonly HashSet s_forbiddenTrimmings = new() { "unsigned", "per" }; - - /// - public void Trim(NameTrimmerContext context) - { - string? identifiedPrefix = null; - List localNames = null!; - var nPasses = HasRawPass - ? HasNaivePass - ? 3 - : 2 - : 1; - var naive = false; - if (identifiedPrefix is null) - { - for (var i = 0; i < nPasses; i++) // try with both trimming name and non trimming name - { - // Attempt to identify the hint being used. - string? hint = null; - foreach (var candidateHint in context.Configuration.GlobalPrefixHints ?? []) - { - var match = true; - foreach (var (name, _) in context.Names.Values) - { - if (!name.StartsWith(candidateHint, StringComparison.OrdinalIgnoreCase)) - { - match = false; - break; - } - } - - if (match) - { - hint = candidateHint; - break; - } - } - - var result = GetPrefix( - context.Container, - hint, - context.Names, - context.Configuration.PrefixOverrides, - context.NonDeterminant, - i == 0, - naive = i == 2 - ); - - if (result is null) - { - // skip outright. - return; - } - - (identifiedPrefix, localNames) = result.Value; - - // If we have found a prefix, - if ( - identifiedPrefix.Length > 0 - && identifiedPrefix.Length < localNames.Min(x => x.TrimmingName.Length) - ) - { - // break and use it for trimming! - break; - } - - // If not, do most of them at least start with the hint? - if ( - hint is null - || localNames.Count(x => - x.TrimmingName.StartsWith(hint, StringComparison.OrdinalIgnoreCase) - ) - >= localNames.Count / 2 - ) - { - // Nope, nothing we can do it seems, we've already tried both trimming name and non trimming name... - continue; - } - - // The prefix is the hint! - identifiedPrefix = hint; - naive = true; - break; - } - } - - // If identifiedPrefix is null, we fall back to the hints. I know we've checked above whether this is the - // obvious answer for a given pass, but if we've still got no possible prefix after all of the passes then this - // is better than nothing - if the name doesn't start with the prefix we simply won't use the prefix. - if ( - string.IsNullOrWhiteSpace(identifiedPrefix) - && context.Configuration.GlobalPrefixHints is not { Count: > 0 } - ) - { - return; - } - - identifiedPrefix = identifiedPrefix?.Trim('_'); - foreach (var (oldPrimary, secondary, originalName, trimmingName) in localNames) - { - foreach ( - var candidatePrefix in !string.IsNullOrWhiteSpace(identifiedPrefix) - ? [identifiedPrefix] // otherwise we fall back to the hints... - : context.Configuration.GlobalPrefixHints ?? [] - ) - { - if ( - naive - && ( - candidatePrefix.Length >= trimmingName.Length - || !trimmingName.StartsWith( - candidatePrefix, - StringComparison.OrdinalIgnoreCase - ) - ) - ) - { - continue; - } - - var oldPrimaryI = 0; - var isPrefixTooLong = false; - for (var candidateI = 0; candidateI < candidatePrefix.Length; candidateI++) - { - if (oldPrimaryI >= oldPrimary.Length) - { - isPrefixTooLong = true; - break; - } - - if ( - char.ToLower(candidatePrefix[candidateI]) - == char.ToLower(oldPrimary[oldPrimaryI]) - ) - { - oldPrimaryI++; - continue; - } - - if (candidatePrefix[candidateI] == '_') - { - oldPrimaryI++; - } - } - - if (isPrefixTooLong) - { - continue; - } - - // this was trimmingName originally. given that we're using trimming name to determine a prefix but then - // using that prefix on the old primary, this could cause intended behaviour in some cases. there's probably - // a better way to do this. (this is working around glDisablei -> glDisable -> Disablei). - context.Names[originalName] = new CandidateNames( - oldPrimary[oldPrimaryI..].Trim('_'), - secondary - ); - break; - } - } - } - - /// - /// Gets the prefix for the given constituents of the given container. - /// - /// The container name if applicable. - /// The global prefix hint if applicable. - /// The names to get a prefix for. - /// Prefix overrides. - /// List of names that should not be used for prefix determination. - /// - /// Whether to use or to use the native name as-is. - /// - /// - /// Just match the start of the strings, don't bother checking for obvious name separation gaps. - /// - /// - /// Null to skip this container outright, empty if no prefix was found, or the prefix otherwise. - /// - /// A local names list is also returned. - /// This is the list of names to be used for the remainder of the trimming process - /// and contains the trimming name and original name. - /// - protected (string Prefix, List)? GetPrefix( - string? container, - string? hint, - Dictionary names, - Dictionary? prefixOverrides, - HashSet? nonDeterminant, - bool getTrimmingName, - bool naive - ) - { - // If the type has no members, - if (names.Count == 0) - { - // skip it - return null; - } - - // Get the trimming names - var containerTrimmingName = getTrimmingName - ? GetTrimmingName(prefixOverrides, container ?? hint ?? string.Empty, true, hint) - : container ?? hint ?? string.Empty; - - var localNames = names - .Select(x => new AugmentedCandidateNames( - x.Value.Primary, - x.Value.Secondary, - x.Key, - getTrimmingName - ? GetTrimmingName(prefixOverrides, x.Value.Primary, false, hint) - : x.Value.Primary - )) - .ToList(); - - // Set the prefix to the prefix override for this container, if it exists. - // This is to allow us to handle poorly/inconsistently named containers, - // without putting special cases elsewhere in the logic - // ex: For the enum - // enum Things { - // ThingsRGB - // ThingRGB - // } - // If we specify a prefix override of "Thing", - // then it will trim ThingsRGB to sRGB and ThingRGB to RGB - // a case like this is simple to add a special case for in the generator to handle sRGB specially, - // but see ImageChannelOrder from spirv.h for a more problematic occurrence. - string prefix; - if ( - container is not null - && (prefixOverrides?.TryGetValue(container, out var @override) ?? false) - ) - { - // Use the override - prefix = @override; - } - else - { - if (names.Count == 1) - { - if (!string.IsNullOrWhiteSpace(containerTrimmingName)) - { - // Use the member name and its container. - prefix = NameUtils.FindCommonPrefix( - [ - names - .First(x => !(nonDeterminant?.Contains(x.Key) ?? false)) - .Value.Primary, - containerTrimmingName, - ], - true, - false, - naive - ); - } - else - { - // One name. Can't determine prefix. - prefix = ""; - } - } - else - { - // Common case - Find the prefix based on the container's members - prefix = NameUtils.FindCommonPrefix( - localNames - .Where(x => !(nonDeterminant?.Contains(x.Original) ?? false)) - .Select(x => x.TrimmingName) - .ToList(), - // If naive mode is on and we're trimming type names, allow full matches (method class is - // probably the prefix) - naive && container is null, - false, - naive - ); - } - } - - // If any of the children's trimming name is shorter than the prefix length, - if ( - localNames.Any(x => - x.TrimmingName.Length <= prefix.Length - && !(nonDeterminant?.Contains(x.Original) ?? false) - ) && !string.IsNullOrWhiteSpace(containerTrimmingName) - ) - { - // Do a second pass, but put the container name in the loop to see if it makes a difference - prefix = NameUtils.FindCommonPrefix( - localNames.Select(x => x.TrimmingName).Append(containerTrimmingName).ToList(), - // If naive mode is on and we're trimming type names, allow full matches (method class is probably the - // prefix) - naive && container is null, - false, - naive - ); - } - - // Iterate through all of the forbidden trimmings, - foreach (var word in s_forbiddenTrimmings) - { - // If the prefix starts with a forbidden trimming, - if (prefix.StartsWith($"{word}_")) - { - // Clear the prefix - prefix = string.Empty; - } - - // If the prefix contains the forbidden trimming surrounded by underscores, - var idx = prefix.IndexOf($"_{word}_", StringComparison.OrdinalIgnoreCase); - if (idx != -1) - { - // Trim the end of the prefix to the start of the forbidden trimming - // ex: - // input prefix = THIS_GL_ - // forbidden trimming = GL - // - // resulting prefix = THIS - prefix = prefix[..idx]; - } - } - - return (prefix, localNames); - } - - /// - /// Gets the name to feed into . - /// - /// The prefix overrides. - /// The name to get a trimming name for. - /// Whether the name passed into is the container name. - /// The global prefix hint. - /// The trimming name. - public virtual string GetTrimmingName( - Dictionary? prefixOverrides, - string name, - bool isContainer, - string? hint = null - ) - { - // If theres a prefix override for this enum, - if (prefixOverrides?.ContainsKey(name) ?? false) - { - // Use the raw native name as the trimming name - return name; - } - - if (hint is not null && name.StartsWith(hint, StringComparison.OrdinalIgnoreCase)) - { - return $"{hint}_{name[hint.Length..].Trim('_').LenientUnderscore()}"; - } - - return name.Trim('_').LenientUnderscore(); - } - - /// - /// Similar to , but with some additional information. - /// - /// The preferred version of the trimmed name. - /// The fallback versions of the trimmed name in case the primary does not work. - /// The original, unmodified name. - /// The name used for trimming purposes. - protected record struct AugmentedCandidateNames( - string Primary, - List Secondary, - string Original, - string TrimmingName - ) - { - /// - /// Formats this instance as a string. - /// - public override string ToString() => - $"(Original={Original}, TrimmingName={TrimmingName}, Primary={Primary}, Secondary=[{string.Join(", ", Secondary)}])"; - } -} diff --git a/sources/SilkTouch/SilkTouch/Naming/NameTrimmer217.cs b/sources/SilkTouch/SilkTouch/Naming/NameTrimmer217.cs deleted file mode 100644 index e188daad90..0000000000 --- a/sources/SilkTouch/SilkTouch/Naming/NameTrimmer217.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using Humanizer; - -namespace Silk.NET.SilkTouch.Naming; - -/// -/// The 2.17 name trimmer. -/// -[Obsolete("Use NameTrimmer instead for 3.0 names")] -public class NameTrimmer217 : NameTrimmer -{ - /// - public override Version Version => new(2, 17); - - /// - public override int Order => (int)TrimmerOrder.NameTrimmer217; - - /// - protected override bool HasRawPass => false; - - /// - protected override bool HasNaivePass => false; - - /// - public override string GetTrimmingName( - Dictionary? prefixOverrides, - string name, - bool isContainer, - string? hint = null - ) - { - if (!isContainer) - { - return name; - } - - return !name.Contains('_') ? name.Underscore() : name; - } -} diff --git a/sources/SilkTouch/SilkTouch/Naming/NameTrimmer218.cs b/sources/SilkTouch/SilkTouch/Naming/NameTrimmer218.cs deleted file mode 100644 index fd9a0b8fbf..0000000000 --- a/sources/SilkTouch/SilkTouch/Naming/NameTrimmer218.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Silk.NET.SilkTouch.Naming; - -/// -/// The 2.18 name trimmer. -/// -[Obsolete("Use NameTrimmer instead for 3.0 names")] -public class NameTrimmer218 : NameTrimmer -{ - /// - public override Version Version => new(2, 18); - - /// - public override int Order => (int)TrimmerOrder.NameTrimmer218; - - /// - protected override bool HasRawPass => false; - - /// - protected override bool HasNaivePass => false; -} diff --git a/sources/SilkTouch/SilkTouch/Naming/NameTrimmerContext.cs b/sources/SilkTouch/SilkTouch/Naming/NameTrimmerContext.cs deleted file mode 100644 index caede1740e..0000000000 --- a/sources/SilkTouch/SilkTouch/Naming/NameTrimmerContext.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Silk.NET.SilkTouch.Mods; - -namespace Silk.NET.SilkTouch.Naming; - -/// -/// State made available to implementations when determining a trimmed name. -/// -public readonly struct NameTrimmerContext -{ - /// - /// Gets the name of the "container" (e.g. a type name) of the APIs in . - /// - public string? Container { get; init; } - - /// - /// Gets the identifier for the current generation job, unique across the current - /// instance. - /// - public string? JobKey { get; init; } - - /// - /// Gets a dictionary mapping the original API name to a primary candidate name to rename that API to. The previous - /// names or other names that are otherwise less preferred to the primary name are listed in the optional secondary - /// list (in order of preference). - /// - public required Dictionary Names { get; init; } - - /// - /// Gets the current configuration for the mod. - /// - public PrettifyNames.Configuration Configuration { get; init; } - - /// - /// Gets a set of original API names (i.e. the key stored in ) that have been marked with - /// the [Transformed] attribute. - /// - public HashSet NonDeterminant { get; init; } -} diff --git a/sources/SilkTouch/SilkTouch/Naming/NameUtils.cs b/sources/SilkTouch/SilkTouch/Naming/NameUtils.cs index 9f0b34e21c..391e25a521 100644 --- a/sources/SilkTouch/SilkTouch/Naming/NameUtils.cs +++ b/sources/SilkTouch/SilkTouch/Naming/NameUtils.cs @@ -1,6 +1,5 @@ using System.Buffers; using System.Diagnostics.CodeAnalysis; -using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Logging; using Silk.NET.SilkTouch.Mods; @@ -12,7 +11,7 @@ namespace Silk.NET.SilkTouch.Naming; /// Contains utilities used throughout the naming namespace. /// [SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] -public static partial class NameUtils +public static class NameUtils { /// /// All capital letters. @@ -38,6 +37,19 @@ public static partial class NameUtils "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" ); + /// + /// Prefixes the given identifier with the specified prefix if it starts with a number. + /// + public static string PrefixIfStartsWithNumber(string identifier, string prefix = "X") + { + if (identifier.Length > 0 && char.IsDigit(identifier[0])) + { + return $"X{identifier}"; + } + + return identifier; + } + /// /// Gets the char type for the specified character according /// to the categorization defined by . @@ -174,47 +186,6 @@ public static string FindCommonPrefix( return foundPrefix[..(naive ? foundPrefix.Length : foundPrefix.LastIndexOf('_') + 1)]; } - /// - /// Separates the input words with underscore - /// - /// The string to be underscored - /// - public static string LenientUnderscore(this string input) => - // This is a modified version of Humanizer's Underscore methods with the following changes: - // - The regex ([\p{Ll}\d])([\p{Lu}]) has been replaced with - // ([\p{Ll}\d])(?=[\p{Lu}][\p{Lu}\p{Ll}])([\p{Lu}]) - In this regex, the positive lookahead assertion - // (?=[\p{Lu}][\p{Lu}\p{Ll}]) ensures that the next character after the match is an uppercase letter, - // followed by any letter (uppercase or lowercase). This will only match if the 2nd character after the - // initial match is uppercase. That was suggested by ChatGPT, a human had to add the final - // [\p{Ll}])([\p{Lu}]) to ensure we don't erroneous match non-pascal case strings and to capture the - // second character to ensure we can do the replacement. Still pretty smart though. - // - The final ToLower has been omitted as it was not deemed necessary - // - The regex ([\p{Ll}])([\p{Lu}]) has been added to replace lowercase letters followed by an uppercase letter with the - // same sequence but with an underscore inbetween, - // this fixes cases like SpvImageFormatR32ui being Spv_Image_FormatR32ui instead of Spv_Image_Format_R32ui - KebabOrSpace() - .Replace( - LowerUpper() - .Replace( - LowerUpperAnyUpper() - .Replace(LowerUpperLower().Replace(input, "$1_$2"), "$1_$2"), - "$1_$2" - ), - "_" - ); - - [GeneratedRegex(@"[-\s]")] - private static partial Regex KebabOrSpace(); - - [GeneratedRegex(@"([\p{Ll}])([\p{Lu}])")] - private static partial Regex LowerUpper(); - - [GeneratedRegex(@"([\p{Ll}])(?=[\p{Lu}][\p{Lu}\p{Ll}])([\p{Lu}])")] - private static partial Regex LowerUpperAnyUpper(); - - [GeneratedRegex(@"([\p{Lu}]+)([\p{Lu}][\p{Ll}])")] - private static partial Regex LowerUpperLower(); - /// /// Rename all symbols with the given new names /// diff --git a/sources/SilkTouch/SilkTouch/Naming/TrimmerOrder.cs b/sources/SilkTouch/SilkTouch/Naming/TrimmerOrder.cs deleted file mode 100644 index 1ec873a1e9..0000000000 --- a/sources/SilkTouch/SilkTouch/Naming/TrimmerOrder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Silk.NET.SilkTouch.Naming; - -/// -/// Defines the order for SilkTouch's implementations. -/// -internal enum TrimmerOrder -{ - NameAffixerEarlyTrimmer = 100, - - NameTrimmer = 200, - NameTrimmer217 = 210, - NameTrimmer218 = 220, - - PrettifyNamesTrimmer = 400, - - NameAffixerLateTrimmer = 500, -} diff --git a/sources/SilkTouch/SilkTouch/ServiceCollectionExtensions.cs b/sources/SilkTouch/SilkTouch/ServiceCollectionExtensions.cs index 4809f51f0b..66bf03df6a 100644 --- a/sources/SilkTouch/SilkTouch/ServiceCollectionExtensions.cs +++ b/sources/SilkTouch/SilkTouch/ServiceCollectionExtensions.cs @@ -54,8 +54,6 @@ static ServiceCollectionExtensions() /// /// /// - /// - /// One or more s /// An appropriate implementation of /// Mod implementations referenced in the configurations /// @@ -96,16 +94,13 @@ IConfiguration config // - https://andrewlock.net/how-to-register-a-service-with-multiple-interfaces-for-in-asp-net-core-di/ // - https://discordapp.com/channels/143867839282020352/663803973119115264/1129546023388332075 (C# Discord) - // services.AddSingleton(); <-- this is a mod now services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.TryAddSingleton(s => s.GetRequiredService() ); - services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(s => s.GetRequiredService()); services.AddSingleton(s => s.GetRequiredService()); services.AddSingleton(typeof(IJobDependency<>), typeof(JobDependencies.Global<>)); services.TryAddSingleton(); diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoEXT.gen.cs index 13b4dabafe..77a76d9b27 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoEXT.gen.cs @@ -26,5 +26,5 @@ public unsafe partial struct DebugMarkerMarkerInfoEXT [NativeName("color")] [SupportedApiProfile("vulkan", ["VK_EXT_debug_marker"], ImpliesSets = ["VK_EXT_debug_report"])] - public DebugMarkerMarkerInfoExtColor Color; + public DebugMarkerMarkerInfoEXTColor Color; } diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoExtColor.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoEXTColor.gen.cs similarity index 91% rename from sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoExtColor.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoEXTColor.gen.cs index a087892818..d5f5533600 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoExtColor.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugMarkerMarkerInfoEXTColor.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_color_e__FixedBuffer")] [InlineArray(4)] [SupportedApiProfile("vulkan")] -public partial struct DebugMarkerMarkerInfoExtColor +public partial struct DebugMarkerMarkerInfoEXTColor { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackEXT.gen.cs index 1fbcc76130..17ca5c46b9 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackEXT.gen.cs @@ -52,7 +52,7 @@ public DebugReportCallbackEXT( ) => Pointer = ptr; [SupportedApiProfile("vulkan", ["VK_EXT_debug_report"])] - public DebugReportCallbackEXT(DebugReportCallbackDelegateEXT proc) => + public DebugReportCallbackEXT(DebugReportCallbackEXTDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); [SupportedApiProfile("vulkan", ["VK_EXT_debug_report"])] diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackDelegateEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackEXTDelegate.gen.cs similarity index 91% rename from sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackDelegateEXT.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackEXTDelegate.gen.cs index 6d5f18666f..1fc82b973b 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackDelegateEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugReportCallbackEXTDelegate.gen.cs @@ -10,7 +10,7 @@ namespace Silk.NET.Vulkan; [NativeName("PFN_vkDebugReportCallbackEXT")] [SupportedApiProfile("vulkan")] -public unsafe delegate uint DebugReportCallbackDelegateEXT( +public unsafe delegate uint DebugReportCallbackEXTDelegate( DebugReportFlagsEXT arg0, DebugReportObjectTypeEXT arg1, ulong arg2, diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelEXT.gen.cs index 13684e4abe..ef3b1e23fd 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelEXT.gen.cs @@ -26,5 +26,5 @@ public unsafe partial struct DebugUtilsLabelEXT [NativeName("color")] [SupportedApiProfile("vulkan", ["VK_EXT_debug_utils"])] - public DebugUtilsLabelExtColor Color; + public DebugUtilsLabelEXTColor Color; } diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelExtColor.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelEXTColor.gen.cs similarity index 92% rename from sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelExtColor.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelEXTColor.gen.cs index ead85ca18f..26aabcef9d 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelExtColor.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsLabelEXTColor.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_color_e__FixedBuffer")] [InlineArray(4)] [SupportedApiProfile("vulkan")] -public partial struct DebugUtilsLabelExtColor +public partial struct DebugUtilsLabelEXTColor { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackEXT.gen.cs index 282236565a..1ac52b77f8 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackEXT.gen.cs @@ -40,7 +40,7 @@ public DebugUtilsMessengerCallbackEXT( ) => Pointer = ptr; [SupportedApiProfile("vulkan", ["VK_EXT_debug_utils"])] - public DebugUtilsMessengerCallbackEXT(DebugUtilsMessengerCallbackDelegateEXT proc) => + public DebugUtilsMessengerCallbackEXT(DebugUtilsMessengerCallbackEXTDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); [SupportedApiProfile("vulkan", ["VK_EXT_debug_utils"])] diff --git a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackDelegateEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackEXTDelegate.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackDelegateEXT.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackEXTDelegate.gen.cs index 91a410e8c5..4b0d3d12ee 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackDelegateEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DebugUtilsMessengerCallbackEXTDelegate.gen.cs @@ -10,7 +10,7 @@ namespace Silk.NET.Vulkan; [NativeName("PFN_vkDebugUtilsMessengerCallbackEXT")] [SupportedApiProfile("vulkan")] -public unsafe delegate uint DebugUtilsMessengerCallbackDelegateEXT( +public unsafe delegate uint DebugUtilsMessengerCallbackEXTDelegate( DebugUtilsMessageSeverityFlagsEXT arg0, DebugUtilsMessageTypeFlagsEXT arg1, DebugUtilsMessengerCallbackDataEXT* arg2, diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoEXT.gen.cs index c241a1bc4d..0428db281f 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoEXT.gen.cs @@ -42,7 +42,7 @@ public unsafe partial struct DeviceFaultInfoEXT "VK_EXT_device_fault+VK_VERSION_1_1", ] )] - public DeviceFaultInfoExtDescription Description; + public DeviceFaultInfoEXTDescription Description; [NativeName("pAddressInfos")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoExtDescription.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoEXTDescription.gen.cs similarity index 92% rename from sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoExtDescription.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoEXTDescription.gen.cs index c4cbc58aa9..a2f27be648 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoExtDescription.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultInfoEXTDescription.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_description_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct DeviceFaultInfoExtDescription +public partial struct DeviceFaultInfoEXTDescription { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneEXT.gen.cs index 0a7a83c41a..603198dba3 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneEXT.gen.cs @@ -75,7 +75,7 @@ public partial struct DeviceFaultVendorBinaryHeaderVersionOneEXT "VK_EXT_device_fault+VK_VERSION_1_1", ] )] - public DeviceFaultVendorBinaryHeaderVersionOneExtPipelineCacheUuid PipelineCacheUuid; + public DeviceFaultVendorBinaryHeaderVersionOneEXTPipelineCacheUuid PipelineCacheUuid; [NativeName("applicationNameOffset")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneExtPipelineCacheUuid.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneEXTPipelineCacheUuid.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneExtPipelineCacheUuid.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneEXTPipelineCacheUuid.gen.cs index ed9aa0c92f..6ce5eea9de 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneExtPipelineCacheUuid.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorBinaryHeaderVersionOneEXTPipelineCacheUuid.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_pipelineCacheUUID_e__FixedBuffer")] [InlineArray(16)] [SupportedApiProfile("vulkan")] -public partial struct DeviceFaultVendorBinaryHeaderVersionOneExtPipelineCacheUuid +public partial struct DeviceFaultVendorBinaryHeaderVersionOneEXTPipelineCacheUuid { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoEXT.gen.cs index b4e39a666c..753adcbc03 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoEXT.gen.cs @@ -21,7 +21,7 @@ public partial struct DeviceFaultVendorInfoEXT "VK_EXT_device_fault+VK_VERSION_1_1", ] )] - public DeviceFaultVendorInfoExtDescription Description; + public DeviceFaultVendorInfoEXTDescription Description; [NativeName("vendorFaultCode")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoExtDescription.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoEXTDescription.gen.cs similarity index 91% rename from sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoExtDescription.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoEXTDescription.gen.cs index f84c0d4223..6f754dab2e 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoExtDescription.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceFaultVendorInfoEXTDescription.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_description_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct DeviceFaultVendorInfoExtDescription +public partial struct DeviceFaultVendorInfoEXTDescription { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKHR.gen.cs index 44e75160f8..fed8459d69 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKHR.gen.cs @@ -37,7 +37,7 @@ public unsafe partial struct DeviceGroupPresentCapabilitiesKHR ImpliesSets = ["VK_KHR_surface"], RequireAll = true )] - public DeviceGroupPresentCapabilitiesKhrPresentMask PresentMask; + public DeviceGroupPresentCapabilitiesKHRPresentMask PresentMask; [NativeName("modes")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKhrPresentMask.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKHRPresentMask.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKhrPresentMask.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKHRPresentMask.gen.cs index d6b865390b..ebee5fd756 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKhrPresentMask.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceGroupPresentCapabilitiesKHRPresentMask.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_presentMask_e__FixedBuffer")] [InlineArray(32)] [SupportedApiProfile("vulkan")] -public partial struct DeviceGroupPresentCapabilitiesKhrPresentMask +public partial struct DeviceGroupPresentCapabilitiesKHRPresentMask { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackEXT.gen.cs index 547894dd2f..9f9fa3e3e3 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackEXT.gen.cs @@ -53,7 +53,7 @@ public DeviceMemoryReportCallbackEXT( "VK_EXT_device_memory_report+VK_VERSION_1_1", ] )] - public DeviceMemoryReportCallbackEXT(DeviceMemoryReportCallbackDelegateEXT proc) => + public DeviceMemoryReportCallbackEXT(DeviceMemoryReportCallbackEXTDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackDelegateEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackEXTDelegate.gen.cs similarity index 89% rename from sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackDelegateEXT.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackEXTDelegate.gen.cs index deaccc8c73..c5ca8bf774 100644 --- a/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackDelegateEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/DeviceMemoryReportCallbackEXTDelegate.gen.cs @@ -10,7 +10,7 @@ namespace Silk.NET.Vulkan; [NativeName("PFN_vkDeviceMemoryReportCallbackEXT")] [SupportedApiProfile("vulkan")] -public unsafe delegate void DeviceMemoryReportCallbackDelegateEXT( +public unsafe delegate void DeviceMemoryReportCallbackEXTDelegate( DeviceMemoryReportCallbackDataEXT* arg0, void* arg1 ); diff --git a/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrLUNARG.gen.cs b/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrLUNARG.gen.cs index efa078ca71..d6faa30480 100644 --- a/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrLUNARG.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrLUNARG.gen.cs @@ -25,7 +25,7 @@ public GetInstanceProcAddrLUNARG( ) => Pointer = ptr; [SupportedApiProfile("vulkan", ["VK_LUNARG_direct_driver_loading"])] - public GetInstanceProcAddrLUNARG(GetInstanceProcAddrDelegateLUNARG proc) => + public GetInstanceProcAddrLUNARG(GetInstanceProcAddrLUNARGDelegate proc) => Pointer = SilkMarshal.DelegateToPtr(proc); [SupportedApiProfile("vulkan", ["VK_LUNARG_direct_driver_loading"])] diff --git a/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrDelegateLUNARG.gen.cs b/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrLUNARGDelegate.gen.cs similarity index 96% rename from sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrDelegateLUNARG.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrLUNARGDelegate.gen.cs index 3a8b09e9da..2f7915729f 100644 --- a/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrDelegateLUNARG.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/GetInstanceProcAddrLUNARGDelegate.gen.cs @@ -10,7 +10,7 @@ namespace Silk.NET.Vulkan; [NativeName("PFN_vkGetInstanceProcAddrLUNARG")] [SupportedApiProfile("vulkan")] -public unsafe delegate GetInstanceProcAddrLunargP2 GetInstanceProcAddrDelegateLUNARG( +public unsafe delegate GetInstanceProcAddrLunargP2 GetInstanceProcAddrLUNARGDelegate( InstanceHandle arg0, sbyte* arg1 ); diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionARM.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionARM.gen.cs index dec072b919..b97c601f2f 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionARM.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionARM.gen.cs @@ -54,5 +54,5 @@ public unsafe partial struct PerformanceCounterDescriptionARM "VK_ARM_performance_counters_by_region+VK_VERSION_1_1", ] )] - public PerformanceCounterDescriptionArmName Name; + public PerformanceCounterDescriptionARMName Name; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionArmName.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionARMName.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionArmName.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionARMName.gen.cs index e20908c4ce..5a86dc4127 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionArmName.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionARMName.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_name_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PerformanceCounterDescriptionArmName +public partial struct PerformanceCounterDescriptionARMName { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHR.gen.cs index 2eb342b252..d1652a9826 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHR.gen.cs @@ -53,7 +53,7 @@ public unsafe partial struct PerformanceCounterDescriptionKHR "VK_KHR_performance_query+VK_VERSION_1_1", ] )] - public PerformanceCounterDescriptionKhrName Name; + public PerformanceCounterDescriptionKHRName Name; [NativeName("category")] [SupportedApiProfile( @@ -64,7 +64,7 @@ public unsafe partial struct PerformanceCounterDescriptionKHR "VK_KHR_performance_query+VK_VERSION_1_1", ] )] - public PerformanceCounterDescriptionKhrCategory Category; + public PerformanceCounterDescriptionKHRCategory Category; [NativeName("description")] [SupportedApiProfile( @@ -75,5 +75,5 @@ public unsafe partial struct PerformanceCounterDescriptionKHR "VK_KHR_performance_query+VK_VERSION_1_1", ] )] - public PerformanceCounterDescriptionKhrDescription Description; + public PerformanceCounterDescriptionKHRDescription Description; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrCategory.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRCategory.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrCategory.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRCategory.gen.cs index ee58dfe571..41ebd3e9fe 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrCategory.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRCategory.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_category_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PerformanceCounterDescriptionKhrCategory +public partial struct PerformanceCounterDescriptionKHRCategory { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoExtDescription.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRDescription.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoExtDescription.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRDescription.gen.cs index 5fe2577487..8a1728d76d 100644 --- a/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoExtDescription.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRDescription.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_description_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct RenderPassSubpassFeedbackInfoExtDescription +public partial struct PerformanceCounterDescriptionKHRDescription { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrName.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRName.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrName.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRName.gen.cs index a35447ccba..f58216aeb8 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrName.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKHRName.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_name_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PerformanceCounterDescriptionKhrName +public partial struct PerformanceCounterDescriptionKHRName { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKHR.gen.cs index 4802d80517..62d78a8919 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKHR.gen.cs @@ -75,5 +75,5 @@ public unsafe partial struct PerformanceCounterKHR "VK_KHR_performance_query+VK_VERSION_1_1", ] )] - public PerformanceCounterKhrUuid Uuid; + public PerformanceCounterKHRUuid Uuid; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKhrUuid.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKHRUuid.gen.cs similarity index 92% rename from sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKhrUuid.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKHRUuid.gen.cs index 3a78cef254..dbb1421f79 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKhrUuid.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterKHRUuid.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_uuid_e__FixedBuffer")] [InlineArray(16)] [SupportedApiProfile("vulkan")] -public partial struct PerformanceCounterKhrUuid +public partial struct PerformanceCounterKHRUuid { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEI.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEI.gen.cs index b92c913fde..77b0b6c226 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEI.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEI.gen.cs @@ -43,7 +43,7 @@ public unsafe partial struct PhysicalDeviceClusterCullingShaderPropertiesHUAWEI "VK_HUAWEI_cluster_culling_shader+VK_VERSION_1_1", ] )] - public PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupCount MaxWorkGroupCount; + public PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupCount MaxWorkGroupCount; [NativeName("maxWorkGroupSize")] [SupportedApiProfile( @@ -54,7 +54,7 @@ public unsafe partial struct PhysicalDeviceClusterCullingShaderPropertiesHUAWEI "VK_HUAWEI_cluster_culling_shader+VK_VERSION_1_1", ] )] - public PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupSize MaxWorkGroupSize; + public PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupSize MaxWorkGroupSize; [NativeName("maxOutputClusterCount")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupCount.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupCount.gen.cs similarity index 96% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupCount.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupCount.gen.cs index 48dab6dbde..b7d88a6160 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupCount.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupCount.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_maxWorkGroupCount_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupCount +public partial struct PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupCount { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupSize.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupSize.gen.cs similarity index 96% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupSize.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupSize.gen.cs index 0485b6731f..65713a1cec 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupSize.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupSize.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_maxWorkGroupSize_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceClusterCullingShaderPropertiesHuaweiMaxWorkGroupSize +public partial struct PhysicalDeviceClusterCullingShaderPropertiesHUAWEIMaxWorkGroupSize { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportARM.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportARM.gen.cs index 8ba7a9716d..61f19560dd 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportARM.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportARM.gen.cs @@ -26,7 +26,7 @@ public partial struct PhysicalDeviceDataGraphOperationSupportARM ["VK_ARM_data_graph"], ImpliesSets = ["VK_KHR_deferred_host_operations", "VK_KHR_maintenance5", "VK_VERSION_1_3"] )] - public PhysicalDeviceDataGraphOperationSupportArmName Name; + public PhysicalDeviceDataGraphOperationSupportARMName Name; [NativeName("version")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportArmName.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportARMName.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportArmName.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportARMName.gen.cs index 2576ec8325..d9e71b528e 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportArmName.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceDataGraphOperationSupportARMName.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_name_e__FixedBuffer")] [InlineArray(128)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceDataGraphOperationSupportArmName +public partial struct PhysicalDeviceDataGraphOperationSupportARMName { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKHR.gen.cs index 1c49013c9e..8cdd72e207 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKHR.gen.cs @@ -34,5 +34,5 @@ public unsafe partial struct PhysicalDeviceLayeredApiPropertiesKHR [NativeName("deviceName")] [SupportedApiProfile("vulkan", ["VK_KHR_maintenance7"], ImpliesSets = ["VK_VERSION_1_1"])] - public PhysicalDeviceLayeredApiPropertiesKhrDeviceName DeviceName; + public PhysicalDeviceLayeredApiPropertiesKHRDeviceName DeviceName; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKhrDeviceName.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKHRDeviceName.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKhrDeviceName.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKHRDeviceName.gen.cs index 865e576fb0..22f7aac188 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKhrDeviceName.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceLayeredApiPropertiesKHRDeviceName.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_deviceName_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceLayeredApiPropertiesKhrDeviceName +public partial struct PhysicalDeviceLayeredApiPropertiesKHRDeviceName { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXT.gen.cs index c90d993fb7..2ad35cf788 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXT.gen.cs @@ -43,7 +43,7 @@ public unsafe partial struct PhysicalDeviceMemoryBudgetPropertiesEXT "VK_EXT_memory_budget+VK_VERSION_1_1", ] )] - public PhysicalDeviceMemoryBudgetPropertiesExtHeapBudget HeapBudget; + public PhysicalDeviceMemoryBudgetPropertiesEXTHeapBudget HeapBudget; [NativeName("heapUsage")] [SupportedApiProfile( @@ -54,5 +54,5 @@ public unsafe partial struct PhysicalDeviceMemoryBudgetPropertiesEXT "VK_EXT_memory_budget+VK_VERSION_1_1", ] )] - public PhysicalDeviceMemoryBudgetPropertiesExtHeapUsage HeapUsage; + public PhysicalDeviceMemoryBudgetPropertiesEXTHeapUsage HeapUsage; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesExtHeapBudget.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXTHeapBudget.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesExtHeapBudget.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXTHeapBudget.gen.cs index 894f05aec0..ad7dd9f29d 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesExtHeapBudget.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXTHeapBudget.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_heapBudget_e__FixedBuffer")] [InlineArray(16)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceMemoryBudgetPropertiesExtHeapBudget +public partial struct PhysicalDeviceMemoryBudgetPropertiesEXTHeapBudget { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesExtHeapUsage.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXTHeapUsage.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesExtHeapUsage.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXTHeapUsage.gen.cs index d0a0f80ac0..0e4dba1860 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesExtHeapUsage.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMemoryBudgetPropertiesEXTHeapUsage.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_heapUsage_e__FixedBuffer")] [InlineArray(16)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceMemoryBudgetPropertiesExtHeapUsage +public partial struct PhysicalDeviceMemoryBudgetPropertiesEXTHeapUsage { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXT.gen.cs index cc7a986b13..e0de0c0c94 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXT.gen.cs @@ -42,7 +42,7 @@ public unsafe partial struct PhysicalDeviceMeshShaderPropertiesEXT ["VK_EXT_mesh_shader"], ImpliesSets = ["VK_EXT_mesh_shader+VK_KHR_spirv_1_4", "VK_EXT_mesh_shader+VK_VERSION_1_2"] )] - public PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupCount MaxTaskWorkGroupCount; + public PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupCount MaxTaskWorkGroupCount; [NativeName("maxTaskWorkGroupInvocations")] [SupportedApiProfile( @@ -58,7 +58,7 @@ public unsafe partial struct PhysicalDeviceMeshShaderPropertiesEXT ["VK_EXT_mesh_shader"], ImpliesSets = ["VK_EXT_mesh_shader+VK_KHR_spirv_1_4", "VK_EXT_mesh_shader+VK_VERSION_1_2"] )] - public PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupSize MaxTaskWorkGroupSize; + public PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupSize MaxTaskWorkGroupSize; [NativeName("maxTaskPayloadSize")] [SupportedApiProfile( @@ -98,7 +98,7 @@ public unsafe partial struct PhysicalDeviceMeshShaderPropertiesEXT ["VK_EXT_mesh_shader"], ImpliesSets = ["VK_EXT_mesh_shader+VK_KHR_spirv_1_4", "VK_EXT_mesh_shader+VK_VERSION_1_2"] )] - public PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupCount MaxMeshWorkGroupCount; + public PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupCount MaxMeshWorkGroupCount; [NativeName("maxMeshWorkGroupInvocations")] [SupportedApiProfile( @@ -114,7 +114,7 @@ public unsafe partial struct PhysicalDeviceMeshShaderPropertiesEXT ["VK_EXT_mesh_shader"], ImpliesSets = ["VK_EXT_mesh_shader+VK_KHR_spirv_1_4", "VK_EXT_mesh_shader+VK_VERSION_1_2"] )] - public PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupSize MaxMeshWorkGroupSize; + public PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupSize MaxMeshWorkGroupSize; [NativeName("maxMeshSharedMemorySize")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupCount.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupCount.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupCount.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupCount.gen.cs index d1f2310b36..977a31b1fa 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupCount.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupCount.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_maxMeshWorkGroupCount_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupCount +public partial struct PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupCount { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupSize.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupSize.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupSize.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupSize.gen.cs index 12961ac8a9..b30925a2a9 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupSize.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupSize.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_maxMeshWorkGroupSize_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceMeshShaderPropertiesExtMaxMeshWorkGroupSize +public partial struct PhysicalDeviceMeshShaderPropertiesEXTMaxMeshWorkGroupSize { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupCount.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupCount.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupCount.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupCount.gen.cs index a557c05273..e41d505b44 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupCount.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupCount.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_maxTaskWorkGroupCount_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupCount +public partial struct PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupCount { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupSize.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupSize.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupSize.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupSize.gen.cs index b06d3e34c6..2f4d299bac 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupSize.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupSize.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_maxTaskWorkGroupSize_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceMeshShaderPropertiesExtMaxTaskWorkGroupSize +public partial struct PhysicalDeviceMeshShaderPropertiesEXTMaxTaskWorkGroupSize { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesEXT.gen.cs index 5ab9bde64a..3d88b2a27e 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesEXT.gen.cs @@ -65,7 +65,7 @@ public unsafe partial struct PhysicalDeviceSampleLocationsPropertiesEXT "VK_EXT_sample_locations+VK_VERSION_1_1", ] )] - public PhysicalDeviceSampleLocationsPropertiesExtSampleLocationCoordinateRange SampleLocationCoordinateRange; + public PhysicalDeviceSampleLocationsPropertiesEXTSampleLocationCoordinateRange SampleLocationCoordinateRange; [NativeName("sampleLocationSubPixelBits")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesExtSampleLocationCoordinateRange.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesEXTSampleLocationCoordinateRange.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesExtSampleLocationCoordinateRange.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesEXTSampleLocationCoordinateRange.gen.cs index 3417743e63..4d369f33c8 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesExtSampleLocationCoordinateRange.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceSampleLocationsPropertiesEXTSampleLocationCoordinateRange.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_sampleLocationCoordinateRange_e__FixedBuffer")] [InlineArray(2)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceSampleLocationsPropertiesExtSampleLocationCoordinateRange +public partial struct PhysicalDeviceSampleLocationsPropertiesEXTSampleLocationCoordinateRange { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesEXT.gen.cs index 0b5368f576..d5a8af6c6a 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesEXT.gen.cs @@ -46,5 +46,5 @@ public unsafe partial struct PhysicalDeviceShaderModuleIdentifierPropertiesEXT "VK_VERSION_1_3", ] )] - public PhysicalDeviceShaderModuleIdentifierPropertiesExtShaderModuleIdentifierAlgorithmUuid ShaderModuleIdentifierAlgorithmUuid; + public PhysicalDeviceShaderModuleIdentifierPropertiesEXTShaderModuleIdentifierAlgorithmUuid ShaderModuleIdentifierAlgorithmUuid; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesExtShaderModuleIdentifierAlgorithmUuid.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesEXTShaderModuleIdentifierAlgorithmUuid.gen.cs similarity index 94% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesExtShaderModuleIdentifierAlgorithmUuid.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesEXTShaderModuleIdentifierAlgorithmUuid.gen.cs index a424c4fe84..f9eef0036e 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesExtShaderModuleIdentifierAlgorithmUuid.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderModuleIdentifierPropertiesEXTShaderModuleIdentifierAlgorithmUuid.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_shaderModuleIdentifierAlgorithmUUID_e__FixedBuffer")] [InlineArray(16)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceShaderModuleIdentifierPropertiesExtShaderModuleIdentifierAlgorithmUuid +public partial struct PhysicalDeviceShaderModuleIdentifierPropertiesEXTShaderModuleIdentifierAlgorithmUuid { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesEXT.gen.cs index fae13ddf43..69948c0476 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesEXT.gen.cs @@ -46,7 +46,7 @@ public unsafe partial struct PhysicalDeviceShaderObjectPropertiesEXT "VK_VERSION_1_3", ] )] - public PhysicalDeviceShaderObjectPropertiesExtShaderBinaryUuid ShaderBinaryUuid; + public PhysicalDeviceShaderObjectPropertiesEXTShaderBinaryUuid ShaderBinaryUuid; [NativeName("shaderBinaryVersion")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesExtShaderBinaryUuid.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesEXTShaderBinaryUuid.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesExtShaderBinaryUuid.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesEXTShaderBinaryUuid.gen.cs index d5d7775d49..158faa64c8 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesExtShaderBinaryUuid.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PhysicalDeviceShaderObjectPropertiesEXTShaderBinaryUuid.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_shaderBinaryUUID_e__FixedBuffer")] [InlineArray(16)] [SupportedApiProfile("vulkan")] -public partial struct PhysicalDeviceShaderObjectPropertiesExtShaderBinaryUuid +public partial struct PhysicalDeviceShaderObjectPropertiesEXTShaderBinaryUuid { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKHR.gen.cs index 1b625fb2ad..8277e212c0 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKHR.gen.cs @@ -54,5 +54,5 @@ public unsafe partial struct PipelineBinaryKeyKHR "VK_KHR_pipeline_binary+VK_VERSION_1_4", ] )] - public PipelineBinaryKeyKhrKey Key; + public PipelineBinaryKeyKHRKey Key; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKhrKey.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKHRKey.gen.cs similarity index 92% rename from sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKhrKey.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKHRKey.gen.cs index 2ebcc9e12b..64cc2768fe 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKhrKey.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineBinaryKeyKHRKey.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_key_e__FixedBuffer")] [InlineArray(32)] [SupportedApiProfile("vulkan")] -public partial struct PipelineBinaryKeyKhrKey +public partial struct PipelineBinaryKeyKHRKey { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQCOM.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQCOM.gen.cs index 4fd572d78c..a11b1850c3 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQCOM.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQCOM.gen.cs @@ -49,5 +49,5 @@ public partial struct PipelineCacheHeaderVersionDataGraphQCOM ["VK_QCOM_data_graph_model"], ImpliesSets = ["VK_ARM_data_graph"] )] - public PipelineCacheHeaderVersionDataGraphQcomToolchainVersion ToolchainVersion; + public PipelineCacheHeaderVersionDataGraphQCOMToolchainVersion ToolchainVersion; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQcomToolchainVersion.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQCOMToolchainVersion.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQcomToolchainVersion.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQCOMToolchainVersion.gen.cs index 6b3d5605f2..deb955425d 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQcomToolchainVersion.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineCacheHeaderVersionDataGraphQCOMToolchainVersion.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_toolchainVersion_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct PipelineCacheHeaderVersionDataGraphQcomToolchainVersion +public partial struct PipelineCacheHeaderVersionDataGraphQCOMToolchainVersion { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHR.gen.cs index 185d3d494a..2bacc42a67 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHR.gen.cs @@ -42,7 +42,7 @@ public unsafe partial struct PipelineExecutableInternalRepresentationKHR "VK_KHR_pipeline_executable_properties+VK_VERSION_1_1", ] )] - public PipelineExecutableInternalRepresentationKhrName Name; + public PipelineExecutableInternalRepresentationKHRName Name; [NativeName("description")] [SupportedApiProfile( @@ -53,7 +53,7 @@ public unsafe partial struct PipelineExecutableInternalRepresentationKHR "VK_KHR_pipeline_executable_properties+VK_VERSION_1_1", ] )] - public PipelineExecutableInternalRepresentationKhrDescription Description; + public PipelineExecutableInternalRepresentationKHRDescription Description; [NativeName("isText")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKhrDescription.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHRDescription.gen.cs similarity index 88% rename from sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKhrDescription.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHRDescription.gen.cs index 312e53184c..c67b997886 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKhrDescription.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHRDescription.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_description_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PipelineExecutableInternalRepresentationKhrDescription +public partial struct PipelineExecutableInternalRepresentationKHRDescription { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKhrName.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHRName.gen.cs similarity index 89% rename from sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKhrName.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHRName.gen.cs index 0349deb036..b6a86fbd66 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKhrName.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableInternalRepresentationKHRName.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_name_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PipelineExecutableInternalRepresentationKhrName +public partial struct PipelineExecutableInternalRepresentationKHRName { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHR.gen.cs index f3df15140f..39c513e0de 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHR.gen.cs @@ -54,7 +54,7 @@ public unsafe partial struct PipelineExecutablePropertiesKHR "VK_KHR_pipeline_executable_properties+VK_VERSION_1_1", ] )] - public PipelineExecutablePropertiesKhrName Name; + public PipelineExecutablePropertiesKHRName Name; [NativeName("description")] [SupportedApiProfile( @@ -65,7 +65,7 @@ public unsafe partial struct PipelineExecutablePropertiesKHR "VK_KHR_pipeline_executable_properties+VK_VERSION_1_1", ] )] - public PipelineExecutablePropertiesKhrDescription Description; + public PipelineExecutablePropertiesKHRDescription Description; [NativeName("subgroupSize")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKhrDescription.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHRDescription.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKhrDescription.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHRDescription.gen.cs index 98a785eccc..5087c7a96f 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKhrDescription.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHRDescription.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_description_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PipelineExecutablePropertiesKhrDescription +public partial struct PipelineExecutablePropertiesKHRDescription { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKhrName.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHRName.gen.cs similarity index 91% rename from sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKhrName.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHRName.gen.cs index 2ef8155c5c..34610b935b 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKhrName.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutablePropertiesKHRName.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_name_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PipelineExecutablePropertiesKhrName +public partial struct PipelineExecutablePropertiesKHRName { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHR.gen.cs index afd8dd8105..68684fac74 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHR.gen.cs @@ -43,7 +43,7 @@ public unsafe partial struct PipelineExecutableStatisticKHR "VK_KHR_pipeline_executable_properties+VK_VERSION_1_1", ] )] - public PipelineExecutableStatisticKhrName Name; + public PipelineExecutableStatisticKHRName Name; [NativeName("description")] [SupportedApiProfile( @@ -54,7 +54,7 @@ public unsafe partial struct PipelineExecutableStatisticKHR "VK_KHR_pipeline_executable_properties+VK_VERSION_1_1", ] )] - public PipelineExecutableStatisticKhrDescription Description; + public PipelineExecutableStatisticKHRDescription Description; [NativeName("format")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKhrDescription.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHRDescription.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKhrDescription.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHRDescription.gen.cs index f0ac80cbde..415856170c 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKhrDescription.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHRDescription.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_description_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PipelineExecutableStatisticKhrDescription +public partial struct PipelineExecutableStatisticKHRDescription { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKhrName.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHRName.gen.cs similarity index 91% rename from sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKhrName.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHRName.gen.cs index a375d53881..83ad7e8b27 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKhrName.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineExecutableStatisticKHRName.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_name_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PipelineExecutableStatisticKhrName +public partial struct PipelineExecutableStatisticKHRName { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKHR.gen.cs index 6bbf687e7a..501fbdc92e 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKHR.gen.cs @@ -58,5 +58,5 @@ public unsafe partial struct PipelineFragmentShadingRateStateCreateInfoKHR "VK_VERSION_1_2", ] )] - public PipelineFragmentShadingRateStateCreateInfoKhrCombinerOps CombinerOps; + public PipelineFragmentShadingRateStateCreateInfoKHRCombinerOps CombinerOps; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKhrCombinerOps.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKHRCombinerOps.gen.cs similarity index 97% rename from sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKhrCombinerOps.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKHRCombinerOps.gen.cs index 610ce41098..09d0f5a570 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKhrCombinerOps.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelineFragmentShadingRateStateCreateInfoKHRCombinerOps.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_combinerOps_e__FixedBuffer")] [InlineArray(2)] [SupportedApiProfile("vulkan")] -public partial struct PipelineFragmentShadingRateStateCreateInfoKhrCombinerOps +public partial struct PipelineFragmentShadingRateStateCreateInfoKHRCombinerOps { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierEXT.gen.cs index 3399de1e61..033a8f07e2 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierEXT.gen.cs @@ -42,5 +42,5 @@ public unsafe partial struct PipelinePropertiesIdentifierEXT "VK_EXT_pipeline_properties+VK_VERSION_1_1", ] )] - public PipelinePropertiesIdentifierExtPipelineIdentifier PipelineIdentifier; + public PipelinePropertiesIdentifierEXTPipelineIdentifier PipelineIdentifier; } diff --git a/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierExtPipelineIdentifier.gen.cs b/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierEXTPipelineIdentifier.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierExtPipelineIdentifier.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierEXTPipelineIdentifier.gen.cs index 5ea1bbef40..094bcb22ea 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierExtPipelineIdentifier.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/PipelinePropertiesIdentifierEXTPipelineIdentifier.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_pipelineIdentifier_e__FixedBuffer")] [InlineArray(16)] [SupportedApiProfile("vulkan")] -public partial struct PipelinePropertiesIdentifierExtPipelineIdentifier +public partial struct PipelinePropertiesIdentifierEXTPipelineIdentifier { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoEXT.gen.cs index e438d100dc..0b5bac773a 100644 --- a/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoEXT.gen.cs @@ -31,7 +31,7 @@ public partial struct RenderPassSubpassFeedbackInfoEXT "VK_EXT_subpass_merge_feedback+VK_VERSION_1_1", ] )] - public RenderPassSubpassFeedbackInfoExtDescription Description; + public RenderPassSubpassFeedbackInfoEXTDescription Description; [NativeName("postMergeIndex")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrDescription.gen.cs b/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoEXTDescription.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrDescription.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoEXTDescription.gen.cs index e3dfc1c0dd..524f869655 100644 --- a/sources/Vulkan/Vulkan/Vulkan/PerformanceCounterDescriptionKhrDescription.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/RenderPassSubpassFeedbackInfoEXTDescription.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_description_e__FixedBuffer")] [InlineArray(256)] [SupportedApiProfile("vulkan")] -public partial struct PerformanceCounterDescriptionKhrDescription +public partial struct RenderPassSubpassFeedbackInfoEXTDescription { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierEXT.gen.cs b/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierEXT.gen.cs index 03390913c3..fd46feafdb 100644 --- a/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierEXT.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierEXT.gen.cs @@ -58,5 +58,5 @@ public unsafe partial struct ShaderModuleIdentifierEXT "VK_VERSION_1_3", ] )] - public ShaderModuleIdentifierExtIdentifier Identifier; + public ShaderModuleIdentifierEXTIdentifier Identifier; } diff --git a/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierExtIdentifier.gen.cs b/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierEXTIdentifier.gen.cs similarity index 91% rename from sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierExtIdentifier.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierEXTIdentifier.gen.cs index 0bdc1fbe07..bd65d09623 100644 --- a/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierExtIdentifier.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/ShaderModuleIdentifierEXTIdentifier.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_identifier_e__FixedBuffer")] [InlineArray(32)] [SupportedApiProfile("vulkan")] -public partial struct ShaderModuleIdentifierExtIdentifier +public partial struct ShaderModuleIdentifierEXTIdentifier { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAMD.gen.cs b/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAMD.gen.cs index ff42a5f68d..90b1d3d7e1 100644 --- a/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAMD.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAMD.gen.cs @@ -38,5 +38,5 @@ public partial struct ShaderStatisticsInfoAMD [NativeName("computeWorkGroupSize")] [SupportedApiProfile("vulkan", ["VK_AMD_shader_info"])] - public ShaderStatisticsInfoAmdComputeWorkGroupSize ComputeWorkGroupSize; + public ShaderStatisticsInfoAMDComputeWorkGroupSize ComputeWorkGroupSize; } diff --git a/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAmdComputeWorkGroupSize.gen.cs b/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAMDComputeWorkGroupSize.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAmdComputeWorkGroupSize.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAMDComputeWorkGroupSize.gen.cs index 27cb1d8d62..bd4f621b25 100644 --- a/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAmdComputeWorkGroupSize.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/ShaderStatisticsInfoAMDComputeWorkGroupSize.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_computeWorkGroupSize_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct ShaderStatisticsInfoAmdComputeWorkGroupSize +public partial struct ShaderStatisticsInfoAMDComputeWorkGroupSize { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKHR.gen.cs index f4738cc432..d607fcd235 100644 --- a/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKHR.gen.cs @@ -21,5 +21,5 @@ public partial struct TransformMatrixKHR "VK_KHR_deferred_host_operations+VK_VERSION_1_2", ] )] - public TransformMatrixKhrMatrix Matrix; + public TransformMatrixKHRMatrix Matrix; } diff --git a/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKhrMatrix.gen.cs b/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKHRMatrix.gen.cs similarity index 92% rename from sources/Vulkan/Vulkan/Vulkan/TransformMatrixKhrMatrix.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/TransformMatrixKHRMatrix.gen.cs index 4e4539a9a0..50e6bcdcfc 100644 --- a/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKhrMatrix.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/TransformMatrixKHRMatrix.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_matrix_e__FixedBuffer")] [InlineArray(3 * 4)] [SupportedApiProfile("vulkan")] -public partial struct TransformMatrixKhrMatrix +public partial struct TransformMatrixKHRMatrix { [NativeName("e0_0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKHR.gen.cs index 5a0f43fb19..90fbb40509 100644 --- a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKHR.gen.cs @@ -42,7 +42,7 @@ public unsafe partial struct VideoDecodeAv1PictureInfoKHR ["VK_KHR_video_decode_av1"], ImpliesSets = ["VK_KHR_video_decode_queue"] )] - public VideoDecodeAv1PictureInfoKhrReferenceNameSlotIndices ReferenceNameSlotIndices; + public VideoDecodeAv1PictureInfoKHRReferenceNameSlotIndices ReferenceNameSlotIndices; [NativeName("frameHeaderOffset")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs index 2366c0fb58..b2393cbd5f 100644 --- a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_referenceNameSlotIndices_e__FixedBuffer")] [InlineArray(7)] [SupportedApiProfile("vulkan")] -public partial struct VideoDecodeAv1PictureInfoKhrReferenceNameSlotIndices +public partial struct VideoDecodeAv1PictureInfoKHRReferenceNameSlotIndices { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKHR.gen.cs index 5d182704e4..c6a7ff5ab9 100644 --- a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKHR.gen.cs @@ -41,7 +41,7 @@ public unsafe partial struct VideoDecodeVp9PictureInfoKHR ["VK_KHR_video_decode_vp9"], ImpliesSets = ["VK_KHR_video_decode_queue"] )] - public VideoDecodeVp9PictureInfoKhrReferenceNameSlotIndices ReferenceNameSlotIndices; + public VideoDecodeVp9PictureInfoKHRReferenceNameSlotIndices ReferenceNameSlotIndices; [NativeName("uncompressedHeaderOffset")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKhrReferenceNameSlotIndices.gen.cs b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKHRReferenceNameSlotIndices.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKhrReferenceNameSlotIndices.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKHRReferenceNameSlotIndices.gen.cs index 440db46db7..78b884b45f 100644 --- a/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKhrReferenceNameSlotIndices.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/VideoDecodeVp9PictureInfoKHRReferenceNameSlotIndices.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_referenceNameSlotIndices_e__FixedBuffer")] [InlineArray(3)] [SupportedApiProfile("vulkan")] -public partial struct VideoDecodeVp9PictureInfoKhrReferenceNameSlotIndices +public partial struct VideoDecodeVp9PictureInfoKHRReferenceNameSlotIndices { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKHR.gen.cs b/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKHR.gen.cs index dbf5460fb2..ef8754bab0 100644 --- a/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKHR.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKHR.gen.cs @@ -65,7 +65,7 @@ public unsafe partial struct VideoEncodeAv1PictureInfoKHR ["VK_KHR_video_encode_av1"], ImpliesSets = ["VK_KHR_video_encode_queue"] )] - public VideoEncodeAv1PictureInfoKhrReferenceNameSlotIndices ReferenceNameSlotIndices; + public VideoEncodeAv1PictureInfoKHRReferenceNameSlotIndices ReferenceNameSlotIndices; [NativeName("primaryReferenceCdfOnly")] [SupportedApiProfile( diff --git a/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs b/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs similarity index 90% rename from sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs rename to sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs index d166afde1d..10a02cf16c 100644 --- a/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKhrReferenceNameSlotIndices.gen.cs +++ b/sources/Vulkan/Vulkan/Vulkan/VideoEncodeAv1PictureInfoKHRReferenceNameSlotIndices.gen.cs @@ -11,7 +11,7 @@ namespace Silk.NET.Vulkan; [NativeName("_referenceNameSlotIndices_e__FixedBuffer")] [InlineArray(7)] [SupportedApiProfile("vulkan")] -public partial struct VideoEncodeAv1PictureInfoKhrReferenceNameSlotIndices +public partial struct VideoEncodeAv1PictureInfoKHRReferenceNameSlotIndices { [NativeName("e0")] [SupportedApiProfile("vulkan")] diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.DoesNotIdentifyPrefix_WhenSingleName_WithNoHint.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.DoesNotIdentifyPrefix_WhenSingleName_WithNoHint.verified.txt new file mode 100644 index 0000000000..5b3fe30996 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.DoesNotIdentifyPrefix_WhenSingleName_WithNoHint.verified.txt @@ -0,0 +1,3 @@ +public enum VkPresentModeKHR +{ +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.DoesNotTrimTypeName_WhenNotMatchingHint_AndOnlyOneType.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.DoesNotIdentifyPrefix_WhenSingleName_WithNonMatchingHint.verified.txt similarity index 100% rename from tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.DoesNotTrimTypeName_WhenNotMatchingHint_AndOnlyOneType.verified.txt rename to tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.DoesNotIdentifyPrefix_WhenSingleName_WithNonMatchingHint.verified.txt diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesPrefix_WhenMatchingHint.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesPrefix_WhenMatchingHint.verified.txt new file mode 100644 index 0000000000..3e84535354 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesPrefix_WhenMatchingHint.verified.txt @@ -0,0 +1,4 @@ +[NameAffix("Prefix", "SharedPrefix", "Vk")] +public enum VkPresentModeKHR +{ +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix.verified.txt new file mode 100644 index 0000000000..fda9eee7f4 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix.verified.txt @@ -0,0 +1,7 @@ +public enum OcclusionQueryParameterNameNV +{ + [NameAffix("Prefix", "SharedPrefix", "GL_PIXEL_COUNT")] + GL_PIXEL_COUNT_NV = 34918, + [NameAffix("Prefix", "SharedPrefix", "GL_PIXEL_COUNT")] + GL_PIXEL_COUNT_AVAILABLE_NV = 34919 +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix2.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix2.verified.txt new file mode 100644 index 0000000000..e667f964d3 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix2.verified.txt @@ -0,0 +1,9 @@ +public enum VocalMorpherPhoneme +{ + [NameAffix("Prefix", "SharedPrefix", "AL_VOCAL_MORPHER_PHONEME")] + AL_VOCAL_MORPHER_PHONEME_A = 0, + [NameAffix("Prefix", "SharedPrefix", "AL_VOCAL_MORPHER_PHONEME")] + AL_VOCAL_MORPHER_PHONEME_E = 1, + [NameAffix("Prefix", "SharedPrefix", "AL_VOCAL_MORPHER_PHONEME")] + AL_VOCAL_MORPHER_PHONEME_I = 2 +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=glfw.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=glfw.verified.txt new file mode 100644 index 0000000000..80b5bf0e4f --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=glfw.verified.txt @@ -0,0 +1,17 @@ +public struct Glfw; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWallocator; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWcursor; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWgamepadstate; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWgammaramp; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWimage; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWmonitor; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWvidmode; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWwindow; \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=null.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=null.verified.txt new file mode 100644 index 0000000000..80b5bf0e4f --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefixGlfw_hint=null.verified.txt @@ -0,0 +1,17 @@ +public struct Glfw; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWallocator; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWcursor; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWgamepadstate; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWgammaramp; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWimage; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWmonitor; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWvidmode; +[NameAffix("Prefix", "SharedPrefix", "GLFW")] +public struct GLFWwindow; \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_ForTypes.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_ForTypes.verified.txt new file mode 100644 index 0000000000..ae42e933ba --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_ForTypes.verified.txt @@ -0,0 +1,9 @@ +[NameAffix("Prefix", "SharedPrefix", "VkPresent")] +public enum VkPresentModeKHR +{ +} + +[NameAffix("Prefix", "SharedPrefix", "VkPresent")] +public enum VkPresentIdKHR +{ +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt new file mode 100644 index 0000000000..cf2cfb5ef8 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt @@ -0,0 +1,10 @@ +[NameAffix("Suffix", "KhronosVendor", "KHR")] +public enum VkPresentModeKHR +{ + [NameAffix("Prefix", "SharedPrefix", "VK_PRESENT_MODE_FIFO_LATEST")] + [NameAffix("Suffix", "KhronosVendor", "KHR")] + VK_PRESENT_MODE_FIFO_LATEST_READY_KHR = 1000361000, + [NameAffix("Prefix", "SharedPrefix", "VK_PRESENT_MODE_FIFO_LATEST")] + [NameAffix("Suffix", "KhronosVendor", "EXT")] + VK_PRESENT_MODE_FIFO_LATEST_READY_EXT = VK_PRESENT_MODE_FIFO_LATEST_READY_KHR +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenSuffixesDeclared.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenSuffixesDeclared.verified.txt new file mode 100644 index 0000000000..15ef517d5e --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.IdentifiesSharedPrefix_WhenSuffixesDeclared.verified.txt @@ -0,0 +1,9 @@ +public enum OcclusionQueryParameterNameNV +{ + [NameAffix("Prefix", "SharedPrefix", "GL_PIXEL")] + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_NV = 34918, + [NameAffix("Prefix", "SharedPrefix", "GL_PIXEL")] + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_AVAILABLE_NV = 34919 +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.MultipleGlobalPrefixHints.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.MultipleGlobalPrefixHints.verified.txt new file mode 100644 index 0000000000..72bc5da1a1 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.MultipleGlobalPrefixHints.verified.txt @@ -0,0 +1,5 @@ +public enum ContextFlagsEXT +{ + [NameAffix("Prefix", "SharedPrefix", "ALC")] + ALC_CONTEXT_DEBUG_BIT_EXT +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.PreserveKhronosNamespaceEnumPrefix.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.PreserveKhronosNamespaceEnumPrefix.verified.txt similarity index 100% rename from tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.PreserveKhronosNamespaceEnumPrefix.verified.txt rename to tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.PreserveKhronosNamespaceEnumPrefix.verified.txt diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionEvalTargetNV.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionEvalTargetNV.verified.txt new file mode 100644 index 0000000000..ce47f6c2b4 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionEvalTargetNV.verified.txt @@ -0,0 +1,7 @@ +public enum EvalTargetNV +{ + [NameAffix("Prefix", "SharedPrefix", "GL")] + GL_EVAL_2D_NV, + [NameAffix("Prefix", "SharedPrefix", "GL")] + GL_EVAL_TRIANGULAR_2D_NV +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionFragmentShaderColorModMaskATI.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionFragmentShaderColorModMaskATI.verified.txt new file mode 100644 index 0000000000..c705fa7e85 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionFragmentShaderColorModMaskATI.verified.txt @@ -0,0 +1,11 @@ +public enum FragmentShaderDestModMask +{ + [NameAffix("Prefix", "SharedPrefix", "GL")] + GL_2X_BIT_ATI, + [NameAffix("Prefix", "SharedPrefix", "GL")] + GL_COMP_BIT_ATI, + [NameAffix("Prefix", "SharedPrefix", "GL")] + GL_NEGATE_BIT_ATI, + [NameAffix("Prefix", "SharedPrefix", "GL")] + GL_BIAS_BIT_ATI +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionSingleMemberEnumUsesGlobalPrefixHint.verified.txt b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionSingleMemberEnumUsesGlobalPrefixHint.verified.txt new file mode 100644 index 0000000000..129f94dbeb --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.RegressionSingleMemberEnumUsesGlobalPrefixHint.verified.txt @@ -0,0 +1,5 @@ +public enum EvalMapsModeNV +{ + [NameAffix("Prefix", "SharedPrefix", "GL")] + GL_FILL_NV +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.cs b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.cs new file mode 100644 index 0000000000..c87e545903 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/IdentifySharedPrefixesTests.cs @@ -0,0 +1,610 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; +using Silk.NET.SilkTouch.Mods; + +namespace Silk.NET.SilkTouch.UnitTests.Naming; + +public class IdentifySharedPrefixesTests +{ + static IdentifySharedPrefixesTests() + { + if (!VerifyDiffPlex.Initialized) + { + VerifyDiffPlex.Initialize(); + } + } + + [Test] + public async Task IdentifiesSharedPrefix() + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "OcclusionQueryParameterNameNV.gen.cs", + """ + public enum OcclusionQueryParameterNameNV + { + GL_PIXEL_COUNT_NV = 34918, + GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The prefix shared by the member names should be identified (GL_PIXEL_COUNT) + // The type itself should be left untouched + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task IdentifiesSharedPrefix2() + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "VocalMorpherPhoneme.gen.cs", + """ + public enum VocalMorpherPhoneme + { + AL_VOCAL_MORPHER_PHONEME_A = 0, + AL_VOCAL_MORPHER_PHONEME_E = 1, + AL_VOCAL_MORPHER_PHONEME_I = 2, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The prefix shared by the member names should be identified (AL_VOCAL_MORPHER_PHONEME) + // The type itself should be left untouched + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + [TestCase(null)] + [TestCase("glfw")] + public async Task IdentifiesSharedPrefixGlfw(string? hint) + { + // This is ported from the old NameTrimmerTests + var project = TestUtils + .CreateTestProject() + .AddDocument( + "VocalMorpherPhoneme.gen.cs", + """ + public struct Glfw; + public struct GLFWallocator; + public struct GLFWcursor; + public struct GLFWgamepadstate; + public struct GLFWgammaramp; + public struct GLFWimage; + public struct GLFWmonitor; + public struct GLFWvidmode; + public struct GLFWwindow; + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + { + GlobalPrefixHints = hint is null ? [] : [hint], + } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The hint should not affect the output because the shared prefix is shared by most of the names + // Glfw should not have a prefix + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task IdentifiesSharedPrefix_ForTypes() + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "Vk.gen.cs", + """ + public enum VkPresentModeKHR { } + public enum VkPresentIdKHR { } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The prefixes should be identified as "VkPresent", not "Vk" + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task IdentifiesSharedPrefix_WhenSuffixesDeclared() + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "OcclusionQueryParameterNameNV.gen.cs", + """ + public enum OcclusionQueryParameterNameNV + { + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_NV = 34918, + + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The declaration of the 2 NV member suffixes should make PrettifyNames trim less of the member name + // IdentifySharedPrefixes should only use the unaffixed name for prefix identification + // The shared prefix should be "GL_PIXEL" + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task HintShouldNotAffectSharedPrefixIdentification() + { + string result1; + string result2; + + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "OcclusionQueryParameterNameNV.gen.cs", + """ + public enum OcclusionQueryParameterNameNV + { + GL_PIXEL_COUNT_NV = 34918, + GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["gl"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + result1 = result!.NormalizeWhitespace().ToString(); + } + + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "OcclusionQueryParameterNameNV.gen.cs", + """ + public enum OcclusionQueryParameterNameNV + { + GL_PIXEL_COUNT_NV = 34918, + GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + result2 = result!.NormalizeWhitespace().ToString(); + } + + // The two results should match because member names share prefixes in both cases, regardless of what the hint is + // The NameAffix attributes are also required to cause the regression back when this test was first added + Assert.That(result1, Is.EqualTo(result2)); + } + + [Test] + public async Task HintShouldNotAffectSharedPrefixIdentification_WhenAffixesDeclared() + { + string result1; + string result2; + + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "OcclusionQueryParameterNameNV.gen.cs", + """ + public enum OcclusionQueryParameterNameNV + { + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_NV = 34918, + + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["gl"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + result1 = result!.NormalizeWhitespace().ToString(); + } + + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "OcclusionQueryParameterNameNV.gen.cs", + """ + public enum OcclusionQueryParameterNameNV + { + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_NV = 34918, + + [NameAffix("Suffix", "KhronosVendor", "NV")] + GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + result2 = result!.NormalizeWhitespace().ToString(); + } + + // The two results should match because member names share prefixes in both cases, regardless of what the hint is + // The NameAffix attributes are also required to cause the regression back when this test was first added + Assert.That(result1, Is.EqualTo(result2)); + } + + [Test] + public async Task IdentifiesSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict() + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "VkPresentModeKHR.gen.cs", + """ + [NameAffix("Suffix", "KhronosVendor", "KHR")] + public enum VkPresentModeKHR + { + [NameAffix("Suffix", "KhronosVendor", "KHR")] + VK_PRESENT_MODE_FIFO_LATEST_READY_KHR = 1000361000, + + [NameAffix("Suffix", "KhronosVendor", "EXT")] + VK_PRESENT_MODE_FIFO_LATEST_READY_EXT = VK_PRESENT_MODE_FIFO_LATEST_READY_KHR, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // This test should run without erroring + // This is to catch potential regressions + // where the names without affixes would conflict + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task IdentifiesPrefix_WhenMatchingHint() + { + var project = TestUtils + .CreateTestProject() + .AddDocument("VkPresentModeKHR.gen.cs", "public enum VkPresentModeKHR { }") + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["vk"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The type prefix should be identified as Vk + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task DoesNotIdentifyPrefix_WhenSingleName_WithNoHint() + { + var project = TestUtils + .CreateTestProject() + .AddDocument("VkPresentModeKHR.gen.cs", "public enum VkPresentModeKHR { }") + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // No prefix should be identified + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task DoesNotIdentifyPrefix_WhenSingleName_WithNonMatchingHint() + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "OcclusionQueryParameterNameNV.gen.cs", + "public enum OcclusionQueryParameterNameNV { }" + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["gl"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // No prefix should be identified + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task PreserveKhronosNamespaceEnumPrefix() + { + var project = TestUtils + .CreateTestProject() + .AddDocument( + "GLEnum.gen.cs", + """ + [NameAffix("Prefix", "KhronosNamespaceEnum", "GL")] + public enum GLEnum { } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["gl"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The presence of the NameAffix attribute should prevent the GL- prefix of GLEnum from being identified as a shared prefix + // This is because IdentifySharedPrefixes should only use the unaffixed name for prefix identification + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task RegressionFragmentShaderColorModMaskATI() + { + // This is ported from the old NameTrimmerTests + var project = TestUtils + .CreateTestProject() + .AddDocument( + "FragmentShaderDestModMask.gen.cs", + """ + public enum FragmentShaderDestModMask + { + GL_2X_BIT_ATI, + GL_COMP_BIT_ATI, + GL_NEGATE_BIT_ATI, + GL_BIAS_BIT_ATI, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["gl"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The identified prefix should be "GL" + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task RegressionEvalTargetNV() + { + // This is ported from the old NameTrimmerTests + var project = TestUtils + .CreateTestProject() + .AddDocument( + "EvalTargetNV.gen.cs", + """ + public enum EvalTargetNV + { + GL_EVAL_2D_NV, + GL_EVAL_TRIANGULAR_2D_NV, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["gl"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The identified prefix should be "GL" + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task RegressionSingleMemberEnumUsesGlobalPrefixHint() + { + // This is ported from the old NameTrimmerTests + var project = TestUtils + .CreateTestProject() + .AddDocument( + "EvalMapsModeNV.gen.cs", + """ + public enum EvalMapsModeNV + { + GL_FILL_NV, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["gl"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The identified prefix should be "GL" + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } + + [Test] + public async Task MultipleGlobalPrefixHints() + { + // This is ported from the old NameTrimmerTests + var project = TestUtils + .CreateTestProject() + .AddDocument( + "ContextFlagsEXT.gen.cs", + """ + public enum ContextFlagsEXT + { + ALC_CONTEXT_DEBUG_BIT_EXT, + } + """ + ) + .Project; + + var context = new DummyModContext() { SourceProject = project }; + + var identifySharedPrefixes = new IdentifySharedPrefixes( + new DummyOptions( + new IdentifySharedPrefixes.Configuration() { GlobalPrefixHints = ["alc", "al"] } + ) + ); + + await identifySharedPrefixes.ExecuteAsync(context); + + // The identified prefix should be "ALC" + var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); + await Verify(result!.NormalizeWhitespace().ToString()); + } +} diff --git a/tests/SilkTouch/SilkTouch/Naming/NamePrettifierTests.cs b/tests/SilkTouch/SilkTouch/Naming/NamePrettifierTests.cs index 206162a001..b60e81f769 100644 --- a/tests/SilkTouch/SilkTouch/Naming/NamePrettifierTests.cs +++ b/tests/SilkTouch/SilkTouch/Naming/NamePrettifierTests.cs @@ -71,17 +71,21 @@ public string AcronymsWithNumbers2(string input, int longAcronymThreshold = 0) = public string ConsecutiveAcronyms(string input, int longAcronymThreshold = 0) => new NamePrettifier(longAcronymThreshold).Prettify(input); + /// + /// C# identifiers cannot start with numbers, but no longer handles this + /// in favor of calling separately. + /// [Theory] - // C# identifiers cannot start with numbers - [TestCase("123", ExpectedResult = "X123")] - [TestCase("123Hello", ExpectedResult = "X123Hello")] + [TestCase("123", ExpectedResult = "123")] + [TestCase("123Hello", ExpectedResult = "123Hello")] public string StartsWithNumber(string input, int longAcronymThreshold = 0) => new NamePrettifier(longAcronymThreshold).Prettify(input); [Theory] // Add x between numbers to maintain separation - [TestCase("123_123_123", ExpectedResult = "X123x123x123")] + [TestCase("123_123_123", ExpectedResult = "123x123x123")] [TestCase("Hello123_123_123", ExpectedResult = "Hello123x123x123")] + [TestCase("Hello123X123X123", ExpectedResult = "Hello123x123x123")] public string ConsecutiveNumbers(string input, int longAcronymThreshold = 0) => new NamePrettifier(longAcronymThreshold).Prettify(input); @@ -171,4 +175,18 @@ public void Lowercase_AfterNumber_IsPartOf_NewWord() Assert.That(nameTransformer.Prettify("MONO16f"), Is.EqualTo("Mono16F")); } } + + [Test] + public void EmptyInput_IsAllowed() + { + var nameTransformer = new NamePrettifier(4); + nameTransformer.Prettify(""); + } + + [Test] + public void EmptyOutput_IsAllowed() + { + var nameTransformer = new NamePrettifier(4); + nameTransformer.Prettify("_"); + } } diff --git a/tests/SilkTouch/SilkTouch/Naming/NameSplitterTests.cs b/tests/SilkTouch/SilkTouch/Naming/NameSplitterTests.cs index 2bf02680a8..a227ab2cd9 100644 --- a/tests/SilkTouch/SilkTouch/Naming/NameSplitterTests.cs +++ b/tests/SilkTouch/SilkTouch/Naming/NameSplitterTests.cs @@ -12,7 +12,7 @@ public void SplitByCasing() { using (Assert.EnterMultipleScope()) { - Assert.That(NameSplitter.BreakIntoWords("HelloWorld"), Is.EqualTo(["Hello", "World"])); + Assert.That(NameSplitter.SplitIntoWords("HelloWorld"), Is.EqualTo(["Hello", "World"])); } } @@ -21,9 +21,9 @@ public void SplitBySeparator() { using (Assert.EnterMultipleScope()) { - Assert.That(NameSplitter.BreakIntoWords("Hello_World"), Is.EqualTo(["Hello", "World"])); + Assert.That(NameSplitter.SplitIntoWords("Hello_World"), Is.EqualTo(["Hello", "World"])); Assert.That( - NameSplitter.BreakIntoWords("_Hello_World_"), + NameSplitter.SplitIntoWords("_Hello_World_"), Is.EqualTo(["Hello", "World"]) ); } @@ -34,12 +34,12 @@ public void PreserveAcronym() { using (Assert.EnterMultipleScope()) { - Assert.That(NameSplitter.BreakIntoWords("HelloUI"), Is.EqualTo(["Hello", "UI"])); - Assert.That(NameSplitter.BreakIntoWords("HelloGUI"), Is.EqualTo(["Hello", "GUI"])); - Assert.That(NameSplitter.BreakIntoWords("GUIHello"), Is.EqualTo(["GUI", "Hello"])); - Assert.That(NameSplitter.BreakIntoWords("GUI_Hello"), Is.EqualTo(["GUI", "Hello"])); + Assert.That(NameSplitter.SplitIntoWords("HelloUI"), Is.EqualTo(["Hello", "UI"])); + Assert.That(NameSplitter.SplitIntoWords("HelloGUI"), Is.EqualTo(["Hello", "GUI"])); + Assert.That(NameSplitter.SplitIntoWords("GUIHello"), Is.EqualTo(["GUI", "Hello"])); + Assert.That(NameSplitter.SplitIntoWords("GUI_Hello"), Is.EqualTo(["GUI", "Hello"])); Assert.That( - NameSplitter.BreakIntoWords("ABC_XYZ_Hello"), + NameSplitter.SplitIntoWords("ABC_XYZ_Hello"), Is.EqualTo(["ABC", "XYZ", "Hello"]) ); } @@ -50,9 +50,10 @@ public void SplitByNumber() { using (Assert.EnterMultipleScope()) { - Assert.That(NameSplitter.BreakIntoWords("123"), Is.EqualTo(["123"])); - Assert.That(NameSplitter.BreakIntoWords("A123A"), Is.EqualTo(["A", "123", "A"])); - Assert.That(NameSplitter.BreakIntoWords("a123a"), Is.EqualTo(["a", "123", "a"])); + Assert.That(NameSplitter.SplitIntoWords("Image2D"), Is.EqualTo(["Image", "2", "D"])); + Assert.That(NameSplitter.SplitIntoWords("123"), Is.EqualTo(["123"])); + Assert.That(NameSplitter.SplitIntoWords("A123A"), Is.EqualTo(["A", "123", "A"])); + Assert.That(NameSplitter.SplitIntoWords("a123a"), Is.EqualTo(["a", "123", "a"])); } } @@ -61,8 +62,8 @@ public void SplitNumberOtherNumberPattern() { using (Assert.EnterMultipleScope()) { - Assert.That(NameSplitter.BreakIntoWords("8x8"), Is.EqualTo(["8", "x", "8"])); - Assert.That(NameSplitter.BreakIntoWords("8X8"), Is.EqualTo(["8", "X", "8"])); + Assert.That(NameSplitter.SplitIntoWords("8x8"), Is.EqualTo(["8", "x", "8"])); + Assert.That(NameSplitter.SplitIntoWords("8X8"), Is.EqualTo(["8", "X", "8"])); } } @@ -72,7 +73,7 @@ public void ComplexCases() using (Assert.EnterMultipleScope()) { Assert.That( - NameSplitter.BreakIntoWords("SpvImageFormatR32ui"), + NameSplitter.SplitIntoWords("SpvImageFormatR32ui"), Is.EqualTo(["Spv", "Image", "Format", "R", "32", "ui"]) ); } diff --git a/tests/SilkTouch/SilkTouch/Naming/NameTrimmerTests.cs b/tests/SilkTouch/SilkTouch/Naming/NameTrimmerTests.cs deleted file mode 100644 index c2dcdae2f8..0000000000 --- a/tests/SilkTouch/SilkTouch/Naming/NameTrimmerTests.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Silk.NET.SilkTouch.Mods; -using Silk.NET.SilkTouch.Naming; - -namespace Silk.NET.SilkTouch.UnitTests.Naming; - -public class NameTrimmerTests : NameTrimmer -{ - [Test, TestCase(null), TestCase("glfw")] - public void SimpleGlfwTestDetermination(string? hint) - { - var test = new Dictionary - { - { "GLFWallocator", new CandidateNames("GLFWallocator", []) }, - { "GLFWgammaramp", new CandidateNames("GLFWgammaramp", []) }, - { "GLFWgamepadstate", new CandidateNames("GLFWgamepadstate", []) }, - { "GLFWvidmode", new CandidateNames("GLFWvidmode", []) }, - { "GLFWimage", new CandidateNames("GLFWimage", []) }, - { "Glfw", new CandidateNames("Glfw", []) }, - { "GLFWcursor", new CandidateNames("GLFWcursor", []) }, - { "GLFWmonitor", new CandidateNames("GLFWmonitor", []) }, - { "GLFWwindow", new CandidateNames("GLFWwindow", []) }, - }; - Assert.That( - GetPrefix(null, hint, test, null, null, false, true)?.Prefix, - Is.EqualTo("GLFW") - ); - Trim( - new NameTrimmerContext - { - Configuration = new PrettifyNames.Configuration - { - GlobalPrefixHints = hint is null ? null : [hint], - }, - Names = test, - JobKey = "GLFW", - } - ); - var expected = new Dictionary - { - { "GLFWallocator", "Allocator" }, - { "GLFWgammaramp", "Gammaramp" }, - { "GLFWgamepadstate", "Gamepadstate" }, - { "GLFWvidmode", "Vidmode" }, - { "GLFWimage", "Image" }, - { "Glfw", "Glfw" }, - { "GLFWcursor", "Cursor" }, - { "GLFWmonitor", "Monitor" }, - { "GLFWwindow", "Window" }, - }; - foreach (var (key, (trimmed, _)) in test) - { - Assert.That(new NamePrettifier(4).Prettify(trimmed), Is.EqualTo(expected[key])); - } - } - - [Test] - public void RegressionFragmentShaderColorModMaskATI() - { - var test = new Dictionary - { - { "GL_2X_BIT_ATI", new CandidateNames("GL_2X_BIT_ATI", []) }, - { "GL_COMP_BIT_ATI", new CandidateNames("GL_COMP_BIT_ATI", []) }, - { "GL_NEGATE_BIT_ATI", new CandidateNames("GL_NEGATE_BIT_ATI", []) }, - { "GL_BIAS_BIT_ATI", new CandidateNames("GL_BIAS_BIT_ATI", []) }, - }; - Trim( - new NameTrimmerContext - { - Container = "FragmentShaderColorModMaskATI", - Configuration = new PrettifyNames.Configuration { GlobalPrefixHints = ["gl"] }, - Names = test, - JobKey = "OpenGL", - } - ); - var expected = new Dictionary - { - { "GL_2X_BIT_ATI", "X2XBitAti" }, - { "GL_COMP_BIT_ATI", "CompBitAti" }, - { "GL_NEGATE_BIT_ATI", "NegateBitAti" }, - { "GL_BIAS_BIT_ATI", "BiasBitAti" }, - }; - foreach (var (key, (trimmed, _)) in test) - { - Assert.That(new NamePrettifier(4).Prettify(trimmed), Is.EqualTo(expected[key])); - } - } - - [Test] - public void RegressionEvalTargetNV() - { - var test = new Dictionary - { - { "GL_EVAL_2D_NV", new CandidateNames("GL_EVAL_2D_NV", []) }, - { "GL_EVAL_TRIANGULAR_2D_NV", new CandidateNames("GL_EVAL_TRIANGULAR_2D_NV", []) }, - }; - Trim( - new NameTrimmerContext - { - Container = "EvalTargetNV", - Configuration = new PrettifyNames.Configuration { GlobalPrefixHints = ["gl"] }, - Names = test, - JobKey = "OpenGL", - } - ); - var expected = new Dictionary - { - { "GL_EVAL_2D_NV", "Eval2DNv" }, - { "GL_EVAL_TRIANGULAR_2D_NV", "EvalTriangular2DNv" }, - }; - foreach (var (key, (trimmed, _)) in test) - { - Assert.That(new NamePrettifier(4).Prettify(trimmed), Is.EqualTo(expected[key])); - } - } - - [Test] - public void RegressionSingleMemberEnumUsesGlobalPrefixHint() - { - var names = new Dictionary - { - { "GL_FILL_NV", new CandidateNames("GL_FILL_NV", []) }, - }; - var ctx = new NameTrimmerContext - { - Configuration = new PrettifyNames.Configuration { GlobalPrefixHints = ["gl"] }, - Container = "EvalMapsModeNV", - JobKey = "OpenGL", - Names = names, - }; - var uut = new NameTrimmer(); - uut.Trim(ctx); - Assert.That(names["GL_FILL_NV"].Primary, Is.EqualTo("FILL_NV")); - } - - [Test] - public void MultipleGlobalPrefixHints() - { - var names = new Dictionary - { - { "ALC_CONTEXT_DEBUG_BIT_EXT", new CandidateNames("ALC_CONTEXT_DEBUG_BIT_EXT", []) }, - }; - var ctx = new NameTrimmerContext - { - Configuration = new PrettifyNames.Configuration { GlobalPrefixHints = ["alc", "al"] }, - Container = "ContextFlagsEXT", - JobKey = "OpenAL", - Names = names, - }; - var uut = new NameTrimmer(); - uut.Trim(ctx); - Assert.That( - names["ALC_CONTEXT_DEBUG_BIT_EXT"].Primary, - Is.EqualTo("CONTEXT_DEBUG_BIT_EXT") - ); - } -} diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.ConflictsAreResolved_ForMethodsAndConstants.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.ConflictsAreResolved_ForMethodsAndConstants.verified.txt new file mode 100644 index 0000000000..82cbc8b186 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.ConflictsAreResolved_ForMethodsAndConstants.verified.txt @@ -0,0 +1,7 @@ +public class Sdl +{ + public static delegate* MainValue => &Main; + + [NameAffix("Prefix", "SharedPrefix", "SDL")] + public static extern int Main(int argc, sbyte** argv); +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.Regression_IncorrectSecondary_ChosenAsFallback.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.FallbackIsChosenCorrectly.verified.txt similarity index 70% rename from tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.Regression_IncorrectSecondary_ChosenAsFallback.verified.txt rename to tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.FallbackIsChosenCorrectly.verified.txt index 1dfd9680df..2fcf850618 100644 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.Regression_IncorrectSecondary_ChosenAsFallback.verified.txt +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.FallbackIsChosenCorrectly.verified.txt @@ -1,21 +1,17 @@ public class AL { + [NameAffix("Prefix", "SharedPrefix", "al")] [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] [NameAffix("Suffix", "KhronosVendor", "SOFT")] public void GetBufferPtrDirectSOFT() { } + [NameAffix("Prefix", "SharedPrefix", "al")] [NameAffix("Suffix", "KhronosFunctionDataType", "v")] [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] [NameAffix("Suffix", "KhronosVendor", "SOFT")] public void GetBufferPtrvDirectSOFT() { } - - // This is to ensure that prefix identification doesn't trim too much - [NameAffix("Suffix", "KhronosFunctionDataType", "i")] - public void Filter() - { - } } \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.FallbackIsChosenCorrectly_ReversedPriority.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.FallbackIsChosenCorrectly_ReversedPriority.verified.txt new file mode 100644 index 0000000000..dbf9e98f30 --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.FallbackIsChosenCorrectly_ReversedPriority.verified.txt @@ -0,0 +1,17 @@ +public class AL +{ + [NameAffix("Prefix", "SharedPrefix", "al")] + [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + public void GetBufferPtrDirectSOFT() + { + } + + [NameAffix("Prefix", "SharedPrefix", "al")] + [NameAffix("Suffix", "KhronosFunctionDataType", "v")] + [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + public void alGetBufferPtrDirectSOFT() + { + } +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.InconsistentCasing_LettersFollowingNumbers_WhenAffixesDeclared.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.InconsistentCasing_LettersFollowingNumbers_WhenAffixesDeclared.verified.txt index ecb0d71c12..8721f7cebd 100644 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.InconsistentCasing_LettersFollowingNumbers_WhenAffixesDeclared.verified.txt +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.InconsistentCasing_LettersFollowingNumbers_WhenAffixesDeclared.verified.txt @@ -1,15 +1,19 @@ public enum GLEnum { + [NameAffix("Prefix", "SharedPrefix", "GL")] [NameAffix("Suffix", "KhronosVendor", "EXT")] Rgb16EXT = 32852, + [NameAffix("Prefix", "SharedPrefix", "GL")] [NameAffix("Suffix", "KhronosVendor", "EXT")] Rgb16FEXT = 34843, } public enum ALEnum { + [NameAffix("Prefix", "SharedPrefix", "AL")] [NameAffix("Suffix", "KhronosVendor", "SOFT")] Mono16SOFT = 4353, + [NameAffix("Prefix", "SharedPrefix", "AL")] [NameAffix("Suffix", "KhronosVendor", "SOFT")] Mono32FSOFT = 65552, } \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.Regression_UnexpectedCasingChangesInFormatEnums.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.Regression_UnexpectedCasingChangesInFormatEnums.verified.txt index 9d50423d57..a7cb359827 100644 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.Regression_UnexpectedCasingChangesInFormatEnums.verified.txt +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.Regression_UnexpectedCasingChangesInFormatEnums.verified.txt @@ -1,7 +1,9 @@ public enum InternalFormat { + [NameAffix("Prefix", "SharedPrefix", "GL")] [NameAffix("Suffix", "KhronosVendor", "ARB")] Rgba32FARB = 34836, + [NameAffix("Prefix", "SharedPrefix", "GL")] [NameAffix("Suffix", "KhronosVendor", "ARB")] Rgb32FARB = 34837, } \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes.verified.txt new file mode 100644 index 0000000000..df3e0cb7be --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes.verified.txt @@ -0,0 +1,14 @@ +[NameAffix("Suffix", "Test", "ShouldBeInOutputName")] +public struct GamepadBindingShouldBeInOutputName +{ +} + +[NameAffix("Prefix", "NestedStructParent", nameof(GamepadBindingShouldBeInOutputName))] +public struct GamepadBindingShouldBeInOutputNameInput +{ +} + +[NameAffix("Prefix", "NestedStructParent", nameof(GamepadBindingShouldBeInOutputNameInput))] +public struct GamepadBindingShouldBeInOutputNameInputAxis +{ +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_FromParentScope.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_FromParentScope.verified.txt new file mode 100644 index 0000000000..7b445817ef --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_FromParentScope.verified.txt @@ -0,0 +1,6 @@ +[NameAffix("Suffix", "Test", "Suffix")] +public struct ASuffix +{ + [NameAffix("Suffix", "Test", nameof(ASuffix))] + public static int BASuffix; +} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_WhenOverridden.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_WhenOverridden.verified.txt new file mode 100644 index 0000000000..4a49dc4b7a --- /dev/null +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.SuccessfullyUsesReferencedAffixes_WhenOverridden.verified.txt @@ -0,0 +1,4 @@ +public struct BufferCallbackSOFT; +[NameAffix("Prefix", "FunctionPointerParent", nameof(BufferCallbackSOFT))] +[NameAffix("Suffix", "FunctionPointerDelegateType", "Delegate")] +public delegate int BufferCallbackSOFTDelegate(); \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsPrefix_WhenMatchingHint.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsPrefix_WhenMatchingHint.verified.txt deleted file mode 100644 index f1b60dc396..0000000000 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsPrefix_WhenMatchingHint.verified.txt +++ /dev/null @@ -1,3 +0,0 @@ -public enum PresentModeKhr -{ -} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix.verified.txt deleted file mode 100644 index 9dae8fbf05..0000000000 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix.verified.txt +++ /dev/null @@ -1,5 +0,0 @@ -public enum OcclusionQueryParameterNameNV -{ - Nv = 34918, - AvailableNv = 34919, -} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix2.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix2.verified.txt deleted file mode 100644 index 268d9a10e9..0000000000 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix2.verified.txt +++ /dev/null @@ -1,6 +0,0 @@ -public enum VocalMorpherPhoneme -{ - A = 0, - E = 1, - I = 2, -} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_ForTypes.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_ForTypes.verified.txt deleted file mode 100644 index 584ba3824f..0000000000 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_ForTypes.verified.txt +++ /dev/null @@ -1,7 +0,0 @@ -public enum ModeKhr -{ -} - -public enum IdKhr -{ -} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared.verified.txt deleted file mode 100644 index 5bffc42913..0000000000 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared.verified.txt +++ /dev/null @@ -1,7 +0,0 @@ -public enum OcclusionQueryParameterNameNV -{ - [NameAffix("Suffix", "KhronosVendor", "NV")] - CountNV = 34918, - [NameAffix("Suffix", "KhronosVendor", "NV")] - CountAvailableNV = 34919, -} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt deleted file mode 100644 index b4cf1ecbe0..0000000000 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.TrimsSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict.verified.txt +++ /dev/null @@ -1,8 +0,0 @@ -[NameAffix("Suffix", "KhronosVendor", "KHR")] -public enum VkPresentModeKHR -{ - [NameAffix("Suffix", "KhronosVendor", "KHR")] - ReadyKHR = 1000361000, - [NameAffix("Suffix", "KhronosVendor", "EXT")] - ReadyEXT = ReadyKHR, -} \ No newline at end of file diff --git a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.cs b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.cs index d4576a8c84..57a296fbec 100644 --- a/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.cs +++ b/tests/SilkTouch/SilkTouch/Naming/PrettifyNamesTests.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis; using Microsoft.Extensions.Logging.Abstractions; using Silk.NET.SilkTouch.Mods; -using Silk.NET.SilkTouch.Naming; namespace Silk.NET.SilkTouch.UnitTests.Naming; @@ -19,17 +18,22 @@ static PrettifyNamesTests() } [Test] - public async Task TrimsSharedPrefix() + public async Task Regression_UnexpectedCasingChangesInFormatEnums() { var project = TestUtils .CreateTestProject() .AddDocument( - "OcclusionQueryParameterNameNV.gen.cs", + "InternalFormat.gen.cs", """ - public enum OcclusionQueryParameterNameNV + public enum InternalFormat { - GL_PIXEL_COUNT_NV = 34918, - GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + [NameAffix("Prefix", "SharedPrefix", "GL")] + [NameAffix("Suffix", "KhronosVendor", "ARB")] + GL_RGBA32F_ARB = 34836, + + [NameAffix("Prefix", "SharedPrefix", "GL")] + [NameAffix("Suffix", "KhronosVendor", "ARB")] + GL_RGB32F_ARB = 34837, } """ ) @@ -39,31 +43,61 @@ public enum OcclusionQueryParameterNameNV var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions(new PrettifyNames.Configuration()), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions( + new PrettifyNames.Configuration() + { + LongAcronymThreshold = 3, + Affixes = + { + { + "SharedPrefix", + new PrettifyNames.NameAffixConfiguration() { Remove = true } + }, + }, + } + ) ); await prettifyNames.ExecuteAsync(context); - // The prefix shared by the member names should be trimmed - // The type name should not be modified + // This is to catch a bug revealed by changing NameTrimmer to be executed after affix removal by NameAffixerEarlyTrimmer + // The underlying reason is actually unrelated and was an issue that existed long before + // NameUtilsTests.Prettify_IsNotAffectedBy_TrailingUnderscore tests for the underlying issue + // + // While the core issue is already covered by another test, + // this test is kept because the format enums tend to be a bit sensitive to codebase changes var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); } [Test] - public async Task TrimsSharedPrefix2() + public async Task InconsistentCasing_LettersFollowingNumbers_WhenAffixesDeclared() { var project = TestUtils .CreateTestProject() .AddDocument( - "VocalMorpherPhoneme.gen.cs", + "Test.gen.cs", """ - public enum VocalMorpherPhoneme + public enum GLEnum { - AL_VOCAL_MORPHER_PHONEME_A = 0, - AL_VOCAL_MORPHER_PHONEME_E = 1, - AL_VOCAL_MORPHER_PHONEME_I = 2, + [NameAffix("Prefix", "SharedPrefix", "GL")] + [NameAffix("Suffix", "KhronosVendor", "EXT")] + GL_RGB16_EXT = 32852, + + [NameAffix("Prefix", "SharedPrefix", "GL")] + [NameAffix("Suffix", "KhronosVendor", "EXT")] + GL_RGB16F_EXT = 34843, + } + + public enum ALEnum + { + [NameAffix("Prefix", "SharedPrefix", "AL")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + AL_MONO16_SOFT = 4353, + + [NameAffix("Prefix", "SharedPrefix", "AL")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + AL_MONO32F_SOFT = 65552, } """ ) @@ -73,28 +107,53 @@ public enum VocalMorpherPhoneme var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions(new PrettifyNames.Configuration()), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions( + new PrettifyNames.Configuration() + { + LongAcronymThreshold = 4, + Affixes = + { + { + "SharedPrefix", + new PrettifyNames.NameAffixConfiguration() { Remove = true } + }, + }, + } + ) ); await prettifyNames.ExecuteAsync(context); - // The prefix shared by the member names should be trimmed - // The type name should not be modified + // This is to catch an inconsistency related to how letters following numbers are handled + // In both cases, MONO should be prettified as Mono + // NameUtilsTests.Prettify_Capital_AfterNumber_DoesNotAffect_PreviousWord tests for the underlying issue + // + // Note that the NameAffix attributes do affect the output var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); } [Test] - public async Task TrimsSharedPrefix_ForTypes() + public async Task FallbackIsChosenCorrectly() { var project = TestUtils .CreateTestProject() .AddDocument( - "Vk.gen.cs", + "AL.gen.cs", """ - public enum VkPresentModeKHR { } - public enum VkPresentIdKHR { } + public class AL + { + [NameAffix("Prefix", "SharedPrefix", "al")] + [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + public void alGetBufferPtrDirectSOFT() { } + + [NameAffix("Prefix", "SharedPrefix", "al")] + [NameAffix("Suffix", "KhronosFunctionDataType", "v")] + [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + public void alGetBufferPtrvDirectSOFT() { } + } """ ) .Project; @@ -103,32 +162,66 @@ public enum VkPresentIdKHR { } var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions(new PrettifyNames.Configuration()), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions( + new PrettifyNames.Configuration() + { + LongAcronymThreshold = 4, + Affixes = + { + { + "SharedPrefix", + new PrettifyNames.NameAffixConfiguration() + { + DiscriminatorPriority = 0, + IsDiscriminator = true, + } + }, + { + "KhronosFunctionDataType", + new PrettifyNames.NameAffixConfiguration() + { + DiscriminatorPriority = 1, + IsDiscriminator = true, + } + }, + }, + } + ) ); await prettifyNames.ExecuteAsync(context); - // The type names should be trimmed as ModeKHR and IdKHR + // This is to catch a regression where choosing the shortest secondary available is not always correct + // The second method (with the -v suffix) should not have the shared prefix restored + // Eg: We don't want AlGetBufferPtr + // + // The expected output is: + // GetBufferPtrDirectSOFT + // GetBufferPtrvDirectSOFT var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); } [Test] - public async Task TrimsSharedPrefix_WhenAffixesDeclared() + public async Task FallbackIsChosenCorrectly_ReversedPriority() { var project = TestUtils .CreateTestProject() .AddDocument( - "OcclusionQueryParameterNameNV.gen.cs", + "AL.gen.cs", """ - public enum OcclusionQueryParameterNameNV + public class AL { - [NameAffix("Suffix", "KhronosVendor", "NV")] - GL_PIXEL_COUNT_NV = 34918, + [NameAffix("Prefix", "SharedPrefix", "al")] + [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + public void alGetBufferPtrDirectSOFT() { } - [NameAffix("Suffix", "KhronosVendor", "NV")] - GL_PIXEL_COUNT_AVAILABLE_NV = 34919, + [NameAffix("Prefix", "SharedPrefix", "al")] + [NameAffix("Suffix", "KhronosFunctionDataType", "v")] + [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] + [NameAffix("Suffix", "KhronosVendor", "SOFT")] + public void alGetBufferPtrvDirectSOFT() { } } """ ) @@ -138,187 +231,60 @@ public enum OcclusionQueryParameterNameNV var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions(new PrettifyNames.Configuration()), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions( + new PrettifyNames.Configuration() + { + LongAcronymThreshold = 4, + Affixes = + { + { + "SharedPrefix", + new PrettifyNames.NameAffixConfiguration() + { + DiscriminatorPriority = 1, + IsDiscriminator = true, + } + }, + { + "KhronosFunctionDataType", + new PrettifyNames.NameAffixConfiguration() + { + DiscriminatorPriority = 0, + IsDiscriminator = true, + } + }, + }, + } + ) ); await prettifyNames.ExecuteAsync(context); - // The declaration of the 2 NV member suffixes should make PrettifyNames trim less of the member name - // This is because NameTrimmer only sees the name without the suffixes - // The type name should remain unchanged except for the removal of the NV suffix + // This ensures that the config is respected // - // Note: When this test was first added, the names were not being trimmed at all. - // The fix was to ensure NameTrimmer.GetTrimmingName trimmed the trailing underscore. + // The expected output is: + // GetBufferPtrDirectSOFT + // alGetBufferPtrDirectSOFT (affixes are not prettified by default) var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); } [Test] - public async Task HintShouldNotAffectSharedPrefixTrimming() - { - string result1; - string result2; - - { - var project = TestUtils - .CreateTestProject() - .AddDocument( - "OcclusionQueryParameterNameNV.gen.cs", - """ - public enum OcclusionQueryParameterNameNV - { - GL_PIXEL_COUNT_NV = 34918, - GL_PIXEL_COUNT_AVAILABLE_NV = 34919, - } - """ - ) - .Project; - - var context = new DummyModContext() { SourceProject = project }; - - var prettifyNames = new PrettifyNames( - NullLogger.Instance, - new DummyOptions( - new PrettifyNames.Configuration() { GlobalPrefixHints = ["gl"] } - ), - [new DummyJobDependency([new NameTrimmer()])] - ); - - await prettifyNames.ExecuteAsync(context); - - var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); - result1 = result!.NormalizeWhitespace().ToString(); - } - - { - var project = TestUtils - .CreateTestProject() - .AddDocument( - "OcclusionQueryParameterNameNV.gen.cs", - """ - public enum OcclusionQueryParameterNameNV - { - GL_PIXEL_COUNT_NV = 34918, - GL_PIXEL_COUNT_AVAILABLE_NV = 34919, - } - """ - ) - .Project; - - var context = new DummyModContext() { SourceProject = project }; - - var prettifyNames = new PrettifyNames( - NullLogger.Instance, - new DummyOptions(new PrettifyNames.Configuration()), - [new DummyJobDependency([new NameTrimmer()])] - ); - - await prettifyNames.ExecuteAsync(context); - - var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); - result2 = result!.NormalizeWhitespace().ToString(); - } - - // The two results should match because member names share prefixes in both cases, regardless of what the hint is - // The NameAffix attributes are also required to cause the regression back when this test was first added - Assert.That(result1, Is.EqualTo(result2)); - } - - [Test] - public async Task HintShouldNotAffectSharedPrefixTrimming_WhenAffixesDeclared() - { - string result1; - string result2; - - { - var project = TestUtils - .CreateTestProject() - .AddDocument( - "OcclusionQueryParameterNameNV.gen.cs", - """ - public enum OcclusionQueryParameterNameNV - { - [NameAffix("Suffix", "KhronosVendor", "NV")] - GL_PIXEL_COUNT_NV = 34918, - - [NameAffix("Suffix", "KhronosVendor", "NV")] - GL_PIXEL_COUNT_AVAILABLE_NV = 34919, - } - """ - ) - .Project; - - var context = new DummyModContext() { SourceProject = project }; - - var prettifyNames = new PrettifyNames( - NullLogger.Instance, - new DummyOptions( - new PrettifyNames.Configuration() { GlobalPrefixHints = ["gl"] } - ), - [new DummyJobDependency([new NameTrimmer()])] - ); - - await prettifyNames.ExecuteAsync(context); - - var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); - result1 = result!.NormalizeWhitespace().ToString(); - } - - { - var project = TestUtils - .CreateTestProject() - .AddDocument( - "OcclusionQueryParameterNameNV.gen.cs", - """ - public enum OcclusionQueryParameterNameNV - { - [NameAffix("Suffix", "KhronosVendor", "NV")] - GL_PIXEL_COUNT_NV = 34918, - - [NameAffix("Suffix", "KhronosVendor", "NV")] - GL_PIXEL_COUNT_AVAILABLE_NV = 34919, - } - """ - ) - .Project; - - var context = new DummyModContext() { SourceProject = project }; - - var prettifyNames = new PrettifyNames( - NullLogger.Instance, - new DummyOptions(new PrettifyNames.Configuration()), - [new DummyJobDependency([new NameTrimmer()])] - ); - - await prettifyNames.ExecuteAsync(context); - - var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); - result2 = result!.NormalizeWhitespace().ToString(); - } - - // The two results should match because member names share prefixes in both cases, regardless of what the hint is - // The NameAffix attributes are also required to cause the regression back when this test was first added - Assert.That(result1, Is.EqualTo(result2)); - } - - [Test] - public async Task TrimsSharedPrefix_WhenAffixesDeclared_AndNamesWithoutAffixesConflict() + public async Task SuccessfullyUsesReferencedAffixes() { var project = TestUtils .CreateTestProject() .AddDocument( - "VkPresentModeKHR.gen.cs", + "SDL.gen.cs", """ - [NameAffix("Suffix", "KhronosVendor", "KHR")] - public enum VkPresentModeKHR - { - [NameAffix("Suffix", "KhronosVendor", "KHR")] - VK_PRESENT_MODE_FIFO_LATEST_READY_KHR = 1000361000, + [NameAffix("Suffix", "Test", "ShouldBeInOutputName")] + public struct GamepadBinding { } - [NameAffix("Suffix", "KhronosVendor", "EXT")] - VK_PRESENT_MODE_FIFO_LATEST_READY_EXT = VK_PRESENT_MODE_FIFO_LATEST_READY_KHR, - } + [NameAffix("Prefix", "NestedStructParent", nameof(GamepadBinding))] + public struct GamepadBindingInput { } + + [NameAffix("Prefix", "NestedStructParent", nameof(GamepadBindingInput))] + public struct GamepadBindingInputAxis { } """ ) .Project; @@ -327,52 +293,65 @@ public enum VkPresentModeKHR var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions(new PrettifyNames.Configuration()), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions(new PrettifyNames.Configuration()) ); await prettifyNames.ExecuteAsync(context); - // This test should run without erroring - // This is to catch a regression where NameTrimmer would error - // since the names with the affixes removed would conflict + // All names should start with GamepadBindingShouldBeInOutputName var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); } [Test] - public async Task TrimsPrefix_WhenMatchingHint() + public async Task SuccessfullyUsesReferencedAffixes_FromParentScope() { + // Note that at time of writing, no nested scopes are supported + // This means that the only valid scope is the global scope var project = TestUtils .CreateTestProject() - .AddDocument("VkPresentModeKHR.gen.cs", "public enum VkPresentModeKHR { }") + .AddDocument( + "Test.gen.cs", + """ + [NameAffix("Suffix", "Test", "Suffix")] + public struct A + { + [NameAffix("Suffix", "Test", nameof(A))] + public static int B; + } + """ + ) .Project; var context = new DummyModContext() { SourceProject = project }; var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions( - new PrettifyNames.Configuration() { GlobalPrefixHints = ["vk"] } - ), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions(new PrettifyNames.Configuration()) ); await prettifyNames.ExecuteAsync(context); - // The type name should be trimmed as PresentModeKHR + // A should become ASuffix + // B should become BASuffix var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); } [Test] - public async Task DoesNotTrimTypeName_WhenNotMatchingHint_AndOnlyOneType() + public async Task SuccessfullyUsesReferencedAffixes_WhenOverridden() { var project = TestUtils .CreateTestProject() .AddDocument( - "OcclusionQueryParameterNameNV.gen.cs", - "public enum OcclusionQueryParameterNameNV { }" + "AL.gen.cs", + """ + public struct ALBUFFERCALLBACKTYPESOFT; + + [NameAffix("Prefix", "FunctionPointerParent", nameof(ALBUFFERCALLBACKTYPESOFT))] + [NameAffix("Suffix", "FunctionPointerDelegateType", "Delegate")] + public delegate int ALBUFFERCALLBACKTYPESOFTDelegate(); + """ ) .Project; @@ -381,34 +360,33 @@ public async Task DoesNotTrimTypeName_WhenNotMatchingHint_AndOnlyOneType() var prettifyNames = new PrettifyNames( NullLogger.Instance, new DummyOptions( - new PrettifyNames.Configuration() { GlobalPrefixHints = ["gl"] } - ), - [new DummyJobDependency([new NameTrimmer()])] + new PrettifyNames.Configuration() + { + NameOverrides = { { "ALBUFFERCALLBACKTYPESOFT", "BufferCallbackSOFT" } }, + } + ) ); await prettifyNames.ExecuteAsync(context); - // The type name should remain as OcclusionQueryParameterNameNV + // Both names should be affected by the override var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); } [Test] - public async Task Regression_UnexpectedCasingChangesInFormatEnums() + public void CycleInReferencedAffixes_Throws() { var project = TestUtils .CreateTestProject() .AddDocument( - "InternalFormat.gen.cs", + "Test.gen.cs", """ - public enum InternalFormat - { - [NameAffix("Suffix", "KhronosVendor", "ARB")] - GL_RGBA32F_ARB = 34836, + [NameAffix("Suffix", "Test", nameof(B))] + public struct A { } - [NameAffix("Suffix", "KhronosVendor", "ARB")] - GL_RGB32F_ARB = 34837, - } + [NameAffix("Suffix", "Test", nameof(A))] + public struct B { } """ ) .Project; @@ -417,49 +395,25 @@ public enum InternalFormat var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions( - new PrettifyNames.Configuration() { LongAcronymThreshold = 3 } - ), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions(new PrettifyNames.Configuration()) ); - await prettifyNames.ExecuteAsync(context); - - // This is to catch a bug revealed by changing NameTrimmer to be executed after affix removal by NameAffixerEarlyTrimmer - // The underlying reason is actually unrelated and was an issue that existed long before - // NameUtilsTests.Prettify_IsNotAffectedBy_TrailingUnderscore tests for the underlying issue - // - // While the core issue is already covered by another test, - // this test is kept because the format enums tend to be a bit sensitive to codebase changes - var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); - await Verify(result!.NormalizeWhitespace().ToString()); + Assert.ThrowsAsync(async () => + { + await prettifyNames.ExecuteAsync(context); + }); } [Test] - public async Task InconsistentCasing_LettersFollowingNumbers_WhenAffixesDeclared() + public void MissingReferencedAffix_Throws() { var project = TestUtils .CreateTestProject() .AddDocument( "Test.gen.cs", """ - public enum GLEnum - { - [NameAffix("Suffix", "KhronosVendor", "EXT")] - GL_RGB16_EXT = 32852, - - [NameAffix("Suffix", "KhronosVendor", "EXT")] - GL_RGB16F_EXT = 34843, - } - - public enum ALEnum - { - [NameAffix("Suffix", "KhronosVendor", "SOFT")] - AL_MONO16_SOFT = 4353, - - [NameAffix("Suffix", "KhronosVendor", "SOFT")] - AL_MONO32F_SOFT = 65552, - } + [NameAffix("Suffix", "Test", nameof(B))] + public struct A { } """ ) .Project; @@ -468,45 +422,31 @@ public enum ALEnum var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions( - new PrettifyNames.Configuration() { LongAcronymThreshold = 4 } - ), - [new DummyJobDependency([new NameTrimmer()])] + new DummyOptions(new PrettifyNames.Configuration()) ); - await prettifyNames.ExecuteAsync(context); - - // This is to catch an inconsistency related to how letters following numbers are handled - // In both cases, MONO should be prettified as Mono - // NameUtilsTests.Prettify_Capital_AfterNumber_DoesNotAffect_PreviousWord tests for the underlying issue - // - // Note that the NameAffix attributes do affect the output - var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); - await Verify(result!.NormalizeWhitespace().ToString()); + Assert.ThrowsAsync(async () => + { + await prettifyNames.ExecuteAsync(context); + }); } [Test] - public async Task Regression_IncorrectSecondary_ChosenAsFallback() + public async Task ConflictsAreResolved_ForMethodsAndConstants() { + // This test focuses on an edge case where method conflicts might be resolved while + // ignoring the fact that a constant also wants to have the same output name var project = TestUtils .CreateTestProject() .AddDocument( - "AL.gen.cs", + "Sdl.gen.cs", """ - public class AL + public class Sdl { - [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] - [NameAffix("Suffix", "KhronosVendor", "SOFT")] - public void alGetBufferPtrDirectSOFT() { } - - [NameAffix("Suffix", "KhronosFunctionDataType", "v")] - [NameAffix("Suffix", "KhronosNonVendorSuffix", "Direct")] - [NameAffix("Suffix", "KhronosVendor", "SOFT")] - public void alGetBufferPtrvDirectSOFT() { } + public static delegate* main => &SDL_main; - // This is to ensure that prefix identification doesn't trim too much - [NameAffix("Suffix", "KhronosFunctionDataType", "i")] - public void alFilteri() { } + [NameAffix("Prefix", "SharedPrefix", "SDL")] + public static extern int SDL_main(int argc, sbyte** argv); } """ ) @@ -516,59 +456,31 @@ public void alFilteri() { } var prettifyNames = new PrettifyNames( NullLogger.Instance, - new DummyOptions( - new PrettifyNames.Configuration() + new DummyOptions(new PrettifyNames.Configuration()) + { + Value = { - LongAcronymThreshold = 4, - GlobalPrefixHints = ["al"], Affixes = { { - "KhronosFunctionDataType", - new PrettifyNames.NameAffixConfiguration() { IsDiscriminator = true } + "SharedPrefix", + new PrettifyNames.NameAffixConfiguration() + { + DiscriminatorPriority = 0, + IsDiscriminator = true, + } }, }, - } - ), - [new DummyJobDependency([new NameTrimmer()])] - ); - - await prettifyNames.ExecuteAsync(context); - - // This is to catch a regression where choosing the shortest secondary available is not always correct - // The second method (with the -v suffix) should not have the global prefix restored - // Eg: We don't want AlGetBufferPtr - var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); - await Verify(result!.NormalizeWhitespace().ToString()); - } - - [Test] - public async Task PreserveKhronosNamespaceEnumPrefix() - { - var project = TestUtils - .CreateTestProject() - .AddDocument( - "GLEnum.gen.cs", - """ - [NameAffix("Prefix", "KhronosNamespaceEnum", "GL")] - public enum GLEnum { } - """ - ) - .Project; - - var context = new DummyModContext() { SourceProject = project }; - - var prettifyNames = new PrettifyNames( - NullLogger.Instance, - new DummyOptions( - new PrettifyNames.Configuration() { GlobalPrefixHints = ["gl"] } - ), - [new DummyJobDependency([new NameTrimmer()])] + }, + } ); await prettifyNames.ExecuteAsync(context); - // The presence of the NameAffix attribute should prevent the GL- prefix of GLEnum from being removed + // The two members should not be output as the same name + // Expected: + // Property is named "MainValue" + // Method is named "Main" var result = await context.SourceProject.Documents.First().GetSyntaxRootAsync(); await Verify(result!.NormalizeWhitespace().ToString()); }