diff --git a/.build/.build.csproj b/.build/.build.csproj index b3e4dba53..7233e8972 100644 --- a/.build/.build.csproj +++ b/.build/.build.csproj @@ -2,11 +2,12 @@ Exe - net5.0 + net6.0 false False CS0649;CS0169 + 1 diff --git a/.build/Build.cs b/.build/Build.cs index 836d1713f..f98da474f 100644 --- a/.build/Build.cs +++ b/.build/Build.cs @@ -28,8 +28,7 @@ public partial class Solution : NukeBuild, IGenerateCodeCoverageReport, IGenerateCodeCoverageSummary, IGenerateCodeCoverageBadges, - IHaveConfiguration, - ICanLint + IHaveConfiguration { /// /// Support plugins are available for: diff --git a/.build/Solution.cs b/.build/Solution.cs index 47f084d9a..5b98afc89 100644 --- a/.build/Solution.cs +++ b/.build/Solution.cs @@ -11,11 +11,11 @@ InvokeTargets = new[] { nameof(Default) }, NonEntryTargets = new[] { nameof(ICIEnvironment.CIEnvironment), - nameof(ITriggerCodeCoverageReports.Trigger_Code_Coverage_Reports), - nameof(ITriggerCodeCoverageReports.Generate_Code_Coverage_Report_Cobertura), - nameof(IGenerateCodeCoverageBadges.Generate_Code_Coverage_Badges), - nameof(IGenerateCodeCoverageReport.Generate_Code_Coverage_Report), - nameof(IGenerateCodeCoverageSummary.Generate_Code_Coverage_Summary), + nameof(ITriggerCodeCoverageReports.TriggerCodeCoverageReports), + nameof(ITriggerCodeCoverageReports.GenerateCodeCoverageReportCobertura), + nameof(IGenerateCodeCoverageBadges.GenerateCodeCoverageBadges), + nameof(IGenerateCodeCoverageReport.GenerateCodeCoverageReport), + nameof(IGenerateCodeCoverageSummary.GenerateCodeCoverageSummary), nameof(Default) }, ExcludedTargets = new[] @@ -26,20 +26,24 @@ } )] [GitHubActionsSteps( - "ci", GitHubActionsImage.MacOsLatest, GitHubActionsImage.WindowsLatest, GitHubActionsImage.UbuntuLatest, + "ci", + GitHubActionsImage.MacOsLatest, + GitHubActionsImage.WindowsLatest, + GitHubActionsImage.UbuntuLatest, AutoGenerate = false, On = new[] { GitHubActionsTrigger.Push }, OnPushTags = new[] { "v*" }, - OnPushBranches = new[] { "master", "next" }, - OnPullRequestBranches = new[] { "master", "next" }, + OnPushBranches = new[] { "master", "main", "next" }, + OnPullRequestBranches = new[] { "master", "main", "next" }, InvokedTargets = new[] { nameof(Default) }, - NonEntryTargets = new[] { + NonEntryTargets = new[] + { nameof(ICIEnvironment.CIEnvironment), - nameof(ITriggerCodeCoverageReports.Trigger_Code_Coverage_Reports), - nameof(ITriggerCodeCoverageReports.Generate_Code_Coverage_Report_Cobertura), - nameof(IGenerateCodeCoverageBadges.Generate_Code_Coverage_Badges), - nameof(IGenerateCodeCoverageReport.Generate_Code_Coverage_Report), - nameof(IGenerateCodeCoverageSummary.Generate_Code_Coverage_Summary), + nameof(ITriggerCodeCoverageReports.TriggerCodeCoverageReports), + nameof(ITriggerCodeCoverageReports.GenerateCodeCoverageReportCobertura), + nameof(IGenerateCodeCoverageBadges.GenerateCodeCoverageBadges), + nameof(IGenerateCodeCoverageReport.GenerateCodeCoverageReport), + nameof(IGenerateCodeCoverageSummary.GenerateCodeCoverageSummary), nameof(Default) }, ExcludedTargets = new[] { nameof(ICanClean.Clean), nameof(ICanRestoreWithDotNetCore.DotnetToolRestore) }, @@ -48,27 +52,40 @@ [PrintBuildVersion] [PrintCIEnvironment] [UploadLogs] +[TitleEvents] public partial class Solution { public static RocketSurgeonGitHubActionsConfiguration Middleware(RocketSurgeonGitHubActionsConfiguration configuration) { - var buildJob = configuration.Jobs.First(z => z.Name == "Build"); + var buildJob = configuration.Jobs.OfType().First(z => z.Name == "Build"); + buildJob.FailFast = false; var checkoutStep = buildJob.Steps.OfType().Single(); // For fetch all checkoutStep.FetchDepth = 0; + buildJob.Environment["NUGET_PACKAGES"] = "${{ github.workspace }}/.nuget/packages"; buildJob.Steps.InsertRange( buildJob.Steps.IndexOf(checkoutStep) + 1, new BaseGitHubActionsStep[] { new RunStep("Fetch all history for all tags and branches") { Run = "git fetch --prune" }, - new SetupDotNetStep("Use .NET Core 2.1 SDK") { - DotNetVersion = "2.1.x" + new UsingStep("NuGet Cache") + { + Uses = "actions/cache@v2", + With = + { + ["path"] = "${{ github.workspace }}/.nuget/packages", + // keep in mind using central package versioning here + ["key"] = + "${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Build.targets', '**/Directory.Build.props', '**/*.csproj') }}", + ["restore-keys"] = @"| + ${{ runner.os }}-nuget-" + } }, new SetupDotNetStep("Use .NET Core 3.1 SDK") { DotNetVersion = "3.1.x" }, - new SetupDotNetStep("Use .NET Core 5.0 SDK") { - DotNetVersion = "5.0.x" + new SetupDotNetStep("Use .NET Core 6.0 SDK") { + DotNetVersion = "6.0.x" }, } ); @@ -115,24 +132,6 @@ public static RocketSurgeonGitHubActionsConfiguration Middleware(RocketSurgeonGi } ); - - /* - - - publish: "${{ parameters.Artifacts }}/logs/" - displayName: Publish Logs - artifact: "Logs${{ parameters.Postfix }}" - condition: always() - - - publish: ${{ parameters.Coverage }} - displayName: Publish Coverage - artifact: "Coverage${{ parameters.Postfix }}" - condition: always() - - - publish: "${{ parameters.Artifacts }}/nuget/" - displayName: Publish NuGet Artifacts - artifact: "NuGet${{ parameters.Postfix }}" - condition: always() - */ return configuration; } } diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 19029998d..74333ac0c 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -1,48 +1,54 @@ { - "version": 1, - "isRoot": true, - "tools": { - "cake.tool": { - "version": "1.1.0", - "commands": [ - "dotnet-cake" - ] - }, - "gitversion.tool": { - "version": "5.7.0", - "commands": [ - "dotnet-gitversion" - ] - }, - "dotnet-reportgenerator-globaltool": { - "version": "4.8.12", - "commands": [ - "reportgenerator" - ] - }, - "codecov.tool": { - "version": "1.13.0", - "commands": [ - "codecov" - ] - }, - "nuke.globaltool": { - "version": "5.3.0", - "commands": [ - "nuke" - ] - }, - "nukeeper": { - "version": "0.34.0", - "commands": [ - "nukeeper" - ] - }, - "jetbrains.resharper.globaltools": { - "version": "2021.2.1", - "commands": [ - "jb" - ] + "version": 1, + "isRoot": true, + "tools": { + "dotnet-outdated": { + "version": "2.11.0", + "commands": [ + "dotnet-outdated" + ] + }, + "gitversion.tool": { + "version": "5.8.2", + "commands": [ + "dotnet-gitversion" + ] + }, + "dotnet-reportgenerator-globaltool": { + "version": "5.0.4", + "commands": [ + "reportgenerator" + ] + }, + "nuke.globaltool": { + "version": "6.0.1", + "commands": [ + "nuke" + ] + }, + "codecov.tool": { + "version": "1.13.0", + "commands": [ + "codecov" + ] + }, + "jetbrains.resharper.globaltools": { + "version": "2021.3.3", + "commands": [ + "jb" + ] + }, + "dotnet-format": { + "version": "5.1.250801", + "commands": [ + "dotnet-format" + ] + }, + "nukeeper": { + "version": "0.35.0", + "commands": [ + "nukeeper" + ] + } } - } -} \ No newline at end of file +} diff --git a/.editorconfig b/.editorconfig index 81d812533..737469427 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,132 +1,1013 @@ -root=true +root = true + +[*.{cs, cshtml}] +charset = utf-8 +indent_style = space +indent_size = 4 +max_line_length = 160 +insert_final_newline = true + +[*.{js, ts, vue}] +indent_style = space +indent_size = 4 +insert_final_newline = true +max_line_length = 160 + +[*.{json, xml, yml, yaml}] +indent_style = space +indent_size = 2 +insert_final_newline = true +max_line_length = 160 + [*] -charset=utf-8 -indent_style=space -indent_size=4 -trim_trailing_whitespace=true -insert_final_newline=true -max_line_length=180 -end_of_line=crlf +#### .NET Coding Conventions #### -# Microsoft .NET properties -csharp_new_line_before_members_in_object_initializers=false -csharp_new_line_before_open_brace=types,methods,properties,indexers,events,event_accessors,control_blocks,anonymous_types,object_collections,array_initializers,local_functions -csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion -csharp_space_between_parentheses=expressions -csharp_style_expression_bodied_accessors=true:suggestion -csharp_style_expression_bodied_constructors=true:none -csharp_style_expression_bodied_indexers=true:none -csharp_style_expression_bodied_methods=true:none -csharp_style_expression_bodied_operators=true:none -csharp_style_expression_bodied_properties=true:suggestion -csharp_style_var_elsewhere=true:warning -csharp_style_var_for_built_in_types=true:warning -csharp_style_var_when_type_is_apparent=true:warning -dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:warning -dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:warning -dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:warning -dotnet_style_predefined_type_for_locals_parameters_members=true:error -dotnet_style_predefined_type_for_member_access=true:error -dotnet_style_qualification_for_event=false:warning -dotnet_style_qualification_for_field=false:warning -dotnet_style_qualification_for_method=false:warning -dotnet_style_qualification_for_property=false:warning -dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion -# Sort using and Import directives with System.* appearing first -dotnet_sort_system_directives_first=true -# Suggest more modern language features when available -dotnet_style_coalesce_expression=true:error -dotnet_style_collection_initializer=true:suggestion -dotnet_style_explicit_tuple_names=true:error -dotnet_style_null_propagation=true:warning -dotnet_style_object_initializer=true:warning - -# Naming Conventions: -# Pascal Casing -#dotnet_naming_symbols.method_and_property_symbols.applicable_kinds= method,property,enum -#dotnet_naming_symbols.method_and_property_symbols.applicable_accessibilities = * -#dotnet_naming_style.pascal_case_style.capitalization = pascal_case -csharp_style_conditional_delegate_call=true:suggestion -csharp_style_inlined_variable_declaration=true:error -csharp_style_pattern_matching_over_as_with_null_check=true:error -csharp_style_pattern_matching_over_is_with_cast_check=true:error -csharp_style_throw_expression=true:suggestion -csharp_new_line_before_catch=true -csharp_new_line_before_else=true -csharp_new_line_before_finally=true -csharp_new_line_before_members_in_anonymous_types=true +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:warning +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_property = false:warning + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion + +# Expression-level preferences +csharp_style_deconstructed_variable_declaration = true:warning +csharp_style_inlined_variable_declaration = true:warning +csharp_style_throw_expression = true:warning +dotnet_style_coalesce_expression = true:warning +dotnet_style_collection_initializer = true:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_null_propagation = true:warning +dotnet_style_object_initializer = true:warning +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning + +# Field preferences +dotnet_style_readonly_field = true:warning + +# Parameter preferences +dotnet_code_quality_unused_parameters = non_public:suggestion + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:suggestion +csharp_style_expression_bodied_constructors = true:suggestion +csharp_style_expression_bodied_indexers = true:suggestion +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = true:suggestion +csharp_style_expression_bodied_methods = true:suggestion +csharp_style_expression_bodied_operators = true:suggestion +csharp_style_expression_bodied_properties = true:suggestion + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:warning +csharp_style_pattern_matching_over_is_with_cast_check = true:warning +csharp_style_prefer_switch_expression = true:warning + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:warning + +# Modifier preferences +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, static, readonly, override, extern, unsafe, volatile, async:suggestion + +# Code-block preferences +csharp_prefer_braces = true:none +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:warning +csharp_style_pattern_local_over_anonymous_function = true:warning +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_range_operator = true:warning +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion + +# 'using' directive preferences + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = no_change +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = expressions +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.type_parameter_should_be_begins_with_t.severity = suggestion +dotnet_naming_rule.type_parameter_should_be_begins_with_t.symbols = type_parameter +dotnet_naming_rule.type_parameter_should_be_begins_with_t.style = begins_with_t + +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = local +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case + +dotnet_naming_rule.static_field_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.static_field_should_be_pascal_case.symbols = static_field +dotnet_naming_rule.static_field_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.const_field_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.const_field_should_be_pascal_case.symbols = const_field +dotnet_naming_rule.const_field_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.private_field_members_should_be_underscore_camel_case.severity = suggestion +dotnet_naming_rule.private_field_members_should_be_underscore_camel_case.symbols = private_field +dotnet_naming_rule.private_field_members_should_be_underscore_camel_case.style = _camel_case + +dotnet_naming_rule.field_should_be_camel_case.severity = suggestion +dotnet_naming_rule.field_should_be_camel_case.symbols = field +dotnet_naming_rule.field_should_be_camel_case.style = camel_case + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = * +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.local.applicable_kinds = local, local_function +dotnet_naming_symbols.local.applicable_accessibilities = * +dotnet_naming_symbols.local.required_modifiers = +dotnet_naming_symbols.type_parameter.applicable_kinds = type_parameter +dotnet_naming_symbols.type_parameter.applicable_accessibilities = * +dotnet_naming_symbols.type_parameter.required_modifiers = +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum, delegate +dotnet_naming_symbols.types.applicable_accessibilities = * +dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = * +dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.private_field.applicable_kinds = field +dotnet_naming_symbols.private_field.applicable_accessibilities = private, private_protected +dotnet_naming_symbols.private_field.required_modifiers = +dotnet_naming_symbols.field.applicable_kinds = field +dotnet_naming_symbols.field.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.field.required_modifiers = +dotnet_naming_symbols.static_field.applicable_kinds = field +dotnet_naming_symbols.static_field.applicable_accessibilities = +dotnet_naming_symbols.static_field.required_modifiers = static + +dotnet_naming_symbols.const_field.applicable_kinds = field +dotnet_naming_symbols.const_field.applicable_accessibilities = * +dotnet_naming_symbols.const_field.required_modifiers = const + +# Naming styles + +# dotnet_naming_style.pascal_case.required_prefix = +# dotnet_naming_style.pascal_case.required_suffix = +# dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +# dotnet_naming_style.camel_case.required_prefix = +# dotnet_naming_style.camel_case.required_suffix = +# dotnet_naming_style.camel_case.word_separator = +dotnet_naming_style.camel_case.capitalization = camel_case + +dotnet_naming_style._camel_case.required_prefix = _ +# dotnet_naming_style._camel_case.required_suffix = +# dotnet_naming_style._camel_case.word_separator = +dotnet_naming_style._camel_case.capitalization = camel_case + +dotnet_naming_style.begins_with_i.required_prefix = I +# dotnet_naming_style.begins_with_i.required_suffix = +# dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.begins_with_t.required_prefix = T +# dotnet_naming_style.begins_with_t.required_suffix = +# dotnet_naming_style.begins_with_t.word_separator = +dotnet_naming_style.begins_with_t.capitalization = pascal_case + +dotnet_diagnostic.ide0058.severity = none + +# CodeQuality +# CA1000: Do not declare static members on generic types +# dotnet_diagnostic.CA1000.severity = warning + +# CA1001: Types that own disposable fields should be disposable +# dotnet_diagnostic.CA1001.severity = warning + +# CA1003: Use generic event handler instances +# dotnet_diagnostic.CA1003.severity = none + +# CA1008: Enums should have zero value +# dotnet_diagnostic.CA1008.severity = none + +# CA1010: Collections should implement generic interface +# dotnet_diagnostic.CA1010.severity = warning + +# CA1012: Abstract types should not have constructors +# dotnet_diagnostic.CA1012.severity = none + +# CA1014: Mark assemblies with CLSCompliant +# dotnet_diagnostic.CA1014.severity = none + +# CA1016: Mark assemblies with assembly version +# dotnet_diagnostic.CA1016.severity = warning + +# CA1017: Mark assemblies with ComVisible +# dotnet_diagnostic.CA1017.severity = none + +# CA1018: Mark attributes with AttributeUsageAttribute +# dotnet_diagnostic.CA1018.severity = warning + +# CA1019: Define accessors for attribute arguments +# dotnet_diagnostic.CA1019.severity = none + +# CA1024: Use properties where appropriate +# dotnet_diagnostic.CA1024.severity = none + +# CA1027: Mark enums with FlagsAttribute +# dotnet_diagnostic.CA1027.severity = none + +# CA1028: Enum Storage should be Int32 +# dotnet_diagnostic.CA1028.severity = warning + +# CA1030: Use events where appropriate +# dotnet_diagnostic.CA1030.severity = warning + +# CA1031: Do not catch general exception types +# dotnet_diagnostic.CA1031.severity = warning + +# CA1032: Implement standard exception constructors +# dotnet_diagnostic.CA1032.severity = warning + +# CA1033: Interface methods should be callable by child types +# dotnet_diagnostic.CA1033.severity = none + +# CA1034: Nested types should not be visible +# dotnet_diagnostic.CA1034.severity = warning + +# CA1036: Override methods on comparable types +# dotnet_diagnostic.CA1036.severity = warning + +# CA1040: Avoid empty interfaces +# dotnet_diagnostic.CA1040.severity = warning + +# CA1041: Provide ObsoleteAttribute message +# dotnet_diagnostic.CA1041.severity = warning + +# CA1043: Use Integral Or String Argument For Indexers +# dotnet_diagnostic.CA1043.severity = warning + +# CA1044: Properties should not be write only +# dotnet_diagnostic.CA1044.severity = warning + +# CA1050: Declare types in namespaces +# dotnet_diagnostic.CA1050.severity = none + +# CA1051: Do not declare visible instance fields +# dotnet_diagnostic.CA1051.severity = warning + +# CA1052: Static holder types should be Static or NotInheritable +# dotnet_diagnostic.CA1052.severity = warning + +# CA1054: Uri parameters should not be strings +# dotnet_diagnostic.CA1054.severity = warning + +# CA1055: Uri return values should not be strings +# dotnet_diagnostic.CA1055.severity = warning + +# CA1056: Uri properties should not be strings +# dotnet_diagnostic.CA1056.severity = warning + +# CA1060: Move pinvokes to native methods class +# dotnet_diagnostic.CA1060.severity = none + +# CA1061: Do not hide base class methods +# dotnet_diagnostic.CA1061.severity = warning + +# CA1062: Validate arguments of public methods +dotnet_diagnostic.ca1062.severity = none + +# CA1063: Implement IDisposable Correctly +# dotnet_diagnostic.CA1063.severity = none + +# CA1064: Exceptions should be public +# dotnet_diagnostic.CA1064.severity = warning + +# CA1065: Do not raise exceptions in unexpected locations +# dotnet_diagnostic.CA1065.severity = warning + +# CA1066: Type {0} should implement IEquatable because it overrides Equals +# dotnet_diagnostic.CA1066.severity = warning + +# CA1067: Override Object.Equals(object) when implementing IEquatable +# dotnet_diagnostic.CA1067.severity = warning + +# CA1068: CancellationToken parameters must come last +# dotnet_diagnostic.CA1068.severity = warning + +# CA1200: Avoid using cref tags with a prefix +# dotnet_diagnostic.CA1200.severity = warning + +# CA1501: Avoid excessive inheritance +# dotnet_diagnostic.CA1501.severity = none + +# CA1502: Avoid excessive complexity +# dotnet_diagnostic.CA1502.severity = none + +# CA1505: Avoid unmaintainable code +# dotnet_diagnostic.CA1505.severity = none + +# CA1506: Avoid excessive class coupling +# dotnet_diagnostic.CA1506.severity = none + +# CA1507: Use nameof to express symbol names +# dotnet_diagnostic.CA1507.severity = warning + +# CA1508: Avoid dead conditional code +# dotnet_diagnostic.CA1508.severity = none + +# CA1509: Invalid entry in code metrics rule specification file +# dotnet_diagnostic.CA1509.severity = none + +# CA1707: Identifiers should not contain underscores +# dotnet_diagnostic.CA1707.severity = none + +# CA1708: Identifiers should differ by more than case +# dotnet_diagnostic.CA1708.severity = none + +# CA1710: Identifiers should have correct suffix +# dotnet_diagnostic.CA1710.severity = warning + +# CA1711: Identifiers should not have incorrect suffix +# dotnet_diagnostic.CA1711.severity = none + +# CA1712: Do not prefix enum values with type name +# dotnet_diagnostic.CA1712.severity = warning + +# CA1714: Flags enums should have plural names +# dotnet_diagnostic.CA1714.severity = warning + +# CA1715: Identifiers should have correct prefix +# dotnet_diagnostic.CA1715.severity = warning + +# CA1716: Identifiers should not match keywords +# dotnet_diagnostic.CA1716.severity = warning + +# CA1717: Only FlagsAttribute enums should have plural names +# dotnet_diagnostic.CA1717.severity = warning + +# CA1720: Identifier contains type name +# dotnet_diagnostic.CA1720.severity = warning + +# CA1721: Property names should not match get methods +# dotnet_diagnostic.CA1721.severity = warning + +# CA1724: Type names should not match namespaces +# dotnet_diagnostic.CA1724.severity = warning + +# CA1725: Parameter names should match base declaration +# dotnet_diagnostic.CA1725.severity = none + +# CA1801: Review unused parameters +# dotnet_diagnostic.CA1801.severity = warning + +# CA1802: Use literals where appropriate +# dotnet_diagnostic.CA1802.severity = warning + +# CA1806: Do not ignore method results +# dotnet_diagnostic.CA1806.severity = warning + +# CA1812: Avoid uninstantiated internal classes +# dotnet_diagnostic.CA1812.severity = none + +# CA1814: Prefer jagged arrays over multidimensional +# dotnet_diagnostic.CA1814.severity = warning + +# CA1815: Override equals and operator equals on value types +# dotnet_diagnostic.CA1815.severity = warning + +# CA1819: Properties should not return arrays +# dotnet_diagnostic.CA1819.severity = warning + +# CA1821: Remove empty Finalizers +# dotnet_diagnostic.CA1821.severity = warning + +# CA1822: Mark members as static +# dotnet_diagnostic.CA1822.severity = warning + +# CA1823: Avoid unused private fields +# dotnet_diagnostic.CA1823.severity = warning + +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.ca2007.severity = none + +# CA2119: Seal methods that satisfy private interfaces +# dotnet_diagnostic.CA2119.severity = warning + +# CA2200: Rethrow to preserve stack details. +# dotnet_diagnostic.CA2200.severity = warning + +# CA2211: Non-constant fields should not be visible +# dotnet_diagnostic.CA2211.severity = warning + +# CA2214: Do not call overridable methods in constructors +# dotnet_diagnostic.CA2214.severity = warning + +# CA2217: Do not mark enums with FlagsAttribute +# dotnet_diagnostic.CA2217.severity = none + +# CA2218: Override GetHashCode on overriding Equals +# dotnet_diagnostic.CA2218.severity = warning + +# CA2219: Do not raise exceptions in finally clauses +# dotnet_diagnostic.CA2219.severity = warning + +# CA2224: Override Equals on overloading operator equals +# dotnet_diagnostic.CA2224.severity = warning + +# CA2225: Operator overloads have named alternates +# dotnet_diagnostic.CA2225.severity = warning + +# CA2226: Operators should have symmetrical overloads +# dotnet_diagnostic.CA2226.severity = warning + +# CA2227: Collection properties should be read only +# dotnet_diagnostic.CA2227.severity = warning + +# CA2231: Overload operator equals on overriding value type Equals +# dotnet_diagnostic.CA2231.severity = warning + +# CA2234: Pass system uri objects instead of strings +# dotnet_diagnostic.CA2234.severity = warning + +# CA2244: Do not duplicate indexed element initializations +# dotnet_diagnostic.CA2244.severity = warning + +# CA2245: Do not assign a property to itself. +# dotnet_diagnostic.CA2245.severity = warning + +# CA2246: Assigning symbol and its member in the same statement. +# dotnet_diagnostic.CA2246.severity = warning + +# NetCore + +# CA1303: Do not pass literals as localized parameters +# dotnet_diagnostic.CA1303.severity = none + +# CA1304: Specify CultureInfo +# dotnet_diagnostic.CA1304.severity = none + +# CA1305: Specify IFormatProvider +# dotnet_diagnostic.CA1305.severity = none + +# CA1307: Specify StringComparison +# dotnet_diagnostic.CA1307.severity = warning + +# CA1308: Normalize strings to uppercase +# dotnet_diagnostic.CA1308.severity = warning + +# CA1309: Use ordinal stringcomparison +# dotnet_diagnostic.CA1309.severity = none + +# CA1401: P/Invokes should not be visible +# dotnet_diagnostic.CA1401.severity = warning + +# CA1810: Initialize reference type static fields inline +# dotnet_diagnostic.CA1810.severity = warning + +# CA1813: Avoid unsealed attributes +# dotnet_diagnostic.CA1813.severity = none + +# CA1816: Dispose methods should call SuppressFinalize +# dotnet_diagnostic.CA1816.severity = none + +# CA1820: Test for empty strings using string length +# dotnet_diagnostic.CA1820.severity = warning + +# CA1824: Mark assemblies with NeutralResourcesLanguageAttribute +# dotnet_diagnostic.CA1824.severity = warning + +# CA1825: Avoid zero-length array allocations. +# dotnet_diagnostic.CA1825.severity = warning + +# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly +# dotnet_diagnostic.CA1826.severity = warning + +# CA1827: Do not use Count() or LongCount() when Any() can be used +# dotnet_diagnostic.CA1827.severity = warning + +# CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used +# dotnet_diagnostic.CA1828.severity = warning + +# CA1829: Use Length/Count property instead of Count() when available +# dotnet_diagnostic.CA1829.severity = warning + +# CA2000: Dispose objects before losing scope +# dotnet_diagnostic.CA2000.severity = warning + +# CA2002: Do not lock on objects with weak identity +# dotnet_diagnostic.CA2002.severity = warning + +# CA2008: Do not create tasks without passing a TaskScheduler +# dotnet_diagnostic.CA2008.severity = warning + +# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value +# dotnet_diagnostic.CA2009.severity = warning + +# CA2010: Always consume the value returned by methods marked with PreserveSigAttribute +# dotnet_diagnostic.CA2010.severity = warning + +# CA2100: Review SQL queries for security vulnerabilities +# dotnet_diagnostic.CA2100.severity = warning + +# CA2101: Specify marshaling for P/Invoke string arguments +# dotnet_diagnostic.CA2101.severity = warning + +# CA2201: Do not raise reserved exception types +# dotnet_diagnostic.CA2201.severity = none + +# CA2207: Initialize value type static fields inline +# dotnet_diagnostic.CA2207.severity = warning + +# CA2208: Instantiate argument exceptions correctly +# dotnet_diagnostic.CA2208.severity = warning + +# CA2213: Disposable fields should be disposed +# dotnet_diagnostic.CA2213.severity = warning + +# CA2216: Disposable types should declare finalizer +# dotnet_diagnostic.CA2216.severity = warning + +# CA2229: Implement serialization constructors +# dotnet_diagnostic.CA2229.severity = warning + +# CA2235: Mark all non-serializable fields +# dotnet_diagnostic.CA2235.severity = warning + +# CA2237: Mark ISerializable types with serializable +# dotnet_diagnostic.CA2237.severity = warning + +# CA2241: Provide correct arguments to formatting methods +# dotnet_diagnostic.CA2241.severity = warning + +# CA2242: Test for NaN correctly +# dotnet_diagnostic.CA2242.severity = warning + +# CA2243: Attribute string literals should parse correctly +# dotnet_diagnostic.CA2243.severity = warning + +# CA2300: Do not use insecure deserializer BinaryFormatter +# dotnet_diagnostic.CA2300.severity = none + +# CA2301: Do not call BinaryFormatter.Deserialize without first setting BinaryFormatter.Binder +# dotnet_diagnostic.CA2301.severity = none + +# CA2302: Ensure BinaryFormatter.Binder is set before calling BinaryFormatter.Deserialize +# dotnet_diagnostic.CA2302.severity = none + +# CA2305: Do not use insecure deserializer LosFormatter +# dotnet_diagnostic.CA2305.severity = none + +# CA2310: Do not use insecure deserializer NetDataContractSerializer +# dotnet_diagnostic.CA2310.severity = none + +# CA2311: Do not deserialize without first setting NetDataContractSerializer.Binder +# dotnet_diagnostic.CA2311.severity = none + +# CA2312: Ensure NetDataContractSerializer.Binder is set before deserializing +# dotnet_diagnostic.CA2312.severity = none + +# CA2315: Do not use insecure deserializer ObjectStateFormatter +# dotnet_diagnostic.CA2315.severity = none + +# CA2321: Do not deserialize with JavaScriptSerializer using a SimpleTypeResolver +# dotnet_diagnostic.CA2321.severity = none + +# CA2322: Ensure JavaScriptSerializer is not initialized with SimpleTypeResolver before deserializing +# dotnet_diagnostic.CA2322.severity = none + +# CA2326: Do not use TypeNameHandling values other than None +# dotnet_diagnostic.CA2326.severity = none + +# CA2327: Do not use insecure JsonSerializerSettings +# dotnet_diagnostic.CA2327.severity = none + +# CA2328: Ensure that JsonSerializerSettings are secure +# dotnet_diagnostic.CA2328.severity = none + +# CA2329: Do not deserialize with JsonSerializer using an insecure configuration +# dotnet_diagnostic.CA2329.severity = none + +# CA2330: Ensure that JsonSerializer has a secure configuration when deserializing +# dotnet_diagnostic.CA2330.severity = none + +# CA3001: Review code for SQL injection vulnerabilities +# dotnet_diagnostic.CA3001.severity = none + +# CA3002: Review code for XSS vulnerabilities +# dotnet_diagnostic.CA3002.severity = none + +# CA3003: Review code for file path injection vulnerabilities +# dotnet_diagnostic.CA3003.severity = none + +# CA3004: Review code for information disclosure vulnerabilities +# dotnet_diagnostic.CA3004.severity = none + +# CA3005: Review code for LDAP injection vulnerabilities +# dotnet_diagnostic.CA3005.severity = none + +# CA3006: Review code for process command injection vulnerabilities +# dotnet_diagnostic.CA3006.severity = none + +# CA3007: Review code for open redirect vulnerabilities +# dotnet_diagnostic.CA3007.severity = none + +# CA3008: Review code for XPath injection vulnerabilities +# dotnet_diagnostic.CA3008.severity = none + +# CA3009: Review code for XML injection vulnerabilities +# dotnet_diagnostic.CA3009.severity = none + +# CA3010: Review code for XAML injection vulnerabilities +# dotnet_diagnostic.CA3010.severity = none + +# CA3011: Review code for DLL injection vulnerabilities +# dotnet_diagnostic.CA3011.severity = none + +# CA3012: Review code for regex injection vulnerabilities +# dotnet_diagnostic.CA3012.severity = none + +# CA3061: Do Not Add Schema By URL +# dotnet_diagnostic.CA3061.severity = warning + +# CA5350: Do Not Use Weak Cryptographic Algorithms +# dotnet_diagnostic.CA5350.severity = warning + +# CA5351: Do Not Use Broken Cryptographic Algorithms +# dotnet_diagnostic.CA5351.severity = warning + +# CA5358: Do Not Use Unsafe Cipher Modes +# dotnet_diagnostic.CA5358.severity = none + +# CA5359: Do Not Disable Certificate Validation +# dotnet_diagnostic.CA5359.severity = warning + +# CA5360: Do Not Call Dangerous Methods In Deserialization +# dotnet_diagnostic.CA5360.severity = warning + +# CA5361: Do Not Disable SChannel Use of Strong Crypto +# dotnet_diagnostic.CA5361.severity = warning + +# CA5362: Do Not Refer Self In Serializable Class +# dotnet_diagnostic.CA5362.severity = none + +# CA5363: Do Not Disable Request Validation +# dotnet_diagnostic.CA5363.severity = warning + +# CA5364: Do Not Use Deprecated Security Protocols +# dotnet_diagnostic.CA5364.severity = warning + +# CA5365: Do Not Disable HTTP Header Checking +# dotnet_diagnostic.CA5365.severity = warning + +# CA5366: Use XmlReader For DataSet Read Xml +# dotnet_diagnostic.CA5366.severity = warning + +# CA5367: Do Not Serialize Types With Pointer Fields +# dotnet_diagnostic.CA5367.severity = none + +# CA5368: Set ViewStateUserKey For Classes Derived From Page +# dotnet_diagnostic.CA5368.severity = warning + +# CA5369: Use XmlReader For Deserialize +# dotnet_diagnostic.CA5369.severity = warning + +# CA5370: Use XmlReader For Validating Reader +# dotnet_diagnostic.CA5370.severity = warning + +# CA5371: Use XmlReader For Schema Read +# dotnet_diagnostic.CA5371.severity = warning + +# CA5372: Use XmlReader For XPathDocument +# dotnet_diagnostic.CA5372.severity = warning + +# CA5373: Do not use obsolete key derivation function +# dotnet_diagnostic.CA5373.severity = warning + +# CA5374: Do Not Use XslTransform +# dotnet_diagnostic.CA5374.severity = warning + +# CA5375: Do Not Use Account Shared Access Signature +# dotnet_diagnostic.CA5375.severity = none + +# CA5376: Use SharedAccessProtocol HttpsOnly +# dotnet_diagnostic.CA5376.severity = warning + +# CA5377: Use Container Level Access Policy +# dotnet_diagnostic.CA5377.severity = warning + +# CA5378: Do not disable ServicePointManagerSecurityProtocols +# dotnet_diagnostic.CA5378.severity = warning + +# CA5379: Do Not Use Weak Key Derivation Function Algorithm +# dotnet_diagnostic.CA5379.severity = warning + +# CA5380: Do Not Add Certificates To Root Store +# dotnet_diagnostic.CA5380.severity = warning + +# CA5381: Ensure Certificates Are Not Added To Root Store +# dotnet_diagnostic.CA5381.severity = warning + +# CA5382: Use Secure Cookies In ASP.Net Core +# dotnet_diagnostic.CA5382.severity = none + +# CA5383: Ensure Use Secure Cookies In ASP.Net Core +# dotnet_diagnostic.CA5383.severity = none + +# CA5384: Do Not Use Digital Signature Algorithm (DSA) +# dotnet_diagnostic.CA5384.severity = warning + +# CA5385: Use Rivest–Shamir–Adleman (RSA) Algorithm With Sufficient Key Size +# dotnet_diagnostic.CA5385.severity = warning + +# CA5386: Avoid hardcoding SecurityProtocolType value +# dotnet_diagnostic.CA5386.severity = none + +# CA5387: Do Not Use Weak Key Derivation Function With Insufficient Iteration Count +# dotnet_diagnostic.CA5387.severity = none + +# CA5388: Ensure Sufficient Iteration Count When Using Weak Key Derivation Function +# dotnet_diagnostic.CA5388.severity = none + +# CA5389: Do Not Add Archive Item's Path To The Target File System Path +# dotnet_diagnostic.CA5389.severity = none + +# CA5390: Do not hard-code encryption key +# dotnet_diagnostic.CA5390.severity = none + +# CA5391: Use antiforgery tokens in ASP.NET Core MVC controllers +# dotnet_diagnostic.CA5391.severity = none + +# CA5392: Use DefaultDllImportSearchPaths attribute for P/Invokes +# dotnet_diagnostic.CA5392.severity = none + +# CA5393: Do not use unsafe DllImportSearchPath value +# dotnet_diagnostic.CA5393.severity = none + +# CA5394: Do not use insecure randomness +# dotnet_diagnostic.CA5394.severity = none + +# CA5395: Miss HttpVerb attribute for action methods +# dotnet_diagnostic.CA5395.severity = none + +# CA5396: Set HttpOnly to true for HttpCookie +# dotnet_diagnostic.CA5396.severity = none + +# CA5397: Do not use deprecated SslProtocols values +# dotnet_diagnostic.CA5397.severity = warning + +# CA5398: Avoid hardcoded SslProtocols values +# dotnet_diagnostic.CA5398.severity = none + +# CA5399: HttpClients should enable certificate revocation list checks +# dotnet_diagnostic.CA5399.severity = none + +# CA5400: Ensure HttpClient certificate revocation list check is not disabled +# dotnet_diagnostic.CA5400.severity = none + +# CA5401: Do not use CreateEncryptor with non-default IV +# dotnet_diagnostic.CA5401.severity = none + +# CA5402: Use CreateEncryptor with the default IV +# dotnet_diagnostic.CA5402.severity = none + +# CA5403: Do not hard-code certificate +# dotnet_diagnostic.CA5403.severity = none + +# NetFramework + +# CA1058: Types should not extend certain base types +# dotnet_diagnostic.CA1058.severity = warning + +# CA2153: Do Not Catch Corrupted State Exceptions +# dotnet_diagnostic.CA2153.severity = warning + +# CA3075: Insecure DTD processing in XML +# dotnet_diagnostic.CA3075.severity = warning + +# CA3076: Insecure XSLT script processing. +# dotnet_diagnostic.CA3076.severity = warning + +# CA3077: Insecure Processing in API Design, XmlDocument and XmlTextReader +# dotnet_diagnostic.CA3077.severity = warning + +# CA3147: Mark Verb Handlers With Validate Antiforgery Token +# dotnet_diagnostic.CA3147.severity = warning + +# PublicApi + +# RS0016: Add public types and members to the declared API +# dotnet_diagnostic.RS0016.severity = warning + +# RS0017: Remove deleted types and members from the declared API +# dotnet_diagnostic.RS0017.severity = warning + +# RS0022: Constructor make noninheritable base class inheritable +# dotnet_diagnostic.RS0022.severity = warning + +# RS0024: The contents of the public API files are invalid +# dotnet_diagnostic.RS0024.severity = warning + +# RS0025: Do not duplicate symbols in public API files +# dotnet_diagnostic.RS0025.severity = warning + +# RS0026: Do not add multiple public overloads with optional parameters +# dotnet_diagnostic.RS0026.severity = warning + +# RS0027: Public API with optional parameter(s) should have the most parameters amongst its public overloads. +# dotnet_diagnostic.RS0027.severity = warning # ReSharper properties -resharper_accessor_declaration_braces=end_of_line -resharper_align_linq_query=true -resharper_align_multiline_argument=true -resharper_align_multiline_calls_chain=true -resharper_align_multiline_extends_list=true -resharper_align_multiline_for_stmt=true -resharper_align_multiline_parameter=true -resharper_align_multiple_declaration=true -resharper_align_multline_type_parameter_constrains=true -resharper_align_multline_type_parameter_list=true -resharper_align_tuple_components=true -resharper_autodetect_indent_settings=true -resharper_constructor_or_destructor_body=expression_body -resharper_csharp_anonymous_method_declaration_braces=end_of_line -resharper_csharp_outdent_commas=true -resharper_csharp_outdent_dots=true -resharper_csharp_space_within_parentheses=true -resharper_csharp_wrap_after_declaration_lpar=true -resharper_csharp_wrap_after_invocation_lpar=true -resharper_csharp_wrap_before_binary_opsign=true -resharper_csharp_wrap_before_declaration_rpar=true -resharper_csharp_wrap_before_invocation_rpar=true -resharper_enforce_line_ending_style=true -resharper_initializer_braces=end_of_line -resharper_int_align_switch_expressions=true -resharper_int_align_switch_sections=true -resharper_keep_existing_enum_arrangement=true -resharper_keep_existing_switch_expression_arrangement=false -resharper_max_initializer_elements_on_line=2 -resharper_method_or_operator_body=expression_body -resharper_outdent_binary_ops=true -resharper_place_comments_at_first_column=true -resharper_place_simple_enum_on_single_line=true -resharper_space_around_arrow_op=true -resharper_space_within_single_line_array_initializer_braces=true -resharper_use_heuristics_for_body_style=false -resharper_use_indent_from_vs=false -resharper_wrap_lines=true -resharper_xmldoc_allow_far_alignment=true -resharper_xmldoc_attribute_style=on_single_line -resharper_xmldoc_indent_text=ZeroIndent -resharper_xmldoc_max_blank_lines_between_tags=1 -resharper_xmldoc_pi_attribute_style=on_single_line -resharper_xmldoc_space_after_last_pi_attribute=true +resharper_align_linq_query = true +resharper_align_multiline_argument = true +resharper_align_multiline_array_and_object_initializer = false +resharper_align_multiline_binary_expressions_chain = false +resharper_align_multiline_calls_chain = true +resharper_align_multiline_expression = true +resharper_align_multiline_extends_list = true +resharper_align_multiline_for_stmt = true +resharper_align_multiline_parameter = true +resharper_align_multiline_switch_expression = false +resharper_align_multiple_declaration = true +resharper_align_multline_type_parameter_constrains = true +resharper_align_multline_type_parameter_list = true +resharper_align_tuple_components = true +resharper_arguments_anonymous_function = positional +resharper_autodetect_indent_settings = true +resharper_braces_for_for = not_required +resharper_braces_for_foreach = not_required +resharper_braces_for_ifelse = not_required_for_both +resharper_braces_for_while = not_required +resharper_braces_redundant = false +resharper_constructor_or_destructor_body = block_body +resharper_continuous_indent_multiplier = 1 +resharper_cpp_empty_block_style = multiline +resharper_cpp_outdent_commas = false +resharper_cpp_outdent_dots = false +resharper_cpp_wrap_after_declaration_lpar = false +resharper_cpp_wrap_after_invocation_lpar = false +resharper_cpp_wrap_before_declaration_rpar = false +resharper_cpp_wrap_before_invocation_rpar = false +resharper_csharp_align_multiline_argument = true +resharper_csharp_align_multiline_binary_expressions_chain = true +resharper_csharp_align_multiline_expression = false +resharper_csharp_brace_style = next_line +resharper_csharp_empty_block_style = multiline +resharper_csharp_outdent_commas = true +resharper_csharp_outdent_dots = true +resharper_csharp_place_comments_at_first_column = true +resharper_csharp_wrap_after_declaration_lpar = true +resharper_csharp_wrap_after_invocation_lpar = true +resharper_csharp_wrap_before_binary_opsign = true +resharper_csharp_wrap_before_declaration_rpar = true +resharper_csharp_wrap_before_invocation_rpar = true +resharper_csharp_wrap_multiple_declaration_style = chop_if_long +resharper_empty_block_style = together_same_line +resharper_indent_anonymous_method_block = false +resharper_int_align_switch_expressions = true +resharper_int_align_switch_sections = true +resharper_keep_existing_declaration_block_arrangement = false +resharper_keep_existing_embedded_block_arrangement = false +resharper_keep_existing_enum_arrangement = true +resharper_keep_existing_invocation_parens_arrangement = true +resharper_keep_existing_linebreaks = true +resharper_keep_existing_switch_expression_arrangement = false +resharper_keep_user_linebreaks = true +resharper_max_initializer_elements_on_line = 2 +resharper_method_or_operator_body = block_body +resharper_outdent_binary_ops = true +resharper_outdent_commas = true +resharper_outdent_dots = true +resharper_space_around_arrow_op = true +resharper_space_within_single_line_array_initializer_braces = true +resharper_use_heuristics_for_body_style = true +resharper_use_indent_from_vs = false +resharper_wrap_after_declaration_lpar = true +resharper_wrap_after_invocation_lpar = true +resharper_wrap_arguments_style = wrap_if_long +resharper_wrap_before_declaration_rpar = true +resharper_wrap_before_invocation_rpar = true +resharper_wrap_chained_method_calls = wrap_if_long +resharper_wrap_multiple_declaration_style = chop_if_long +resharper_wrap_object_and_collection_initializer_style = chop_if_long +resharper_xmldoc_attribute_style = on_single_line +resharper_xmldoc_pi_attribute_style = on_single_line +resharper_xmldoc_space_after_last_pi_attribute = true +resharper_xmldoc_space_before_self_closing = true # ReSharper inspection severities -resharper_annotate_can_be_null_parameter_highlighting=warning -resharper_annotate_can_be_null_type_member_highlighting=warning -resharper_arrange_missing_parentheses_highlighting=warning -resharper_arrange_this_qualifier_highlighting=warning -resharper_built_in_type_reference_style_for_member_access_highlighting=error -resharper_built_in_type_reference_style_highlighting=error -resharper_enforce_do_while_statement_braces_highlighting=warning -resharper_enforce_fixed_statement_braces_highlighting=warning -resharper_enforce_foreach_statement_braces_highlighting=warning -resharper_enforce_for_statement_braces_highlighting=warning -resharper_enforce_if_statement_braces_highlighting=warning -resharper_enforce_lock_statement_braces_highlighting=warning -resharper_enforce_using_statement_braces_highlighting=warning -resharper_enforce_while_statement_braces_highlighting=warning -resharper_redundant_default_member_initializer_highlighting=hint -resharper_remove_redundant_braces_highlighting=warning -resharper_suggest_var_or_type_built_in_types_highlighting=warning -resharper_suggest_var_or_type_elsewhere_highlighting=warning -resharper_suggest_var_or_type_simple_types_highlighting=warning -resharper_unnecessary_whitespace_highlighting=warning -resharper_use_null_propagation_when_possible_highlighting=suggestion -resharper_web_config_module_not_resolved_highlighting=warning -resharper_web_config_type_not_resolved_highlighting=warning -resharper_web_config_wrong_module_highlighting=warning +resharper_annotate_can_be_null_parameter_highlighting = warning +resharper_annotate_can_be_null_type_member_highlighting = warning +resharper_arrange_constructor_or_destructor_body_highlighting = none +resharper_arrange_method_or_operator_body_highlighting = none +resharper_arrange_redundant_parentheses_highlighting = hint +resharper_arrange_this_qualifier_highlighting = hint +resharper_arrange_type_member_modifiers_highlighting = hint +resharper_arrange_type_modifiers_highlighting = hint +resharper_built_in_type_reference_style_for_member_access_highlighting = hint +resharper_built_in_type_reference_style_highlighting = hint +resharper_enforce_do_while_statement_braces_highlighting = warning +resharper_enforce_fixed_statement_braces_highlighting = warning +resharper_enforce_foreach_statement_braces_highlighting = warning +resharper_enforce_for_statement_braces_highlighting = warning +resharper_enforce_if_statement_braces_highlighting = warning +resharper_enforce_lock_statement_braces_highlighting = warning +resharper_enforce_using_statement_braces_highlighting = warning +resharper_enforce_while_statement_braces_highlighting = warning +resharper_redundant_base_qualifier_highlighting = warning +resharper_redundant_default_member_initializer_highlighting = hint +resharper_remove_redundant_braces_highlighting = warning +resharper_suggest_var_or_type_built_in_types_highlighting = hint +resharper_suggest_var_or_type_elsewhere_highlighting = hint +resharper_suggest_var_or_type_simple_types_highlighting = hint +resharper_unnecessary_whitespace_highlighting = warning +resharper_use_null_propagation_when_possible_highlighting = suggestion +resharper_web_config_module_not_resolved_highlighting = warning +resharper_web_config_type_not_resolved_highlighting = warning +resharper_web_config_wrong_module_highlighting = warning +resharper_partial_type_with_single_part_highlighting = none # .NET Analzyer settings # VSTHRD200: Use "Async" suffix for awaitable methods @@ -134,35 +1015,37 @@ dotnet_diagnostic.VSTHRD200.severity = none # CA2007: Do not directly await a Task dotnet_diagnostic.CA2007.severity = error -[*.{cs,cshtml}] -charset=utf-8 -indent_style=space -indent_size=4 -insert_final_newline=true - -[*.{js,ts,vue}] -indent_style=space -indent_size=4 -insert_final_newline=true - -[*.{xml,yml,yaml}] -indent_style=space -indent_size=2 -insert_final_newline=true - -[*.json] -indent_style=space -indent_size=4 -insert_final_newline=true - -[*.{xml,csproj,props,targets}] -indent_style=space - -[{*.har,*.inputactions,*.jsb2,*.jsb3,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] -indent_style=space -indent_size=2 - -[*.{appxmanifest,asax,ascx,aspx,build,cg,cginc,compute,cs,cshtml,dtd,fs,fsi,fsscript,fsx,hlsl,hlsli,hlslinc,master,ml,mli,nuspec,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}] -indent_style=space -indent_size=4 -tab_width=4 +ij_xml_align_attributes = true +ij_xml_align_text = false +ij_xml_attribute_wrap = normal +ij_xml_block_comment_at_first_column = true +ij_xml_keep_blank_lines = 2 +ij_xml_keep_indents_on_empty_lines = false +ij_xml_keep_line_breaks = true +ij_xml_keep_line_breaks_in_text = true +ij_xml_keep_whitespaces = true +ij_xml_keep_whitespaces_around_cdata = preserve +ij_xml_keep_whitespaces_inside_cdata = false +ij_xml_line_comment_at_first_column = true +ij_xml_space_after_tag_name = false +ij_xml_space_around_equals_in_attribute = false +ij_xml_space_inside_empty_tag = true +ij_xml_text_wrap = off + +# Microsoft .NET properties +dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True +dotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field +dotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef +dotnet_naming_rule.unity_serialized_field_rule.severity = warning +dotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style +dotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols +dotnet_naming_style.lower_camel_case_style.capitalization = camel_case +dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = * +dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds = +dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field +dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance + +[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,dtd,fs,fsi,fsscript,fsx,hlsl,hlsli,hlslinc,master,ml,mli,nuspec,paml,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}] +indent_style = space +indent_size = 4 +tab_width = 4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7351596b..dc540b305 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,17 +19,21 @@ name: ci on: push: branches: - - master - - next + - 'master' + - 'main' + - 'next' tags: - - v* + - 'v*' pull_request: branches: - - master - - next + - 'master' + - 'main' + - 'next' jobs: Build: + env: + NUGET_PACKAGES: '${{ github.workspace }}/.nuget/packages' strategy: fail-fast: false matrix: @@ -44,18 +48,21 @@ jobs: - name: Fetch all history for all tags and branches run: | git fetch --prune - - name: 🔨 Use .NET Core 2.1 SDK - uses: actions/setup-dotnet@v1.9.0 + - name: NuGet Cache + uses: actions/cache@v2 with: - dotnet-version: '2.1.x' + path: '${{ github.workspace }}/.nuget/packages' + key: "${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Build.targets', '**/Directory.Build.props', '**/*.csproj') }}" + restore-keys: | + ${{ runner.os }}-nuget- - name: 🔨 Use .NET Core 3.1 SDK uses: actions/setup-dotnet@v1.9.0 with: dotnet-version: '3.1.x' - - name: 🔨 Use .NET Core 5.0 SDK + - name: 🔨 Use .NET Core 6.0 SDK uses: actions/setup-dotnet@v1.9.0 with: - dotnet-version: '5.0.x' + dotnet-version: '6.0.x' - name: 🎁 dotnet tool restore run: | dotnet tool restore @@ -67,7 +74,7 @@ jobs: dotnet nuke Build --skip - name: 🚦 Test run: | - dotnet nuke Test Trigger_Code_Coverage_Reports Generate_Code_Coverage_Report_Cobertura Generate_Code_Coverage_Badges Generate_Code_Coverage_Summary Generate_Code_Coverage_Report --skip + dotnet nuke Test TriggerCodeCoverageReports GenerateCodeCoverageReportCobertura GenerateCodeCoverageBadges GenerateCodeCoverageSummary GenerateCodeCoverageReport --skip - name: 📦 Pack run: | dotnet nuke Pack --skip @@ -78,21 +85,18 @@ jobs: fail_ci_if_error: 'true' - name: 🏺 Publish logs if: always() - continue-on-error: true uses: actions/upload-artifact@v2 with: name: 'logs' path: 'artifacts/logs/' - name: 🏺 Publish coverage data if: always() - continue-on-error: true uses: actions/upload-artifact@v2 with: name: 'coverage' path: 'coverage/' - name: 🏺 Publish test data if: always() - continue-on-error: true uses: actions/upload-artifact@v2 with: name: 'test data' @@ -103,3 +107,10 @@ jobs: with: name: 'nuget' path: 'artifacts/nuget/' + Publish: + needs: + - Build + secrets: + RSG_NUGET_API_KEY: '${{ secrets.RSG_NUGET_API_KEY }}' + RSG_AZURE_DEVOPS: '${{ secrets.RSG_AZURE_DEVOPS }}' + uses: RocketSurgeonsGuild/actions/.github/workflows/publish-nuget.yml@v0.3.0 diff --git a/.gitignore b/.gitignore index 97caab569..f2f6f24b6 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ coverage.json coverage.info /codealike.json .tmp/ +.nuke/temp/ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..c6d920851 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,9 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged -d -r +dotnet nuke --generate-configuration GitHubActions_ci --host GitHubActions +git add .github/workflows/ci.yml +dotnet nuke --generate-configuration GitHubActions_ci-ignore --host GitHubActions +git add .github/workflows/ci-ignore.yml +git add .nuke/build.schema.json \ No newline at end of file diff --git a/.huskyrc b/.huskyrc deleted file mode 100644 index 80f5453bb..000000000 --- a/.huskyrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "hooks": { - "pre-commit": "lint-staged" - } -} \ No newline at end of file diff --git a/.lintstagedrc b/.lintstagedrc deleted file mode 100644 index 3dff2b2fb..000000000 --- a/.lintstagedrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "*.{cs,vb}": [ - "dotnet nuke lint --no-logo --lint-files" - ], - "*.{js,ts,jsx,tsx,json,yml,yaml}": [ - "prettier --write" - ] -} diff --git a/.lintstagedrc.js b/.lintstagedrc.js new file mode 100644 index 000000000..8403c0104 --- /dev/null +++ b/.lintstagedrc.js @@ -0,0 +1,28 @@ +function forEachChunk(chunks, callback, chunkSize = 50) { + var mappedFiles = []; + var files = chunks.concat(); + while (files.length > 0) { + var chunk = files.splice(0, chunkSize); + mappedFiles = mappedFiles.concat(callback(chunk)); + } + return mappedFiles; +} + +function cleanupcode(filenames) { + var sln = require('./.nuke/parameters.json').Solution; + return forEachChunk(filenames, chunk => [ + `dotnet jb cleanupcode ${sln} "--profile=Full Cleanup" "--disable-settings-layers=GlobalAll;GlobalPerProduct;SolutionPersonal;ProjectPersonal" "--include=${chunk.join( + ';' + )}"`, + ]); +} + +module.exports = { + '*.cs': filenames => { + return [`echo "'${filenames.join(`' '`)}'" | dotnet format --include -`].concat(cleanupcode(filenames)); + }, + '*.{csproj,targets,props,xml}': filenames => + forEachChunk(filenames, chunk => [`prettier --write '${chunk.join(`' '`)}'`]), + '*.{js,ts,jsx,tsx,json,yml,yaml}': filenames => + forEachChunk(filenames, chunk => [`prettier --write '${chunk.join(`' '`)}'`]), +}; diff --git a/.nuke b/.nuke deleted file mode 100644 index d1bf89faf..000000000 --- a/.nuke +++ /dev/null @@ -1,2 +0,0 @@ -LSP.sln - diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json new file mode 100644 index 000000000..f99d257e6 --- /dev/null +++ b/.nuke/build.schema.json @@ -0,0 +1,157 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Build Schema", + "$ref": "#/definitions/build", + "definitions": { + "build": { + "type": "object", + "properties": { + "Artifacts": { + "type": "string", + "description": "The directory where artifacts are to be dropped" + }, + "Configuration": { + "type": "string", + "description": "Configuration to build", + "enum": [ + "Debug", + "Release" + ] + }, + "Continue": { + "type": "boolean", + "description": "Indicates to continue a previously failed build attempt" + }, + "Coverage": { + "type": "string", + "description": "The directory where coverage artifacts are to be dropped" + }, + "Help": { + "type": "boolean", + "description": "Shows the help text for this build assembly" + }, + "Host": { + "type": "string", + "description": "Host for execution. Default is 'automatic'", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "NoLogo": { + "type": "boolean", + "description": "Disables displaying the NUKE logo" + }, + "Partition": { + "type": "string", + "description": "Partition to use on CI" + }, + "Plan": { + "type": "boolean", + "description": "Shows the execution plan (HTML)" + }, + "Profile": { + "type": "array", + "description": "Defines the profiles to load", + "items": { + "type": "string" + } + }, + "Root": { + "type": "string", + "description": "Root directory during build execution" + }, + "Skip": { + "type": "array", + "description": "List of targets to be skipped. Empty list skips all dependencies", + "items": { + "type": "string", + "enum": [ + "Build", + "BuildVersion", + "Clean", + "CoreBuild", + "CorePack", + "CoreRestore", + "CoreTest", + "Default", + "DotnetToolRestore", + "Generate_Code_Coverage_Badges", + "Generate_Code_Coverage_Report", + "Generate_Code_Coverage_Report_Cobertura", + "Generate_Code_Coverage_Summary", + "GenerateCodeCoverageBadges", + "GenerateCodeCoverageReport", + "GenerateCodeCoverageReportCobertura", + "GenerateCodeCoverageSummary", + "GenerateReadme", + "Pack", + "Restore", + "Test", + "Trigger_Code_Coverage_Reports", + "TriggerCodeCoverageReports" + ] + } + }, + "Solution": { + "type": "string", + "description": "Path to a solution file that is automatically loaded" + }, + "Target": { + "type": "array", + "description": "List of targets to be invoked. Default is '{default_target}'", + "items": { + "type": "string", + "enum": [ + "Build", + "BuildVersion", + "Clean", + "CoreBuild", + "CorePack", + "CoreRestore", + "CoreTest", + "Default", + "DotnetToolRestore", + "Generate_Code_Coverage_Badges", + "Generate_Code_Coverage_Report", + "Generate_Code_Coverage_Report_Cobertura", + "Generate_Code_Coverage_Summary", + "GenerateCodeCoverageBadges", + "GenerateCodeCoverageReport", + "GenerateCodeCoverageReportCobertura", + "GenerateCodeCoverageSummary", + "GenerateReadme", + "Pack", + "Restore", + "Test", + "Trigger_Code_Coverage_Reports", + "TriggerCodeCoverageReports" + ] + } + }, + "Verbosity": { + "type": "string", + "description": "Logging verbosity during build execution. Default is 'Normal'", + "enum": [ + "Minimal", + "Normal", + "Quiet", + "Verbose" + ] + } + } + } + } +} \ No newline at end of file diff --git a/.nuke/parameters.json b/.nuke/parameters.json new file mode 100644 index 000000000..2d4a451b6 --- /dev/null +++ b/.nuke/parameters.json @@ -0,0 +1,4 @@ +{ + "$schema": "./build.schema.json", + "Solution": "LSP.sln" +} \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 2faf38352..33227515d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,4 @@ azure-pipelines.nuke.yml .github/workflows/ci.yml +.github/workflows/ci-ignore.yml +.nuke/build.schema.json diff --git a/Directory.Build.props b/Directory.Build.props index 2b19c9ec0..0eaf54839 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -28,7 +28,13 @@ true - + diff --git a/Directory.Build.targets b/Directory.Build.targets index 50e19ac9f..c40b47dd6 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,53 +1,52 @@  - - $(BaseIntermediateOutputPath)\GeneratedFiles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/azure-pipelines.nuke.yml b/azure-pipelines.nuke.yml index 633418b1c..308824ac0 100644 --- a/azure-pipelines.nuke.yml +++ b/azure-pipelines.nuke.yml @@ -23,7 +23,7 @@ parameters: steps: - pwsh: dotnet nuke Build --skip --artifacts '${{ parameters.Artifacts }}' --coverage '${{ parameters.Coverage }}' --configuration '${{ parameters.Configuration }}' --verbosity '${{ parameters.Verbosity }}' displayName: '⚙ Build' - - pwsh: dotnet nuke Test Trigger_Code_Coverage_Reports Generate_Code_Coverage_Report_Cobertura Generate_Code_Coverage_Badges Generate_Code_Coverage_Summary Generate_Code_Coverage_Report --skip --artifacts '${{ parameters.Artifacts }}' --coverage '${{ parameters.Coverage }}' --configuration '${{ parameters.Configuration }}' --verbosity '${{ parameters.Verbosity }}' + - pwsh: dotnet nuke Test TriggerCodeCoverageReports GenerateCodeCoverageReportCobertura GenerateCodeCoverageBadges GenerateCodeCoverageSummary GenerateCodeCoverageReport --skip --artifacts '${{ parameters.Artifacts }}' --coverage '${{ parameters.Coverage }}' --configuration '${{ parameters.Configuration }}' --verbosity '${{ parameters.Verbosity }}' displayName: '🚦 Test' - pwsh: dotnet nuke Pack --skip --artifacts '${{ parameters.Artifacts }}' --coverage '${{ parameters.Coverage }}' --configuration '${{ parameters.Configuration }}' --verbosity '${{ parameters.Verbosity }}' displayName: '📦 Pack' diff --git a/benchmarks/Pipeline/Pipeline.csproj b/benchmarks/Pipeline/Pipeline.csproj index 15cca63e3..0027f64e2 100644 --- a/benchmarks/Pipeline/Pipeline.csproj +++ b/benchmarks/Pipeline/Pipeline.csproj @@ -9,7 +9,7 @@ - + diff --git a/build.cmd b/build.cmd new file mode 100755 index 000000000..b08cc590f --- /dev/null +++ b/build.cmd @@ -0,0 +1,7 @@ +:; set -eo pipefail +:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) +:; ${SCRIPT_DIR}/build.sh "$@" +:; exit $? + +@ECHO OFF +powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %* diff --git a/build.ps1 b/build.ps1 index 91f068d7d..9f908eb3d 100644 --- a/build.ps1 +++ b/build.ps1 @@ -4,9 +4,9 @@ Param( [string[]]$BuildArguments ) -Write-Output "Windows PowerShell $($Host.Version)" +Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)" -Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { exit 1 } +Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 } $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent ########################################################################### @@ -14,14 +14,15 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent ########################################################################### $BuildProjectFile = "$PSScriptRoot\.build\.build.csproj" -$TempDirectory = "$PSScriptRoot\\.tmp" +$TempDirectory = "$PSScriptRoot\\.nuke\temp" $DotNetGlobalFile = "$PSScriptRoot\\global.json" -$DotNetInstallUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1" +$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" $DotNetChannel = "Current" $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 +$env:DOTNET_MULTILEVEL_LOOKUP = 0 ########################################################################### # EXECUTION @@ -32,37 +33,37 @@ function ExecSafe([scriptblock] $cmd) { if ($LASTEXITCODE) { exit $LASTEXITCODE } } -# If global.json exists, load expected version -if (Test-Path $DotNetGlobalFile) { - $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) - if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { - $DotNetVersion = $DotNetGlobal.sdk.version - } -} - -# If dotnet is installed locally, and expected version is not set or installation matches the expected version -if ((Get-Command "dotnet" -ErrorAction SilentlyContinue) -ne $null -and ` - (!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) { +# If dotnet CLI is installed globally and it matches requested version, use for execution +if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and ` + $(dotnet --version) -and $LASTEXITCODE -eq 0) { $env:DOTNET_EXE = (Get-Command "dotnet").Path } else { - $DotNetDirectory = "$TempDirectory\dotnet-win" - $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" - # Download install script $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" - md -force $TempDirectory > $null + New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile) + # If global.json exists, load expected version + if (Test-Path $DotNetGlobalFile) { + $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) + if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { + $DotNetVersion = $DotNetGlobal.sdk.version + } + } + # Install by channel or version + $DotNetDirectory = "$TempDirectory\dotnet-win" if (!(Test-Path variable:DotNetVersion)) { - ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } } else { - ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } } + $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" } Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)" -ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false } +ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet } ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments } diff --git a/build.sh b/build.sh index 25b34f4c2..75f7d9930 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -echo $(bash --version 2>&1 | head -n 1) +bash --version 2>&1 | head -n 1 set -eo pipefail SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) @@ -10,53 +10,53 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) ########################################################################### BUILD_PROJECT_FILE="$SCRIPT_DIR/.build/.build.csproj" -TEMP_DIRECTORY="$SCRIPT_DIR//.tmp" +TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" -DOTNET_INSTALL_URL="https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.sh" +DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" DOTNET_CHANNEL="Current" export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +export DOTNET_MULTILEVEL_LOOKUP=0 ########################################################################### # EXECUTION ########################################################################### function FirstJsonValue { - perl -nle 'print $1 if m{"'$1'": "([^"\-]+)",?}' <<< ${@:2} + perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}" } -# If global.json exists, load expected version -if [ -f "$DOTNET_GLOBAL_FILE" ]; then - DOTNET_VERSION=$(FirstJsonValue "version" $(cat "$DOTNET_GLOBAL_FILE")) - if [ "$DOTNET_VERSION" == "" ]; then - unset DOTNET_VERSION - fi -fi - -# If dotnet is installed locally, and expected version is not set or installation matches the expected version -if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") ]]; then +# If dotnet CLI is installed globally and it matches requested version, use for execution +if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then export DOTNET_EXE="$(command -v dotnet)" else - DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" - export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" - # Download install script DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" mkdir -p "$TEMP_DIRECTORY" curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" chmod +x "$DOTNET_INSTALL_FILE" + # If global.json exists, load expected version + if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then + DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")") + if [[ "$DOTNET_VERSION" == "" ]]; then + unset DOTNET_VERSION + fi + fi + # Install by channel or version - if [ -z ${DOTNET_VERSION+x} ]; then + DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" + if [[ -z ${DOTNET_VERSION+x} ]]; then "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path else "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path fi + export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" fi echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)" -"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false +"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" diff --git a/global.json b/global.json new file mode 100644 index 000000000..403171d04 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "6.0.200" + } +} \ No newline at end of file diff --git a/package.json b/package.json index 434e4b243..f731e5687 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,12 @@ { "private": true, "devDependencies": { - "husky": "^7.0.2", - "lint-staged": "^11.1.2", - "prettier": "^2.5.1" + "@prettier/plugin-xml": "1.2.0", + "husky": "7.0.4", + "lint-staged": "12.3.4", + "prettier": "2.5.1" + }, + "scripts": { + "prepare": "husky install" } } diff --git a/sample/SampleServer/SampleServer.csproj b/sample/SampleServer/SampleServer.csproj index ce86be19e..2f6296f5d 100644 --- a/sample/SampleServer/SampleServer.csproj +++ b/sample/SampleServer/SampleServer.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/src/JsonRpc.Generators/AssemblyCapabilityKeyAttributeGenerator.cs b/src/JsonRpc.Generators/AssemblyCapabilityKeyAttributeGenerator.cs index 55dd9ae7a..538a04a54 100644 --- a/src/JsonRpc.Generators/AssemblyCapabilityKeyAttributeGenerator.cs +++ b/src/JsonRpc.Generators/AssemblyCapabilityKeyAttributeGenerator.cs @@ -1,113 +1,84 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace OmniSharp.Extensions.JsonRpc.Generators { [Generator] - public class AssemblyCapabilityKeyAttributeGenerator : CachedSourceGenerator + public class AssemblyCapabilityKeyAttributeGenerator : IIncrementalGenerator { - protected override void Execute( - GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic - ) + public void Initialize(IncrementalGeneratorInitializationContext context) { - var namespaces = new HashSet() { "OmniSharp.Extensions.LanguageServer.Protocol" }; - var types = syntaxReceiver.FoundNodes - .Concat(syntaxReceiver.Handlers) - .Select( - options => { - var semanticModel = context.Compilation.GetSemanticModel(options.SyntaxTree); - foreach (var item in options.SyntaxTree.GetCompilationUnitRoot() - .Usings - .Where(z => z.Alias == null) - .Select(z => z.Name.ToFullString())) - { - namespaces.Add(item); - } - - var typeSymbol = semanticModel.GetDeclaredSymbol(options)!; + var syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (syntaxNode, token) => + { + if (syntaxNode.Parent is TypeDeclarationSyntax) return false; + if (syntaxNode is TypeDeclarationSyntax { Arity: 0, BaseList: { } bl } typeDeclarationSyntax + and (ClassDeclarationSyntax or RecordDeclarationSyntax) + && !typeDeclarationSyntax.Modifiers.Any(SyntaxKind.AbstractKeyword) + && typeDeclarationSyntax.AttributeLists.ContainsAttribute("CapabilityKey") + && bl.Types.Any( + z => z.Type switch + { + SimpleNameSyntax + { + Identifier: { Text: "ICapability" or "DynamicCapability" or "IDynamicCapability" or "LinkSupportCapability" }, Arity: 0 + } => true, + _ => false + } + )) + { + return true; + } - return SyntaxFactory.Attribute( - SyntaxFactory.IdentifierName("AssemblyCapabilityKey"), SyntaxFactory.AttributeArgumentList( - SyntaxFactory.SeparatedList( - new[] { - SyntaxFactory.AttributeArgument( - SyntaxFactory.TypeOfExpression(SyntaxFactory.ParseName(typeSymbol.ToDisplayString())) - ), - }.Concat(options.AttributeLists.GetAttribute("CapabilityKey")!.ArgumentList!.Arguments) - ) - ) - ); - } - ) - .ToArray(); - if (types.Any()) - { - var cu = SyntaxFactory.CompilationUnit() - .WithUsings(SyntaxFactory.List(namespaces.OrderBy(z => z).Select(z => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(z))))) - .AddAttributeLists( - SyntaxFactory.AttributeList( - target: SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword)), SyntaxFactory.SeparatedList(types) - ) - ) - .WithLeadingTrivia(SyntaxFactory.Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); + return false; + }, + transform: (syntaxContext, token) => + { + var namespaces = new HashSet() { "OmniSharp.Extensions.LanguageServer.Protocol" }; + var tds = (TypeDeclarationSyntax)syntaxContext.Node; + + foreach (var item in syntaxContext.Node.SyntaxTree.GetCompilationUnitRoot() + .Usings.Where(z => z.Alias == null) + .Select(z => z.Name.ToFullString())) + { + namespaces.Add(item); + } - context.AddSource("AssemblyCapabilityKeys.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); - } - } + var typeSymbol = syntaxContext.SemanticModel.GetDeclaredSymbol(syntaxContext.Node)!; - public AssemblyCapabilityKeyAttributeGenerator() : base(() => new SyntaxReceiver(Cache)) - { + return (namespaces, Attribute(IdentifierName("AssemblyCapabilityKey"), AttributeArgumentList(SeparatedList(new[] { AttributeArgument(TypeOfExpression(ParseName(typeSymbol.ToDisplayString()))), }.Concat(tds.AttributeLists.GetAttribute("CapabilityKey")!.ArgumentList!.Arguments))))); + } + ).Collect(); + + context.RegisterSourceOutput(syntaxProvider, GenerateAssemblyCapabilityKeys); } - public static CacheContainer Cache = new(); - - public class SyntaxReceiver : SyntaxReceiverCache + private void GenerateAssemblyCapabilityKeys(SourceProductionContext context, ImmutableArray<(HashSet namespaces, AttributeSyntax attribute)> types) { - public List Handlers { get; } = new(); - - public override string? GetKey(TypeDeclarationSyntax syntax) - { - var hasher = new CacheKeyHasher(); - hasher.Append(syntax.SyntaxTree.FilePath); - hasher.Append(syntax.Keyword.Text); - hasher.Append(syntax.Identifier.Text); - hasher.Append(syntax.TypeParameterList); - hasher.Append(syntax.AttributeLists); - hasher.Append(syntax.BaseList); - - return hasher; - } - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public override void OnVisitNode(TypeDeclarationSyntax syntaxNode) - { - if (syntaxNode.Parent is TypeDeclarationSyntax) return; - if (syntaxNode is ClassDeclarationSyntax or RecordDeclarationSyntax - && syntaxNode.Arity == 0 - && !syntaxNode.Modifiers.Any(SyntaxKind.AbstractKeyword) - && syntaxNode.AttributeLists.ContainsAttribute("CapabilityKey") - && syntaxNode.BaseList is { } bl && bl.Types.Any( - z => z.Type switch { - SimpleNameSyntax { Identifier: { Text: "ICapability" or "DynamicCapability" or "IDynamicCapability" or "LinkSupportCapability" }, Arity: 0 } => true, - _ => false - } - )) + var namespaces = types.Aggregate( + new HashSet(), (set, tuple) => { - Handlers.Add(syntaxNode); - } - } + foreach (var name in tuple.namespaces) + { + set.Add(name); + } - public SyntaxReceiver(CacheContainer cache) : base(cache) + return set; + } + ); + if (types.Any()) { + var cu = CompilationUnit() + .WithUsings(List(namespaces.OrderBy(z => z).Select(z => UsingDirective(ParseName(z))))) + .AddAttributeLists(AttributeList(target: AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), SeparatedList(types.Select(z => z.attribute)))); + + context.AddSource("AssemblyCapabilityKeys.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); } } } diff --git a/src/JsonRpc.Generators/AssemblyJsonRpcHandlersAttributeGenerator.cs b/src/JsonRpc.Generators/AssemblyJsonRpcHandlersAttributeGenerator.cs index 81b6f97df..9871cd1bb 100644 --- a/src/JsonRpc.Generators/AssemblyJsonRpcHandlersAttributeGenerator.cs +++ b/src/JsonRpc.Generators/AssemblyJsonRpcHandlersAttributeGenerator.cs @@ -1,122 +1,89 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; -using OmniSharp.Extensions.JsonRpc.Generators.Contexts; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace OmniSharp.Extensions.JsonRpc.Generators { [Generator] - public class AssemblyJsonRpcHandlersAttributeGenerator : CachedSourceGenerator + public class AssemblyJsonRpcHandlersAttributeGenerator : IIncrementalGenerator { - protected override void Execute( - GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic - ) + public void Initialize(IncrementalGeneratorInitializationContext context) { - var namespaces = new HashSet() { "OmniSharp.Extensions.JsonRpc" }; - var types = syntaxReceiver.FoundNodes - .Concat(syntaxReceiver.Handlers) - .Select( - options => { - var semanticModel = context.Compilation.GetSemanticModel(options.SyntaxTree); - var typeSymbol = semanticModel.GetDeclaredSymbol(options)!; + var syntaxProvider = context + .SyntaxProvider + .CreateSyntaxProvider( + predicate: (syntaxNode, token) => + { + if (syntaxNode.Parent is TypeDeclarationSyntax) return false; + if (syntaxNode is TypeDeclarationSyntax { Arity: 0, BaseList: { } bl } typeDeclarationSyntax + and (ClassDeclarationSyntax or RecordDeclarationSyntax) + && !typeDeclarationSyntax.Modifiers.Any(SyntaxKind.AbstractKeyword) + && typeDeclarationSyntax.AttributeLists.ContainsAttribute("Method") + && bl.Types.Any( + z => z.Type switch + { + SimpleNameSyntax { Identifier: { Text: "IJsonRpcNotificationHandler" }, Arity: 0 or 1 } => true, + SimpleNameSyntax { Identifier: { Text: "ICanBeResolvedHandler" }, Arity: 1 } => true, + SimpleNameSyntax { Identifier: { Text: "IJsonRpcRequestHandler" }, Arity: 1 or 2 } => true, + SimpleNameSyntax { Identifier: { Text: "IJsonRpcHandler" }, Arity: 0 } => true, + _ => false + } + )) + { + return true; + } - return AttributeArgument(TypeOfExpression(ParseName(typeSymbol.ToDisplayString()))); - } - ) - .ToArray(); - if (types.Any()) - { - var cu = CompilationUnit() - .WithUsings(List(namespaces.OrderBy(z => z).Select(z => UsingDirective(ParseName(z))))) - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(CarriageReturnLineFeed); - while (types.Length > 0) - { - var innerTypes = types.Take(10).ToArray(); - types = types.Skip(10).ToArray(); - cu = cu.AddAttributeLists( - AttributeList( - target: AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), - SingletonSeparatedList(Attribute(IdentifierName("AssemblyJsonRpcHandlers"), AttributeArgumentList(SeparatedList(innerTypes)))) - ) - ); - } - context.AddSource("AssemblyJsonRpcHandlers.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); - } - } + if (syntaxNode is InterfaceDeclarationSyntax { Arity: 0, BaseList: { } bl2 } interfaceDeclarationSyntax + && interfaceDeclarationSyntax.AttributeLists.ContainsAttribute("Method") + && bl2.Types.Any( + z => z.Type switch + { + SimpleNameSyntax { Identifier: { Text: "IJsonRpcNotificationHandler" }, Arity: 0 or 1 } => true, + SimpleNameSyntax { Identifier: { Text: "ICanBeResolvedHandler" }, Arity: 1 } => true, + SimpleNameSyntax { Identifier: { Text: "IJsonRpcRequestHandler" }, Arity: 1 or 2 } => true, + SimpleNameSyntax { Identifier: { Text: "IJsonRpcHandler" }, Arity: 0 } => true, + _ => false + } + )) + { + return true; + } - public AssemblyJsonRpcHandlersAttributeGenerator() : base(() => new SyntaxReceiver(Cache)) - { - } + return false; + }, + transform: (syntaxContext, token) => AttributeArgument( + TypeOfExpression( + ParseName(syntaxContext.SemanticModel.GetDeclaredSymbol(syntaxContext.Node)!.ToDisplayString()) + ) + ) + ) + .Collect(); - public static CacheContainer Cache = new(); + context.RegisterSourceOutput(syntaxProvider, GenerateAssemblyJsonRpcHandlers); + } - public class SyntaxReceiver : SyntaxReceiverCache + private void GenerateAssemblyJsonRpcHandlers(SourceProductionContext context, ImmutableArray types) { - public List Handlers { get; } = new(); - - public override string? GetKey(TypeDeclarationSyntax syntax) - { - var hasher = new CacheKeyHasher(); - hasher.Append(syntax.SyntaxTree.FilePath); - hasher.Append(syntax.Keyword.Text); - hasher.Append(syntax.Identifier.Text); - hasher.Append(syntax.TypeParameterList); - hasher.Append(syntax.AttributeLists); - hasher.Append(syntax.BaseList); - return hasher; - } - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public override void OnVisitNode(TypeDeclarationSyntax syntaxNode) + var namespaces = new HashSet() { "OmniSharp.Extensions.JsonRpc" }; + if (types.Any()) { - if (syntaxNode.Parent is TypeDeclarationSyntax) return; - if (syntaxNode is ClassDeclarationSyntax or RecordDeclarationSyntax - && syntaxNode.Arity == 0 - && !syntaxNode.Modifiers.Any(SyntaxKind.AbstractKeyword) - && syntaxNode.AttributeLists.ContainsAttribute("Method") - && syntaxNode.BaseList is { } bl && bl.Types.Any( - z => z.Type switch { - SimpleNameSyntax { Identifier: { Text: "IJsonRpcNotificationHandler" }, Arity: 0 or 1 } => true, - SimpleNameSyntax { Identifier: { Text: "ICanBeResolvedHandler" }, Arity: 1 } => true, - SimpleNameSyntax { Identifier: { Text: "IJsonRpcRequestHandler" }, Arity: 1 or 2 } => true, - SimpleNameSyntax { Identifier: { Text: "IJsonRpcHandler" }, Arity: 0 } => true, - _ => false - } - )) - { - Handlers.Add(syntaxNode); - } - - if (syntaxNode is InterfaceDeclarationSyntax - && syntaxNode.Arity == 0 - && syntaxNode.AttributeLists.ContainsAttribute("Method") - && syntaxNode.BaseList is { } bl2 && bl2.Types.Any( - z => z.Type switch { - SimpleNameSyntax { Identifier: { Text: "IJsonRpcNotificationHandler" }, Arity: 0 or 1 } => true, - SimpleNameSyntax { Identifier: { Text: "ICanBeResolvedHandler" }, Arity: 1 } => true, - SimpleNameSyntax { Identifier: { Text: "IJsonRpcRequestHandler" }, Arity: 1 or 2 } => true, - SimpleNameSyntax { Identifier: { Text: "IJsonRpcHandler" }, Arity: 0 } => true, - _ => false - } - )) + var cu = CompilationUnit() + .WithUsings(List(namespaces.OrderBy(z => z).Select(z => UsingDirective(ParseName(z))))); + while (types.Length > 0) { - Handlers.Add(syntaxNode); + var innerTypes = types.Take(10).ToArray(); + types = types.Skip(10).ToImmutableArray(); + cu = cu.AddAttributeLists(AttributeList(target: AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), SingletonSeparatedList(Attribute(IdentifierName("AssemblyJsonRpcHandlers"), AttributeArgumentList(SeparatedList(innerTypes)))))); } - } - public SyntaxReceiver(CacheContainer cache) : base(cache) - { + context.AddSource("AssemblyJsonRpcHandlers.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); } } } diff --git a/src/JsonRpc.Generators/AutoImplementParamsGenerator.cs b/src/JsonRpc.Generators/AutoImplementParamsGenerator.cs index 541aa1c2b..74287848d 100644 --- a/src/JsonRpc.Generators/AutoImplementParamsGenerator.cs +++ b/src/JsonRpc.Generators/AutoImplementParamsGenerator.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -5,69 +6,84 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using static OmniSharp.Extensions.JsonRpc.Generators.CommonElements; namespace OmniSharp.Extensions.JsonRpc.Generators { [Generator] - public class AutoImplementParamsGenerator : CachedSourceGenerator + public class AutoImplementParamsGenerator : IIncrementalGenerator { - protected override void Execute( - GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic - ) + public void Initialize(IncrementalGeneratorInitializationContext context) { - foreach (var candidate in syntaxReceiver.Candidates) - { - var members = new List(); - var model = context.Compilation.GetSemanticModel(candidate.SyntaxTree); - var symbol = model.GetDeclaredSymbol(candidate); - if (symbol is null) continue; + var _attributes = "Method,RegistrationOptions"; + var _interfaces = "IPartialItemsRequest,IPartialItemRequest,IWorkDoneProgressParams,IHandlerIdentity"; - var autoImplementProperties = AutoImplementInterfaces(candidate, symbol).ToArray(); - if (autoImplementProperties is { Length: > 0 }) + var syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (syntaxNode, token) => { - var extendedParams = candidate - .WithAttributeLists(List()) - .WithMembers(List(autoImplementProperties)) - .WithConstraintClauses(List()) - .WithBaseList(null); - members.Add(extendedParams); - } + if (syntaxNode is TypeDeclarationSyntax typeDeclarationSyntax and (ClassDeclarationSyntax or RecordDeclarationSyntax) + && ( typeDeclarationSyntax.AttributeLists.ContainsAttribute(_attributes) + || typeDeclarationSyntax.BaseList?.Types.Any(type => type.Type.GetSyntaxName() is { } n && _interfaces.Contains(n)) == true + ) + ) + { + return true; + } - if (members.Count == 0) continue; + return false; + }, transform: (syntaxContext, token) => { return syntaxContext; } + ); - if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword))) - { - cacheDiagnostic(candidate, static c => Diagnostic.Create(GeneratorDiagnostics.MustBePartial, c.Identifier.GetLocation(), c.Identifier.Text)); - } - var cu = CompilationUnit( - List(), - List(candidate.SyntaxTree.GetCompilationUnitRoot().Usings), - List(), - SingletonList( - NamespaceDeclaration(ParseName(symbol.ContainingNamespace.ToDisplayString())) - .WithMembers(List(members)) - ) - ) - .AddUsings(UsingDirective(ParseName("OmniSharp.Extensions.LanguageServer.Protocol.Serialization"))) - .WithLeadingTrivia() - .WithTrailingTrivia() - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool), Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true))) - .WithTrailingTrivia(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)), CarriageReturnLineFeed); + context.RegisterSourceOutput(syntaxProvider, GenerateAutoImplementedInterfaces); + } - addCacheSource( - $"{Path.GetFileNameWithoutExtension(candidate.SyntaxTree.FilePath)}_{candidate.Identifier.Text}{( candidate.Arity > 0 ? candidate.Arity.ToString() : "" )}.cs", - candidate, - cu.NormalizeWhitespace().GetText(Encoding.UTF8) - ); + private static void GenerateAutoImplementedInterfaces(SourceProductionContext context, GeneratorSyntaxContext syntaxContext) + { + var candidate = (TypeDeclarationSyntax)syntaxContext.Node; + var members = new List(); + var model = syntaxContext.SemanticModel; + var symbol = model.GetDeclaredSymbol(candidate); + if (symbol is null) return; + + var autoImplementProperties = AutoImplementInterfaces(candidate, symbol).ToArray(); + if (autoImplementProperties is { Length: > 0 }) + { + var extendedParams = candidate.WithAttributeLists(List()) + .WithMembers(List(autoImplementProperties)) + .WithConstraintClauses(List()) + .WithBaseList(null); + members.Add(extendedParams); } + + if (members.Count == 0) return; + + if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword))) + { + context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.MustBePartial, candidate.Identifier.GetLocation(), candidate.Identifier.Text)); + } + + var cu = CompilationUnit( + List(), List(candidate.SyntaxTree.GetCompilationUnitRoot().Usings), List(), + SingletonList( + NamespaceDeclaration(ParseName(symbol.ContainingNamespace.ToDisplayString())) + .WithMembers(List(members)) + ) + ) + .AddUsings(UsingDirective(ParseName("OmniSharp.Extensions.LanguageServer.Protocol.Serialization"))) + .WithLeadingTrivia() + .WithTrailingTrivia() + .WithLeadingTrivia(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true))) + .WithTrailingTrivia(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true))); + + context.AddSource( + $"{Path.GetFileNameWithoutExtension(candidate.SyntaxTree.FilePath)}_{candidate.Identifier.Text}{( candidate.Arity > 0 ? candidate.Arity.ToString() : "" )}.cs", + cu.NormalizeWhitespace().GetText(Encoding.UTF8) + ); } - private static IEnumerable AutoImplementInterfaces(TypeDeclarationSyntax syntax, INamedTypeSymbol symbol) + private static IEnumerable AutoImplementInterfaces(BaseTypeDeclarationSyntax syntax, INamedTypeSymbol symbol) { if (syntax.BaseList?.Types.Any(z => z.Type.GetSyntaxName() is "IWorkDoneProgressParams") == true && symbol.GetMembers("WorkDoneToken").IsEmpty) @@ -93,19 +109,27 @@ private static IEnumerable AutoImplementInterfaces(Type yield return PropertyDeclaration(PredefinedType(Token(SyntaxKind.StringKeyword)), Identifier("__identity")) .WithAttributeLists( List( - new[] { + new[] + { AttributeList( SeparatedList( - new[] { + new[] + { Attribute(IdentifierName("JsonProperty")) .WithArgumentList( AttributeArgumentList( SeparatedList( - new[] { - AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal("$$__handler_id__$$"))), + new[] + { + AttributeArgument( + LiteralExpression( + SyntaxKind.StringLiteralExpression, Literal("$$__handler_id__$$") + ) + ), AttributeArgument( MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, IdentifierName("DefaultValueHandling"), + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("DefaultValueHandling"), IdentifierName("Ignore") ) ) @@ -137,57 +161,5 @@ private static IEnumerable AutoImplementInterfaces(Type .WithAccessorList(GetInitAccessor); } } - - public AutoImplementParamsGenerator() : base(() => new SyntaxReceiver(Cache)) - { - } - - public static CacheContainer Cache = new(); - - public class SyntaxReceiver : SyntaxReceiverCache - { - private readonly string _attributes; - private readonly string _interfaces; - public List Candidates { get; } = new(); - - public SyntaxReceiver(CacheContainer cacheContainer) : base(cacheContainer) - { - _attributes = "Method,RegistrationOptions"; - _interfaces = "IPartialItemsRequest,IPartialItemRequest,IWorkDoneProgressParams,IHandlerIdentity"; - } - - public override string? GetKey(TypeDeclarationSyntax syntax) - { - var hasher = new CacheKeyHasher(); - hasher.Append(syntax.SyntaxTree.FilePath); - hasher.Append(syntax.Keyword.Text); - hasher.Append(syntax.Identifier.Text); - hasher.Append(syntax.TypeParameterList); - hasher.Append(syntax.AttributeLists); - hasher.Append(syntax.BaseList); - foreach (var item in syntax.Members.OfType().Select(z => z.Identifier.Text)) - { - hasher.Append(item); - } - - return hasher; - } - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public override void OnVisitNode(TypeDeclarationSyntax syntaxNode) - { - // any field with at least one attribute is a candidate for property generation - if (syntaxNode is ClassDeclarationSyntax or RecordDeclarationSyntax - && ( syntaxNode.AttributeLists.ContainsAttribute(_attributes) - || syntaxNode.BaseList?.Types.Any(type => type.Type.GetSyntaxName() is { } n && _interfaces.Contains(n)) == true - ) - ) - { - Candidates.Add(syntaxNode); - } - } - } } } diff --git a/src/JsonRpc.Generators/Cache/AddCacheSource.cs b/src/JsonRpc.Generators/Cache/AddCacheSource.cs deleted file mode 100644 index e593a0c81..000000000 --- a/src/JsonRpc.Generators/Cache/AddCacheSource.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; - -namespace OmniSharp.Extensions.JsonRpc.Generators.Cache -{ - public delegate void AddCacheSource(string hintName, T syntaxNode, SourceText sourceText) where T : SyntaxNode; - - public delegate void ReportCacheDiagnostic(T syntaxNode, CacheDiagnosticFactory diagnostic) where T : SyntaxNode; - - public delegate Diagnostic CacheDiagnosticFactory(T syntaxNode) where T : SyntaxNode; - - public delegate Location LocationFactory(T syntaxNode) where T : SyntaxNode; -} diff --git a/src/JsonRpc.Generators/Cache/CacheContainer.cs b/src/JsonRpc.Generators/Cache/CacheContainer.cs deleted file mode 100644 index 7b8084630..000000000 --- a/src/JsonRpc.Generators/Cache/CacheContainer.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Immutable; -using System.Threading; -using Microsoft.CodeAnalysis; - -namespace OmniSharp.Extensions.JsonRpc.Generators.Cache -{ - public class CacheContainer where T : SyntaxNode - { - private ImmutableDictionary> _sourceTexts; - private ImmutableDictionary>> _cacheDiagnostics; - - public CacheContainer() - { - _sourceTexts = ImmutableDictionary>.Empty; - _cacheDiagnostics = ImmutableDictionary>>.Empty; - } - - public ImmutableDictionary> SourceTexts => _sourceTexts; - public ImmutableDictionary>> Diagnostics => _cacheDiagnostics; - - public void Swap( - ImmutableDictionary.Builder sources)>.Builder foundCache, - ImmutableDictionary>.Builder>.Builder diagnosticFactories - ) - { - Interlocked.Exchange( - ref _sourceTexts, - foundCache.ToImmutableDictionary(z => z.Key, z => z.Value.sources.ToImmutable()) - ); - Interlocked.Exchange( - ref _cacheDiagnostics, - diagnosticFactories.ToImmutableDictionary(z => z.Key, z => z.Value.ToImmutable()) - ); - } - } -} diff --git a/src/JsonRpc.Generators/Cache/CacheKeyHasher.cs b/src/JsonRpc.Generators/Cache/CacheKeyHasher.cs deleted file mode 100644 index 2061cbbee..000000000 --- a/src/JsonRpc.Generators/Cache/CacheKeyHasher.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace OmniSharp.Extensions.JsonRpc.Generators.Cache -{ - class CacheKeyHasher : IDisposable - { - public static bool Cache = true; - private readonly SHA1 _hasher; - - public CacheKeyHasher() - { - _hasher = SHA1.Create(); - } - - public void Append(string textToHash) - { - var inputBuffer = Encoding.UTF8.GetBytes(textToHash); - _hasher.TransformBlock(inputBuffer, 0, inputBuffer.Length, inputBuffer, 0); - } - - public void Append(TypeSyntax? typeSyntax) - { - if (typeSyntax?.GetSyntaxName() is { } a) - { - Append(a); - } - - if (typeSyntax is GenericNameSyntax gns) - { - foreach (var item in gns.TypeArgumentList.Arguments) - { - Append(item); - } - } - } - - public void Append(TypeParameterListSyntax? typeParameterListSyntax) - { - if (typeParameterListSyntax is null or { Parameters: { Count: 0 } }) return; - foreach (var item in typeParameterListSyntax.Parameters) - { - Append(item.Identifier.Text); - Append(item.AttributeLists); - } - } - - public void Append(BaseListSyntax? baseListSyntax) - { - if (baseListSyntax is null) return; - foreach (var item in baseListSyntax.Types) - { - Append(item.Type); - } - } - - public void Append(SyntaxList attributeList) - { - foreach (var item in attributeList) - { - Append(item); - } - } - - public void Append(SyntaxList items) - where T : MemberDeclarationSyntax - { - if (items is { Count: 0 }) return; - foreach (var item in items.OfType()) - { - Append(item.AttributeLists); - if (item is PropertyDeclarationSyntax p) - { - Append(p.Identifier.Text); - Append(p.Type); - } - } - } - - public void Append(AttributeListSyntax attributeList) - { - if (attributeList is { Attributes: { Count: 0 } }) return; - foreach (var item in attributeList.Attributes) - { - Append(item); - } - } - - public void Append(AttributeSyntax attribute) - { - Append(attribute.Name.GetSyntaxName() ?? string.Empty); - if (attribute.ArgumentList?.Arguments is { Count: > 0 } arguments) - { - foreach (var item in arguments) - { - if (item.NameEquals is { }) - { - Append(item.NameEquals.Name.GetSyntaxName() ?? string.Empty); - } - - Append( - item switch { - { Expression: TypeOfExpressionSyntax tyof } => tyof.Type.GetSyntaxName() is { Length: > 0 } name ? name : string.Empty, - { Expression: LiteralExpressionSyntax { } literal } => literal.Token.Text, - _ => string.Empty - } - ); - } - } - } - - private string ConvertByteArrayToString() - { - _hasher.TransformFinalBlock(Array.Empty(), 0, 0); - var sb = new StringBuilder(); - foreach (var b in _hasher.Hash) - { - sb.Append(b.ToString("X2")); - } - - return sb.ToString(); - } - - public override string ToString() => ConvertByteArrayToString(); - - public static implicit operator string(CacheKeyHasher value) => value.ToString(); - - public void Dispose() => _hasher.Dispose(); - } -} diff --git a/src/JsonRpc.Generators/Cache/CachedSourceGenerator.cs b/src/JsonRpc.Generators/Cache/CachedSourceGenerator.cs deleted file mode 100644 index 1f1cd0c42..000000000 --- a/src/JsonRpc.Generators/Cache/CachedSourceGenerator.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using Microsoft.CodeAnalysis; - -namespace OmniSharp.Extensions.JsonRpc.Generators.Cache -{ - /// - /// We're not supposed to do this... but in realistic. - /// - public abstract class CachedSourceGenerator : ISourceGenerator - where T : ISyntaxReceiver, IReceiverCache - where TSyntax : SyntaxNode - { - private readonly Func _syntaxReceiverFactory; - - public CachedSourceGenerator(Func syntaxReceiverFactory) - { - _syntaxReceiverFactory = syntaxReceiverFactory; - } - - public void Initialize(GeneratorInitializationContext context) - { - context.RegisterForSyntaxNotifications(() => _syntaxReceiverFactory()); - } - - public void Execute(GeneratorExecutionContext context) - { - if (!( context.SyntaxReceiver is T syntaxReceiver )) return; - - syntaxReceiver.Start(context); - Execute( - context, syntaxReceiver, - (name, node, text) => { - context.AddSource(name, text); - - if (CacheKeyHasher.Cache) - { - syntaxReceiver.AddCacheSource(name, node, text); - } - }, - (node, diagnostic) => { - context.ReportDiagnostic(diagnostic(node)); - - if (CacheKeyHasher.Cache) - { - syntaxReceiver.ReportCacheDiagnostic(node, diagnostic); - } - } - ); - foreach (var item in syntaxReceiver.CachedSources) - { - context.AddSource(item.Name, item.SourceText); - } - - foreach (var item in syntaxReceiver.CachedDiagnostics) - { - context.ReportDiagnostic(item); - } - - syntaxReceiver.Finish(context); - } - - protected abstract void Execute( - GeneratorExecutionContext context, T syntaxReceiver, AddCacheSource addCacheSource, ReportCacheDiagnostic cacheDiagnostic - ); - } -} diff --git a/src/JsonRpc.Generators/Cache/IReceiverCache.cs b/src/JsonRpc.Generators/Cache/IReceiverCache.cs deleted file mode 100644 index d1e72827e..000000000 --- a/src/JsonRpc.Generators/Cache/IReceiverCache.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; - -namespace OmniSharp.Extensions.JsonRpc.Generators.Cache -{ - public interface IReceiverCache - where T : SyntaxNode - { - string? GetKey(T syntax); - void Start(GeneratorExecutionContext context); - void Finish(GeneratorExecutionContext context); - IEnumerable CachedSources { get; } - IEnumerable CachedDiagnostics { get; } - void AddCacheSource(string hintName, T syntaxNode, SourceText sourceText); - void ReportCacheDiagnostic(T syntaxNode, CacheDiagnosticFactory diagnostic); - } -} diff --git a/src/JsonRpc.Generators/Cache/SourceTextCache.cs b/src/JsonRpc.Generators/Cache/SourceTextCache.cs deleted file mode 100644 index 6abdd658f..000000000 --- a/src/JsonRpc.Generators/Cache/SourceTextCache.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; - -namespace OmniSharp.Extensions.JsonRpc.Generators.Cache -{ - public record SourceTextCache(string Name, SourceText SourceText); - public record DiagnosticCache(ImmutableArray> Diagnostics) where T : SyntaxNode; -} diff --git a/src/JsonRpc.Generators/Cache/SyntaxReceiverCache.cs b/src/JsonRpc.Generators/Cache/SyntaxReceiverCache.cs deleted file mode 100644 index 5620f5b6b..000000000 --- a/src/JsonRpc.Generators/Cache/SyntaxReceiverCache.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; - -namespace OmniSharp.Extensions.JsonRpc.Generators.Cache -{ - public abstract class SyntaxReceiverCache : IReceiverCache, ISyntaxReceiver - where T : SyntaxNode - { - private readonly CacheContainer _cache; - private readonly ImmutableDictionary.Builder sources)>.Builder _foundSourceTexts; - private readonly ImmutableDictionary>.Builder>.Builder _foundDiagnosticFactories; - private readonly List _cachedSources = new(); - private readonly List _cachedDiagnostics = new(); - private readonly List _foundNodes = new(); - - protected SyntaxReceiverCache(CacheContainer cache) - { - _cache = cache; - _foundSourceTexts = ImmutableDictionary.Builder sources)>.Empty.ToBuilder(); - _foundDiagnosticFactories = ImmutableDictionary>.Builder>.Empty.ToBuilder(); - } - - public abstract string? GetKey(T syntax); - - public void Start(GeneratorExecutionContext context) - { - // TODO: Check if options disable cache - try - { - // check stuff - _cache.Swap(_foundSourceTexts, _foundDiagnosticFactories); - } - catch - { - _cachedSources.Clear(); - _cachedDiagnostics.Clear(); - foreach (var found in _foundSourceTexts.Values) - { - OnVisitNode(found.Item1); - } - } - } - - public void Finish(GeneratorExecutionContext context) - { - // TODO: Check if options disable cache - try - { - // check stuff - _cache.Swap(_foundSourceTexts, _foundDiagnosticFactories); - } - catch - { - _cache.Swap( - ImmutableDictionary.Builder sources)>.Empty.ToBuilder(), - ImmutableDictionary>.Builder>.Empty.ToBuilder() - ); - } - } - - public IEnumerable CachedSources => _cachedSources; - public IEnumerable CachedDiagnostics => _cachedDiagnostics; - public IEnumerable FoundNodes => _foundNodes; - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (syntaxNode is not T v) return; - if (GetKey(v) is { } key) - { - if (_cache.SourceTexts.TryGetValue(key, out var cacheValue)) - { - _foundSourceTexts.Add(key, ( v, cacheValue.ToBuilder() )); - _cachedSources.AddRange(cacheValue); - } - - if (_cache.Diagnostics.TryGetValue(key, out var diagnostics)) - { - _foundDiagnosticFactories.Add(key, diagnostics.ToBuilder()); - _cachedDiagnostics.AddRange(diagnostics.Select(f => f(v))); - } - - if (_foundSourceTexts.ContainsKey(key) || _foundDiagnosticFactories.ContainsKey(key)) - { - _foundNodes.Add(v); - return; - } - } - - OnVisitNode(v); - } - - public void AddCacheSource(string hintName, T syntaxNode, SourceText sourceText) - { - if (GetKey(syntaxNode) is not { } key) return; - if (!_foundSourceTexts.TryGetValue(key, out var data)) - { - var array = ImmutableArray.Create(new SourceTextCache(hintName, sourceText)).ToBuilder(); - _foundSourceTexts.Add(key, ( syntaxNode, array )); - } - else - { - data.sources.Add(new SourceTextCache(hintName, sourceText)); - } - } - - public void ReportCacheDiagnostic(T syntaxNode, CacheDiagnosticFactory diagnostic) - { - if (GetKey(syntaxNode) is not { } key) return; - if (!_foundDiagnosticFactories.TryGetValue(key, out var array)) - { - array = ImmutableArray.Create(diagnostic).ToBuilder(); - _foundDiagnosticFactories.Add(key, array); - } - else - { - array.Add(diagnostic); - } - } - - public abstract void OnVisitNode(T syntaxNode); - } -} diff --git a/src/JsonRpc.Generators/Contexts/DapAttributes.cs b/src/JsonRpc.Generators/Contexts/DapAttributes.cs index 1f55ce153..d081deade 100644 --- a/src/JsonRpc.Generators/Contexts/DapAttributes.cs +++ b/src/JsonRpc.Generators/Contexts/DapAttributes.cs @@ -1,16 +1,14 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; namespace OmniSharp.Extensions.JsonRpc.Generators.Contexts { record DapAttributes { public static DapAttributes? Parse( - GeneratorExecutionContext context, - AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic, - TypeDeclarationSyntax syntax, + Compilation compilation, + TypeDeclarationSyntax candidateClass, + SemanticModel model, INamedTypeSymbol symbol ) { diff --git a/src/JsonRpc.Generators/Contexts/ExtensionMethodContext.cs b/src/JsonRpc.Generators/Contexts/ExtensionMethodContext.cs index 3dc33a5df..49e08ae49 100644 --- a/src/JsonRpc.Generators/Contexts/ExtensionMethodContext.cs +++ b/src/JsonRpc.Generators/Contexts/ExtensionMethodContext.cs @@ -9,8 +9,7 @@ record ExtensionMethodContext( TypeDeclarationSyntax TypeDeclaration, INamedTypeSymbol TypeSymbol, TypeSyntax Item, - ImmutableArray RelatedItems, - GeneratorExecutionContext Context + ImmutableArray RelatedItems ) { public bool IsProxy { get; init; } diff --git a/src/JsonRpc.Generators/Contexts/GeneratorData.cs b/src/JsonRpc.Generators/Contexts/GeneratorData.cs index a5cd7f311..8af0444e6 100644 --- a/src/JsonRpc.Generators/Contexts/GeneratorData.cs +++ b/src/JsonRpc.Generators/Contexts/GeneratorData.cs @@ -1,10 +1,9 @@ +using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; using static OmniSharp.Extensions.JsonRpc.Generators.Helpers; namespace OmniSharp.Extensions.JsonRpc.Generators.Contexts @@ -21,38 +20,23 @@ abstract record GeneratorData( HashSet AdditionalUsings, List AssemblyJsonRpcHandlersAttributeArguments, SemanticModel Model, - GeneratorExecutionContext Context + Compilation Compilation ) { - private AddCacheSource AddCacheSourceDelegate { get; init; } - private ReportCacheDiagnostic CacheDiagnosticDelegate { get; init; } - - public void AddSource(string hintName, SourceText sourceText) - { - AddCacheSourceDelegate(hintName, TypeDeclaration, sourceText); - } - - public void ReportDiagnostic(CacheDiagnosticFactory diagnostic) - { - CacheDiagnosticDelegate(TypeDeclaration, diagnostic); - } - public static GeneratorData? Create( - GeneratorExecutionContext context, + Compilation compilation, TypeDeclarationSyntax candidateClass, - AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic, + SemanticModel model, HashSet additionalUsings ) { - var model = context.Compilation.GetSemanticModel(candidateClass.SyntaxTree); - var symbol = model.GetDeclaredSymbol(candidateClass); + var symbol = model.GetDeclaredSymbol(candidateClass) is { } nts ? nts : null; if (symbol == null) return null; var requestType = GetRequestType(candidateClass, symbol); if (requestType == null) return null; - var jsonRpcAttributes = JsonRpcAttributes.Parse(context, addCacheSource, cacheDiagnostic, candidateClass, symbol, additionalUsings); - var lspAttributes = LspAttributes.Parse(context, addCacheSource, cacheDiagnostic, candidateClass, symbol); - var dapAttributes = DapAttributes.Parse(context, addCacheSource, cacheDiagnostic, candidateClass, symbol); + var jsonRpcAttributes = JsonRpcAttributes.Parse(compilation, candidateClass, model, symbol, additionalUsings); + var lspAttributes = LspAttributes.Parse(compilation, candidateClass, model, symbol); + var dapAttributes = DapAttributes.Parse(compilation, candidateClass, model, symbol); additionalUsings.Add(jsonRpcAttributes.HandlerNamespace); additionalUsings.Add(jsonRpcAttributes.ModelNamespace); @@ -75,9 +59,8 @@ HashSet additionalUsings GetPartialItems(candidateClass, symbol, requestType), additionalUsings, new List(), - model, - context - ) { CacheDiagnosticDelegate = cacheDiagnostic, AddCacheSourceDelegate = addCacheSource }; + model, compilation + ); } if (IsNotification(candidateClass)) @@ -93,9 +76,8 @@ HashSet additionalUsings GetRegistrationOptions(candidateClass, symbol, lspAttributes), additionalUsings, new List(), - model, - context - ) { CacheDiagnosticDelegate = cacheDiagnostic, AddCacheSourceDelegate = addCacheSource }; + model, compilation + ); } return null; @@ -109,8 +91,7 @@ HashSet additionalUsings && tds.AttributeLists.ContainsAttribute("GenerateHandler") )?.GetSyntax() is TypeDeclarationSyntax declarationSyntax) { - return Create(parent.Context, declarationSyntax, parent.AddCacheSourceDelegate, parent.CacheDiagnosticDelegate, parent.AdditionalUsings) as RequestItem; - } + return Create(parent.Compilation, declarationSyntax, parent.Compilation.GetSemanticModel(declarationSyntax.SyntaxTree), parent.AdditionalUsings) as RequestItem; } return null; } diff --git a/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs b/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs index f72061692..17b5c6adb 100644 --- a/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs +++ b/src/JsonRpc.Generators/Contexts/JsonRpcAttributes.cs @@ -5,18 +5,19 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; namespace OmniSharp.Extensions.JsonRpc.Generators.Contexts { record JsonRpcAttributes( SyntaxAttributeData? GenerateHandlerMethods, ImmutableArray HandlerRegistries, + ImmutableArray HandlerRegistryDiagnostics, string HandlerMethodName, string PartialHandlerMethodName, bool AllowDerivedRequests, SyntaxAttributeData? GenerateRequestMethods, ImmutableArray RequestProxies, + ImmutableArray RequestProxyDiagnostics, string RequestMethodName, SyntaxAttributeData? GenerateHandler, string HandlerNamespace, @@ -25,27 +26,30 @@ string ModelNamespace ) { public static JsonRpcAttributes Parse( - GeneratorExecutionContext context, - AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic, + Compilation compilation, TypeDeclarationSyntax syntax, + SemanticModel model, INamedTypeSymbol symbol, HashSet additionalUsings ) { - var generateHandlerMethodsAttributeSymbol = context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.JsonRpc.Generation.GenerateHandlerMethodsAttribute"); - var generateRequestMethodsAttributeSymbol = context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.JsonRpc.Generation.GenerateRequestMethodsAttribute"); - var generateHandlerAttributeSymbol = context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.JsonRpc.Generation.GenerateHandlerAttribute"); + var generateHandlerMethodsAttributeSymbol = + compilation.GetTypeByMetadataName("OmniSharp.Extensions.JsonRpc.Generation.GenerateHandlerMethodsAttribute"); + var generateRequestMethodsAttributeSymbol = + compilation.GetTypeByMetadataName("OmniSharp.Extensions.JsonRpc.Generation.GenerateRequestMethodsAttribute"); + var generateHandlerAttributeSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.JsonRpc.Generation.GenerateHandlerAttribute"); var handlerName = Helpers.SpecialCasedHandlerName(symbol).Split('.').Last(); var attributes = new JsonRpcAttributes( null, ImmutableArray.Empty, + ImmutableArray.Empty, GetHandlerMethodName(symbol, handlerName), GetPartialHandlerMethodName(symbol, handlerName), false, null, ImmutableArray.Empty, + ImmutableArray.Empty, GetRequestMethodName(syntax, symbol, handlerName), null, symbol.ContainingNamespace.ToDisplayString(), @@ -55,70 +59,92 @@ HashSet additionalUsings if (symbol.GetAttribute(generateHandlerAttributeSymbol) is { } generateHandlerData) { - attributes = attributes with { + attributes = attributes with + { GenerateHandler = SyntaxAttributeData.Parse(generateHandlerData), AllowDerivedRequests = generateHandlerData .NamedArguments .Select(z => z is { Key: "AllowDerivedRequests", Value: { Value: true } }) .Count(z => z) is > 0, - HandlerNamespace = generateHandlerData is { ConstructorArguments: { Length: >=1 } arguments } + HandlerNamespace = generateHandlerData is { ConstructorArguments: { Length: >= 1 } arguments } ? arguments[0].Value as string ?? attributes.HandlerNamespace : attributes.HandlerNamespace, HandlerName = generateHandlerData is { NamedArguments: { Length: >= 1 } namedArguments } ? namedArguments .Select(z => z is { Key: "Name", Value: { Value: string str } } ? str : null) - .FirstOrDefault(z => z is { Length: >0 }) ?? attributes.HandlerName + .FirstOrDefault(z => z is { Length: > 0 }) ?? attributes.HandlerName : attributes.HandlerName - }; + }; - attributes = attributes with { + attributes = attributes with + { HandlerMethodName = GetHandlerMethodName(symbol, attributes.HandlerName), PartialHandlerMethodName = GetPartialHandlerMethodName(symbol, attributes.HandlerName), RequestMethodName = GetRequestMethodName(syntax, symbol, attributes.HandlerName) - }; + }; } if (symbol.GetAttribute(generateHandlerMethodsAttributeSymbol) is { } generateHandlerMethodsData) { var data = SyntaxAttributeData.Parse(generateHandlerMethodsData); - attributes = attributes with { + var diagnostics = new List(); + var syntaxes = new List(); + foreach (var registry in GetHandlerRegistries( + syntax, + generateHandlerMethodsData, + symbol, + additionalUsings + )) + { + if (registry.diagnostic is { }) diagnostics.Add(registry.diagnostic); + if (registry.typeSyntax is { }) syntaxes.Add(registry.typeSyntax); + } + + attributes = attributes with + { GenerateHandlerMethods = data, HandlerMethodName = generateHandlerMethodsData .NamedArguments .Select(z => z is { Key: "MethodName", Value: { Value: string value } } ? value : null) .FirstOrDefault(z => z is not null) ?? attributes.HandlerMethodName, - HandlerRegistries = GetHandlerRegistries( - a => cacheDiagnostic(syntax, a), - generateHandlerMethodsData, - symbol, - additionalUsings - ).ToImmutableArray() - }; + HandlerRegistries = syntaxes.ToImmutableArray(), + HandlerRegistryDiagnostics = diagnostics.ToImmutableArray() + }; } if (symbol.GetAttribute(generateRequestMethodsAttributeSymbol) is { } generateRequestMethodsData) { var data = SyntaxAttributeData.Parse(generateRequestMethodsData); - attributes = attributes with { + var diagnostics = new List(); + var syntaxes = new List(); + foreach (var registry in GetRequestProxies( + syntax, + generateRequestMethodsData, + symbol, + additionalUsings + )) + { + if (registry.diagnostic is { }) diagnostics.Add(registry.diagnostic); + if (registry.typeSyntax is { }) syntaxes.Add(registry.typeSyntax); + } + + attributes = attributes with + { GenerateRequestMethods = data, RequestMethodName = generateRequestMethodsData .NamedArguments .Select(z => z is { Key: "MethodName", Value: { Value: string value } } ? value : null) .FirstOrDefault(z => z is not null) ?? attributes.RequestMethodName, - RequestProxies = GetRequestProxies( - (a) => cacheDiagnostic(syntax, a), - generateRequestMethodsData, - symbol, - additionalUsings - ).ToImmutableArray() - }; + RequestProxies = syntaxes.ToImmutableArray(), + RequestProxyDiagnostics = diagnostics.ToImmutableArray() + }; } return attributes; } - private static IEnumerable GetHandlerRegistries( - Action> cacheDiagnostic, + private static IEnumerable<(TypeSyntax? typeSyntax, Diagnostic? diagnostic)> GetHandlerRegistries( + TypeDeclarationSyntax typeDeclarationSyntax, AttributeData attributeData, INamedTypeSymbol interfaceType, HashSet additionalUsings @@ -130,7 +156,7 @@ HashSet additionalUsings { if (item.Expression is TypeOfExpressionSyntax typeOfExpressionSyntax) { - yield return typeOfExpressionSyntax.Type; + yield return ( typeOfExpressionSyntax.Type, null ); foundValue = true; } } @@ -142,11 +168,15 @@ HashSet additionalUsings var attribute = interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute"); if (attribute.ConstructorArguments.Length < 2) { - cacheDiagnostic(static c => Diagnostic.Create(GeneratorDiagnostics.MissingDirection, c.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation())); + yield return ( null, Diagnostic.Create( + GeneratorDiagnostics.MissingDirection, + typeDeclarationSyntax.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation() + ) + ); yield break; } - var direction = (int) interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute").ConstructorArguments[1].Value!; + var direction = (int)interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute").ConstructorArguments[1].Value!; /* Unspecified = 0b0000, @@ -160,12 +190,12 @@ HashSet additionalUsings additionalUsings.Add("OmniSharp.Extensions.LanguageServer.Protocol.Server"); if (( direction & 0b0001 ) == 0b0001) { - yield return LanguageProtocolServerToClientRegistry; + yield return ( LanguageProtocolServerToClientRegistry, null ); } if (( direction & 0b0010 ) == 0b0010) { - yield return LanguageProtocolClientToServerRegistry; + yield return ( LanguageProtocolClientToServerRegistry, null ); } yield break; @@ -176,11 +206,16 @@ HashSet additionalUsings var attribute = interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute"); if (attribute.ConstructorArguments.Length < 2) { - cacheDiagnostic(static c => Diagnostic.Create(GeneratorDiagnostics.MissingDirection, c.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation())); + yield return ( + null, + Diagnostic.Create( + GeneratorDiagnostics.MissingDirection, typeDeclarationSyntax.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation() + ) + ); yield break; } - var direction = (int) interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute").ConstructorArguments[1].Value!; + var direction = (int)interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute").ConstructorArguments[1].Value!; /* Unspecified = 0b0000, @@ -194,18 +229,23 @@ HashSet additionalUsings additionalUsings.Add("OmniSharp.Extensions.DebugAdapter.Protocol.Server"); if (( direction & 0b0001 ) == 0b0001) { - yield return DebugProtocolServerToClientRegistry; + yield return ( DebugProtocolServerToClientRegistry, null ); } if (( direction & 0b0010 ) == 0b0010) { - yield return DebugProtocolClientToServerRegistry; + yield return ( DebugProtocolClientToServerRegistry, null ); } yield break; } - cacheDiagnostic(static c => Diagnostic.Create(GeneratorDiagnostics.CouldNotInferRequestRouter, c.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation())); + yield return ( + null, + Diagnostic.Create( + GeneratorDiagnostics.CouldNotInferRequestRouter, typeDeclarationSyntax.AttributeLists.GetAttribute("GenerateHandlerMethods")?.GetLocation() + ) + ); } private static NameSyntax LanguageProtocolServerToClientRegistry { get; } = @@ -221,8 +261,8 @@ HashSet additionalUsings SyntaxFactory.IdentifierName("IDebugAdapterServerRegistry"); - private static IEnumerable GetRequestProxies( - Action> cacheDiagnostic, + private static IEnumerable<(TypeSyntax? typeSyntax, Diagnostic? diagnostic)> GetRequestProxies( + TypeDeclarationSyntax typeDeclarationSyntax, AttributeData attributeData, INamedTypeSymbol interfaceType, HashSet additionalUsings @@ -234,7 +274,7 @@ HashSet additionalUsings { if (item.Expression is TypeOfExpressionSyntax typeOfExpressionSyntax) { - yield return typeOfExpressionSyntax.Type; + yield return ( typeOfExpressionSyntax.Type, null ); foundValue = true; } } @@ -246,11 +286,16 @@ HashSet additionalUsings var attribute = interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute"); if (attribute.ConstructorArguments.Length < 2) { - cacheDiagnostic(static c => Diagnostic.Create(GeneratorDiagnostics.MissingDirection, c.AttributeLists.GetAttribute("GenerateRequestMethods")?.GetLocation())); + yield return ( null, + Diagnostic.Create( + GeneratorDiagnostics.MissingDirection, + typeDeclarationSyntax.AttributeLists.GetAttribute("GenerateRequestMethods")?.GetLocation() + ) + ); yield break; } - var direction = (int) interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute")!.ConstructorArguments[1].Value!; + var direction = (int)interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute")!.ConstructorArguments[1].Value!; /* Unspecified = 0b0000, @@ -265,12 +310,12 @@ HashSet additionalUsings additionalUsings.Add("OmniSharp.Extensions.LanguageServer.Protocol.Client"); if (( direction & 0b0001 ) == 0b0001) { - yield return LanguageProtocolServerToClient; + yield return ( LanguageProtocolServerToClient, null ); } if (( direction & 0b0010 ) == 0b0010) { - yield return LanguageProtocolClientToServer; + yield return ( LanguageProtocolClientToServer, null ); } yield break; @@ -281,11 +326,16 @@ HashSet additionalUsings var attribute = interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute"); if (attribute.ConstructorArguments.Length < 2) { - cacheDiagnostic(static c => Diagnostic.Create(GeneratorDiagnostics.MissingDirection, c.AttributeLists.GetAttribute("GenerateRequestMethods")?.GetLocation())); + yield return ( null, + Diagnostic.Create( + GeneratorDiagnostics.MissingDirection, + typeDeclarationSyntax.AttributeLists.GetAttribute("GenerateRequestMethods")?.GetLocation() + ) + ); yield break; } - var direction = (int) interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute").ConstructorArguments[1].Value!; + var direction = (int)interfaceType.GetAttributes().First(z => z.AttributeClass?.Name == "MethodAttribute").ConstructorArguments[1].Value!; /* Unspecified = 0b0000, @@ -298,18 +348,23 @@ HashSet additionalUsings if (( direction & 0b0001 ) == 0b0001) { - yield return DebugProtocolServerToClient; + yield return ( DebugProtocolServerToClient, null ); } if (( direction & 0b0010 ) == 0b0010) { - yield return DebugProtocolClientToServer; + yield return ( DebugProtocolClientToServer, null ); } yield break; } - cacheDiagnostic(static c => Diagnostic.Create(GeneratorDiagnostics.CouldNotInferRequestRouter, c.AttributeLists.GetAttribute("GenerateRequestMethods")?.GetLocation())); + yield return ( null, + Diagnostic.Create( + GeneratorDiagnostics.CouldNotInferRequestRouter, + typeDeclarationSyntax.AttributeLists.GetAttribute("GenerateRequestMethods")?.GetLocation() + ) + ); } private static NameSyntax LanguageProtocolServerToClient { get; } = diff --git a/src/JsonRpc.Generators/Contexts/LspAttributes.cs b/src/JsonRpc.Generators/Contexts/LspAttributes.cs index 4c55f36e2..3dda28f14 100644 --- a/src/JsonRpc.Generators/Contexts/LspAttributes.cs +++ b/src/JsonRpc.Generators/Contexts/LspAttributes.cs @@ -1,7 +1,6 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; namespace OmniSharp.Extensions.JsonRpc.Generators.Contexts { @@ -23,10 +22,9 @@ bool CanHaveData ) { public static LspAttributes? Parse( - GeneratorExecutionContext context, - AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic, + Compilation compilation, TypeDeclarationSyntax syntax, + SemanticModel model, INamedTypeSymbol symbol) { var prefix = "OmniSharp.Extensions.LanguageServer.Protocol.Generation"; @@ -40,7 +38,7 @@ bool CanHaveData }; { - var attributeSymbol = context.Compilation.GetTypeByMetadataName($"{prefix}.GenerateTypedDataAttribute"); + var attributeSymbol = compilation.GetTypeByMetadataName($"{prefix}.GenerateTypedDataAttribute"); if (symbol.GetAttribute(attributeSymbol) is { } data && data.ApplicationSyntaxReference?.GetSyntax() is AttributeSyntax attributeSyntax) { attributes = attributes with { @@ -50,7 +48,7 @@ bool CanHaveData } } { - var attributeSymbol = context.Compilation.GetTypeByMetadataName($"{prefix}.GenerateContainerAttribute"); + var attributeSymbol = compilation.GetTypeByMetadataName($"{prefix}.GenerateContainerAttribute"); if (symbol.GetAttribute(attributeSymbol) is { } data && data.ApplicationSyntaxReference?.GetSyntax() is AttributeSyntax attributeSyntax) { attributes = attributes with { @@ -60,7 +58,7 @@ bool CanHaveData } } { - var attributeSymbol = context.Compilation.GetTypeByMetadataName($"{prefix}.RegistrationOptionsKeyAttribute"); + var attributeSymbol = compilation.GetTypeByMetadataName($"{prefix}.RegistrationOptionsKeyAttribute"); if (symbol.GetAttribute(attributeSymbol) is { ConstructorArguments: { Length: >=1 } arguments } data && arguments[0].Kind is TypedConstantKind.Primitive && arguments[0].Value is string value && data.ApplicationSyntaxReference?.GetSyntax() is AttributeSyntax attributeSyntax) @@ -72,21 +70,21 @@ bool CanHaveData } } { - var (syntaxAttributeData, syntaxSymbol) = ExtractAttributeTypeData(symbol, context.Compilation.GetTypeByMetadataName($"{prefix}.CapabilityAttribute")); + var (syntaxAttributeData, syntaxSymbol) = ExtractAttributeTypeData(symbol, compilation.GetTypeByMetadataName($"{prefix}.CapabilityAttribute")); attributes = attributes with { CapabilityAttribute = syntaxAttributeData, Capability = syntaxSymbol }; } { - var (syntaxAttributeData, syntaxSymbol) = ExtractAttributeTypeData(symbol, context.Compilation.GetTypeByMetadataName($"{prefix}.ResolverAttribute")); + var (syntaxAttributeData, syntaxSymbol) = ExtractAttributeTypeData(symbol, compilation.GetTypeByMetadataName($"{prefix}.ResolverAttribute")); attributes = attributes with { ResolverAttribute = syntaxAttributeData, Resolver = syntaxSymbol }; } { - var (syntaxAttributeData, syntaxSymbol) = ExtractAttributeTypeData(symbol, context.Compilation.GetTypeByMetadataName($"{prefix}.RegistrationOptionsAttribute")); + var (syntaxAttributeData, syntaxSymbol) = ExtractAttributeTypeData(symbol, compilation.GetTypeByMetadataName($"{prefix}.RegistrationOptionsAttribute")); attributes = attributes with { RegistrationOptionsAttribute = syntaxAttributeData, RegistrationOptions = syntaxSymbol diff --git a/src/JsonRpc.Generators/Contexts/NotificationItem.cs b/src/JsonRpc.Generators/Contexts/NotificationItem.cs index 6d9d7a111..24b2eab64 100644 --- a/src/JsonRpc.Generators/Contexts/NotificationItem.cs +++ b/src/JsonRpc.Generators/Contexts/NotificationItem.cs @@ -16,10 +16,10 @@ record NotificationItem( HashSet AdditionalUsings, List AssemblyJsonRpcHandlersAttributeArguments, SemanticModel Model, - GeneratorExecutionContext Context + Compilation Compilation ) : GeneratorData( TypeDeclaration, TypeSymbol, JsonRpcAttributes, LspAttributes, DapAttributes, Request, Capability, RegistrationOptions, - AdditionalUsings, AssemblyJsonRpcHandlersAttributeArguments, Model, Context + AdditionalUsings, AssemblyJsonRpcHandlersAttributeArguments, Model, Compilation ); } diff --git a/src/JsonRpc.Generators/Contexts/RegistrationOptionAttributes.cs b/src/JsonRpc.Generators/Contexts/RegistrationOptionAttributes.cs index f94a2844d..dd19d8100 100644 --- a/src/JsonRpc.Generators/Contexts/RegistrationOptionAttributes.cs +++ b/src/JsonRpc.Generators/Contexts/RegistrationOptionAttributes.cs @@ -20,18 +20,18 @@ record RegistrationOptionAttributes( bool ImplementsStaticRegistrationOptions ) { - public static RegistrationOptionAttributes? Parse(GeneratorExecutionContext context, TypeDeclarationSyntax syntax, INamedTypeSymbol symbol) + public static RegistrationOptionAttributes? Parse(Compilation compilation, TypeDeclarationSyntax syntax, INamedTypeSymbol symbol) { var registrationOptionsAttributeSymbol = - context.Compilation.GetTypeByMetadataName($"OmniSharp.Extensions.LanguageServer.Protocol.Generation.GenerateRegistrationOptionsAttribute"); + compilation.GetTypeByMetadataName($"OmniSharp.Extensions.LanguageServer.Protocol.Generation.GenerateRegistrationOptionsAttribute"); var registrationOptionsConverterAttributeSymbol = - context.Compilation.GetTypeByMetadataName($"OmniSharp.Extensions.LanguageServer.Protocol.RegistrationOptionsConverterAttribute"); -// var registrationOptionsInterfaceSymbol = context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions"); + compilation.GetTypeByMetadataName($"OmniSharp.Extensions.LanguageServer.Protocol.RegistrationOptionsConverterAttribute"); +// var registrationOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions"); var textDocumentRegistrationOptionsInterfaceSymbol = - context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.ITextDocumentRegistrationOptions"); - var workDoneProgressOptionsInterfaceSymbol = context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions"); + compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.ITextDocumentRegistrationOptions"); + var workDoneProgressOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions"); var staticRegistrationOptionsInterfaceSymbol = - context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IStaticRegistrationOptions"); + compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IStaticRegistrationOptions"); if (!( symbol.GetAttribute(registrationOptionsAttributeSymbol) is { } data )) return null; if (!( data.ApplicationSyntaxReference?.GetSyntax() is AttributeSyntax attributeSyntax )) return null; diff --git a/src/JsonRpc.Generators/Contexts/RequestItem.cs b/src/JsonRpc.Generators/Contexts/RequestItem.cs index 109d2ab88..3b5103243 100644 --- a/src/JsonRpc.Generators/Contexts/RequestItem.cs +++ b/src/JsonRpc.Generators/Contexts/RequestItem.cs @@ -20,11 +20,11 @@ record RequestItem( HashSet AdditionalUsings, List AssemblyJsonRpcHandlersAttributeArguments, SemanticModel Model, - GeneratorExecutionContext Context + Compilation Compilation ) : GeneratorData( TypeDeclaration, TypeSymbol, JsonRpcAttributes, LspAttributes, DapAttributes, Request, Capability, RegistrationOptions, - AdditionalUsings, AssemblyJsonRpcHandlersAttributeArguments, Model, Context + AdditionalUsings, AssemblyJsonRpcHandlersAttributeArguments, Model, Compilation ); // record PartialItem(TypeSyntax Syntax, INamedTypeSymbol Symbol, SyntaxSymbol Item) : SyntaxSymbol(Syntax, Symbol); diff --git a/src/JsonRpc.Generators/EnumLikeStringGenerator.cs b/src/JsonRpc.Generators/EnumLikeStringGenerator.cs index bef33165e..25d2b6e42 100644 --- a/src/JsonRpc.Generators/EnumLikeStringGenerator.cs +++ b/src/JsonRpc.Generators/EnumLikeStringGenerator.cs @@ -5,67 +5,55 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace OmniSharp.Extensions.JsonRpc.Generators { [Generator] - public class EnumLikeStringGenerator : CachedSourceGenerator + public class EnumLikeStringGenerator : IIncrementalGenerator { - protected override void Execute( - GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic - ) + public void Initialize(IncrementalGeneratorInitializationContext context) { - foreach (var candidate in syntaxReceiver.Candidates) - { - var model = context.Compilation.GetSemanticModel(candidate.SyntaxTree); - var symbol = model.GetDeclaredSymbol(candidate); - if (symbol is null) continue; + var syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (node, token) => node is StructDeclarationSyntax tds && tds.AttributeLists.ContainsAttribute("StringEnum"), + transform: (syntaxContext, token) => syntaxContext + ); + + context.RegisterSourceOutput(syntaxProvider, GenerateEnum); + } - if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword))) - { - cacheDiagnostic(candidate, static c => Diagnostic.Create(GeneratorDiagnostics.MustBePartial, c.Identifier.GetLocation(), c.Identifier.Text)); - continue; - } + private void GenerateEnum(SourceProductionContext context, GeneratorSyntaxContext syntaxContext) + { + var candidate = (StructDeclarationSyntax)syntaxContext.Node; + var model = syntaxContext.SemanticModel; + var symbol = model.GetDeclaredSymbol(syntaxContext.Node); + if (symbol is null) return; - if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.ReadOnlyKeyword))) - { - cacheDiagnostic(candidate, static c => Diagnostic.Create(GeneratorDiagnostics.MustBeReadOnly, c.Identifier.GetLocation(), c.Identifier.Text)); - continue; - } + if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword))) + { + context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.MustBePartial, candidate.Identifier.GetLocation(), candidate.Identifier.Text)); + return; + } - var cu = CompilationUnit( - List(), - List(), - List(), - SingletonList( - NamespaceDeclaration(ParseName(symbol.ContainingNamespace.ToDisplayString())) - .WithMembers(SingletonList(GetImplementation(candidate))) - ) - ) - .AddUsings( - UsingDirective(ParseName("System")), - UsingDirective(ParseName("System.Collections.Generic")), - UsingDirective(ParseName("System.Diagnostics")), - UsingDirective(ParseName("System.Linq")), - UsingDirective(ParseName("System.Reflection")), - UsingDirective(ParseName("Newtonsoft.Json")), - UsingDirective(ParseName("OmniSharp.Extensions.JsonRpc")), - UsingDirective(ParseName("OmniSharp.Extensions.JsonRpc.Serialization.Converters")) + if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.ReadOnlyKeyword))) + { + context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.MustBeReadOnly, candidate.Identifier.GetLocation(), candidate.Identifier.Text)); + return; + } + + var cu = CompilationUnit( + List(), List(), List(), SingletonList( + NamespaceDeclaration(ParseName(symbol.ContainingNamespace.ToDisplayString())) + .WithMembers(SingletonList(GetImplementation(candidate))) ) - .WithLeadingTrivia() - .WithTrailingTrivia() - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool), Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true))) - .WithTrailingTrivia(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)), CarriageReturnLineFeed); + ) + .AddUsings(UsingDirective(ParseName("System")), UsingDirective(ParseName("System.Collections.Generic")), UsingDirective(ParseName("System.Diagnostics")), UsingDirective(ParseName("System.Linq")), UsingDirective(ParseName("System.Reflection")), UsingDirective(ParseName("Newtonsoft.Json")), UsingDirective(ParseName("OmniSharp.Extensions.JsonRpc")), UsingDirective(ParseName("OmniSharp.Extensions.JsonRpc.Serialization.Converters"))) + .WithLeadingTrivia() + .WithTrailingTrivia() + .WithLeadingTrivia(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true))) + .WithTrailingTrivia(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true))); - addCacheSource( - $"{Path.GetFileNameWithoutExtension(candidate.SyntaxTree.FilePath)}_{candidate.Identifier.Text}{( candidate.Arity > 0 ? candidate.Arity.ToString() : "" )}.cs", - candidate, - cu.NormalizeWhitespace().GetText(Encoding.UTF8) - ); - } + context.AddSource($"{Path.GetFileNameWithoutExtension(candidate.SyntaxTree.FilePath)}_{candidate.Identifier.Text}{( candidate.Arity > 0 ? candidate.Arity.ToString() : "" )}.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); } private static StructDeclarationSyntax GetImplementation(StructDeclarationSyntax syntax) @@ -862,45 +850,5 @@ private static StructDeclarationSyntax GetImplementation(StructDeclarationSyntax ) ; } - - public EnumLikeStringGenerator() : base(() => new SyntaxReceiver(Cache)) - { - } - - public static CacheContainer Cache = new(); - - public class SyntaxReceiver : SyntaxReceiverCache - { - public List Candidates { get; } = new(); - - public SyntaxReceiver(CacheContainer cacheContainer) : base(cacheContainer) - { - } - - public override string? GetKey(StructDeclarationSyntax syntax) - { - var hasher = new CacheKeyHasher(); - hasher.Append(syntax.SyntaxTree.FilePath); - hasher.Append(syntax.Keyword.Text); - hasher.Append(syntax.Identifier.Text); - hasher.Append(syntax.TypeParameterList); - hasher.Append(syntax.AttributeLists); - hasher.Append(syntax.BaseList); - - return hasher; - } - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public override void OnVisitNode(StructDeclarationSyntax syntaxNode) - { - // any field with at least one attribute is a candidate for property generation - if (syntaxNode.AttributeLists.ContainsAttribute("StringEnum")) - { - Candidates.Add(syntaxNode); - } - } - } } } diff --git a/src/JsonRpc.Generators/GenerateHandlerMethodsGenerator.cs b/src/JsonRpc.Generators/GenerateHandlerMethodsGenerator.cs index a07d42697..9f954c748 100644 --- a/src/JsonRpc.Generators/GenerateHandlerMethodsGenerator.cs +++ b/src/JsonRpc.Generators/GenerateHandlerMethodsGenerator.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; using OmniSharp.Extensions.JsonRpc.Generators.Strategies; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; @@ -15,155 +14,167 @@ namespace OmniSharp.Extensions.JsonRpc.Generators { [Generator] - public class GenerateHandlerMethodsGenerator : CachedSourceGenerator + public class GenerateHandlerMethodsGenerator : IIncrementalGenerator { - protected override void Execute( - GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic - ) + public void Initialize(IncrementalGeneratorInitializationContext context) { - var handlers = new List(); - foreach (var candidateClass in syntaxReceiver.Candidates) + var _attributes = "GenerateHandler,GenerateRequestMethods,GenerateHandlerMethods"; + var syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (syntaxNode, token) => + syntaxNode is TypeDeclarationSyntax tds + and (ClassDeclarationSyntax or RecordDeclarationSyntax or InterfaceDeclarationSyntax) + && tds.AttributeLists.ContainsAttribute(_attributes), transform: (syntaxContext, token) => syntaxContext + ) + .Combine(context.CompilationProvider) + .Select( + (tuple, token) => + { + var (syntaxContext, compilaiton) = tuple; + var additionalUsings = new HashSet + { + "System", + "System.Collections.Generic", + "System.Threading", + "System.Threading.Tasks", + "MediatR", + "Microsoft.Extensions.DependencyInjection" + }; + + GeneratorData? actionItem = null; + Diagnostic? diagnostic = null; + + try + { + actionItem = GeneratorData.Create( + compilaiton, (TypeDeclarationSyntax)syntaxContext.Node, syntaxContext.SemanticModel, additionalUsings + ); + } + catch (Exception e) + { + diagnostic = Diagnostic.Create( + GeneratorDiagnostics.Exception, syntaxContext.Node.GetLocation(), e.Message, + e.StackTrace ?? string.Empty + ); + Debug.WriteLine(e); + Debug.WriteLine(e.StackTrace); + } + + return ( actionItem, diagnostic, additionalUsings ); + } + ); + + context.RegisterSourceOutput(syntaxProvider, GenerateHandlerMethods); + context.RegisterSourceOutput(syntaxProvider.Where(z => z.actionItem is {}).SelectMany((z, _) => z.actionItem!.AssemblyJsonRpcHandlersAttributeArguments).Collect(), GenerateAssemblyJsonRpcHandlers); + } + + private void GenerateHandlerMethods(SourceProductionContext context, (GeneratorData? actionItem, Diagnostic? diagnostic, HashSet additionalUsings) valueTuple) + { + var (actionItem, diagnostic, additionalUsings) = valueTuple; + // context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.Message, null, $"candidate: {candidateClass.Identifier.ToFullString()}")); + // can this be async??? + context.CancellationToken.ThrowIfCancellationRequested(); + + if (actionItem is null) { -// context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.Message, null, $"candidate: {candidateClass.Identifier.ToFullString()}")); - // can this be async??? - context.CancellationToken.ThrowIfCancellationRequested(); - - var additionalUsings = new HashSet { - "System", - "System.Collections.Generic", - "System.Threading", - "System.Threading.Tasks", - "MediatR", - "Microsoft.Extensions.DependencyInjection" - }; - - GeneratorData? actionItem = null; - - try - { - actionItem = GeneratorData.Create(context, candidateClass, addCacheSource, cacheDiagnostic, additionalUsings); - } - catch (Exception e) - { - context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.Exception, candidateClass.GetLocation(), e.Message, e.StackTrace ?? string.Empty)); - Debug.WriteLine(e); - Debug.WriteLine(e.StackTrace); - } + context.ReportDiagnostic(diagnostic!); + return; + } - if (actionItem is null) continue; - - var members = CompilationUnitGeneratorStrategies.Aggregate( - new List(), (m, strategy) => { - try - { - m.AddRange(strategy.Apply(actionItem)); - } - catch (Exception e) - { - context.ReportDiagnostic( - Diagnostic.Create( - GeneratorDiagnostics.Exception, candidateClass.GetLocation(), $"Strategy {strategy.GetType().FullName} failed!" + " - " + e.Message, - e.StackTrace ?? string.Empty - ) - ); - Debug.WriteLine($"Strategy {strategy.GetType().FullName} failed!"); - Debug.WriteLine(e); - Debug.WriteLine(e.StackTrace); - } - - return m; - } - ); - - if (!members.Any()) continue; - - var namespacesMapping = new Dictionary() { - ["OmniSharp.Extensions.DebugAdapter"] = new[] { - "OmniSharp.Extensions.DebugAdapter.Protocol", - "OmniSharp.Extensions.DebugAdapter.Protocol.Models", - "OmniSharp.Extensions.DebugAdapter.Protocol.Events", - "OmniSharp.Extensions.DebugAdapter.Protocol.Requests" - }, - ["OmniSharp.Extensions.LanguageProtocol"] = new[] { - "OmniSharp.Extensions.LanguageServer.Protocol", - "OmniSharp.Extensions.LanguageServer.Protocol.Models" - }, - }; - - foreach (var assembly in actionItem.Context.Compilation.References - .Select(actionItem.Context.Compilation.GetAssemblyOrModuleSymbol) - .OfType() - .Concat(new[] { actionItem.Context.Compilation.Assembly })) + var candidateClass = actionItem.TypeDeclaration; + + var members = CompilationUnitGeneratorStrategies.Aggregate( + new List(), (m, strategy) => { - if (namespacesMapping.TryGetValue(assembly.Name, out var additionalNamespaceUsings)) + try { - foreach (var item in additionalNamespaceUsings) - { - additionalUsings.Add(item); - } + m.AddRange(strategy.Apply(context, actionItem)); } + catch (Exception e) + { + context.ReportDiagnostic( + Diagnostic.Create( + GeneratorDiagnostics.Exception, candidateClass.GetLocation(), + $"Strategy {strategy.GetType().FullName} failed!" + " - " + e.Message, e.StackTrace ?? string.Empty + ) + ); + Debug.WriteLine($"Strategy {strategy.GetType().FullName} failed!"); + Debug.WriteLine(e); + Debug.WriteLine(e.StackTrace); + } + + return m; } + ); - var existingUsings = candidateClass.SyntaxTree.GetCompilationUnitRoot() - .Usings - .Select(x => x.WithoutTrivia()) - .Union( - additionalUsings - .Except( - candidateClass.SyntaxTree.GetCompilationUnitRoot() - .Usings - .Where(z => z.Alias == null) - .Select(z => z.Name.ToFullString()) - ) - .Except(new [] { "" }) // I think there is a better way... but for now.. - .Distinct() - .Select(z => UsingDirective(IdentifierName(z))) - ) - .OrderBy(x => x.Name.ToFullString()) - .ToImmutableArray(); - - var cu = CompilationUnit( - List(), - List(existingUsings), - List(), - List(members) - ) - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(CarriageReturnLineFeed); - - addCacheSource( - $"{candidateClass.Identifier.Text}{( candidateClass.Arity > 0 ? candidateClass.Arity.ToString() : "" )}.cs", - candidateClass, - cu.NormalizeWhitespace().GetText(Encoding.UTF8) - ); - - handlers.AddRange(actionItem.AssemblyJsonRpcHandlersAttributeArguments); - } + if (!members.Any()) return; + var namespacesMapping = new Dictionary() + { + ["OmniSharp.Extensions.DebugAdapter"] = new[] + { + "OmniSharp.Extensions.DebugAdapter.Protocol", "OmniSharp.Extensions.DebugAdapter.Protocol.Models", + "OmniSharp.Extensions.DebugAdapter.Protocol.Events", "OmniSharp.Extensions.DebugAdapter.Protocol.Requests" + }, + ["OmniSharp.Extensions.LanguageProtocol"] = new[] + { "OmniSharp.Extensions.LanguageServer.Protocol", "OmniSharp.Extensions.LanguageServer.Protocol.Models" }, + }; + + foreach (var assembly in actionItem.Compilation.References.Select(actionItem.Compilation.GetAssemblyOrModuleSymbol) + .OfType() + .Concat(new[] { actionItem.Compilation.Assembly })) { - var namespaces = new HashSet() { "OmniSharp.Extensions.JsonRpc" }; - if (handlers.Any()) + if (namespacesMapping.TryGetValue(assembly.Name, out var additionalNamespaceUsings)) { - var types = handlers.ToArray(); - var cu = CompilationUnit() - .WithUsings(List(namespaces.OrderBy(z => z).Select(z => UsingDirective(ParseName(z))))) - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(CarriageReturnLineFeed); - while (types.Length > 0) + foreach (var item in additionalNamespaceUsings) { - var innerTypes = types.Take(10).ToArray(); - types = types.Skip(10).ToArray(); - cu = cu.AddAttributeLists( - AttributeList( - target: AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), - SingletonSeparatedList(Attribute(IdentifierName("AssemblyJsonRpcHandlers"), AttributeArgumentList(SeparatedList(innerTypes)))) - ) - ); + additionalUsings.Add(item); } + } + } - context.AddSource("GeneratedAssemblyJsonRpcHandlers.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); + var existingUsings = candidateClass.SyntaxTree.GetCompilationUnitRoot() + .Usings.Select(x => x.WithoutTrivia()) + .Union( + additionalUsings.Except( + candidateClass.SyntaxTree.GetCompilationUnitRoot() + .Usings.Where(z => z.Alias == null) + .Select(z => z.Name.ToFullString()) + ) + .Except(new[] { "" }) // I think there is a better way... but for now.. + .Distinct() + .Select(z => UsingDirective(IdentifierName(z))) + ) + .OrderBy(x => x.Name.ToFullString()) + .ToImmutableArray(); + + var cu = CompilationUnit(List(), List(existingUsings), List(), List(members)); + + context.AddSource( + $"{candidateClass.Identifier.Text}{( candidateClass.Arity > 0 ? candidateClass.Arity.ToString() : "" )}.cs", + cu.NormalizeWhitespace().GetText(Encoding.UTF8) + ); + } + + private void GenerateAssemblyJsonRpcHandlers(SourceProductionContext context, ImmutableArray handlers) + { + var namespaces = new HashSet() { "OmniSharp.Extensions.JsonRpc" }; + if (handlers.Any()) + { + var cu = CompilationUnit() + .WithUsings(List(namespaces.OrderBy(z => z).Select(z => UsingDirective(ParseName(z))))); + while (handlers.Length > 0) + { + var innerTypes = handlers.Take(10).ToArray(); + handlers = handlers.Skip(10).ToImmutableArray(); + cu = cu.AddAttributeLists( + AttributeList( + target: AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), + SingletonSeparatedList(Attribute(IdentifierName("AssemblyJsonRpcHandlers"), AttributeArgumentList(SeparatedList(innerTypes)))) + ) + ); } + + context.AddSource("GeneratedAssemblyJsonRpcHandlers.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); } } @@ -196,46 +207,5 @@ private static ImmutableArray GetCompilationU ); return compilationUnitStrategies; } - - public GenerateHandlerMethodsGenerator() : base(() => new SyntaxReceiver(Cache)) - { - } - - public static CacheContainer Cache = new(); - - public class SyntaxReceiver : SyntaxReceiverCache - { - private string _attributes; - public List Candidates { get; } = new(); - - public SyntaxReceiver(CacheContainer cache) : base(cache) - { - _attributes = "GenerateHandler,GenerateRequestMethods,GenerateHandlerMethods"; - } - - public override string? GetKey(TypeDeclarationSyntax syntax) - { - var hasher = new CacheKeyHasher(); - hasher.Append(syntax.SyntaxTree.FilePath); - hasher.Append(syntax.Keyword.Text); - hasher.Append(syntax.Identifier.Text); - hasher.Append(syntax.TypeParameterList); - hasher.Append(syntax.AttributeLists); - hasher.Append(syntax.BaseList); - return hasher; - } - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public override void OnVisitNode(TypeDeclarationSyntax syntaxNode) - { - // any field with at least one attribute is a candidate for property generation - if (syntaxNode is ClassDeclarationSyntax or RecordDeclarationSyntax or InterfaceDeclarationSyntax && syntaxNode.AttributeLists.ContainsAttribute(_attributes)) - { - Candidates.Add(syntaxNode); - } - } - } } } diff --git a/src/JsonRpc.Generators/ICompilationUnitGeneratorStrategy.cs b/src/JsonRpc.Generators/ICompilationUnitGeneratorStrategy.cs index c3a147903..d7cc10336 100644 --- a/src/JsonRpc.Generators/ICompilationUnitGeneratorStrategy.cs +++ b/src/JsonRpc.Generators/ICompilationUnitGeneratorStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -6,6 +7,6 @@ namespace OmniSharp.Extensions.JsonRpc.Generators { internal interface ICompilationUnitGeneratorStrategy { - IEnumerable Apply(GeneratorData item); + IEnumerable Apply(SourceProductionContext context, GeneratorData item); } } diff --git a/src/JsonRpc.Generators/IExtensionMethodContextGeneratorStrategy.cs b/src/JsonRpc.Generators/IExtensionMethodContextGeneratorStrategy.cs index 7160e8285..8d3e5bff8 100644 --- a/src/JsonRpc.Generators/IExtensionMethodContextGeneratorStrategy.cs +++ b/src/JsonRpc.Generators/IExtensionMethodContextGeneratorStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -6,6 +7,6 @@ namespace OmniSharp.Extensions.JsonRpc.Generators { internal interface IExtensionMethodContextGeneratorStrategy { - IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item); + IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item); } } diff --git a/src/JsonRpc.Generators/IExtensionMethodGeneratorStrategy.cs b/src/JsonRpc.Generators/IExtensionMethodGeneratorStrategy.cs index c1bf09b8b..537177649 100644 --- a/src/JsonRpc.Generators/IExtensionMethodGeneratorStrategy.cs +++ b/src/JsonRpc.Generators/IExtensionMethodGeneratorStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -6,6 +7,6 @@ namespace OmniSharp.Extensions.JsonRpc.Generators { internal interface IExtensionMethodGeneratorStrategy { - IEnumerable Apply(GeneratorData item); + IEnumerable Apply(SourceProductionContext context, GeneratorData item); } } diff --git a/src/JsonRpc.Generators/JsonRpc.Generators.csproj b/src/JsonRpc.Generators/JsonRpc.Generators.csproj index 8f0a15cc0..7854d8f6f 100644 --- a/src/JsonRpc.Generators/JsonRpc.Generators.csproj +++ b/src/JsonRpc.Generators/JsonRpc.Generators.csproj @@ -11,15 +11,15 @@ - - + + <_Parameter1>Generation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100391db875e68eb4bfef49ce14313b9e13f2cd3cc89eb273bbe6c11a55044c7d4f566cf092e1c77ef9e7c75b1496ae7f95d925938f5a01793dd8d9f99ae0a7595779b71b971287d7d7b5960d052078d14f5ce1a85ea5c9fb2f59ac735ff7bc215cab469b7c3486006860bad6f4c3b5204ea2f28dd4e1d05e2cca462cfd593b9f9f - + diff --git a/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs b/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs index 00884886a..edf1356f9 100644 --- a/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs +++ b/src/JsonRpc.Generators/RegistrationOptionsGenerator.cs @@ -1,284 +1,358 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace OmniSharp.Extensions.JsonRpc.Generators { [Generator] - public class RegistrationOptionsGenerator : CachedSourceGenerator + public class RegistrationOptionsGenerator : IIncrementalGenerator { - private static string[] RequiredUsings = { + private static string[] RequiredUsings = + { "OmniSharp.Extensions.LanguageServer.Protocol", "OmniSharp.Extensions.LanguageServer.Protocol.Serialization", "OmniSharp.Extensions.LanguageServer.Protocol.Server.Capabilities", }; - protected override void Execute( - GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic - ) + private record AttributeData( + INamedTypeSymbol RegistrationOptionsInterfaceSymbol, INamedTypeSymbol TextDocumentRegistrationOptionsInterfaceSymbol, + INamedTypeSymbol WorkDoneProgressOptionsInterfaceSymbol, INamedTypeSymbol StaticRegistrationOptionsInterfaceSymbol + ); + public void Initialize(IncrementalGeneratorInitializationContext context) { - var compilation = context.Compilation; - - var registrationOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions")!; - var textDocumentRegistrationOptionsInterfaceSymbol = - compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.ITextDocumentRegistrationOptions")!; - var workDoneProgressOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions")!; - var staticRegistrationOptionsInterfaceSymbol = compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Models.IStaticRegistrationOptions")!; + var attributes = context.CompilationProvider + .Select( + (compilation, token) => + { + var registrationOptionsInterfaceSymbol = + compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions")!; + var textDocumentRegistrationOptionsInterfaceSymbol = + compilation.GetTypeByMetadataName( + "OmniSharp.Extensions.LanguageServer.Protocol.Models.ITextDocumentRegistrationOptions" + )!; + var workDoneProgressOptionsInterfaceSymbol = + compilation.GetTypeByMetadataName( + "OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions" + )!; + var staticRegistrationOptionsInterfaceSymbol = + compilation.GetTypeByMetadataName( + "OmniSharp.Extensions.LanguageServer.Protocol.Models.IStaticRegistrationOptions" + )!; + return new AttributeData( + registrationOptionsInterfaceSymbol, textDocumentRegistrationOptionsInterfaceSymbol, + workDoneProgressOptionsInterfaceSymbol, staticRegistrationOptionsInterfaceSymbol + ); + } + ); + var syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (syntaxNode, token) => + syntaxNode is TypeDeclarationSyntax tds and (ClassDeclarationSyntax or RecordDeclarationSyntax) + && tds.AttributeLists + .SelectMany(z => z.Attributes) + .Any(z => z.Name.ToFullString().Contains("GenerateRegistrationOptions")), + (syntaxContext, token) => syntaxContext + ) + .Combine(context.CompilationProvider) + .Select( + (tuple, token) => + { + var (syntaxContext, compilation) = tuple; + var typeSymbol = syntaxContext.SemanticModel.GetDeclaredSymbol((TypeDeclarationSyntax)syntaxContext.Node); + if (typeSymbol is not { }) return default!; + var data = RegistrationOptionAttributes.Parse( + compilation, + (TypeDeclarationSyntax)syntaxContext.Node, + typeSymbol + ); + return data is not { } + ? default! + : ( registrationOptions: (TypeDeclarationSyntax)syntaxContext.Node, + semanticModel: syntaxContext.SemanticModel, typeSymbol: typeSymbol, data: data! ); + } + ) + .Where(z => z is { data: { } }) + .Combine(attributes) + .Select( + (tuple, token) => ( + tuple.Left.registrationOptions, tuple.Left.data, tuple.Left.semanticModel, tuple.Left.typeSymbol, + attributes: tuple.Right ) + ) + ; + + context.RegisterSourceOutput(syntaxProvider, GenerateRegistrationOptions); + context.RegisterSourceOutput( + syntaxProvider + .Select( + (tuple, token) => ( namespaces: tuple.typeSymbol.ContainingNamespace.ToDisplayString(), + AttributeArgument(TypeOfExpression(IdentifierName(tuple.typeSymbol.Name))) ) + ) + .Collect(), GenerateAssemblyRegistrationOptions + ); + } - foreach (var registrationOptions in syntaxReceiver.RegistrationOptions) + private void GenerateRegistrationOptions( + SourceProductionContext context, + (TypeDeclarationSyntax registrationOptions, RegistrationOptionAttributes data, SemanticModel semanticModel, INamedTypeSymbol typeSymbol, + AttributeData attributes) valueTuple + ) + { + var (registrationOptions, data, semanticModel, typeSymbol, attributes) = valueTuple; + try { - try + if (!registrationOptions.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword))) { - var semanticModel = context.Compilation.GetSemanticModel(registrationOptions.SyntaxTree); - var typeSymbol = semanticModel.GetDeclaredSymbol(registrationOptions); + context.ReportDiagnostic( + Diagnostic.Create(GeneratorDiagnostics.MustBePartial, registrationOptions.Identifier.GetLocation(), registrationOptions.Identifier.Text) + ); + return; + } - if (typeSymbol is not { }) continue; - var data = RegistrationOptionAttributes.Parse(context, registrationOptions, typeSymbol); - if (data is not { }) continue; + var extendedRegistrationOptions = registrationOptions.WithAttributeLists(List()) + .WithBaseList( + BaseList( + SingletonSeparatedList( + SimpleBaseType( + ParseName(attributes.RegistrationOptionsInterfaceSymbol.ToDisplayString()) + ) + ) + ) + ) + .WithMembers(List()); - if (!registrationOptions.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword))) - { - cacheDiagnostic(registrationOptions, static r => Diagnostic.Create(GeneratorDiagnostics.MustBePartial, r.Identifier.GetLocation(), r.Identifier.Text)); - continue; - } - var extendedRegistrationOptions = registrationOptions - .WithAttributeLists(List()) - .WithBaseList( - BaseList( - SingletonSeparatedList( - SimpleBaseType(ParseName(registrationOptionsInterfaceSymbol.ToDisplayString())) - ) - ) - ) - .WithMembers(List()); - - - var staticRegistrationOptions = registrationOptions - .WithIdentifier(Identifier($"StaticOptions")) - .WithMembers(List(registrationOptions.Members.OfType())) - .WithAttributeLists(List()); - - var staticBaseList = - registrationOptions.BaseList?.Types.Where(z => z.Type.GetSyntaxName() != textDocumentRegistrationOptionsInterfaceSymbol.Name).ToArray() - ?? Array.Empty(); - if (staticBaseList.Length > 0) - { - staticRegistrationOptions = staticRegistrationOptions.WithBaseList(BaseList(SeparatedList(staticBaseList))); - } - else + var staticRegistrationOptions = registrationOptions.WithIdentifier(Identifier($"StaticOptions")) + .WithMembers( + List( + registrationOptions.Members.OfType() + ) + ) + .WithAttributeLists(List()); + + var staticBaseList = + registrationOptions.BaseList?.Types.Where(z => z.Type.GetSyntaxName() != attributes.TextDocumentRegistrationOptionsInterfaceSymbol.Name) + .ToArray() ?? Array.Empty(); + if (staticBaseList.Length > 0) + { + staticRegistrationOptions = staticRegistrationOptions.WithBaseList(BaseList(SeparatedList(staticBaseList))); + } + else + { + staticRegistrationOptions = staticRegistrationOptions.WithBaseList(null); + } + + if (data.KeyExpression is { }) + { + var attributeList = AttributeList( + SingletonSeparatedList( + Attribute( + IdentifierName("RegistrationOptionsKey"), AttributeArgumentList(SeparatedList(data.KeyExpression.Select(AttributeArgument))) + ) + ) + ); + extendedRegistrationOptions = extendedRegistrationOptions.AddAttributeLists(attributeList); + staticRegistrationOptions = staticRegistrationOptions.AddAttributeLists(attributeList); + } + + if (data.SupportsDocumentSelector && !data.ImplementsDocumentSelector) + { + if (registrationOptions.BaseList?.Types.Any( + z => z.Type.ToFullString().Contains(attributes.TextDocumentRegistrationOptionsInterfaceSymbol.Name) + ) != true) { - staticRegistrationOptions = staticRegistrationOptions.WithBaseList(null); + extendedRegistrationOptions = ExtendAndImplementInterface( + extendedRegistrationOptions, attributes.TextDocumentRegistrationOptionsInterfaceSymbol + ); } - if (data.KeyExpression is { }) - { - var attributeList = - AttributeList( - SingletonSeparatedList( - Attribute( - IdentifierName("RegistrationOptionsKey"), - AttributeArgumentList( - SeparatedList(data.KeyExpression.Select(AttributeArgument)) - ) + extendedRegistrationOptions = extendedRegistrationOptions.AddMembers( + PropertyDeclaration(NullableType(IdentifierName("DocumentSelector")), Identifier("DocumentSelector")) + .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) + .WithAccessorList( + AccessorList( + List( + new[] + { + AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) + .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)), + AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) + .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) + } ) ) - ); - extendedRegistrationOptions = extendedRegistrationOptions.AddAttributeLists(attributeList); - staticRegistrationOptions = staticRegistrationOptions.AddAttributeLists(attributeList); - } + ) + ); + } - if (data.SupportsDocumentSelector && !data.ImplementsDocumentSelector) + if (data.SupportsWorkDoneProgress && !data.ImplementsWorkDoneProgress) + { + if (registrationOptions.BaseList?.Types.Any(z => z.Type.GetSyntaxName() == attributes.WorkDoneProgressOptionsInterfaceSymbol.Name) != true) { - if (registrationOptions.BaseList?.Types.Any(z => z.Type.ToFullString().Contains(textDocumentRegistrationOptionsInterfaceSymbol.Name)) != true) - { - extendedRegistrationOptions = ExtendAndImplementInterface(extendedRegistrationOptions, textDocumentRegistrationOptionsInterfaceSymbol); - } - - extendedRegistrationOptions = extendedRegistrationOptions - .AddMembers( - PropertyDeclaration(NullableType(IdentifierName("DocumentSelector")), Identifier("DocumentSelector")) - .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - .WithAccessorList( - AccessorList( - List( - new[] { - AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)), - AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) - } - ) - ) - ) - ); + extendedRegistrationOptions = ExtendAndImplementInterface( + extendedRegistrationOptions, attributes.WorkDoneProgressOptionsInterfaceSymbol + ); + staticRegistrationOptions = ExtendAndImplementInterface(staticRegistrationOptions, attributes.WorkDoneProgressOptionsInterfaceSymbol); } - if (data.SupportsWorkDoneProgress && !data.ImplementsWorkDoneProgress) - { - if (registrationOptions.BaseList?.Types.Any(z => z.Type.GetSyntaxName() == workDoneProgressOptionsInterfaceSymbol.Name) != true) - { - extendedRegistrationOptions = ExtendAndImplementInterface(extendedRegistrationOptions, workDoneProgressOptionsInterfaceSymbol); - staticRegistrationOptions = ExtendAndImplementInterface(staticRegistrationOptions, workDoneProgressOptionsInterfaceSymbol); - } - - staticRegistrationOptions = staticRegistrationOptions.AddMembers(GetWorkDoneProperty()); - extendedRegistrationOptions = extendedRegistrationOptions.AddMembers(GetWorkDoneProperty()); - } + staticRegistrationOptions = staticRegistrationOptions.AddMembers(GetWorkDoneProperty()); + extendedRegistrationOptions = extendedRegistrationOptions.AddMembers(GetWorkDoneProperty()); + } - if (data.SupportsStaticRegistrationOptions && !data.ImplementsStaticRegistrationOptions) + if (data.SupportsStaticRegistrationOptions && !data.ImplementsStaticRegistrationOptions) + { + if (registrationOptions.BaseList?.Types.Any(z => z.Type.GetSyntaxName() == attributes.StaticRegistrationOptionsInterfaceSymbol.Name) + != true) { - if (registrationOptions.BaseList?.Types.Any(z => z.Type.GetSyntaxName() == staticRegistrationOptionsInterfaceSymbol.Name) != true) - { - extendedRegistrationOptions = ExtendAndImplementInterface(extendedRegistrationOptions, staticRegistrationOptionsInterfaceSymbol); - staticRegistrationOptions = ExtendAndImplementInterface(staticRegistrationOptions, staticRegistrationOptionsInterfaceSymbol); - } - - staticRegistrationOptions = staticRegistrationOptions.AddMembers(GetIdProperty()); - extendedRegistrationOptions = extendedRegistrationOptions.AddMembers(GetIdProperty()); + extendedRegistrationOptions = ExtendAndImplementInterface( + extendedRegistrationOptions, attributes.StaticRegistrationOptionsInterfaceSymbol + ); + staticRegistrationOptions = ExtendAndImplementInterface(staticRegistrationOptions, attributes.StaticRegistrationOptionsInterfaceSymbol); } - if (data.RegistrationOptionsConverter is null - && CreateConverter(registrationOptions, staticRegistrationOptions.Members.OfType()) is { } converter) - { - extendedRegistrationOptions = extendedRegistrationOptions - .AddAttributeLists( - AttributeList( - SingletonSeparatedList( - Attribute( - IdentifierName("RegistrationOptionsConverterAttribute"), - AttributeArgumentList( - SingletonSeparatedList( - AttributeArgument( - TypeOfExpression(IdentifierName(converter.Identifier.Text)) + staticRegistrationOptions = staticRegistrationOptions.AddMembers(GetIdProperty()); + extendedRegistrationOptions = extendedRegistrationOptions.AddMembers(GetIdProperty()); + } + + if (data.RegistrationOptionsConverter is null && CreateConverter( + registrationOptions, staticRegistrationOptions.Members.OfType() + ) is { } converter) + { + extendedRegistrationOptions = extendedRegistrationOptions.AddAttributeLists( + AttributeList( + SingletonSeparatedList( + Attribute( + IdentifierName("RegistrationOptionsConverterAttribute"), + AttributeArgumentList( + SingletonSeparatedList( + AttributeArgument( + TypeOfExpression( + IdentifierName(converter.Identifier.Text) + ) + ) + ) + ) + ) + ) + ) ) - ) - ) - ) - ) - ) - ) - .AddMembers(converter); - } + .AddMembers(converter); + } - extendedRegistrationOptions = extendedRegistrationOptions.AddMembers(staticRegistrationOptions); + extendedRegistrationOptions = extendedRegistrationOptions.AddMembers(staticRegistrationOptions); - var members = new List() { extendedRegistrationOptions }; + var members = new List() { extendedRegistrationOptions }; - var cu = CompilationUnit() - .WithUsings(registrationOptions.SyntaxTree.GetCompilationUnitRoot().Usings) - .AddMembers( - NamespaceDeclaration(ParseName(typeSymbol.ContainingNamespace.ToDisplayString())) - .WithMembers(List(members)) - .WithLeadingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true)))) - .WithTrailingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)))) - ) - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(CarriageReturnLineFeed); + var cu = CompilationUnit() + .WithUsings(registrationOptions.SyntaxTree.GetCompilationUnitRoot().Usings) + .AddMembers( + NamespaceDeclaration(ParseName(typeSymbol.ContainingNamespace.ToDisplayString())) + .WithMembers(List(members)) + .WithLeadingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true)))) + .WithTrailingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)))) + ); - foreach (var ns in RequiredUsings) + foreach (var ns in RequiredUsings) + { + if (cu.Usings.All(z => z.Name.ToFullString() != ns)) { - if (cu.Usings.All(z => z.Name.ToFullString() != ns)) - { - cu = cu.AddUsings(UsingDirective(ParseName(ns))); - } + cu = cu.AddUsings(UsingDirective(ParseName(ns))); } - - addCacheSource( - $"{registrationOptions.Identifier.Text}.cs", - registrationOptions, - cu.NormalizeWhitespace().GetText(Encoding.UTF8) - ); - } - catch (Exception e) - { - context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.Exception, registrationOptions.GetLocation(), e.Message, e.StackTrace ?? string.Empty)); - Debug.WriteLine(e); - Debug.WriteLine(e.StackTrace); } + + context.AddSource($"{registrationOptions.Identifier.Text}.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); + } + catch (Exception e) + { + context.ReportDiagnostic( + Diagnostic.Create(GeneratorDiagnostics.Exception, registrationOptions.GetLocation(), e.Message, e.StackTrace ?? string.Empty) + ); + Debug.WriteLine(e); + Debug.WriteLine(e.StackTrace); } + } + private void GenerateAssemblyRegistrationOptions( + SourceProductionContext context, ImmutableArray<(string @namespace, AttributeArgumentSyntax argumentSyntax)> types + ) + { + var namespaces = new HashSet() { "OmniSharp.Extensions.LanguageServer.Protocol" }; + if (types.Any()) { - var namespaces = new HashSet() { "OmniSharp.Extensions.LanguageServer.Protocol" }; - var types = syntaxReceiver.FoundNodes - .Concat(syntaxReceiver.RegistrationOptions) - .Select( - options => { - var semanticModel = context.Compilation.GetSemanticModel(options.SyntaxTree); - var typeSymbol = semanticModel.GetDeclaredSymbol(options)!; - namespaces.Add(typeSymbol.ContainingNamespace.ToDisplayString()); - return AttributeArgument(TypeOfExpression(IdentifierName(typeSymbol.Name))); - } - ) - .ToArray(); - if (types.Any()) + foreach (var item in types) { - var cu = CompilationUnit() - .WithUsings(List(namespaces.OrderBy(z => z).Select(z => UsingDirective(ParseName(z))))) - .AddAttributeLists( - AttributeList( - target: AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), - SingletonSeparatedList(Attribute(IdentifierName("AssemblyRegistrationOptions"), AttributeArgumentList(SeparatedList(types)))) + namespaces.Add(item.@namespace); + } + + var cu = CompilationUnit() + .WithUsings(List(namespaces.OrderBy(z => z).Select(z => UsingDirective(ParseName(z))))) + .AddAttributeLists( + AttributeList( + target: AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)), + SingletonSeparatedList( + Attribute( + IdentifierName("AssemblyRegistrationOptions"), + AttributeArgumentList(SeparatedList(types.Select(z => z.argumentSyntax))) + ) ) ) - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(CarriageReturnLineFeed); + ); - context.AddSource("AssemblyRegistrationOptions.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); - } + context.AddSource("AssemblyRegistrationOptions.cs", cu.NormalizeWhitespace().GetText(Encoding.UTF8)); } + } - static TypeDeclarationSyntax ExtendAndImplementInterface(TypeDeclarationSyntax syntax, ITypeSymbol symbolToExtendFrom) - { - return syntax switch { - ClassDeclarationSyntax cd => cd.AddBaseListTypes(SimpleBaseType(ParseName(symbolToExtendFrom.ToDisplayString()))), - RecordDeclarationSyntax rd => rd.AddBaseListTypes(SimpleBaseType(ParseName(symbolToExtendFrom.ToDisplayString()))), - _ => throw new NotSupportedException() - }; - } - static PropertyDeclarationSyntax GetWorkDoneProperty() + static TypeDeclarationSyntax ExtendAndImplementInterface(TypeDeclarationSyntax syntax, ITypeSymbol symbolToExtendFrom) + { + return syntax switch { - return PropertyDeclaration(PredefinedType(Token(SyntaxKind.BoolKeyword)), Identifier("WorkDoneProgress")) - .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - .WithAttributeLists( - SingletonList( - AttributeList( - SingletonSeparatedList(Attribute(IdentifierName("Optional"))) - ) + ClassDeclarationSyntax cd => cd.AddBaseListTypes(SimpleBaseType(ParseName(symbolToExtendFrom.ToDisplayString()))), + RecordDeclarationSyntax rd => rd.AddBaseListTypes(SimpleBaseType(ParseName(symbolToExtendFrom.ToDisplayString()))), + _ => throw new NotSupportedException() + }; + } + + static PropertyDeclarationSyntax GetWorkDoneProperty() + { + return PropertyDeclaration(PredefinedType(Token(SyntaxKind.BoolKeyword)), Identifier("WorkDoneProgress")) + .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) + .WithAttributeLists( + SingletonList( + AttributeList( + SingletonSeparatedList(Attribute(IdentifierName("Optional"))) ) ) - .WithAccessorList(CommonElements.GetSetAccessor); - } + ) + .WithAccessorList(CommonElements.GetSetAccessor); + } - static PropertyDeclarationSyntax GetIdProperty() - { - return PropertyDeclaration(NullableType(PredefinedType(Token(SyntaxKind.StringKeyword))), Identifier("Id")) - .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - .WithAttributeLists( - SingletonList( - AttributeList( - SingletonSeparatedList(Attribute(IdentifierName("Optional"))) - ) + static PropertyDeclarationSyntax GetIdProperty() + { + return PropertyDeclaration(NullableType(PredefinedType(Token(SyntaxKind.StringKeyword))), Identifier("Id")) + .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) + .WithAttributeLists( + SingletonList( + AttributeList( + SingletonSeparatedList(Attribute(IdentifierName("Optional"))) ) ) - .WithAccessorList(CommonElements.GetSetAccessor); - } + ) + .WithAccessorList(CommonElements.GetSetAccessor); } private static IEnumerable GetMapping(IEnumerable properties, IdentifierNameSyntax paramName) { return properties - .Where(z => z.AccessorList?.Accessors.Any(a => a.Keyword.Kind() == SyntaxKind.SetKeyword || a.Keyword.Kind() == SyntaxKind.InitKeyword) == true) + .Where( + z => z.AccessorList?.Accessors.Any(a => a.Keyword.Kind() == SyntaxKind.SetKeyword || a.Keyword.Kind() == SyntaxKind.InitKeyword) == true + ) .Select( property => AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, @@ -310,7 +384,8 @@ private static IEnumerable GetMapping(IEnumerable GetMapping(IEnumerable GetMapping(IEnumerable new SyntaxReceiver(Cache)) - { - } - - public static CacheContainer Cache = new(); - - public class SyntaxReceiver : SyntaxReceiverCache - { - public List RegistrationOptions { get; } = new(); - - public override string? GetKey(TypeDeclarationSyntax syntax) - { - var hasher = new CacheKeyHasher(); - hasher.Append(syntax.SyntaxTree.FilePath); - hasher.Append(syntax.Keyword.Text); - hasher.Append(syntax.Identifier.Text); - hasher.Append(syntax.TypeParameterList); - hasher.Append(syntax.AttributeLists); - hasher.Append(syntax.BaseList); - foreach (var item in syntax.Members.OfType().Select(z => z.Identifier.Text)) - { - hasher.Append(item); - } - - return hasher; - } - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public override void OnVisitNode(TypeDeclarationSyntax syntaxNode) - { - if (syntaxNode is ClassDeclarationSyntax or RecordDeclarationSyntax - && syntaxNode.AttributeLists - .SelectMany(z => z.Attributes) - .Any(z => z.Name.ToFullString().Contains("GenerateRegistrationOptions")) - ) - { - RegistrationOptions.Add(syntaxNode); - } - } - - public SyntaxReceiver(CacheContainer cache) : base(cache) - { - } - } } } diff --git a/src/JsonRpc.Generators/Strategies/EnsureNamespaceStrategy.cs b/src/JsonRpc.Generators/Strategies/EnsureNamespaceStrategy.cs index 7f4482cde..76e48e5b7 100644 --- a/src/JsonRpc.Generators/Strategies/EnsureNamespaceStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/EnsureNamespaceStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -6,7 +7,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class EnsureNamespaceStrategy : IExtensionMethodGeneratorStrategy { - public IEnumerable Apply(GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, GeneratorData item) { if (item.Capability != null) item.AdditionalUsings.Add(item.Capability.Symbol.ContainingNamespace.ToDisplayString()); if (item.RegistrationOptions != null) item.AdditionalUsings.Add(item.RegistrationOptions.Symbol.ContainingNamespace.ToDisplayString()); diff --git a/src/JsonRpc.Generators/Strategies/ExtensionMethodGeneratorStrategy.cs b/src/JsonRpc.Generators/Strategies/ExtensionMethodGeneratorStrategy.cs index 0b8116e80..182210655 100644 --- a/src/JsonRpc.Generators/Strategies/ExtensionMethodGeneratorStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/ExtensionMethodGeneratorStrategy.cs @@ -19,13 +19,13 @@ public ExtensionMethodGeneratorStrategy(ImmutableArray Apply(GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, GeneratorData item) { var methods = _extensionMethodGeneratorStrategies.Aggregate( new List(), (m, strategy) => { try { - m.AddRange(strategy.Apply(item)); + m.AddRange(strategy.Apply(context, item)); } catch (Exception e) { diff --git a/src/JsonRpc.Generators/Strategies/HandlerGeneratorStrategy.cs b/src/JsonRpc.Generators/Strategies/HandlerGeneratorStrategy.cs index 65881c524..08a0b1368 100644 --- a/src/JsonRpc.Generators/Strategies/HandlerGeneratorStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/HandlerGeneratorStrategy.cs @@ -11,7 +11,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class HandlerGeneratorStrategy : ICompilationUnitGeneratorStrategy { - public IEnumerable Apply(GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, GeneratorData item) { if (item.JsonRpcAttributes.GenerateHandler is not { }) yield break; var members = new List(); diff --git a/src/JsonRpc.Generators/Strategies/HandlerRegistryActionContextRunnerStrategy.cs b/src/JsonRpc.Generators/Strategies/HandlerRegistryActionContextRunnerStrategy.cs index ffda7747c..ab5ddf6df 100644 --- a/src/JsonRpc.Generators/Strategies/HandlerRegistryActionContextRunnerStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/HandlerRegistryActionContextRunnerStrategy.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -14,17 +15,20 @@ public HandlerRegistryActionContextRunnerStrategy(ImmutableArray Apply(GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, GeneratorData item) { + foreach (var diagnostic in item.JsonRpcAttributes.HandlerRegistryDiagnostics) + { + context.ReportDiagnostic(diagnostic); + } return item.JsonRpcAttributes.HandlerRegistries .Select( registry => new ExtensionMethodContext( - item.JsonRpcAttributes.GenerateHandlerMethods!.Data, item.TypeDeclaration, item.TypeSymbol, registry, item.JsonRpcAttributes.HandlerRegistries, - item.Context + item.JsonRpcAttributes.GenerateHandlerMethods!.Data, item.TypeDeclaration, item.TypeSymbol, registry, item.JsonRpcAttributes.HandlerRegistries ) { IsRegistry = true } ) .SelectMany(_ => _strategies, (actionContext, strategy) => new { actionContext, strategy }) - .SelectMany(@t => @t.strategy.Apply(@t.actionContext, item)); + .SelectMany(@t => @t.strategy.Apply(context, @t.actionContext, item)); } } } diff --git a/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithRegistrationOptionsStrategy.cs b/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithRegistrationOptionsStrategy.cs index 660226913..b4f0324bc 100644 --- a/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithRegistrationOptionsStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithRegistrationOptionsStrategy.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -13,7 +14,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class OnNotificationMethodGeneratorWithRegistrationOptionsStrategy : IExtensionMethodContextGeneratorStrategy { - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is not { RegistrationOptions: { } registrationOptions }) yield break; if (item is not NotificationItem notification) yield break; diff --git a/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithoutRegistrationOptionsStrategy.cs b/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithoutRegistrationOptionsStrategy.cs index 984cf5f4b..d0e158e53 100644 --- a/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithoutRegistrationOptionsStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/OnNotificationMethodGeneratorWithoutRegistrationOptionsStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -10,7 +11,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class OnNotificationMethodGeneratorWithoutRegistrationOptionsStrategy : IExtensionMethodContextGeneratorStrategy { - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is { RegistrationOptions: { } }) yield break; if (item is not NotificationItem notification) yield break; diff --git a/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithRegistrationOptionsStrategy.cs b/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithRegistrationOptionsStrategy.cs index 7db3b435e..7ad741a03 100644 --- a/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithRegistrationOptionsStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithRegistrationOptionsStrategy.cs @@ -21,7 +21,7 @@ public OnRequestMethodGeneratorWithRegistrationOptionsStrategy(bool doResolve) _doResolve = doResolve; } - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is not { RegistrationOptions: { } registrationOptions }) yield break; if (item is not RequestItem request) yield break; diff --git a/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithoutRegistrationOptionsStrategy.cs b/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithoutRegistrationOptionsStrategy.cs index 2eecbffe3..0bdcdccaa 100644 --- a/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithoutRegistrationOptionsStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithoutRegistrationOptionsStrategy.cs @@ -19,7 +19,7 @@ public OnRequestMethodGeneratorWithoutRegistrationOptionsStrategy(bool doResolve _doResolve = doResolve; } - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is { RegistrationOptions: { } }) yield break; if (item is not RequestItem request) yield break; diff --git a/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithRegistrationOptionsStrategy.cs b/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithRegistrationOptionsStrategy.cs index b13c22046..303f9908d 100644 --- a/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithRegistrationOptionsStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithRegistrationOptionsStrategy.cs @@ -14,7 +14,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class OnRequestTypedResolveMethodGeneratorWithRegistrationOptionsStrategy : IExtensionMethodContextGeneratorStrategy { - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is not { RegistrationOptions: { } registrationOptions }) yield break; if (item is not RequestItem request) yield break; diff --git a/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithoutRegistrationOptionsStrategy.cs b/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithoutRegistrationOptionsStrategy.cs index 027144aa6..a7f88defc 100644 --- a/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithoutRegistrationOptionsStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithoutRegistrationOptionsStrategy.cs @@ -13,7 +13,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies internal class OnRequestTypedResolveMethodGeneratorWithoutRegistrationOptionsStrategy : IExtensionMethodContextGeneratorStrategy { - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is { RegistrationOptions: { } }) yield break; if (item is not RequestItem request) yield break; diff --git a/src/JsonRpc.Generators/Strategies/RequestProxyActionContextRunnerStrategy.cs b/src/JsonRpc.Generators/Strategies/RequestProxyActionContextRunnerStrategy.cs index 17ee67b1f..791c51ddc 100644 --- a/src/JsonRpc.Generators/Strategies/RequestProxyActionContextRunnerStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/RequestProxyActionContextRunnerStrategy.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -14,17 +15,20 @@ public RequestProxyActionContextRunnerStrategy(ImmutableArray Apply(GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, GeneratorData item) { + foreach (var diagnostic in item.JsonRpcAttributes.RequestProxyDiagnostics) + { + context.ReportDiagnostic(diagnostic); + } return item.JsonRpcAttributes.RequestProxies .Select( registry => new ExtensionMethodContext( - item.JsonRpcAttributes.GenerateRequestMethods!.Data, item.TypeDeclaration, item.TypeSymbol, registry, item.JsonRpcAttributes.RequestProxies, - item.Context + item.JsonRpcAttributes.GenerateRequestMethods!.Data, item.TypeDeclaration, item.TypeSymbol, registry, item.JsonRpcAttributes.RequestProxies ) { IsProxy = true } ) .SelectMany(_ => _strategies, (actionContext, strategy) => new { actionContext, strategy }) - .SelectMany(t => t.strategy.Apply(t.actionContext, item)); + .SelectMany(t => t.strategy.Apply(context, t.actionContext, item)); } } } diff --git a/src/JsonRpc.Generators/Strategies/SendMethodNotificationStrategy.cs b/src/JsonRpc.Generators/Strategies/SendMethodNotificationStrategy.cs index bad6be5c1..265473f86 100644 --- a/src/JsonRpc.Generators/Strategies/SendMethodNotificationStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/SendMethodNotificationStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using OmniSharp.Extensions.JsonRpc.Generators.Contexts; @@ -8,7 +9,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class SendMethodNotificationStrategy : IExtensionMethodContextGeneratorStrategy { - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is not NotificationItem notification) yield break; if (extensionMethodContext is not { IsProxy: true }) yield break; diff --git a/src/JsonRpc.Generators/Strategies/SendMethodRequestStrategy.cs b/src/JsonRpc.Generators/Strategies/SendMethodRequestStrategy.cs index fdcf99139..7bbc19ce3 100644 --- a/src/JsonRpc.Generators/Strategies/SendMethodRequestStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/SendMethodRequestStrategy.cs @@ -9,7 +9,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class SendMethodRequestStrategy : IExtensionMethodContextGeneratorStrategy { - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (item is not RequestItem request) yield break; if (extensionMethodContext is not { IsProxy: true }) yield break; diff --git a/src/JsonRpc.Generators/Strategies/TypedDelegatingHandlerStrategy.cs b/src/JsonRpc.Generators/Strategies/TypedDelegatingHandlerStrategy.cs index f1fbaef01..21d7b9905 100644 --- a/src/JsonRpc.Generators/Strategies/TypedDelegatingHandlerStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/TypedDelegatingHandlerStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; @@ -8,7 +9,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class TypedDelegatingHandlerStrategy : IExtensionMethodGeneratorStrategy { - public IEnumerable Apply(GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, GeneratorData item) { if (item is not RequestItem requestItem) yield break; if (requestItem is not { LspAttributes: { Resolver: { } } }) yield break; diff --git a/src/JsonRpc.Generators/Strategies/WarnIfResponseRouterIsNotProvidedStrategy.cs b/src/JsonRpc.Generators/Strategies/WarnIfResponseRouterIsNotProvidedStrategy.cs index 82c16622d..17eb45176 100644 --- a/src/JsonRpc.Generators/Strategies/WarnIfResponseRouterIsNotProvidedStrategy.cs +++ b/src/JsonRpc.Generators/Strategies/WarnIfResponseRouterIsNotProvidedStrategy.cs @@ -7,7 +7,7 @@ namespace OmniSharp.Extensions.JsonRpc.Generators.Strategies { internal class WarnIfResponseRouterIsNotProvidedStrategy : IExtensionMethodContextGeneratorStrategy { - public IEnumerable Apply(ExtensionMethodContext extensionMethodContext, GeneratorData item) + public IEnumerable Apply(SourceProductionContext context, ExtensionMethodContext extensionMethodContext, GeneratorData item) { if (extensionMethodContext is not { IsProxy: true }) yield break; @@ -20,7 +20,7 @@ public IEnumerable Apply(ExtensionMethodContext extensi && generateRequestMethods.Data.ConstructorArguments[0].Values.Length == 0 ) && !extensionMethodContext.TypeSymbol.ContainingNamespace.ToDisplayString().StartsWith("OmniSharp.Extensions.DebugAdapter.Protocol")) { - item.ReportDiagnostic(static type => Diagnostic.Create(GeneratorDiagnostics.NoResponseRouterProvided, type.Identifier.GetLocation(), type.Identifier.Text)); + context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.NoResponseRouterProvided, item.TypeDeclaration.Identifier.GetLocation(), item.TypeDeclaration.Identifier.Text)); } } } diff --git a/src/JsonRpc.Generators/StronglyTypedGenerator.cs b/src/JsonRpc.Generators/StronglyTypedGenerator.cs index dd83fafdc..42f64bcf5 100644 --- a/src/JsonRpc.Generators/StronglyTypedGenerator.cs +++ b/src/JsonRpc.Generators/StronglyTypedGenerator.cs @@ -5,252 +5,298 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using static OmniSharp.Extensions.JsonRpc.Generators.Helpers; namespace OmniSharp.Extensions.JsonRpc.Generators { [Generator] - public class StronglyTypedGenerator : CachedSourceGenerator + public class StronglyTypedGenerator : IIncrementalGenerator { - private static string[] RequiredUsings = new[] { + private static string[] RequiredUsings = new[] + { "System.Collections.Generic", "System.Collections.ObjectModel", "System.Collections.Immutable", "System.Linq", }; - protected override void Execute( - GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, - ReportCacheDiagnostic cacheDiagnostic - ) - { - var generateTypedDataAttributeSymbol = context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Generation.GenerateTypedDataAttribute"); - var generateContainerAttributeSymbol = context.Compilation.GetTypeByMetadataName("OmniSharp.Extensions.LanguageServer.Protocol.Generation.GenerateContainerAttribute"); + private record AttributeData(INamedTypeSymbol GenerateTypedDataAttributeSymbol, INamedTypeSymbol GenerateContainerAttributeSymbol); - foreach (var classToContain in syntaxReceiver.CreateContainers) - { - var semanticModel = context.Compilation.GetSemanticModel(classToContain.SyntaxTree); - var typeSymbol = semanticModel.GetDeclaredSymbol(classToContain); - var attribute = typeSymbol?.GetAttributes().FirstOrDefault(z => SymbolEqualityComparer.Default.Equals(z.AttributeClass, generateContainerAttributeSymbol)); - if (typeSymbol == null || attribute is null) continue; - - var containerName = attribute is { ConstructorArguments: { Length: > 0 } arguments } ? arguments[0].Value as string : null; - - var container = CreateContainerClass(classToContain, containerName) - .AddAttributeLists( - AttributeList( - SeparatedList( - new[] { - Attribute(ParseName("System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute")), - Attribute(ParseName("System.Runtime.CompilerServices.CompilerGeneratedAttribute")) - } - ) - ) - ); + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var attributes = context.CompilationProvider + .Select( + (compilation, token) => new AttributeData( + compilation.GetTypeByMetadataName( + "OmniSharp.Extensions.LanguageServer.Protocol.Generation.GenerateTypedDataAttribute" + )!, + compilation.GetTypeByMetadataName( + "OmniSharp.Extensions.LanguageServer.Protocol.Generation.GenerateContainerAttribute" + )! + ) + ); - var cu = CompilationUnit() - .WithUsings(classToContain.SyntaxTree.GetCompilationUnitRoot().Usings) - .AddMembers( - NamespaceDeclaration(ParseName(typeSymbol.ContainingNamespace.ToDisplayString())) - .AddMembers(container) - .WithLeadingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true)))) - .WithTrailingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)))) - ) - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(CarriageReturnLineFeed); - - foreach (var ns in RequiredUsings) + var createContainersSyntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (syntaxNode, token) => syntaxNode switch { - if (cu.Usings.All(z => z.Name.ToFullString() != ns)) - { - cu = cu.AddUsings(UsingDirective(ParseName(ns))); - } - } + StructDeclarationSyntax structDeclarationSyntax when structDeclarationSyntax.AttributeLists.ContainsAttribute("GenerateContainer") => true, + TypeDeclarationSyntax typeDeclarationSyntax and (ClassDeclarationSyntax or RecordDeclarationSyntax) when typeDeclarationSyntax + .AttributeLists.ContainsAttribute("GenerateContainer") => true, + _ => false + }, transform: (syntaxContext, token) => syntaxContext + ); - addCacheSource( - $"{containerName ?? classToContain.Identifier.Text + "Container"}.cs", - classToContain, - cu.NormalizeWhitespace().GetText(Encoding.UTF8) - ); - } + var canBeResolvedSyntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (syntaxNode, token) => + syntaxNode is TypeDeclarationSyntax { BaseList: { } } typeDeclarationSyntax and (ClassDeclarationSyntax or RecordDeclarationSyntax) + && syntaxNode.SyntaxTree.HasCompilationUnitRoot + && typeDeclarationSyntax.Members.OfType().Any(z => z.Identifier.Text == "Data") + && typeDeclarationSyntax.BaseList.Types.Any(z => z.Type.GetSyntaxName() == "ICanBeResolved"), + transform: (syntaxContext, token) => syntaxContext + ); - foreach (var canBeResolved in syntaxReceiver.CanBeResolved) - { - var dataInterfaceName = IdentifierName("ICanBeResolved"); - CreateTypedClass( - context, canBeResolved, dataInterfaceName, generateTypedDataAttributeSymbol, generateContainerAttributeSymbol, true, addCacheSource, cacheDiagnostic - ); - } + var canHaveDataSyntaxProvider = context.SyntaxProvider.CreateSyntaxProvider( + predicate: (syntaxNode, token) => + syntaxNode is TypeDeclarationSyntax { BaseList: { } } typeDeclarationSyntax and (ClassDeclarationSyntax or RecordDeclarationSyntax) + && syntaxNode.SyntaxTree.HasCompilationUnitRoot + && typeDeclarationSyntax.Members.OfType().Any(z => z.Identifier.Text == "Data") + && typeDeclarationSyntax.BaseList.Types.Any(z => z.Type.GetSyntaxName() == "ICanHaveData"), transform: (syntaxContext, token) => syntaxContext + ); - foreach (var canBeResolved in syntaxReceiver.CanHaveData) - { - var dataInterfaceName = IdentifierName("ICanHaveData"); - CreateTypedClass( - context, canBeResolved, dataInterfaceName, generateTypedDataAttributeSymbol, generateContainerAttributeSymbol, false, addCacheSource, cacheDiagnostic + context.RegisterSourceOutput(createContainersSyntaxProvider.Combine(attributes), GenerateContainerClass); + context.RegisterSourceOutput(canBeResolvedSyntaxProvider.Combine(attributes), GenerateCanBeResolvedClass); + context.RegisterSourceOutput(canHaveDataSyntaxProvider.Combine(attributes), GenerateCanHaveDataClass); + } + + private void GenerateContainerClass(SourceProductionContext context, (GeneratorSyntaxContext syntaxContext, AttributeData attributeData) valueTuple) + { + var (syntaxContext, attributeData) = valueTuple; + var classToContain = (TypeDeclarationSyntax)syntaxContext.Node; + var typeSymbol = syntaxContext.SemanticModel.GetDeclaredSymbol(classToContain); + var attribute = typeSymbol?.GetAttributes() + .FirstOrDefault( + z => SymbolEqualityComparer.Default.Equals(z.AttributeClass, attributeData.GenerateContainerAttributeSymbol) + ); + if (typeSymbol == null || attribute is null) return; + + var containerName = attribute is { ConstructorArguments: { Length: > 0 } arguments } ? arguments[0].Value as string : null; + + var container = CreateContainerClass(classToContain, containerName) + .AddAttributeLists( + AttributeList( + SeparatedList( + new[] + { + Attribute(ParseName("System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute")), + Attribute(ParseName("System.Runtime.CompilerServices.CompilerGeneratedAttribute")) + } + ) + ) ); - } - static void CreateTypedClass( - GeneratorExecutionContext context, - TypeDeclarationSyntax candidate, - IdentifierNameSyntax dataInterfaceName, - INamedTypeSymbol? generateTypedDataAttributeSymbol, - INamedTypeSymbol? generateContainerAttributeSymbol, - bool includeHandlerIdentity, - AddCacheSource cacheItem, - ReportCacheDiagnostic cacheDiagnostic - ) - { - var semanticModel = context.Compilation.GetSemanticModel(candidate.SyntaxTree); - var typeSymbol = semanticModel.GetDeclaredSymbol(candidate); - var attribute = typeSymbol?.GetAttributes().FirstOrDefault(z => SymbolEqualityComparer.Default.Equals(z.AttributeClass, generateTypedDataAttributeSymbol)); - if (typeSymbol == null || attribute is null) return; - var container = typeSymbol.GetAttributes().FirstOrDefault(z => SymbolEqualityComparer.Default.Equals(z.AttributeClass, generateContainerAttributeSymbol)); + var cu = CompilationUnit() + .WithUsings(classToContain.SyntaxTree.GetCompilationUnitRoot().Usings) + .AddMembers( + NamespaceDeclaration(ParseName(typeSymbol.ContainingNamespace.ToDisplayString())) + .AddMembers(container) + .WithLeadingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true)))) + .WithTrailingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)))) + ); - if (!candidate.Modifiers.Any(SyntaxKind.PartialKeyword)) + foreach (var ns in RequiredUsings) + { + if (cu.Usings.All(z => z.Name.ToFullString() != ns)) { - cacheDiagnostic(candidate, static c => Diagnostic.Create(GeneratorDiagnostics.MustBePartial, c.Identifier.GetLocation(), c.Identifier.Text)); - return; + cu = cu.AddUsings(UsingDirective(ParseName(ns))); } + } - var property = candidate.Members.OfType().Single(z => z.Identifier.Text == "Data"); - var partialClass = candidate - .WithAttributeLists(List()) - .WithBaseList(null) - .WithMembers(List()) - .AddMembers( - GetWithDataMethod(candidate, HandlerIdentityConstraintClause(includeHandlerIdentity, IdentifierName("TData"))), - GetFromMethod(candidate, includeHandlerIdentity) - ); - - var compilationMembers = new List(); - - - var convertFromOperator = GetConvertFromOperator(candidate); - var convertToOperator = GetConvertToOperator(candidate); - // remove the data property - var typedClass = candidate - .WithHandlerIdentityConstraint(includeHandlerIdentity) - .WithMembers(candidate.Members.Replace(property, GetPropertyImpl(property).WithType(IdentifierName("T")))) - .AddMembers( - GetWithDataMethod(candidate, HandlerIdentityConstraintClause(includeHandlerIdentity, IdentifierName("TData"))), - GetExplicitProperty(property, dataInterfaceName), - GetJDataProperty(), - convertFromOperator, - convertToOperator, - GetGenericFromMethod(candidate) - ) - .WithAttributeLists( - List( - candidate.AttributeLists - .Where(z => !z.ContainsAttribute("Method") && !z.ContainsAttribute("GenerateTypedData")) - ) + context.AddSource( + $"{containerName ?? classToContain.Identifier.Text + "Container"}.cs", + cu.NormalizeWhitespace().GetText(Encoding.UTF8) + ); + } + + private void GenerateCanBeResolvedClass(SourceProductionContext context, (GeneratorSyntaxContext syntaxContext, AttributeData attributeData) valueTuple) + { + var (syntaxContext, attributeData) = valueTuple; + var canBeResolved = (TypeDeclarationSyntax)syntaxContext.Node; + var typeSymbol = syntaxContext.SemanticModel.GetDeclaredSymbol(canBeResolved)!; + + var dataInterfaceName = IdentifierName("ICanBeResolved"); + CreateTypedClass( + context, canBeResolved, typeSymbol, dataInterfaceName, attributeData.GenerateTypedDataAttributeSymbol, attributeData.GenerateContainerAttributeSymbol, true + ); + } + + private void GenerateCanHaveDataClass(SourceProductionContext context, (GeneratorSyntaxContext syntaxContext, AttributeData attributeData) valueTuple) + { + var (syntaxContext, attributeData) = valueTuple; + var canBeResolved = (TypeDeclarationSyntax)syntaxContext.Node; + var typeSymbol = syntaxContext.SemanticModel.GetDeclaredSymbol(canBeResolved)!; + + var dataInterfaceName = IdentifierName("ICanHaveData"); + CreateTypedClass( + context, canBeResolved, typeSymbol, dataInterfaceName, attributeData.GenerateTypedDataAttributeSymbol, attributeData.GenerateContainerAttributeSymbol, true + ); + } + + private static void CreateTypedClass( + SourceProductionContext context, + TypeDeclarationSyntax candidate, + INamedTypeSymbol typeSymbol, + IdentifierNameSyntax dataInterfaceName, + INamedTypeSymbol? generateTypedDataAttributeSymbol, + INamedTypeSymbol? generateContainerAttributeSymbol, + bool includeHandlerIdentity + ) + { + var attribute = typeSymbol?.GetAttributes() + .FirstOrDefault(z => SymbolEqualityComparer.Default.Equals(z.AttributeClass, generateTypedDataAttributeSymbol)); + if (typeSymbol == null || attribute is null) return; + var container = typeSymbol.GetAttributes() + .FirstOrDefault(z => SymbolEqualityComparer.Default.Equals(z.AttributeClass, generateContainerAttributeSymbol)); + + if (!candidate.Modifiers.Any(SyntaxKind.PartialKeyword)) + { + context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.MustBePartial, candidate.Identifier.GetLocation(), candidate.Identifier.Text)); + return; + } + + var property = candidate.Members.OfType().Single(z => z.Identifier.Text == "Data"); + var partialClass = candidate + .WithAttributeLists(List()) + .WithBaseList(null) + .WithMembers(List()) + .AddMembers( + GetWithDataMethod(candidate, HandlerIdentityConstraintClause(includeHandlerIdentity, IdentifierName("TData"))), + GetFromMethod(candidate, includeHandlerIdentity) + ); + + var compilationMembers = new List(); + + + var convertFromOperator = GetConvertFromOperator(candidate); + var convertToOperator = GetConvertToOperator(candidate); + // remove the data property + var typedClass = candidate + .WithHandlerIdentityConstraint(includeHandlerIdentity) + .WithMembers(candidate.Members.Replace(property, GetPropertyImpl(property).WithType(IdentifierName("T")))) + .AddMembers( + GetWithDataMethod(candidate, HandlerIdentityConstraintClause(includeHandlerIdentity, IdentifierName("TData"))), + GetExplicitProperty(property, dataInterfaceName), + GetJDataProperty(), + convertFromOperator, + convertToOperator, + GetGenericFromMethod(candidate) + ) + .WithAttributeLists( + List( + candidate.AttributeLists + .Where(z => !z.ContainsAttribute("Method") && !z.ContainsAttribute("GenerateTypedData")) ) - .WithBaseList(BaseList(SingletonSeparatedList(SimpleBaseType(dataInterfaceName)))) - .AddAttributeLists( - AttributeList( - SeparatedList( - new[] { - Attribute(ParseName("System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute")), - Attribute(ParseName("System.Runtime.CompilerServices.CompilerGeneratedAttribute")) - } - ) + ) + .WithBaseList(BaseList(SingletonSeparatedList(SimpleBaseType(dataInterfaceName)))) + .AddAttributeLists( + AttributeList( + SeparatedList( + new[] + { + Attribute(ParseName("System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute")), + Attribute(ParseName("System.Runtime.CompilerServices.CompilerGeneratedAttribute")) + } ) ) + ) // .WithLeadingTrivia(candidate.GetLeadingTrivia().Where(z => !z.ToString().Contains("#nullable"))) // .WithTrailingTrivia(candidate.GetTrailingTrivia().Where(z => !z.ToString().Contains("#nullable"))) - ; + ; - if (container is { }) - { - var containerName = container is { ConstructorArguments: { Length: > 0 } arguments } ? arguments[0].Value as string : null; - var typedContainer = CreateContainerClass(typedClass, containerName) - .WithHandlerIdentityConstraint(includeHandlerIdentity); - - var typedArgumentList = TypeArgumentList(SingletonSeparatedList(IdentifierName("T"))); - typedContainer = typedContainer - .AddMembers( - ConversionOperatorDeclaration(Token(SyntaxKind.ImplicitKeyword), IdentifierName(typedContainer.Identifier)) - .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))) - .WithParameterList( - ParameterList( - SingletonSeparatedList( - Parameter(Identifier("container")) - .WithType(GenericName(typedContainer.Identifier).WithTypeArgumentList(typedArgumentList)) - ) + if (container is { }) + { + var containerName = container is { ConstructorArguments: { Length: > 0 } arguments } ? arguments[0].Value as string : null; + var typedContainer = CreateContainerClass(typedClass, containerName) + .WithHandlerIdentityConstraint(includeHandlerIdentity); + + var typedArgumentList = TypeArgumentList(SingletonSeparatedList(IdentifierName("T"))); + typedContainer = typedContainer + .AddMembers( + ConversionOperatorDeclaration(Token(SyntaxKind.ImplicitKeyword), IdentifierName(typedContainer.Identifier)) + .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))) + .WithParameterList( + ParameterList( + SingletonSeparatedList( + Parameter(Identifier("container")) + .WithType(GenericName(typedContainer.Identifier).WithTypeArgumentList(typedArgumentList)) ) ) - .WithExpressionBody( - ArrowExpressionClause( - ObjectCreationExpression(IdentifierName(typedContainer.Identifier)) - .WithArgumentList( - ArgumentList( - SingletonSeparatedList( - Argument( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName("container"), - IdentifierName("Select") - ) + ) + .WithExpressionBody( + ArrowExpressionClause( + ObjectCreationExpression(IdentifierName(typedContainer.Identifier)) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("container"), + IdentifierName("Select") ) - .WithArgumentList( - ArgumentList( - SingletonSeparatedList( - Argument( - SimpleLambdaExpression(Parameter(Identifier("value"))) - .WithExpressionBody( - CastExpression( - IdentifierName(candidate.Identifier), - IdentifierName("value") - ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + SimpleLambdaExpression(Parameter(Identifier("value"))) + .WithExpressionBody( + CastExpression( + IdentifierName(candidate.Identifier), + IdentifierName("value") ) - ) + ) ) ) ) - ) + ) ) ) ) - ) - ) - .MakeMethodNullable(IdentifierName("container")) - .WithSemicolonToken( - Token(SyntaxKind.SemicolonToken) + ) ) - ); + ) + .MakeMethodNullable(IdentifierName("container")) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ) + ); - compilationMembers.Add(typedContainer); - } + compilationMembers.Add(typedContainer); + } - var cu = CompilationUnit() - .WithUsings(candidate.SyntaxTree.GetCompilationUnitRoot().Usings) - .AddMembers( - NamespaceDeclaration(ParseName(typeSymbol.ContainingNamespace.ToDisplayString())) - .AddMembers(partialClass, typedClass) - .AddMembers(compilationMembers.ToArray()) - .WithLeadingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true)))) - .WithTrailingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)))) - ) - .WithLeadingTrivia(Comment(Preamble.GeneratedByATool)) - .WithTrailingTrivia(CarriageReturnLineFeed); - foreach (var ns in RequiredUsings) + var cu = CompilationUnit() + .WithUsings(candidate.SyntaxTree.GetCompilationUnitRoot().Usings) + .AddMembers( + NamespaceDeclaration(ParseName(typeSymbol.ContainingNamespace.ToDisplayString())) + .AddMembers(partialClass, typedClass) + .AddMembers(compilationMembers.ToArray()) + .WithLeadingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true)))) + .WithTrailingTrivia(TriviaList(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)))) + ); + foreach (var ns in RequiredUsings) + { + if (cu.Usings.All(z => z.Name.ToFullString() != ns)) { - if (cu.Usings.All(z => z.Name.ToFullString() != ns)) - { - cu = cu.AddUsings(UsingDirective(ParseName(ns))); - } + cu = cu.AddUsings(UsingDirective(ParseName(ns))); } - - cacheItem( - $"{Path.GetFileNameWithoutExtension(candidate.SyntaxTree.FilePath)}_{candidate.Identifier.Text}Typed.cs", - candidate, - cu.NormalizeWhitespace().GetText(Encoding.UTF8) - ); } + + context.AddSource( + $"{Path.GetFileNameWithoutExtension(candidate.SyntaxTree.FilePath)}_{candidate.Identifier.Text}Typed.cs", + cu.NormalizeWhitespace().GetText(Encoding.UTF8) + ); } private static MethodDeclarationSyntax GetWithDataMethod(TypeDeclarationSyntax syntax, SyntaxList constraintSyntax) @@ -277,7 +323,8 @@ private static MethodDeclarationSyntax GetWithDataMethod(TypeDeclarationSyntax s SyntaxKind.ObjectInitializerExpression, SeparatedList( GetMapping(syntax, null).Concat( - new ExpressionSyntax[] { + new ExpressionSyntax[] + { AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName("Data"), @@ -337,7 +384,10 @@ private static MethodDeclarationSyntax GetFromMethod(TypeDeclarationSyntax synta private static IEnumerable GetMapping(TypeDeclarationSyntax syntax, IdentifierNameSyntax? paramName) { return syntax.Members.OfType() - .Where(z => z.AccessorList?.Accessors.Any(a => a.Keyword.Kind() == SyntaxKind.SetKeyword || a.Keyword.Kind() == SyntaxKind.InitKeyword) == true) + .Where( + z => z.AccessorList?.Accessors.Any(a => a.Keyword.Kind() == SyntaxKind.SetKeyword || a.Keyword.Kind() == SyntaxKind.InitKeyword) + == true + ) .Where(z => z.Identifier.Text != "Data") .Select( property => AssignmentExpression( @@ -383,7 +433,8 @@ private static ConversionOperatorDeclarationSyntax GetConvertToOperator(TypeDecl SeparatedList( GetMapping(syntax, paramName) .Concat( - new[] { + new[] + { AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName("Data"), @@ -438,7 +489,8 @@ private static ConversionOperatorDeclarationSyntax GetConvertFromOperator(TypeDe SeparatedList( GetMapping(syntax, paramName) .Concat( - new[] { + new[] + { AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName("JData"), @@ -474,18 +526,27 @@ private static PropertyDeclarationSyntax GetJDataProperty() .WithAccessorList( AccessorList( List( - new[] { + new[] + { AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithExpressionBody( ArrowExpressionClause( - InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("GetRawData"))) + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("GetRawData") + ) + ) ) ) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)), AccessorDeclaration(SyntaxKind.InitAccessorDeclaration) .WithExpressionBody( ArrowExpressionClause( - InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("SetRawData"))) + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("SetRawData") + ) + ) .WithArgumentList(ArgumentList(SingletonSeparatedList(Argument(IdentifierName("value"))))) ) ) @@ -501,7 +562,8 @@ static PropertyDeclarationSyntax GetPropertyImpl(PropertyDeclarationSyntax synta return syntax.WithAccessorList( AccessorList( List( - new[] { + new[] + { AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithExpressionBody( ArrowExpressionClause( @@ -573,7 +635,8 @@ private static TypeDeclarationSyntax CreateContainerClass(TypeDeclarationSyntax ) .WithMembers( List( - new MemberDeclarationSyntax[] { + new MemberDeclarationSyntax[] + { ConstructorDeclaration(classIdentifier) .WithModifiers( TokenList( @@ -611,19 +674,27 @@ private static TypeDeclarationSyntax CreateContainerClass(TypeDeclarationSyntax .WithParameterList( ParameterList( SingletonSeparatedList( - Parameter(Identifier("items")).WithType(GenericName(Identifier("IEnumerable")).WithTypeArgumentList(typeArgumentList)) + Parameter(Identifier("items")).WithType( + GenericName(Identifier("IEnumerable")).WithTypeArgumentList(typeArgumentList) + ) ) ) ) .WithInitializer( - ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, ArgumentList(SingletonSeparatedList(Argument(IdentifierName("items"))))) + ConstructorInitializer( + SyntaxKind.BaseConstructorInitializer, ArgumentList(SingletonSeparatedList(Argument(IdentifierName("items")))) + ) ) .WithBody(Block()), ConstructorDeclaration(classIdentifier) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - .WithParameterList(ParameterList(SingletonSeparatedList(ArrayParameter(typeName).WithModifiers(TokenList(Token(SyntaxKind.ParamsKeyword)))))) + .WithParameterList( + ParameterList(SingletonSeparatedList(ArrayParameter(typeName).WithModifiers(TokenList(Token(SyntaxKind.ParamsKeyword))))) + ) .WithInitializer( - ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, ArgumentList(SingletonSeparatedList(Argument(IdentifierName("items"))))) + ConstructorInitializer( + SyntaxKind.BaseConstructorInitializer, ArgumentList(SingletonSeparatedList(Argument(IdentifierName("items")))) + ) ) .WithBody(Block()), AddConversionBody( @@ -649,7 +720,9 @@ private static TypeDeclarationSyntax CreateContainerClass(TypeDeclarationSyntax Identifier("List"), MethodDeclaration(className, Identifier("From")) ) - .WithParameterList(ParameterList(SingletonSeparatedList(ArrayParameter(typeName).WithModifiers(TokenList(Token(SyntaxKind.ParamsKeyword)))))), + .WithParameterList( + ParameterList(SingletonSeparatedList(ArrayParameter(typeName).WithModifiers(TokenList(Token(SyntaxKind.ParamsKeyword))))) + ), AddConversionBody( typeName, Identifier("Collection"), @@ -817,74 +890,5 @@ static BaseMethodDeclarationSyntax AddConversionBody(TypeSyntax typeName, Syntax ); } } - - public StronglyTypedGenerator() : base(() => new SyntaxReceiver(Cache)) - { - } - - public static CacheContainer Cache = new(); - - public class SyntaxReceiver : SyntaxReceiverCache - { - public List CanBeResolved { get; } = new(); - public List CanHaveData { get; } = new(); - public List CreateContainers { get; } = new(); - - public override string? GetKey(TypeDeclarationSyntax syntax) - { - var hasher = new CacheKeyHasher(); - hasher.Append(syntax.SyntaxTree.FilePath); - hasher.Append(syntax.Keyword.Text); - hasher.Append(syntax.Identifier.Text); - hasher.Append(syntax.TypeParameterList); - hasher.Append(syntax.AttributeLists); - hasher.Append(syntax.BaseList); - return hasher; - } - - /// - /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - /// - public override void OnVisitNode(TypeDeclarationSyntax syntaxNode) - { - // any field with at least one attribute is a candidate for property generation - - if (syntaxNode is StructDeclarationSyntax structDeclarationSyntax) - { - if (structDeclarationSyntax.AttributeLists.ContainsAttribute("GenerateContainer")) - { - CreateContainers.Add(structDeclarationSyntax); - } - } - - if (syntaxNode is ClassDeclarationSyntax or RecordDeclarationSyntax) - { - if (syntaxNode.AttributeLists.ContainsAttribute("GenerateContainer")) - { - CreateContainers.Add(syntaxNode); - } - - if ( - syntaxNode.BaseList != null && - syntaxNode.SyntaxTree.HasCompilationUnitRoot && - syntaxNode.Members.OfType().Any(z => z.Identifier.Text == "Data") - ) - { - if (syntaxNode.BaseList.Types.Any(z => z.Type.GetSyntaxName() == "ICanBeResolved")) - { - CanBeResolved.Add(syntaxNode); - } - else if (syntaxNode.BaseList.Types.Any(z => z.Type.GetSyntaxName() == "ICanHaveData")) - { - CanHaveData.Add(syntaxNode); - } - } - } - } - - public SyntaxReceiver(CacheContainer cache) : base(cache) - { - } - } } } diff --git a/src/Protocol/Generation/GenerateContainerAttribute.cs b/src/Protocol/Generation/GenerateContainerAttribute.cs index 793f9bafa..582e7a175 100644 --- a/src/Protocol/Generation/GenerateContainerAttribute.cs +++ b/src/Protocol/Generation/GenerateContainerAttribute.cs @@ -1,11 +1,10 @@ using System; using System.Diagnostics; -using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace OmniSharp.Extensions.LanguageServer.Protocol.Generation { /// - /// Allows generating a typed container counterpart to any model that implements + /// Allows generating a typed container counterpart to any model that implements /// /// /// Efforts will be made to make this available for consumers once source generators land diff --git a/src/Protocol/Generation/GenerateTypedDataAttribute.cs b/src/Protocol/Generation/GenerateTypedDataAttribute.cs index c016fe25f..4b7d222f1 100644 --- a/src/Protocol/Generation/GenerateTypedDataAttribute.cs +++ b/src/Protocol/Generation/GenerateTypedDataAttribute.cs @@ -1,11 +1,10 @@ using System; using System.Diagnostics; -using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace OmniSharp.Extensions.LanguageServer.Protocol.Generation { /// - /// Allows generating a typed counterpart to any model that implements + /// Allows generating a typed counterpart to any model that implements /// /// /// Efforts will be made to make this available for consumers once source generators land diff --git a/test/Client.Tests/Client.Tests.csproj b/test/Client.Tests/Client.Tests.csproj index c5d883459..07ae8a6c0 100644 --- a/test/Client.Tests/Client.Tests.csproj +++ b/test/Client.Tests/Client.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1;net5.0;netcoreapp2.1 + netcoreapp3.1;net6.0 OmniSharp.Extensions.LanguageClient.Tests OmniSharp.Extensions.LanguageServer.Client.Tests diff --git a/test/Dap.Tests/Dap.Tests.csproj b/test/Dap.Tests/Dap.Tests.csproj index 91db07c80..e61abe1ff 100644 --- a/test/Dap.Tests/Dap.Tests.csproj +++ b/test/Dap.Tests/Dap.Tests.csproj @@ -1,6 +1,6 @@  - netcoreapp3.1;net5.0;netcoreapp2.1 + netcoreapp3.1;net6.0 true AnyCPU diff --git a/test/Generation.Tests/AutoImplementParamsGeneratorTests.cs b/test/Generation.Tests/AutoImplementParamsGeneratorTests.cs index 67abc23a2..7d5298c70 100644 --- a/test/Generation.Tests/AutoImplementParamsGeneratorTests.cs +++ b/test/Generation.Tests/AutoImplementParamsGeneratorTests.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using OmniSharp.Extensions.JsonRpc.Generators; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; -using TestingUtils; using Xunit; namespace Generation.Tests @@ -39,22 +37,13 @@ namespace Test public partial class DeclarationParams { [Optional] - public ProgressToken? WorkDoneToken - { - get; - init; - } + public ProgressToken? WorkDoneToken { get; init; } [Optional] - public ProgressToken? PartialResultToken - { - get; - init; - } + public ProgressToken? PartialResultToken { get; init; } } } #nullable restore"; - CacheKeyHasher.Cache = true; await GenerationHelpers.AssertGeneratedAsExpected(source, expected); await GenerationHelpers.AssertGeneratedAsExpected(source, expected); } diff --git a/test/Generation.Tests/EnumLikeStringGeneratorTests.cs b/test/Generation.Tests/EnumLikeStringGeneratorTests.cs index e151a270b..ea2e0b94a 100644 --- a/test/Generation.Tests/EnumLikeStringGeneratorTests.cs +++ b/test/Generation.Tests/EnumLikeStringGeneratorTests.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; using OmniSharp.Extensions.JsonRpc.Generators; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; -using TestingUtils; using Xunit; namespace Generation.Tests @@ -58,7 +56,6 @@ namespace Test } } #nullable restore"; - CacheKeyHasher.Cache = true; await GenerationHelpers.AssertGeneratedAsExpected(source, expected); } } diff --git a/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs b/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs index 1ff3de714..02ecefce5 100644 --- a/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs +++ b/test/Generation.Tests/GeneratedRegistrationOptionsTests.cs @@ -35,11 +35,7 @@ namespace Test public partial class WorkspaceSymbolRegistrationOptions : OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions, OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions { [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } class WorkspaceSymbolRegistrationOptionsConverter : RegistrationOptionsConverterBase { @@ -57,11 +53,7 @@ public override StaticOptions Convert(WorkspaceSymbolRegistrationOptions source) public partial class StaticOptions : OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions { [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } } } } @@ -99,11 +91,7 @@ namespace Test public partial class WorkspaceSymbolRegistrationOptions : OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions { [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } class WorkspaceSymbolRegistrationOptionsConverter : RegistrationOptionsConverterBase { @@ -121,11 +109,7 @@ public override StaticOptions Convert(WorkspaceSymbolRegistrationOptions source) public partial class StaticOptions : IWorkDoneProgressOptions { [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } } } } @@ -208,18 +192,10 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Test [RegistrationOptionsConverterAttribute(typeof(CodeActionRegistrationOptionsConverter))] public partial class CodeActionRegistrationOptions : OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions, OmniSharp.Extensions.LanguageServer.Protocol.Models.ITextDocumentRegistrationOptions, OmniSharp.Extensions.LanguageServer.Protocol.Models.IWorkDoneProgressOptions { - public DocumentSelector? DocumentSelector - { - get; - set; - } + public DocumentSelector? DocumentSelector { get; set; } [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } class CodeActionRegistrationOptionsConverter : RegistrationOptionsConverterBase { @@ -243,13 +219,7 @@ public partial class StaticOptions : OmniSharp.Extensions.LanguageServer.Protoco /// may list out every specific kind they provide. /// [Optional] - public Container? CodeActionKinds - { - get; - set; - } - - = new Container(); + public Container? CodeActionKinds { get; set; } = new Container(); /// /// The server provides support to resolve additional /// information for a code action. @@ -257,18 +227,10 @@ public Container? CodeActionKinds /// @since 3.16.0 /// [Optional] - public bool ResolveProvider - { - get; - set; - } + public bool ResolveProvider { get; set; } [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } } } } @@ -369,18 +331,10 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Test [RegistrationOptionsKey(nameof(ServerCapabilities.CodeActionProvider))] public partial class CodeActionRegistrationOptions : OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions { - public DocumentSelector? DocumentSelector - { - get; - set; - } + public DocumentSelector? DocumentSelector { get; set; } [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } [RegistrationOptionsKey(nameof(ServerCapabilities.CodeActionProvider))] public partial class StaticOptions : IWorkDoneProgressOptions @@ -392,13 +346,7 @@ public partial class StaticOptions : IWorkDoneProgressOptions /// may list out every specific kind they provide. /// [Optional] - public Container? CodeActionKinds - { - get; - set; - } - - = new Container(); + public Container? CodeActionKinds { get; set; } = new Container(); /// /// The server provides support to resolve additional /// information for a code action. @@ -406,18 +354,10 @@ public Container? CodeActionKinds /// @since 3.16.0 /// [Optional] - public bool ResolveProvider - { - get; - set; - } + public bool ResolveProvider { get; set; } [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } } } } diff --git a/test/Generation.Tests/Generation.Tests.csproj b/test/Generation.Tests/Generation.Tests.csproj index 9da152b04..8f8f18ef0 100644 --- a/test/Generation.Tests/Generation.Tests.csproj +++ b/test/Generation.Tests/Generation.Tests.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1;net5.0;netcoreapp2.1 + netcoreapp3.1;net6.0 true AnyCPU @@ -12,6 +12,5 @@ - diff --git a/test/Generation.Tests/GenerationHelpers.cs b/test/Generation.Tests/GenerationHelpers.cs index b1aa84fdc..7f5f38918 100644 --- a/test/Generation.Tests/GenerationHelpers.cs +++ b/test/Generation.Tests/GenerationHelpers.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; @@ -10,9 +11,11 @@ using Microsoft.CodeAnalysis.Text; using Newtonsoft.Json.Linq; using OmniSharp.Extensions.DebugAdapter.Protocol.Client; +//using OmniSharp.Extensions.DebugAdapter.Protocol.Client; using OmniSharp.Extensions.JsonRpc.Generation; using OmniSharp.Extensions.JsonRpc.Generators; using OmniSharp.Extensions.LanguageServer.Protocol.Server; +//using OmniSharp.Extensions.LanguageServer.Protocol.Server; using Xunit; namespace Generation.Tests @@ -23,7 +26,8 @@ static GenerationHelpers() { // this "core assemblies hack" is from https://stackoverflow.com/a/47196516/4418060 var coreAssemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location)!; - var coreAssemblyNames = new[] { + var coreAssemblyNames = new[] + { "mscorlib.dll", "netstandard.dll", "System.dll", @@ -35,9 +39,11 @@ static GenerationHelpers() }; var coreMetaReferences = coreAssemblyNames.Select(x => MetadataReference.CreateFromFile(Path.Combine(coreAssemblyPath, x))); - var otherAssemblies = new[] { + var otherAssemblies = new[] + { typeof(CSharpCompilation).Assembly, typeof(GenerateHandlerMethodsAttribute).Assembly, + typeof(GenerationHelpers).Assembly, typeof(IDebugAdapterClientRegistry).Assembly, typeof(Unit).Assembly, typeof(JToken).Assembly, @@ -54,33 +60,31 @@ static GenerationHelpers() internal const string CSharpDefaultFileExt = "cs"; internal const string TestProjectName = "TestProject"; - internal static readonly string NormalizedPreamble = NormalizeToLf(Preamble.GeneratedByATool + Lf); - internal static readonly ImmutableArray MetadataReferences; - public static async Task AssertGeneratedAsExpected(string source, string expected) where T : ISourceGenerator, new() + public static async Task AssertGeneratedAsExpected(string source, string expected) where T : IIncrementalGenerator, new() { var generatedTree = await GenerateAsync(source); // normalize line endings to just LF - var generatedText = NormalizeToLf(generatedTree.GetText().ToString()).Trim(); + var generatedText = NormalizeToLf(generatedTree.Last().GetText().ToString()).Trim(); // and append preamble to the expected - var expectedText = NormalizedPreamble + NormalizeToLf(expected).Trim(); + var expectedText = NormalizeToLf(expected).Trim(); // Assert.Equal(expectedText, generatedText); generatedText.Should().Be(expectedText); } - public static async Task Generate(string source) where T : ISourceGenerator, new() + public static async Task Generate(string source) where T : IIncrementalGenerator, new() { var generatedTree = await GenerateAsync(source); // normalize line endings to just LF - var generatedText = NormalizeToLf(generatedTree.GetText().ToString()); + var generatedText = NormalizeToLf(generatedTree.Last().GetText().ToString()); // and append preamble to the expected return generatedText; } public static string NormalizeToLf(string input) => input.Replace(CrLf, Lf); - public static async Task GenerateAsync(string source) where T : ISourceGenerator, new() + public static async Task> GenerateAsync(string source) where T : IIncrementalGenerator, new() { var document = CreateProject(source).Documents.Single(); var tree = await document.GetSyntaxTreeAsync(); @@ -89,7 +93,7 @@ static GenerationHelpers() throw new InvalidOperationException("Could not get the syntax tree of the sources"); } - var compilation = (CSharpCompilation) (await document.Project.GetCompilationAsync())!; + var compilation = (CSharpCompilation)( await document.Project.GetCompilationAsync() )!; if (compilation is null) { throw new InvalidOperationException("Could not compile the sources"); @@ -98,10 +102,10 @@ static GenerationHelpers() var diagnostics = compilation.GetDiagnostics(); // Assert.Empty(diagnostics.Where(x => x.Severity >= DiagnosticSeverity.Warning)); - ISourceGenerator generator = new T(); + IIncrementalGenerator generator = new T(); var driver = CSharpGeneratorDriver.Create( - ImmutableArray.Create(generator), + ImmutableArray.Create(generator.AsSourceGenerator()), ImmutableArray.Empty, compilation.SyntaxTrees[0].Options as CSharpParseOptions ); @@ -110,7 +114,9 @@ compilation.SyntaxTrees[0].Options as CSharpParseOptions Assert.Empty(diagnostics.Where(x => x.Severity >= DiagnosticSeverity.Warning)); // the syntax tree added by the generator will be the last one in the compilation - return outputCompilation.SyntaxTrees.Last(z => !z.FilePath.Contains("AssemblyRegistrationOptions") && !z.FilePath.Contains("GeneratedAssemblyJsonRpcHandlers")); + return outputCompilation.SyntaxTrees.Where( + z => !z.FilePath.Contains("AssemblyRegistrationOptions") && !z.FilePath.Contains("GeneratedAssemblyJsonRpcHandlers") + ); } public static Project CreateProject(params string[] sources) diff --git a/test/Generation.Tests/JsonRpcGenerationTests.cs b/test/Generation.Tests/JsonRpcGenerationTests.cs index 87b7e43de..e105db5ad 100644 --- a/test/Generation.Tests/JsonRpcGenerationTests.cs +++ b/test/Generation.Tests/JsonRpcGenerationTests.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using FluentAssertions; using OmniSharp.Extensions.JsonRpc.Generators; -using OmniSharp.Extensions.JsonRpc.Generators.Cache; using TestingUtils; using Xunit; using Xunit.Sdk; @@ -206,7 +205,6 @@ public interface IExitHandler : IJsonRpcNotificationHandler } }"; - CacheKeyHasher.Cache = true; Func a = () => AssertGeneratedAsExpected(source, ""); a.Should().Throw().WithMessage("*Could not infer the request router(s)*"); a.Should().Throw("cache").WithMessage("*Could not infer the request router(s)*"); diff --git a/test/Generation.Tests/LspFeatureTests.cs b/test/Generation.Tests/LspFeatureTests.cs index ed42f75f3..04b2377ef 100644 --- a/test/Generation.Tests/LspFeatureTests.cs +++ b/test/Generation.Tests/LspFeatureTests.cs @@ -54,7 +54,7 @@ abstract public partial class WorkspaceSymbolsHandlerBase : AbstractHandlers.Req [System.Runtime.CompilerServices.CompilerGeneratedAttribute, System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] abstract public partial class WorkspaceSymbolsPartialHandlerBase : AbstractHandlers.PartialResults?, SymbolInformation, WorkspaceSymbolRegistrationOptions, WorkspaceSymbolCapability>, IWorkspaceSymbolsHandler { - protected WorkspaceSymbolsPartialHandlerBase(System.Guid id, IProgressManager progressManager): base(progressManager, Container.From) + protected WorkspaceSymbolsPartialHandlerBase(System.Guid id, IProgressManager progressManager) : base(progressManager, Container.From) { } } @@ -109,12 +109,6 @@ public static ILanguageServerRegistry ObserveWorkspaceSymbols(this ILanguageServ public async Task Supports_Generating_Custom_Language_Extensions() { var source = @" -// ------------------------------------------------------------------------------ -// -// This code was generated a code generator. -// -// ------------------------------------------------------------------------------ - using MediatR; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Generation; @@ -189,11 +183,7 @@ namespace Lsp.Tests.Integration.Fixtures public partial class UnitTestRegistrationOptions : OmniSharp.Extensions.LanguageServer.Protocol.IRegistrationOptions { [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } class UnitTestRegistrationOptionsConverter : RegistrationOptionsConverterBase { @@ -211,18 +201,10 @@ public override StaticOptions Convert(UnitTestRegistrationOptions source) public partial class StaticOptions : IWorkDoneProgressOptions { [Optional] - public bool SupportsDebugging - { - get; - set; - } + public bool SupportsDebugging { get; set; } [Optional] - public bool WorkDoneProgress - { - get; - set; - } + public bool WorkDoneProgress { get; set; } } } } @@ -321,7 +303,7 @@ abstract public partial class DiscoverUnitTestsHandlerBase : AbstractHandlers.Re [System.Runtime.CompilerServices.CompilerGeneratedAttribute, System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] abstract public partial class DiscoverUnitTestsPartialHandlerBase : AbstractHandlers.PartialResults, UnitTest, UnitTestRegistrationOptions, UnitTestCapability>, IDiscoverUnitTestsHandler { - protected DiscoverUnitTestsPartialHandlerBase(System.Guid id, IProgressManager progressManager): base(progressManager, Container.From) + protected DiscoverUnitTestsPartialHandlerBase(System.Guid id, IProgressManager progressManager) : base(progressManager, Container.From) { } } diff --git a/test/Generation.Tests/TypedCanBeResolvedTests.cs b/test/Generation.Tests/TypedCanBeResolvedTests.cs index 2d7b0b28e..e34a0b47c 100644 --- a/test/Generation.Tests/TypedCanBeResolvedTests.cs +++ b/test/Generation.Tests/TypedCanBeResolvedTests.cs @@ -98,10 +98,9 @@ public CodeLens WithData(TData data) public static CodeLens? From(CodeLens? item) where T : class?, IHandlerIdentity? => item switch { - not null => item, _ => null - } - - ; + not null => item, + _ => null + }; } /// @@ -118,29 +117,17 @@ public partial record CodeLens : ICanBeResolved where T : class?, IHandlerIde /// /// The range in which this code lens is valid. Should only span a single line. /// - public Range Range - { - get; - init; - } + public Range Range { get; init; } [Optional] - public Command? Command - { - get; - init; - } + public Command? Command { get; init; } /// /// A data entry field that is preserved on a code lens item between /// a code lens and a code lens resolve request. /// [Optional] - public T Data - { - get => this.GetRawData()!; - init => this.SetRawData(value); - } + public T Data { get => this.GetRawData()!; init => this.SetRawData(value); } private string DebuggerDisplay => $""{Range}{(Command != null ? $"" {Command}"" : """")}""; public override string ToString() => DebuggerDisplay; @@ -150,133 +137,111 @@ public CodeLens WithData(TData data) return new CodeLens{Range = Range, Command = Command, Data = data}; } - JToken? ICanBeResolved.Data - { - get; - init; - } + JToken? ICanBeResolved.Data { get; init; } - private JToken? JData - { - get => this.GetRawData(); - init => this.SetRawData(value); - } + private JToken? JData { get => this.GetRawData(); init => this.SetRawData(value); } public static implicit operator CodeLens(CodeLens value) => new CodeLens{Range = value.Range, Command = value.Command, JData = value.Data}; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""value"")] public static implicit operator CodeLens? (CodeLens? value) => value switch { - not null => new CodeLens{Range = value.Range, Command = value.Command, Data = value.JData}, _ => null - } - - ; + not null => new CodeLens{Range = value.Range, Command = value.Command, Data = value.JData}, + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""item"")] public static CodeLens? From(CodeLens? item) => item switch { - not null => item, _ => null - } - - ; + not null => item, + _ => null + }; } public partial class CodeLensContainer : ContainerBase> where T : class?, IHandlerIdentity? { - public CodeLensContainer(): this(Enumerable.Empty>()) + public CodeLensContainer() : this(Enumerable.Empty>()) { } - public CodeLensContainer(IEnumerable> items): base(items) + public CodeLensContainer(IEnumerable> items) : base(items) { } - public CodeLensContainer(params CodeLens[] items): base(items) + public CodeLensContainer(params CodeLens[] items) : base(items) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(IEnumerable>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (CodeLens[] items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(params CodeLens[] items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (Collection>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(Collection>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (List>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(List>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (in ImmutableArray>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(in ImmutableArray>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (ImmutableList>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(ImmutableList>? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""container"")] public static implicit operator CodeLensContainer? (CodeLensContainer? container) => container switch { - not null => new CodeLensContainer(container.Select(value => (CodeLens)value)), _ => null - } - - ; + not null => new CodeLensContainer(container.Select(value => (CodeLens)value)), + _ => null + }; } } #nullable restore"; @@ -364,95 +329,84 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol.Test [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute, System.Runtime.CompilerServices.CompilerGeneratedAttribute] public partial class CodeLensContainer : ContainerBase { - public CodeLensContainer(): this(Enumerable.Empty()) + public CodeLensContainer() : this(Enumerable.Empty()) { } - public CodeLensContainer(IEnumerable items): base(items) + public CodeLensContainer(IEnumerable items) : base(items) { } - public CodeLensContainer(params CodeLens[] items): base(items) + public CodeLensContainer(params CodeLens[] items) : base(items) { } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(IEnumerable? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (CodeLens[] items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(params CodeLens[] items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (Collection? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(Collection? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (List? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(List? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (in ImmutableArray? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(in ImmutableArray? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static implicit operator CodeLensContainer? (ImmutableList? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""items"")] public static CodeLensContainer? From(ImmutableList? items) => items switch { - not null => new CodeLensContainer(items), _ => null - } - - ; + not null => new CodeLensContainer(items), + _ => null + }; } } #nullable restore"; diff --git a/test/JsonRpc.Tests/JsonRpc.Tests.csproj b/test/JsonRpc.Tests/JsonRpc.Tests.csproj index 2c42ce7ea..163f47307 100644 --- a/test/JsonRpc.Tests/JsonRpc.Tests.csproj +++ b/test/JsonRpc.Tests/JsonRpc.Tests.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1;net5.0;netcoreapp2.1 + netcoreapp3.1;net6.0 true AnyCPU diff --git a/test/Lsp.Integration.Tests/Lsp.Integration.Tests.csproj b/test/Lsp.Integration.Tests/Lsp.Integration.Tests.csproj index 46970d637..4962ff8ef 100644 --- a/test/Lsp.Integration.Tests/Lsp.Integration.Tests.csproj +++ b/test/Lsp.Integration.Tests/Lsp.Integration.Tests.csproj @@ -1,6 +1,6 @@  - net5.0;netcoreapp3.1;netcoreapp2.1 + net6.0;netcoreapp3.1 true AnyCPU diff --git a/test/Lsp.Tests/Lsp.Tests.csproj b/test/Lsp.Tests/Lsp.Tests.csproj index 46970d637..4962ff8ef 100644 --- a/test/Lsp.Tests/Lsp.Tests.csproj +++ b/test/Lsp.Tests/Lsp.Tests.csproj @@ -1,6 +1,6 @@  - net5.0;netcoreapp3.1;netcoreapp2.1 + net6.0;netcoreapp3.1 true AnyCPU