Fork changes

This commit is contained in:
Adam Hathcock
2024-05-21 16:30:10 +01:00
parent 95b5b15cb5
commit 5f92c81965
56 changed files with 2220 additions and 1614 deletions
+564 -2
View File
@@ -1,6 +1,568 @@
# Version: 2.0.1 (Using https://semver.org/)
# Updated: 2020-12-11
# See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
# See https://github.com/RehanSaeed/EditorConfig for updates to this file.
# See http://EditorConfig.org for more information about .editorconfig files.
##########################################
# Common Settings
##########################################
# This file is the top-most EditorConfig file
root = true
# All Files
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
##########################################
# File Extension Settings
##########################################
# Visual Studio Solution Files
[*.sln]
indent_style = tab
# Visual Studio XML Project Files
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML Configuration Files
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
indent_size = 2
# JSON Files
[*.{json,json5,webmanifest}]
indent_size = 2
# YAML Files
[*.{yml,yaml}]
indent_size = 2
# Markdown Files
[*.md]
trim_trailing_whitespace = false
# Web Files
[*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}]
indent_size = 2
# Batch Files
[*.{cmd,bat}]
end_of_line = crlf
charset = utf-8
trim_trailing_whitespace = true
# Bash Files
[*.sh]
end_of_line = lf
# Makefiles
[Makefile]
indent_style = tab
##########################################
# Default .NET Code Style Severities
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope
##########################################
[*.{cs,csx,cake,vb,vbx}]
# Default Severity for all .NET Code Style rules below
dotnet_analyzer_diagnostic.severity = silent
##########################################
# File Header (Uncomment to support file headers)
# https://docs.microsoft.com/visualstudio/ide/reference/add-file-header
##########################################
# [*.{cs,csx,cake,vb,vbx}]
# file_header_template = <copyright file="{fileName}" company="PROJECT-AUTHOR">\n© PROJECT-AUTHOR\n</copyright>
# SA1636: File header copyright text should match
# Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project.
# dotnet_diagnostic.SA1636.severity = none
##########################################
# .NET Language Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions
##########################################
# .NET Code Style Settings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings
[*.{cs,csx,cake,vb,vbx}]
# "this." and "Me." qualifiers
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me
#dotnet_style_qualification_for_field = true:warning
#dotnet_style_qualification_for_property = true:warning
#dotnet_style_qualification_for_method = true:warning
#dotnet_style_qualification_for_event = true:warning
# Language keywords instead of framework type names for type references
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Modifier preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers
dotnet_style_require_accessibility_modifiers = always:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
dotnet_style_readonly_field = true:warning
# Parentheses preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion
# Expression-level preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_prefer_inferred_tuple_names = true:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion
dotnet_diagnostic.IDE0045.severity = suggestion
dotnet_style_prefer_conditional_expression_over_return = false:suggestion
dotnet_diagnostic.IDE0046.severity = suggestion
dotnet_style_prefer_compound_assignment = true:warning
# Null-checking preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
# Parameter preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences
dotnet_code_quality_unused_parameters = all:warning
# More style options (Undocumented)
# https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641
dotnet_style_operator_placement_when_wrapping = end_of_line
# https://github.com/dotnet/roslyn/pull/40070
dotnet_style_prefer_simplified_interpolation = true:warning
# C# Code Style Settings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings
[*.{cs,csx,cake}]
# Implicit and explicit types
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = true:warning
# Expression-bodied members
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members
csharp_style_expression_bodied_methods = true:warning
csharp_style_expression_bodied_constructors = true:warning
csharp_style_expression_bodied_operators = true:warning
csharp_style_expression_bodied_properties = true:warning
csharp_style_expression_bodied_indexers = true:warning
csharp_style_expression_bodied_accessors = true:warning
csharp_style_expression_bodied_lambdas = true:warning
csharp_style_expression_bodied_local_functions = true:warning
# Pattern matching
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
# Inlined variable declarations
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations
csharp_style_inlined_variable_declaration = true:warning
# Expression-level preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
csharp_prefer_simple_default_expression = true:warning
# "Null" checking preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning
# Code block preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences
csharp_prefer_braces = true:warning
# Unused value preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences
csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
dotnet_diagnostic.IDE0058.severity = suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
dotnet_diagnostic.IDE0059.severity = suggestion
# Index and range preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences
csharp_style_prefer_index_operator = true:warning
csharp_style_prefer_range_operator = true:warning
# Miscellaneous preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences
csharp_style_deconstructed_variable_declaration = true:warning
csharp_style_pattern_local_over_anonymous_function = true:warning
csharp_using_directive_placement = outside_namespace:warning
csharp_prefer_static_local_function = true:warning
csharp_prefer_simple_using_statement = true:suggestion
dotnet_diagnostic.IDE0063.severity = suggestion
##########################################
# .NET Formatting Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions
##########################################
# Organize usings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives
dotnet_sort_system_directives_first = true
# Newline options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = no_change
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents_when_block = false
# Spacing options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_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_call_parameter_list_parentheses = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_after_comma = true
csharp_space_before_comma = false
csharp_space_after_dot = false
csharp_space_before_dot = false
csharp_space_after_semicolon_in_for_statement = true
csharp_space_before_semicolon_in_for_statement = false
csharp_space_around_declaration_statements = false
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false
# Wrapping options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
csharp_style_namespace_declarations = file_scoped
##########################################
# .NET Naming Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions
##########################################
[*.{cs,csx,cake,vb,vbx}]
dotnet_diagnostic.CA1000.severity = suggestion
dotnet_diagnostic.CA1001.severity = error
dotnet_diagnostic.CA1018.severity = error
dotnet_diagnostic.CA1036.severity = silent
dotnet_diagnostic.CA1051.severity = suggestion
dotnet_diagnostic.CA1068.severity = error
dotnet_diagnostic.CA1069.severity = error
dotnet_diagnostic.CA1304.severity = error
dotnet_diagnostic.CA1305.severity = suggestion
dotnet_diagnostic.CA1307.severity = suggestion
dotnet_diagnostic.CA1309.severity = suggestion
dotnet_diagnostic.CA1310.severity = error
dotnet_diagnostic.CA1507.severity = suggestion
dotnet_diagnostic.CA1513.severity = suggestion
dotnet_diagnostic.CA1707.severity = suggestion
dotnet_diagnostic.CA1708.severity = suggestion
dotnet_diagnostic.CA1711.severity = suggestion
dotnet_diagnostic.CA1716.severity = suggestion
dotnet_diagnostic.CA1720.severity = suggestion
dotnet_diagnostic.CA1725.severity = suggestion
dotnet_diagnostic.CA1805.severity = suggestion
dotnet_diagnostic.CA1816.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1825.severity = error
dotnet_diagnostic.CA1826.severity = silent
dotnet_diagnostic.CA1827.severity = error
dotnet_diagnostic.CA1829.severity = suggestion
dotnet_diagnostic.CA1834.severity = error
dotnet_diagnostic.CA1845.severity = suggestion
dotnet_diagnostic.CA1848.severity = suggestion
dotnet_diagnostic.CA1852.severity = suggestion
dotnet_diagnostic.CA1860.severity = silent
dotnet_diagnostic.CA2016.severity = suggestion
dotnet_diagnostic.CA2201.severity = error
dotnet_diagnostic.CA2206.severity = error
dotnet_diagnostic.CA2208.severity = error
dotnet_diagnostic.CA2211.severity = error
dotnet_diagnostic.CA2249.severity = error
dotnet_diagnostic.CA2251.severity = error
dotnet_diagnostic.CA2252.severity = none
dotnet_diagnostic.CA2254.severity = suggestion
dotnet_diagnostic.CS0169.severity = error
dotnet_diagnostic.CS0219.severity = error
dotnet_diagnostic.CS0649.severity = suggestion
dotnet_diagnostic.CS1998.severity = error
dotnet_diagnostic.CS8602.severity = error
dotnet_diagnostic.CS8604.severity = error
dotnet_diagnostic.CS8618.severity = error
dotnet_diagnostic.CS0618.severity = suggestion
dotnet_diagnostic.CS1998.severity = error
dotnet_diagnostic.CS4014.severity = error
dotnet_diagnostic.CS8600.severity = error
dotnet_diagnostic.CS8603.severity = error
dotnet_diagnostic.CS8625.severity = error
dotnet_diagnostic.BL0005.severity = suggestion
dotnet_diagnostic.MVC1000.severity = suggestion
dotnet_diagnostic.RZ10012.severity = error
dotnet_diagnostic.IDE0004.severity = error # redundant cast
dotnet_diagnostic.IDE0005.severity = error
dotnet_diagnostic.IDE0007.severity = error # Use var
dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements
dotnet_diagnostic.IDE0010.severity = silent # populate switch
dotnet_diagnostic.IDE0017.severity = suggestion # initialization can be simplified
dotnet_diagnostic.IDE0021.severity = silent # expression body for constructors
dotnet_diagnostic.IDE0022.severity = silent # expression body for methods
dotnet_diagnostic.IDE0023.severity = suggestion # use expression body for operators
dotnet_diagnostic.IDE0024.severity = silent # expression body for operators
dotnet_diagnostic.IDE0025.severity = suggestion # use expression body for properties
dotnet_diagnostic.IDE0027.severity = suggestion # Use expression body for accessors
dotnet_diagnostic.IDE0028.severity = silent # expression body for accessors
dotnet_diagnostic.IDE0032.severity = suggestion # Use auto property
dotnet_diagnostic.IDE0033.severity = error # prefer tuple name
dotnet_diagnostic.IDE0037.severity = suggestion # simplify anonymous type
dotnet_diagnostic.IDE0040.severity = error # modifiers required
dotnet_diagnostic.IDE0041.severity = error # simplify null
dotnet_diagnostic.IDE0042.severity = error # deconstruct variable
dotnet_diagnostic.IDE0044.severity = suggestion # make field only when possible
dotnet_diagnostic.IDE0047.severity = suggestion # parameter name
dotnet_diagnostic.IDE0051.severity = error # unused field
dotnet_diagnostic.IDE0052.severity = error # unused member
dotnet_diagnostic.IDE0053.severity = suggestion # lambda not needed
dotnet_diagnostic.IDE0055.severity = suggestion # Fix formatting
dotnet_diagnostic.IDE0057.severity = suggestion # substring can be simplified
dotnet_diagnostic.IDE0060.severity = suggestion # unused parameters
dotnet_diagnostic.IDE0061.severity = suggestion # local expression body
dotnet_diagnostic.IDE0062.severity = suggestion # local to static
dotnet_diagnostic.IDE0063.severity = error # simplify using
dotnet_diagnostic.IDE0066.severity = suggestion # switch expression
dotnet_diagnostic.IDE0072.severity = suggestion # Populate switch - forces population of all cases even when default specified
dotnet_diagnostic.IDE0078.severity = suggestion # use pattern matching
dotnet_diagnostic.IDE0090.severity = suggestion # new can be simplified
dotnet_diagnostic.IDE0130.severity = suggestion # namespace folder structure
dotnet_diagnostic.IDE0160.severity = silent # Use block namespaces ARE NOT required
dotnet_diagnostic.IDE0161.severity = error # Please use file namespaces
dotnet_diagnostic.IDE0200.severity = suggestion # lambda not needed
dotnet_diagnostic.IDE1006.severity = suggestion # Naming rule violation: These words cannot contain lower case characters
dotnet_diagnostic.IDE0260.severity = suggestion # Use pattern matching
dotnet_diagnostic.IDE0270.severity = suggestion # Null check simplifcation
dotnet_diagnostic.IDE0290.severity = error # Primary Constructor
dotnet_diagnostic.IDE0300.severity = suggestion # Collection
dotnet_diagnostic.IDE0305.severity = suggestion # Collection ToList
dotnet_diagnostic.NX0001.severity = error
dotnet_diagnostic.NX0002.severity = silent
dotnet_diagnostic.NX0003.severity = silent
##########################################
# Styles
##########################################
# camel_case_style - Define the camelCase style
dotnet_naming_style.camel_case_style.capitalization = camel_case
# pascal_case_style - Define the PascalCase style
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# constant_case - Define the CONSTANT_CASE style
dotnet_naming_style.constant_case.capitalization = all_upper
dotnet_naming_style.constant_case.word_separator = _
# first_upper_style - The first character must start with an upper-case character
dotnet_naming_style.first_upper_style.capitalization = first_word_upper
# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
# prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T'
dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
# disallowed_style - Anything that has this style applied is marked as disallowed
dotnet_naming_style.disallowed_style.capitalization = pascal_case
dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file
dotnet_naming_style.internal_error_style.capitalization = pascal_case
dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____
# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case
dotnet_naming_style.underscore_camel_case_style.required_prefix = _
##########################################
# .NET Design Guideline Field Naming Rules
# Naming rules for fields follow the .NET Framework design guidelines
# https://docs.microsoft.com/dotnet/standard/design-guidelines/index
##########################################
# All public/protected/protected_internal constant fields must be constant_case
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning
# All public/protected/protected_internal static readonly fields must be constant_case
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning
# No other public/protected/protected_internal fields are allowed
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error
##########################################
# StyleCop Field Naming Rules
# Naming rules for fields follow the StyleCop analyzers
# This does not override any rules using disallowed_style above
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers
##########################################
# All constant fields must be constant_case
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning
# All static readonly fields must be constant_case
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning
# No non-private instance fields are allowed
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error
# Private fields must be camelCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md
dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private
dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = underscore_camel_case_style
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning
# Local variables must be camelCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md
dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local
dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = warning
# This rule should never fire. However, it's included for at least two purposes:
# First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers.
# Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#).
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = *
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error
##########################################
# Other Naming Rules
##########################################
# All of the following must be PascalCase:
# - Namespaces
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Classes and Enumerations
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Delegates
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types
# - Constructors, Properties, Events, Methods
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members
dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property
dotnet_naming_rule.element_rule.symbols = element_group
dotnet_naming_rule.element_rule.style = pascal_case_style
dotnet_naming_rule.element_rule.severity = warning
# Interfaces use PascalCase and are prefixed with uppercase 'I'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_symbols.interface_group.applicable_kinds = interface
dotnet_naming_rule.interface_rule.symbols = interface_group
dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
dotnet_naming_rule.interface_rule.severity = warning
# Generics Type Parameters use PascalCase and are prefixed with uppercase 'T'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter
dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group
dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style
dotnet_naming_rule.type_parameter_rule.severity = warning
# Function parameters use camelCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters
dotnet_naming_symbols.parameters_group.applicable_kinds = parameter
dotnet_naming_rule.parameters_rule.symbols = parameters_group
dotnet_naming_rule.parameters_rule.style = camel_case_style
dotnet_naming_rule.parameters_rule.severity = warning
##########################################
# License
##########################################
# The following applies as to the .editorconfig file ONLY, and is
# included below for reference, per the requirements of the license
# corresponding to this .editorconfig file.
# See: https://github.com/RehanSaeed/EditorConfig
#
# MIT License
#
# Copyright (c) 2017-2019 Muhammad Rehan Saeed
# Copyright (c) 2019 Henry Gabryjelski
#
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject
# to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
##########################################
-12
View File
@@ -1,12 +0,0 @@
# These are supported funding model platforms
github: [StefH]
patreon: # Replace with a single Patreon username
open_collective: # wiremocknet
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://www.paypal.me/stefheyenrath
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions" # search for actions - there are other options available
directory: "/" # search in .github/workflows under root `/`
schedule:
interval: "weekly" # check for action update every week
-15
View File
@@ -1,15 +0,0 @@
name: CreateRelease
on:
push:
tags:
- "*.*.*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Release
uses: softprops/action-gh-release@v1
+34
View File
@@ -0,0 +1,34 @@
name: "Deploy to Nuget.org"
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
steps:
- name: Checkout Project
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --no-build --configuration Release --verbosity normal
- name: Pack
run: dotnet pack --no-build --configuration Release Speckle.InterfaceGenerator/Speckle.InterfaceGenerator.csproj --output .
- name: Push to nuget.org
run: dotnet nuget push *.nupkg --source "https://api.nuget.org/v3/index.json" --api-key ${{secrets.CONNECTORS_NUGET_TOKEN }} --skip-duplicate
+3 -1
View File
@@ -350,4 +350,6 @@ MigrationBackup/
.ionide/
/tests/ProxyInterfaceSourceGeneratorTests/Destination/Disposable/*.g.cs
.idea/.idea.ProxyInterfaceSourceGenerator Solution/.idea/
.idea/
Speckle.ProxyGenerator.sln.DotSettings
@@ -1,3 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mapster/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Usings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
@@ -1,93 +1,93 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31521.260
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2CE637DC-E8F5-4603-8B57-E51A32F631F1}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Generate-ReleaseNotes.bat = Generate-ReleaseNotes.bat
PackageReadme.md = PackageReadme.md
PackageReleaseNotes.template = PackageReleaseNotes.template
PackageReleaseNotes.txt = PackageReleaseNotes.txt
README.md = README.md
ReleaseNotes.md = ReleaseNotes.md
ToDo.md = ToDo.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{19009F5B-3267-45E2-A8B6-89F2AB47D72C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src-examples", "src-examples", "{38BA087F-EDA1-4F8A-A140-85B84791B815}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceSourceGenerator", "src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj", "{12344228-91F4-4502-9595-39584E5ABB34}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumer", "src-examples\ProxyInterfaceConsumer\ProxyInterfaceConsumer.csproj", "{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceSourceGeneratorTests", "tests\ProxyInterfaceSourceGeneratorTests\ProxyInterfaceSourceGeneratorTests.csproj", "{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerForPnP", "src-examples\ProxyInterfaceConsumerForPnP\ProxyInterfaceConsumerForPnP.csproj", "{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerForAkka", "src-examples\ProxyInterfaceConsumerForAkka\ProxyInterfaceConsumerForAkka.csproj", "{590908DF-A813-467A-94E4-3500020D0D54}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerViaNuGet", "src-examples\ProxyInterfaceConsumerViaNuGet\ProxyInterfaceConsumerViaNuGet.csproj", "{1EA000E4-6103-4577-8D98-BDDA3BE458A2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
DebugAttach|Any CPU = DebugAttach|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.Build.0 = Release|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.Build.0 = Release|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.Build.0 = Release|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.Build.0 = Release|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Release|Any CPU.Build.0 = Release|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{12344228-91F4-4502-9595-39584E5ABB34} = {ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A} = {19009F5B-3267-45E2-A8B6-89F2AB47D72C}
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
{590908DF-A813-467A-94E4-3500020D0D54} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
{1EA000E4-6103-4577-8D98-BDDA3BE458A2} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {585F071D-051D-441C-9C6B-226D9E15A1F5}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31521.260
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2CE637DC-E8F5-4603-8B57-E51A32F631F1}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Generate-ReleaseNotes.bat = Generate-ReleaseNotes.bat
PackageReadme.md = PackageReadme.md
PackageReleaseNotes.template = PackageReleaseNotes.template
PackageReleaseNotes.txt = PackageReleaseNotes.txt
README.md = README.md
ReleaseNotes.md = ReleaseNotes.md
ToDo.md = ToDo.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{19009F5B-3267-45E2-A8B6-89F2AB47D72C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src-examples", "src-examples", "{38BA087F-EDA1-4F8A-A140-85B84791B815}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.ProxyGenerator", "src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj", "{12344228-91F4-4502-9595-39584E5ABB34}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumer", "src-examples\ProxyInterfaceConsumer\ProxyInterfaceConsumer.csproj", "{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceSourceGeneratorTests", "tests\ProxyInterfaceSourceGeneratorTests\ProxyInterfaceSourceGeneratorTests.csproj", "{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerForPnP", "src-examples\ProxyInterfaceConsumerForPnP\ProxyInterfaceConsumerForPnP.csproj", "{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerForAkka", "src-examples\ProxyInterfaceConsumerForAkka\ProxyInterfaceConsumerForAkka.csproj", "{590908DF-A813-467A-94E4-3500020D0D54}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerViaNuGet", "src-examples\ProxyInterfaceConsumerViaNuGet\ProxyInterfaceConsumerViaNuGet.csproj", "{1EA000E4-6103-4577-8D98-BDDA3BE458A2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
DebugAttach|Any CPU = DebugAttach|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.Build.0 = Release|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.Build.0 = Release|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.Build.0 = Release|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.Build.0 = Release|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{590908DF-A813-467A-94E4-3500020D0D54}.Release|Any CPU.Build.0 = Release|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{12344228-91F4-4502-9595-39584E5ABB34} = {ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A} = {19009F5B-3267-45E2-A8B6-89F2AB47D72C}
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
{590908DF-A813-467A-94E4-3500020D0D54} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
{1EA000E4-6103-4577-8D98-BDDA3BE458A2} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {585F071D-051D-441C-9C6B-226D9E15A1F5}
EndGlobalSection
EndGlobal
+7
View File
@@ -0,0 +1,7 @@
{
"sdk": {
"version": "8.0.0",
"rollForward": "latestMinor",
"allowPrerelease": false
}
}
-5
View File
@@ -1,5 +0,0 @@
{
"RoslynExtensionsOptions": {
"enableAnalyzersSupport": true
}
}
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace ProxyInterfaceConsumer
{
@@ -6,11 +7,12 @@ namespace ProxyInterfaceConsumer
{
public int HouseNumber { get; set; }
public event EventHandler<EventArgs> MyEvent;
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public event EventHandler<EventArgs> MyEvent = null!;
public int Weird { get; set; }
public int Weird2()
{
return 0;
}
}
}
}
+12 -6
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace ProxyInterfaceConsumer
@@ -8,24 +9,29 @@ namespace ProxyInterfaceConsumer
private int PrivateId { get; }
public int Id { get; }
public object @object { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public object @object { get; set; }= null!;
public long? NullableLong { get; }
public string Name { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public string Name { get; set; }= null!;
public string? StringNullable { get; set; }
public Address Address { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public Address Address { get; set; }= null!;
public List<Address> AddressesList { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public List<Address> AddressesList { get; set; }= null!;
public Dictionary<string, Address> AddressesDict { get; set; } = new Dictionary<string, Address>();
public Dictionary<Address, Address> AddressesDict2 { get; set; } = new Dictionary<Address, Address>();
public E E { get; set; }
public IMyInterface MyInterface { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public IMyInterface MyInterface { get; set; }= null!;
public bool TMethod<T1, T2>(int x, T1 t1, T2 t2)
where T1 : struct
@@ -102,4 +108,4 @@ namespace ProxyInterfaceConsumer
V1,
V2
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
@@ -65,9 +66,10 @@ public class Test
{
public int Id { get; set; }
public Clazz C { get; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public Clazz C { get; } = null!;
public IList<Clazz> Cs { get; set; }
public IList<Clazz> Cs { get; set; } = new List<Clazz>();
public int AddString(string s)
{
@@ -87,7 +89,7 @@ public class Test
public sealed class Clazz
{
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
}
[ProxyInterfaceGenerator.Proxy(typeof(Test))]
@@ -98,4 +100,4 @@ public partial interface ITest
[ProxyInterfaceGenerator.Proxy(typeof(Clazz))]
public partial interface IClazz
{
}
}
@@ -24,7 +24,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Akka.Actor;
using ProxyInterfaceConsumerForAkka.Interfaces;
@@ -5,12 +6,13 @@ namespace ProxyInterfaceConsumerForAkka;
public class Program
{
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public static void Main()
{
Akka.Remote.AddressUid auid = null;
Akka.Remote.AddressUid auid = null!;
IAddressUid addressUidProxy = new AddressUidProxy(auid);
LocalActorRefProvider p = null;
LocalActorRefProvider p = null!;
ILocalActorRefProvider proxy = new LocalActorRefProviderProxy(p);
}
}
}
@@ -24,7 +24,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>-->
<ProjectReference Include="..\..\src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
@@ -20,7 +20,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace ProxyInterfaceConsumer
@@ -8,24 +9,29 @@ namespace ProxyInterfaceConsumer
private int PrivateId { get; }
public int Id { get; }
public object @object { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public object @object { get; set; }= null!;
public long? NullableLong { get; }
public string Name { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public string Name { get; set; }= null!;
public string? StringNullable { get; set; }
public Address Address { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public Address Address { get; set; }= null!;
public List<Address> AddressesLIst { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public List<Address> AddressesLIst { get; set; }= null!;
public Dictionary<string, Address> AddressesDict { get; set; } = new Dictionary<string, Address>();
public Dictionary<Address, Address> AddressesDict2 { get; set; } = new Dictionary<Address, Address>();
public E E { get; set; }
public IMyInterface MyInterface { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public IMyInterface MyInterface { get; set; }= null!;
public string Add(string s, string @string)
{
@@ -83,4 +89,4 @@ namespace ProxyInterfaceConsumer
V1,
V2
}
}
}
@@ -12,10 +12,10 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="Mapster" Version="7.3.0" />
<PackageReference Include="ProxyInterfaceGenerator" Version="0.0.38">
<PackageReference Include="ProxyInterfaceGenerator" Version="0.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
</Project>
@@ -1,12 +1,12 @@
using Microsoft.CodeAnalysis;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class MethodSymbolExtensions
{
public static string GetMethodNameWithOptionalTypeParameters(this IMethodSymbol method) =>
!method.IsGenericMethod ? method.Name : $"{method.Name}<{string.Join(", ", method.TypeParameters.Select(tp => tp.Name))}>";
//public static string GetWhereStatement(this IMethodSymbol method) =>
// !method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereConstraints()));
using Microsoft.CodeAnalysis;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class MethodSymbolExtensions
{
public static string GetMethodNameWithOptionalTypeParameters(this IMethodSymbol method) =>
!method.IsGenericMethod ? method.Name : $"{method.Name}<{string.Join(", ", method.TypeParameters.Select(tp => tp.Name))}>";
//public static string GetWhereStatement(this IMethodSymbol method) =>
// !method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereConstraints()));
}
@@ -1,88 +1,88 @@
using Microsoft.CodeAnalysis;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class NamedTypeSymbolExtensions
{
public static List<INamedTypeSymbol> GetBaseTypes(this INamedTypeSymbol? type)
{
var types = new List<INamedTypeSymbol>();
bool me = true;
while (type != null && type.SpecialType != SpecialType.System_Object)
{
if (!me)
{
types.Add(type);
}
type = type.BaseType;
me = false;
}
return types;
}
public static string GetFullType(this INamedTypeSymbol namedTypeSymbol)
{
// https://www.codeproject.com/Articles/861548/Roslyn-Code-Analysis-in-Easy-Samples-Part
//var str = new StringBuilder(namedTypeSymbol.Name);
//if (namedTypeSymbol.TypeArguments.Count() > 0)
//{
// str.AppendFormat("<{0}>", string.Join(", ", namedTypeSymbol.TypeArguments.OfType<INamedTypeSymbol>().Select(typeArg => typeArg.GetFullType())));
//}
return namedTypeSymbol.OriginalDefinition.ToString();
}
/// <summary>
/// See https://stackoverflow.com/questions/24157101/roslyns-gettypebymetadataname-and-generic-types
/// </summary>
public static string ResolveProxyClassName(this INamedTypeSymbol namedTypeSymbol)
{
return !namedTypeSymbol.IsGenericType ?
$"{namedTypeSymbol.Name}Proxy" :
$"{namedTypeSymbol.Name}Proxy<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>";
}
public static List<INamedTypeSymbol> ResolveImplementedInterfaces(this INamedTypeSymbol symbol, bool proxyBaseClasses)
{
// Members implemented by us or base classes should go here.
var publicMembers = symbol.GetMembers().Where(m => m.DeclaredAccessibility == Accessibility.Public).ToList();
// Direct interfaces, recursive interfaces or base class interfaces should go here.
var interfaces = new List<INamedTypeSymbol>(symbol.Interfaces);
var baseType = symbol.BaseType;
while (proxyBaseClasses && baseType != null && baseType.SpecialType != SpecialType.System_Object)
{
publicMembers.AddRange(baseType.GetMembers().Where(m => m.DeclaredAccessibility == Accessibility.Public));
interfaces.AddRange(baseType.Interfaces);
baseType = baseType.BaseType;
}
// Filter explicitly implemented interfaces.
var realizedInterfaces = new List<INamedTypeSymbol>();
foreach (var @interface in interfaces)
{
var isRealized = true;
var allMembers = @interface.AllInterfaces.Aggregate(@interface.GetMembers(), (xs, x) => xs.AddRange(x.GetMembers()));
foreach (var member in allMembers)
{
var implementation = symbol.FindImplementationForInterfaceMember(member);
if (!publicMembers.Contains(implementation!))
{
isRealized = false;
break;
}
}
if (isRealized)
{
realizedInterfaces.Add(@interface);
}
}
return realizedInterfaces;
}
using Microsoft.CodeAnalysis;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class NamedTypeSymbolExtensions
{
public static List<INamedTypeSymbol> GetBaseTypes(this INamedTypeSymbol? type)
{
var types = new List<INamedTypeSymbol>();
bool me = true;
while (type != null && type.SpecialType != SpecialType.System_Object)
{
if (!me)
{
types.Add(type);
}
type = type.BaseType;
me = false;
}
return types;
}
public static string GetFullType(this INamedTypeSymbol namedTypeSymbol)
{
// https://www.codeproject.com/Articles/861548/Roslyn-Code-Analysis-in-Easy-Samples-Part
//var str = new StringBuilder(namedTypeSymbol.Name);
//if (namedTypeSymbol.TypeArguments.Count() > 0)
//{
// str.AppendFormat("<{0}>", string.Join(", ", namedTypeSymbol.TypeArguments.OfType<INamedTypeSymbol>().Select(typeArg => typeArg.GetFullType())));
//}
return namedTypeSymbol.OriginalDefinition.ToString();
}
/// <summary>
/// See https://stackoverflow.com/questions/24157101/roslyns-gettypebymetadataname-and-generic-types
/// </summary>
public static string ResolveProxyClassName(this INamedTypeSymbol namedTypeSymbol)
{
return !namedTypeSymbol.IsGenericType ?
$"{namedTypeSymbol.Name}Proxy" :
$"{namedTypeSymbol.Name}Proxy<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>";
}
public static List<INamedTypeSymbol> ResolveImplementedInterfaces(this INamedTypeSymbol symbol, bool proxyBaseClasses)
{
// Members implemented by us or base classes should go here.
var publicMembers = symbol.GetMembers().Where(m => m.DeclaredAccessibility == Accessibility.Public).ToList();
// Direct interfaces, recursive interfaces or base class interfaces should go here.
var interfaces = new List<INamedTypeSymbol>(symbol.Interfaces);
var baseType = symbol.BaseType;
while (proxyBaseClasses && baseType != null && baseType.SpecialType != SpecialType.System_Object)
{
publicMembers.AddRange(baseType.GetMembers().Where(m => m.DeclaredAccessibility == Accessibility.Public));
interfaces.AddRange(baseType.Interfaces);
baseType = baseType.BaseType;
}
// Filter explicitly implemented interfaces.
var realizedInterfaces = new List<INamedTypeSymbol>();
foreach (var @interface in interfaces)
{
var isRealized = true;
var allMembers = @interface.AllInterfaces.Aggregate(@interface.GetMembers(), (xs, x) => xs.AddRange(x.GetMembers()));
foreach (var member in allMembers)
{
var implementation = symbol.FindImplementationForInterfaceMember(member);
if (!publicMembers.Contains(implementation!))
{
isRealized = false;
break;
}
}
if (isRealized)
{
realizedInterfaces.Add(@interface);
}
}
return realizedInterfaces;
}
}
@@ -1,60 +1,60 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using ProxyInterfaceSourceGenerator.Enums;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class ParameterSymbolExtensions
{
private const string ParameterValueNull = "null";
public static bool IsRef(this IParameterSymbol ps)
{
return ps.RefKind is RefKind.Ref or RefKind.RefReadOnly;
}
public static string GetRefKindPrefix(this IParameterSymbol ps)
{
return ps.RefKind switch
{
RefKind.In => "in ",
RefKind.Out => "out ",
RefKind.Ref => "ref ",
_ => string.Empty
};
}
public static string GetParamsPrefix(this IParameterSymbol ps) => ps.IsParams ? "params " : string.Empty;
public static string GetDefaultValue(this IParameterSymbol ps)
{
if (!ps.HasExplicitDefaultValue)
{
return string.Empty;
}
string defaultValue;
if (ps.ExplicitDefaultValue == null)
{
if (ps.NullableAnnotation == NullableAnnotation.Annotated)
{
// The parameter is defined as Nullable, so always use "null".
defaultValue = ParameterValueNull;
}
else
{
defaultValue = ps.Type.IsReferenceType
? ParameterValueNull : // The parameter is a ReferenceType, so use "null".
$"default({ps.Type})"; // The parameter is not a ReferenceType, so use "default(T)".
}
}
else
{
defaultValue = SymbolDisplay.FormatPrimitive(ps.ExplicitDefaultValue, true, false);
}
return $" = {defaultValue}";
}
public static TypeEnum GetTypeEnum(this IParameterSymbol p) => p.Type.GetTypeEnum();
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using ProxyInterfaceSourceGenerator.Enums;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class ParameterSymbolExtensions
{
private const string ParameterValueNull = "null";
public static bool IsRef(this IParameterSymbol ps)
{
return ps.RefKind is RefKind.Ref or RefKind.RefReadOnly;
}
public static string GetRefKindPrefix(this IParameterSymbol ps)
{
return ps.RefKind switch
{
RefKind.In => "in ",
RefKind.Out => "out ",
RefKind.Ref => "ref ",
_ => string.Empty
};
}
public static string GetParamsPrefix(this IParameterSymbol ps) => ps.IsParams ? "params " : string.Empty;
public static string GetDefaultValue(this IParameterSymbol ps)
{
if (!ps.HasExplicitDefaultValue)
{
return string.Empty;
}
string defaultValue;
if (ps.ExplicitDefaultValue == null)
{
if (ps.NullableAnnotation == NullableAnnotation.Annotated)
{
// The parameter is defined as Nullable, so always use "null".
defaultValue = ParameterValueNull;
}
else
{
defaultValue = ps.Type.IsReferenceType
? ParameterValueNull : // The parameter is a ReferenceType, so use "null".
$"default({ps.Type})"; // The parameter is not a ReferenceType, so use "default(T)".
}
}
else
{
defaultValue = SymbolDisplay.FormatPrimitive(ps.ExplicitDefaultValue, true, false);
}
return $" = {defaultValue}";
}
public static TypeEnum GetTypeEnum(this IParameterSymbol p) => p.Type.GetTypeEnum();
}
@@ -1,29 +1,29 @@
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.FileGenerators;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class PropertySymbolExtensions
{
public static TypeEnum GetTypeEnum(this IPropertySymbol p) => p.Type.GetTypeEnum();
public static (string PropertyType, string? PropertyName, string GetSet)? ToPropertyDetails(this IPropertySymbol property, string? overrideType = null)
{
var getIsPublic = property.GetMethod.IsPublic();
var setIsPublic = property.SetMethod.IsPublic();
if (!getIsPublic && !setIsPublic)
{
return null;
}
var get = getIsPublic ? "get; " : string.Empty;
var set = setIsPublic ? "set; " : string.Empty;
var type = !string.IsNullOrEmpty(overrideType) ? overrideType
: BaseGenerator.FixType(property.Type.ToFullyQualifiedDisplayString(), property.NullableAnnotation);
return (type!, property.GetSanitizedName(), $"{{ {get}{set}}}");
}
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.FileGenerators;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class PropertySymbolExtensions
{
public static TypeEnum GetTypeEnum(this IPropertySymbol p) => p.Type.GetTypeEnum();
public static (string PropertyType, string? PropertyName, string GetSet)? ToPropertyDetails(this IPropertySymbol property, string? overrideType = null)
{
var getIsPublic = property.GetMethod.IsPublic();
var setIsPublic = property.SetMethod.IsPublic();
if (!getIsPublic && !setIsPublic)
{
return null;
}
var get = getIsPublic ? "get; " : string.Empty;
var set = setIsPublic ? "set; " : string.Empty;
var type = !string.IsNullOrEmpty(overrideType) ? overrideType
: BaseGenerator.FixType(property.Type.ToFullyQualifiedDisplayString(), property.NullableAnnotation);
return (type!, property.GetSanitizedName(), $"{{ {get}{set}}}");
}
}
@@ -1,74 +1,74 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Text;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class SymbolExtensions
{
private static readonly string[] ExcludedAttributes =
{
"System.Runtime.CompilerServices.NullableAttribute",
"System.Runtime.CompilerServices.NullableContextAttribute",
"System.Runtime.CompilerServices.AsyncStateMachineAttribute"
};
public static IReadOnlyList<string> GetAttributesAsList(this ISymbol symbol)
{
return symbol
.GetAttributes()
.Where(a => a.AttributeClass.IsPublic() && !ExcludedAttributes.Contains(a.AttributeClass?.ToString(), StringComparer.OrdinalIgnoreCase))
.Select(a => $"[{a}]")
.ToArray();
}
public static string GetAttributesPrefix(this ISymbol symbol)
{
var attributes = symbol.GetAttributesAsList();
return attributes.Any() ? $"{string.Join(" ", attributes)} " : string.Empty;
}
//https://stackoverflow.com/questions/27105909/get-fully-qualified-metadata-name-in-roslyn
public static string GetFullMetadataName(this ISymbol? s)
{
if (s == null || IsRootNamespace(s))
{
return string.Empty;
}
var sb = new StringBuilder(s.MetadataName);
var last = s;
s = s.ContainingSymbol;
while (!IsRootNamespace(s))
{
if (s is ITypeSymbol && last is ITypeSymbol)
{
sb.Insert(0, '+');
}
else
{
sb.Insert(0, '.');
}
sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
s = s.ContainingSymbol;
}
return sb.ToString();
}
public static string GetSanitizedName(this ISymbol symbol) =>
symbol.IsKeywordOrReserved() ? $"@{symbol.Name}" : symbol.Name;
public static bool IsKeywordOrReserved(this ISymbol symbol) =>
SyntaxFacts.GetKeywordKind(symbol.Name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(symbol.Name) != SyntaxKind.None;
public static bool IsPublic(this ISymbol? symbol) =>
symbol is { DeclaredAccessibility: Accessibility.Public };
private static bool IsRootNamespace(ISymbol symbol) =>
symbol is INamespaceSymbol { IsGlobalNamespace: true };
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Text;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class SymbolExtensions
{
private static readonly string[] ExcludedAttributes =
{
"System.Runtime.CompilerServices.NullableAttribute",
"System.Runtime.CompilerServices.NullableContextAttribute",
"System.Runtime.CompilerServices.AsyncStateMachineAttribute"
};
public static IReadOnlyList<string> GetAttributesAsList(this ISymbol symbol)
{
return symbol
.GetAttributes()
.Where(a => a.AttributeClass.IsPublic() && !ExcludedAttributes.Contains(a.AttributeClass?.ToString(), StringComparer.OrdinalIgnoreCase))
.Select(a => $"[{a}]")
.ToArray();
}
public static string GetAttributesPrefix(this ISymbol symbol)
{
var attributes = symbol.GetAttributesAsList();
return attributes.Any() ? $"{string.Join(" ", attributes)} " : string.Empty;
}
//https://stackoverflow.com/questions/27105909/get-fully-qualified-metadata-name-in-roslyn
public static string GetFullMetadataName(this ISymbol? s)
{
if (s == null || IsRootNamespace(s))
{
return string.Empty;
}
var sb = new StringBuilder(s.MetadataName);
var last = s;
s = s.ContainingSymbol;
while (!IsRootNamespace(s))
{
if (s is ITypeSymbol && last is ITypeSymbol)
{
sb.Insert(0, '+');
}
else
{
sb.Insert(0, '.');
}
sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
s = s.ContainingSymbol;
}
return sb.ToString();
}
public static string GetSanitizedName(this ISymbol symbol) =>
symbol.IsKeywordOrReserved() ? $"@{symbol.Name}" : symbol.Name;
public static bool IsKeywordOrReserved(this ISymbol symbol) =>
SyntaxFacts.GetKeywordKind(symbol.Name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(symbol.Name) != SyntaxKind.None;
public static bool IsPublic(this ISymbol? symbol) =>
symbol is { DeclaredAccessibility: Accessibility.Public };
private static bool IsRootNamespace(ISymbol symbol) =>
symbol is INamespaceSymbol { IsGlobalNamespace: true };
}
@@ -1,28 +1,28 @@
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Enums;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class TypeSymbolExtensions
{
public static TypeEnum GetTypeEnum(this ITypeSymbol ts)
{
if (ts.IsValueType || ts.IsString())
{
return TypeEnum.ValueTypeOrString;
}
if (ts.TypeKind == TypeKind.Interface)
{
return TypeEnum.Interface;
}
return TypeEnum.Complex;
}
public static bool IsString(this ITypeSymbol ts) =>
ts.ToString().ToLowerInvariant() == "string" || ts.ToString().ToLowerInvariant() == "string?";
public static string ToFullyQualifiedDisplayString(this ITypeSymbol property) =>
property.ToDisplayString(NullableFlowState.None, SymbolDisplayFormat.FullyQualifiedFormat);
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Enums;
namespace ProxyInterfaceSourceGenerator.Extensions;
internal static class TypeSymbolExtensions
{
public static TypeEnum GetTypeEnum(this ITypeSymbol ts)
{
if (ts.IsValueType || ts.IsString())
{
return TypeEnum.ValueTypeOrString;
}
if (ts.TypeKind == TypeKind.Interface)
{
return TypeEnum.Interface;
}
return TypeEnum.Complex;
}
public static bool IsString(this ITypeSymbol ts) =>
ts.ToString().ToLowerInvariant() == "string" || ts.ToString().ToLowerInvariant() == "string?";
public static string ToFullyQualifiedDisplayString(this ITypeSymbol property) =>
property.ToDisplayString(NullableFlowState.None, SymbolDisplayFormat.FullyQualifiedFormat);
}
@@ -1,262 +1,262 @@
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Builders;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal abstract class BaseGenerator
{
protected readonly Context Context;
protected readonly bool SupportsNullable;
protected BaseGenerator(Context context, bool supportsNullable)
{
Context = context;
SupportsNullable = supportsNullable;
}
protected string GetPropertyType(IPropertySymbol property, out bool isReplaced)
{
return GetReplacedTypeAsString(property.Type, out isReplaced);
}
protected string GetParameterType(IParameterSymbol property, out bool isReplaced)
{
return GetReplacedTypeAsString(property.Type, out isReplaced);
}
protected bool TryFindProxyDataByTypeName(string type, [NotNullWhen(true)] out ProxyData? proxyData)
{
proxyData = Context.Candidates.Values.FirstOrDefault(x => x.FullQualifiedTypeName == type);
return proxyData != null;
}
protected string GetWhereStatementFromMethod(IMethodSymbol method)
{
if (!method.IsGenericMethod)
{
return string.Empty;
}
var list = new List<string>();
foreach (var typeParameterSymbol in method.TypeParameters)
{
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
{
list.Add(constraint.ToString());
}
}
return string.Concat(list);
}
protected string ResolveInterfaceNameWithOptionalTypeConstraints(INamedTypeSymbol namedTypeSymbol, string interfaceName)
{
if (!namedTypeSymbol.IsGenericType)
{
return interfaceName;
}
var str = new StringBuilder($"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>");
foreach (var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType<ITypeParameterSymbol>())
{
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
{
str.Append(constraint);
}
}
return str.ToString();
}
/// <summary>
/// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
/// </summary>
public bool TryGetWhereConstraints(ITypeParameterSymbol typeParameterSymbol, bool replaceIt, [NotNullWhen(true)] out ConstraintInfo? constraint)
{
var constraints = new List<string>();
if (typeParameterSymbol.HasReferenceTypeConstraint)
{
constraints.Add("class");
}
if (typeParameterSymbol.HasValueTypeConstraint)
{
constraints.Add("struct");
}
foreach (var namedTypeSymbol in typeParameterSymbol.ConstraintTypes.OfType<INamedTypeSymbol>())
{
if (replaceIt)
{
constraints.Add(GetReplacedTypeAsString(namedTypeSymbol, out _));
}
else
{
constraints.Add(namedTypeSymbol.GetFullType());
}
}
// The new() constraint must be the last constraint specified.
if (typeParameterSymbol.HasConstructorConstraint)
{
constraints.Add("new()");
}
if (constraints.Count > 0)
{
constraint = new(typeParameterSymbol.Name, constraints);
return true;
}
constraint = null;
return false;
}
internal readonly SymbolDisplayFormat NullableDisplayFormat = new SymbolDisplayFormat(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
miscellaneousOptions:
SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
SymbolDisplayMiscellaneousOptions.UseSpecialTypes |
SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier);
protected string GetReplacedTypeAsString(ITypeSymbol typeSymbol, out bool isReplaced)
{
isReplaced = false;
var typeSymbolAsString = typeSymbol.ToFullyQualifiedDisplayString();
var nullableTypeSymbolAsString = typeSymbol.ToDisplayString(NullableFlowState.None, NullableDisplayFormat);
if (TryFindProxyDataByTypeName(typeSymbolAsString, out var existing))
{
if (!Context.ReplacedTypes.ContainsKey(typeSymbolAsString))
{
Context.ReplacedTypes.Add(typeSymbolAsString, existing.FullInterfaceName);
}
isReplaced = true;
return FixType(existing.FullInterfaceName, typeSymbol.NullableAnnotation);
}
ITypeSymbol[] typeArguments;
if (typeSymbol is INamedTypeSymbol namedTypedSymbol1)
{
typeArguments = namedTypedSymbol1.TypeArguments.ToArray();
}
else if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol)
{
typeArguments = new[] { arrayTypeSymbol.ElementType };
}
else
{
return FixType(typeSymbolAsString, typeSymbol.NullableAnnotation);
}
var propertyTypeAsStringToBeModified = nullableTypeSymbolAsString;
foreach (var typeArgument in typeArguments)
{
var typeArgumentAsString = typeArgument.ToFullyQualifiedDisplayString();
if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument))
{
isReplaced = true;
if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString))
{
Context.ReplacedTypes.Add(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
}
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
}
}
return FixType(propertyTypeAsStringToBeModified, typeSymbol.NullableAnnotation);
}
protected bool TryGetNamedTypeSymbolByFullName(TypeKind kind, string name, IEnumerable<string> usings, [NotNullWhen(true)] out ClassSymbol? classSymbol)
{
classSymbol = default;
const string globalPrefix = "global::";
if (name.StartsWith(globalPrefix, StringComparison.Ordinal))
{
name = name.Substring(globalPrefix.Length);
}
// The GetTypeByMetadataName method returns null if no type matches the full name or if 2 or more types (in different assemblies) match the full name.
var symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name);
if (symbol is not null && symbol.TypeKind == kind)
{
classSymbol = new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList());
return true;
}
foreach (var @using in usings)
{
symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName($"{@using}.{name}");
if (symbol is not null && symbol.TypeKind == kind)
{
classSymbol = new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList());
return true;
}
}
return false;
}
protected IReadOnlyList<string> GetMethodParameters(ImmutableArray<IParameterSymbol> parameterSymbols, bool includeType)
{
var methodParameters = new List<string>();
foreach (var parameterSymbol in parameterSymbols)
{
string? type = null;
if (includeType)
{
if (parameterSymbol.GetTypeEnum() == TypeEnum.Complex)
{
type = GetParameterType(parameterSymbol, out _);
}
else
{
type = FixType(parameterSymbol.Type.ToFullyQualifiedDisplayString(), parameterSymbol.NullableAnnotation);
}
}
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
}
return methodParameters;
}
protected IReadOnlyList<ProxyData> GetExtendsProxyData(ProxyData proxyData, ClassSymbol targetClassSymbol)
{
var extendsProxyClasses = new List<ProxyData>();
foreach (var baseType in targetClassSymbol.BaseTypes)
{
var candidate = Context.Candidates.Values.FirstOrDefault(ci => ci.FullQualifiedTypeName == baseType.ToFullyQualifiedDisplayString());
if (candidate is not null)
{
extendsProxyClasses.Add(candidate);
break;
}
}
return extendsProxyClasses;
}
internal static string FixType(string type, NullableAnnotation nullableAnnotation)
{
if (nullableAnnotation == NullableAnnotation.Annotated && !type.EndsWith("?", StringComparison.Ordinal))
{
return $"{type}?";
}
return type;
}
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Builders;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal abstract class BaseGenerator
{
protected readonly Context Context;
protected readonly bool SupportsNullable;
protected BaseGenerator(Context context, bool supportsNullable)
{
Context = context;
SupportsNullable = supportsNullable;
}
protected string GetPropertyType(IPropertySymbol property, out bool isReplaced)
{
return GetReplacedTypeAsString(property.Type, out isReplaced);
}
protected string GetParameterType(IParameterSymbol property, out bool isReplaced)
{
return GetReplacedTypeAsString(property.Type, out isReplaced);
}
protected bool TryFindProxyDataByTypeName(string type, [NotNullWhen(true)] out ProxyData? proxyData)
{
proxyData = Context.Candidates.Values.FirstOrDefault(x => x.FullQualifiedTypeName == type);
return proxyData != null;
}
protected string GetWhereStatementFromMethod(IMethodSymbol method)
{
if (!method.IsGenericMethod)
{
return string.Empty;
}
var list = new List<string>();
foreach (var typeParameterSymbol in method.TypeParameters)
{
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
{
list.Add(constraint.ToString());
}
}
return string.Concat(list);
}
protected string ResolveInterfaceNameWithOptionalTypeConstraints(INamedTypeSymbol namedTypeSymbol, string interfaceName)
{
if (!namedTypeSymbol.IsGenericType)
{
return interfaceName;
}
var str = new StringBuilder($"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>");
foreach (var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType<ITypeParameterSymbol>())
{
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
{
str.Append(constraint);
}
}
return str.ToString();
}
/// <summary>
/// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
/// </summary>
public bool TryGetWhereConstraints(ITypeParameterSymbol typeParameterSymbol, bool replaceIt, [NotNullWhen(true)] out ConstraintInfo? constraint)
{
var constraints = new List<string>();
if (typeParameterSymbol.HasReferenceTypeConstraint)
{
constraints.Add("class");
}
if (typeParameterSymbol.HasValueTypeConstraint)
{
constraints.Add("struct");
}
foreach (var namedTypeSymbol in typeParameterSymbol.ConstraintTypes.OfType<INamedTypeSymbol>())
{
if (replaceIt)
{
constraints.Add(GetReplacedTypeAsString(namedTypeSymbol, out _));
}
else
{
constraints.Add(namedTypeSymbol.GetFullType());
}
}
// The new() constraint must be the last constraint specified.
if (typeParameterSymbol.HasConstructorConstraint)
{
constraints.Add("new()");
}
if (constraints.Count > 0)
{
constraint = new(typeParameterSymbol.Name, constraints);
return true;
}
constraint = null;
return false;
}
internal readonly SymbolDisplayFormat NullableDisplayFormat = new SymbolDisplayFormat(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
miscellaneousOptions:
SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
SymbolDisplayMiscellaneousOptions.UseSpecialTypes |
SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier);
protected string GetReplacedTypeAsString(ITypeSymbol typeSymbol, out bool isReplaced)
{
isReplaced = false;
var typeSymbolAsString = typeSymbol.ToFullyQualifiedDisplayString();
var nullableTypeSymbolAsString = typeSymbol.ToDisplayString(NullableFlowState.None, NullableDisplayFormat);
if (TryFindProxyDataByTypeName(typeSymbolAsString, out var existing))
{
if (!Context.ReplacedTypes.ContainsKey(typeSymbolAsString))
{
Context.ReplacedTypes.Add(typeSymbolAsString, existing.FullInterfaceName);
}
isReplaced = true;
return FixType(existing.FullInterfaceName, typeSymbol.NullableAnnotation);
}
ITypeSymbol[] typeArguments;
if (typeSymbol is INamedTypeSymbol namedTypedSymbol1)
{
typeArguments = namedTypedSymbol1.TypeArguments.ToArray();
}
else if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol)
{
typeArguments = new[] { arrayTypeSymbol.ElementType };
}
else
{
return FixType(typeSymbolAsString, typeSymbol.NullableAnnotation);
}
var propertyTypeAsStringToBeModified = nullableTypeSymbolAsString;
foreach (var typeArgument in typeArguments)
{
var typeArgumentAsString = typeArgument.ToFullyQualifiedDisplayString();
if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument))
{
isReplaced = true;
if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString))
{
Context.ReplacedTypes.Add(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
}
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
}
}
return FixType(propertyTypeAsStringToBeModified, typeSymbol.NullableAnnotation);
}
protected bool TryGetNamedTypeSymbolByFullName(TypeKind kind, string name, IEnumerable<string> usings, [NotNullWhen(true)] out ClassSymbol? classSymbol)
{
classSymbol = default;
const string globalPrefix = "global::";
if (name.StartsWith(globalPrefix, StringComparison.Ordinal))
{
name = name.Substring(globalPrefix.Length);
}
// The GetTypeByMetadataName method returns null if no type matches the full name or if 2 or more types (in different assemblies) match the full name.
var symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name);
if (symbol is not null && symbol.TypeKind == kind)
{
classSymbol = new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList());
return true;
}
foreach (var @using in usings)
{
symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName($"{@using}.{name}");
if (symbol is not null && symbol.TypeKind == kind)
{
classSymbol = new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList());
return true;
}
}
return false;
}
protected IReadOnlyList<string> GetMethodParameters(ImmutableArray<IParameterSymbol> parameterSymbols, bool includeType)
{
var methodParameters = new List<string>();
foreach (var parameterSymbol in parameterSymbols)
{
string? type = null;
if (includeType)
{
if (parameterSymbol.GetTypeEnum() == TypeEnum.Complex)
{
type = GetParameterType(parameterSymbol, out _);
}
else
{
type = FixType(parameterSymbol.Type.ToFullyQualifiedDisplayString(), parameterSymbol.NullableAnnotation);
}
}
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
}
return methodParameters;
}
protected IReadOnlyList<ProxyData> GetExtendsProxyData(ProxyData proxyData, ClassSymbol targetClassSymbol)
{
var extendsProxyClasses = new List<ProxyData>();
foreach (var baseType in targetClassSymbol.BaseTypes)
{
var candidate = Context.Candidates.Values.FirstOrDefault(ci => ci.FullQualifiedTypeName == baseType.ToFullyQualifiedDisplayString());
if (candidate is not null)
{
extendsProxyClasses.Add(candidate);
break;
}
}
return extendsProxyClasses;
}
internal static string FixType(string type, NullableAnnotation nullableAnnotation)
{
if (nullableAnnotation == NullableAnnotation.Annotated && !type.EndsWith("?", StringComparison.Ordinal))
{
return $"{type}?";
}
return type;
}
}
@@ -1,8 +1,8 @@
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal interface IFileGenerator
{
FileData GenerateFile();
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal interface IFileGenerator
{
FileData GenerateFile();
}
@@ -1,8 +1,8 @@
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal interface IFilesGenerator
{
IEnumerable<FileData> GenerateFiles();
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal interface IFilesGenerator
{
IEnumerable<FileData> GenerateFiles();
}
@@ -1,184 +1,184 @@
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
using ProxyInterfaceSourceGenerator.Utils;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
{
private IReadOnlyCollection<INamedTypeSymbol> _implementedInterfaces = new List<INamedTypeSymbol>();
public PartialInterfacesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
{
}
public IEnumerable<FileData> GenerateFiles()
{
foreach (var ci in Context.Candidates)
{
if (TryGenerateFile(ci.Key, ci.Value, out var file))
{
yield return file;
}
}
}
private bool TryGenerateFile(InterfaceDeclarationSyntax ci, ProxyData pd, [NotNullWhen(true)] out FileData? fileData)
{
fileData = default;
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Interface, ci.Identifier.ToString(), pd.Usings, out var sourceInterfaceSymbol))
{
return false;
}
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullMetadataTypeName, pd.Usings, out var targetClassSymbol))
{
return false;
}
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.ShortInterfaceName);
fileData = new FileData(
$"{sourceInterfaceSymbol.Symbol.GetFullMetadataName()}.g.cs",
CreatePartialInterfaceCode(pd.Namespace, targetClassSymbol, interfaceName, pd)
);
return true;
}
private string CreatePartialInterfaceCode(
string ns,
ClassSymbol classSymbol,
string interfaceName,
ProxyData proxyData)
{
var extendsProxyClasses = GetExtendsProxyData(proxyData, classSymbol);
_implementedInterfaces = classSymbol.Symbol.ResolveImplementedInterfaces(proxyData.ProxyBaseClasses);
var implementedInterfacesNames = _implementedInterfaces.Select(i => i.ToFullyQualifiedDisplayString()).ToArray();
var implements = implementedInterfacesNames.Any() ? $" : {string.Join(", ", implementedInterfacesNames)}" : string.Empty;
var @new = extendsProxyClasses.Any() ? "new " : string.Empty;
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(ns);
var events = GenerateEvents(classSymbol, proxyData);
var properties = GenerateProperties(classSymbol, proxyData);
var methods = GenerateMethods(classSymbol, proxyData).TrimEnd();
return $@"//----------------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//----------------------------------------------------------------------------------------
{SupportsNullable.IIf("#nullable enable")}
using System;
{namespaceStart}
public partial interface {interfaceName}{implements}
{{
{@new}{classSymbol} _Instance {{ get; }}
{events +
properties +
methods}
}}
{namespaceEnd}
{SupportsNullable.IIf("#nullable restore")}";
}
private Func<T, bool> InterfaceFilter<T>() where T : ISymbol
{
var hashSet = new HashSet<string>();
foreach (var @interface in _implementedInterfaces)
{
var members = @interface.AllInterfaces.Aggregate(@interface.GetMembers(), (xs, x) => xs.AddRange(x.GetMembers()));
foreach (var member in members)
{
hashSet.Add(member.Name);
}
}
// Member is not already implemented in another interface.
return t => !hashSet.Contains(t.Name);
}
private string GenerateProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData, InterfaceFilter<IPropertySymbol>()))
{
var type = GetPropertyType(property, out var isReplaced);
var getterSetter = isReplaced ? property.ToPropertyDetails(type) : property.ToPropertyDetails();
if (getterSetter is null)
{
continue;
}
var propertyName = getterSetter.Value.PropertyName;
if (property.IsIndexer)
{
var methodParameters = GetMethodParameters(property.Parameters, true);
propertyName = $"this[{string.Join(", ", methodParameters)}]";
}
foreach (var attribute in property.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" {getterSetter.Value.PropertyType} {propertyName} {getterSetter.Value.GetSet}");
str.AppendLine();
}
return str.ToString();
}
private string GenerateMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol, proxyData, InterfaceFilter<IMethodSymbol>()))
{
var methodParameters = GetMethodParameters(method.Parameters, true);
var whereStatement = GetWhereStatementFromMethod(method);
foreach (var attribute in method.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" {GetReplacedTypeAsString(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};");
str.AppendLine();
}
return str.ToString();
}
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData, InterfaceFilter<IMethodSymbol>()))
{
var ps = @event.First().Parameters.First();
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
foreach (var attribute in ps.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" event {type} {@event.Key.GetSanitizedName()};");
str.AppendLine();
}
return str.ToString();
}
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
using ProxyInterfaceSourceGenerator.Utils;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
{
private IReadOnlyCollection<INamedTypeSymbol> _implementedInterfaces = new List<INamedTypeSymbol>();
public PartialInterfacesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
{
}
public IEnumerable<FileData> GenerateFiles()
{
foreach (var ci in Context.Candidates)
{
if (TryGenerateFile(ci.Key, ci.Value, out var file))
{
yield return file;
}
}
}
private bool TryGenerateFile(InterfaceDeclarationSyntax ci, ProxyData pd, [NotNullWhen(true)] out FileData? fileData)
{
fileData = default;
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Interface, ci.Identifier.ToString(), pd.Usings, out var sourceInterfaceSymbol))
{
return false;
}
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullMetadataTypeName, pd.Usings, out var targetClassSymbol))
{
return false;
}
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.ShortInterfaceName);
fileData = new FileData(
$"{sourceInterfaceSymbol.Symbol.GetFullMetadataName()}.g.cs",
CreatePartialInterfaceCode(pd.Namespace, targetClassSymbol, interfaceName, pd)
);
return true;
}
private string CreatePartialInterfaceCode(
string ns,
ClassSymbol classSymbol,
string interfaceName,
ProxyData proxyData)
{
var extendsProxyClasses = GetExtendsProxyData(proxyData, classSymbol);
_implementedInterfaces = classSymbol.Symbol.ResolveImplementedInterfaces(proxyData.ProxyBaseClasses);
var implementedInterfacesNames = _implementedInterfaces.Select(i => i.ToFullyQualifiedDisplayString()).ToArray();
var implements = implementedInterfacesNames.Any() ? $" : {string.Join(", ", implementedInterfacesNames)}" : string.Empty;
var @new = extendsProxyClasses.Any() ? "new " : string.Empty;
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(ns);
var events = GenerateEvents(classSymbol, proxyData);
var properties = GenerateProperties(classSymbol, proxyData);
var methods = GenerateMethods(classSymbol, proxyData).TrimEnd();
return $@"//----------------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//----------------------------------------------------------------------------------------
{SupportsNullable.IIf("#nullable enable")}
using System;
{namespaceStart}
public partial interface {interfaceName}{implements}
{{
{@new}{classSymbol} _Instance {{ get; }}
{events +
properties +
methods}
}}
{namespaceEnd}
{SupportsNullable.IIf("#nullable restore")}";
}
private Func<T, bool> InterfaceFilter<T>() where T : ISymbol
{
var hashSet = new HashSet<string>();
foreach (var @interface in _implementedInterfaces)
{
var members = @interface.AllInterfaces.Aggregate(@interface.GetMembers(), (xs, x) => xs.AddRange(x.GetMembers()));
foreach (var member in members)
{
hashSet.Add(member.Name);
}
}
// Member is not already implemented in another interface.
return t => !hashSet.Contains(t.Name);
}
private string GenerateProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData, InterfaceFilter<IPropertySymbol>()))
{
var type = GetPropertyType(property, out var isReplaced);
var getterSetter = isReplaced ? property.ToPropertyDetails(type) : property.ToPropertyDetails();
if (getterSetter is null)
{
continue;
}
var propertyName = getterSetter.Value.PropertyName;
if (property.IsIndexer)
{
var methodParameters = GetMethodParameters(property.Parameters, true);
propertyName = $"this[{string.Join(", ", methodParameters)}]";
}
foreach (var attribute in property.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" {getterSetter.Value.PropertyType} {propertyName} {getterSetter.Value.GetSet}");
str.AppendLine();
}
return str.ToString();
}
private string GenerateMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol, proxyData, InterfaceFilter<IMethodSymbol>()))
{
var methodParameters = GetMethodParameters(method.Parameters, true);
var whereStatement = GetWhereStatementFromMethod(method);
foreach (var attribute in method.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" {GetReplacedTypeAsString(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};");
str.AppendLine();
}
return str.ToString();
}
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData, InterfaceFilter<IMethodSymbol>()))
{
var ps = @event.First().Parameters.First();
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
foreach (var attribute in ps.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" event {type} {@event.Key.GetSanitizedName()};");
str.AppendLine();
}
return str.ToString();
}
}
@@ -1,383 +1,383 @@
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Builders;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
using ProxyInterfaceSourceGenerator.Types;
using ProxyInterfaceSourceGenerator.Utils;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
{
public ProxyClassesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
{
}
public IEnumerable<FileData> GenerateFiles()
{
foreach (var ci in Context.Candidates)
{
if (TryGenerateFile(ci.Value, out var file))
{
yield return file;
}
}
}
[SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1024:Compare symbols correctly", Justification = "<Pending>")]
private bool TryGenerateFile(ProxyData pd, [NotNullWhen(true)] out FileData? fileData)
{
fileData = default;
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullMetadataTypeName, pd.Usings, out var targetClassSymbol))
{
return false;
}
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.FullInterfaceName);
var className = targetClassSymbol.Symbol.ResolveProxyClassName();
var constructorName = $"{targetClassSymbol.Symbol.Name}Proxy";
var extendsProxyClasses = GetExtendsProxyData(pd, targetClassSymbol);
fileData = new FileData(
$"{targetClassSymbol.Symbol.GetFullMetadataName()}Proxy.g.cs",
CreateProxyClassCode(pd, targetClassSymbol, extendsProxyClasses, interfaceName, className, constructorName)
);
return true;
}
private string CreateProxyClassCode(
ProxyData pd,
ClassSymbol targetClassSymbol,
IReadOnlyList<ProxyData> extendsProxyClasses,
string interfaceName,
string className,
string constructorName)
{
var firstExtends = extendsProxyClasses.FirstOrDefault();
var extends = string.Empty;
var @base = string.Empty;
var @new = string.Empty;
var instanceBaseDefinition = string.Empty;
var instanceBaseSetter = string.Empty;
if (firstExtends is not null)
{
extends = $"global::{firstExtends.NamespaceDot}{firstExtends.ShortMetadataName}Proxy, ";
@base = " : base(instance)";
@new = "new ";
instanceBaseDefinition = $"public {firstExtends.FullQualifiedTypeName} _Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} {{ get; }}";
instanceBaseSetter = $"_Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} = instance;";
}
var @abstract = string.Empty; // targetClassSymbol.Symbol.IsAbstract ? "abstract " : string.Empty;
var properties = GeneratePublicProperties(targetClassSymbol, pd);
var methods = GeneratePublicMethods(targetClassSymbol, pd);
var events = GenerateEvents(targetClassSymbol, pd);
var operators = GenerateOperators(targetClassSymbol, pd);
var configurationForMapster = string.Empty;
if (Context.ReplacedTypes.Count > 0)
{
configurationForMapster = GenerateMapperConfigurationForMapster();
}
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(pd.Namespace);
var accessibility = pd.Accessibility == ProxyClassAccessibility.Internal ? "internal" : "public";
return $@"//----------------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//----------------------------------------------------------------------------------------
{SupportsNullable.IIf("#nullable enable")}
using System;
{namespaceStart}
{accessibility} {@abstract}partial class {className} : {extends}{interfaceName}
{{
public {@new}{targetClassSymbol} _Instance {{ get; }}
{instanceBaseDefinition}
{events +
properties +
methods +
operators}
public {constructorName}({targetClassSymbol} instance){@base}
{{
_Instance = instance;
{instanceBaseSetter}
{configurationForMapster}
}}
}}
{namespaceEnd}
{SupportsNullable.IIf("#nullable restore")}";
}
private string GeneratePublicProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData))
{
var type = GetPropertyType(property, out var isReplaced);
var instance = !property.IsStatic ?
"_Instance" :
$"{targetClassSymbol.Symbol}";
var propertyName = property.GetSanitizedName();
var instancePropertyName = $"{instance}.{propertyName}";
if (property.IsIndexer)
{
var parameters = GetMethodParameters(property.Parameters, true);
propertyName = $"this[{string.Join(", ", parameters)}]";
var instanceParameters = GetMethodParameters(property.Parameters, false);
instancePropertyName = $"{instance}[{string.Join(", ", instanceParameters)}]";
}
var overrideOrVirtual = string.Empty;
if (property.IsOverride)
{
overrideOrVirtual = "override ";
}
else if (property.IsVirtual)
{
overrideOrVirtual = "virtual ";
}
var getIsPublic = property.GetMethod.IsPublic();
var setIsPublic = property.SetMethod.IsPublic();
if (!getIsPublic && !setIsPublic)
{
continue;
}
string get;
string set;
if (isReplaced)
{
get = getIsPublic ? $"get => Mapster.TypeAdapter.Adapt<{type}>({instancePropertyName}); " : string.Empty;
set = setIsPublic ? $"set => {instancePropertyName} = Mapster.TypeAdapter.Adapt<{property.Type}>(value); " : string.Empty;
}
else
{
get = getIsPublic ? $"get => {instancePropertyName}; " : string.Empty;
set = setIsPublic ? $"set => {instancePropertyName} = value; " : string.Empty;
}
foreach (var attribute in property.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" public {overrideOrVirtual}{type} {propertyName} {{ {get}{set}}}");
str.AppendLine();
}
return str.ToString();
}
private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
var methods = MemberHelper.GetPublicMethods(targetClassSymbol, proxyData);
foreach (var method in methods)
{
var methodParameters = new List<string>();
var invokeParameters = new List<string>();
foreach (var parameterSymbol in method.Parameters)
{
var type = GetParameterType(parameterSymbol, out _);
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
// Do not add the '_' for a 'ref' parameter.
invokeParameters.Add($"{parameterSymbol.GetRefKindPrefix()}{parameterSymbol.GetSanitizedName()}{(!parameterSymbol.IsRef()).IIf("_")}");
}
string overrideOrVirtual = string.Empty;
if (method.IsOverride && method.OverriddenMethod != null)
{
var baseType = method.OverriddenMethod.ContainingType.GetFullType();
if (TryGetNamedTypeSymbolByFullName(TypeKind.Class, baseType, Enumerable.Empty<string>(), out _))
{
overrideOrVirtual = "override ";
}
}
else if (method.IsVirtual)
{
overrideOrVirtual = "virtual ";
}
string returnTypeAsString = GetReplacedTypeAsString(method.ReturnType, out var returnIsReplaced);
var whereStatement = GetWhereStatementFromMethod(method);
foreach (var attribute in method.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" public {overrideOrVirtual}{returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement}");
str.AppendLine(@" {");
foreach (var ps in method.Parameters.Where(p => !p.IsRef()))
{
var type = FixType(ps.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), ps.Type.NullableAnnotation);
string normalOrMap = $" = {ps.GetSanitizedName()}";
if (ps.RefKind == RefKind.Out)
{
normalOrMap = string.Empty;
}
else
{
_ = GetParameterType(ps, out var isReplaced); // TODO : response is not used?
if (isReplaced)
{
normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()})";
}
}
str.AppendLine($" {type} {ps.GetSanitizedName()}_{normalOrMap};");
}
var methodName = method.GetMethodNameWithOptionalTypeParameters();
var alternateReturnVariableName = $"result_{methodName.GetDeterministicHashCodeAsString()}";
string instance = method.IsStatic ? targetClassSymbol.Symbol.ToFullyQualifiedDisplayString() : "_Instance";
if (returnTypeAsString == "void")
{
str.AppendLine($" {instance}.{methodName}({string.Join(", ", invokeParameters)});");
}
else
{
str.AppendLine($" var {alternateReturnVariableName} = {instance}.{methodName}({string.Join(", ", invokeParameters)});");
}
foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out))
{
string normalOrMap = $" = {ps.GetSanitizedName()}_";
if (ps.GetTypeEnum() == TypeEnum.Complex)
{
var type = GetParameterType(ps, out var isReplaced);
if (isReplaced)
{
normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()}_)";
}
}
str.AppendLine($" {ps.GetSanitizedName()}{normalOrMap};");
}
if (returnTypeAsString != "void")
{
if (returnIsReplaced)
{
str.AppendLine($" return Mapster.TypeAdapter.Adapt<{returnTypeAsString}>({alternateReturnVariableName});");
}
else
{
str.AppendLine($" return {alternateReturnVariableName};");
}
}
str.AppendLine(" }");
str.AppendLine();
}
return str.ToString();
}
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData))
{
var name = @event.Key.GetSanitizedName();
var ps = @event.First().Parameters.First();
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
foreach (var attribute in ps.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.Append($" public event {type} {name} {{");
if (@event.Any(e => e.MethodKind == MethodKind.EventAdd))
{
str.Append($" add {{ _Instance.{name} += value; }}");
}
if (@event.Any(e => e.MethodKind == MethodKind.EventRemove))
{
str.Append($" remove {{ _Instance.{name} -= value; }}");
}
str.AppendLine(" }");
str.AppendLine();
}
return str.ToString();
}
private string GenerateOperators(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var @operator in MemberHelper.GetPublicStaticOperators(targetClassSymbol, proxyData))
{
foreach (var attribute in @operator.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
if (!@operator.Parameters.Any())
{
continue;
}
var parameter = @operator.Parameters.First();
var proxyClassName = targetClassSymbol.Symbol.ResolveProxyClassName();
var operatorType = @operator.Name.ToLowerInvariant().Replace("op_", string.Empty);
if (operatorType == "explicit")
{
var returnTypeAsString = GetReplacedTypeAsString(@operator.ReturnType, out _);
str.AppendLine($" public static explicit operator {returnTypeAsString}({proxyClassName} {parameter.Name})");
str.AppendLine(@" {");
str.AppendLine($" return ({returnTypeAsString}) {parameter.Name}._Instance;");
str.AppendLine(@" }");
}
else
{
var returnTypeAsString = GetReplacedTypeAsString(parameter.Type, out _);
str.AppendLine($" public static implicit operator {proxyClassName}({returnTypeAsString} {parameter.Name})");
str.AppendLine(@" {");
str.AppendLine($" return new {proxyClassName}(({targetClassSymbol.Symbol.Name}) {parameter.Name});");
str.AppendLine(@" }");
}
str.AppendLine();
}
return str.ToString();
}
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Builders;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
using ProxyInterfaceSourceGenerator.Types;
using ProxyInterfaceSourceGenerator.Utils;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
{
public ProxyClassesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
{
}
public IEnumerable<FileData> GenerateFiles()
{
foreach (var ci in Context.Candidates)
{
if (TryGenerateFile(ci.Value, out var file))
{
yield return file;
}
}
}
[SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1024:Compare symbols correctly", Justification = "<Pending>")]
private bool TryGenerateFile(ProxyData pd, [NotNullWhen(true)] out FileData? fileData)
{
fileData = default;
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullMetadataTypeName, pd.Usings, out var targetClassSymbol))
{
return false;
}
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.FullInterfaceName);
var className = targetClassSymbol.Symbol.ResolveProxyClassName();
var constructorName = $"{targetClassSymbol.Symbol.Name}Proxy";
var extendsProxyClasses = GetExtendsProxyData(pd, targetClassSymbol);
fileData = new FileData(
$"{targetClassSymbol.Symbol.GetFullMetadataName()}Proxy.g.cs",
CreateProxyClassCode(pd, targetClassSymbol, extendsProxyClasses, interfaceName, className, constructorName)
);
return true;
}
private string CreateProxyClassCode(
ProxyData pd,
ClassSymbol targetClassSymbol,
IReadOnlyList<ProxyData> extendsProxyClasses,
string interfaceName,
string className,
string constructorName)
{
var firstExtends = extendsProxyClasses.FirstOrDefault();
var extends = string.Empty;
var @base = string.Empty;
var @new = string.Empty;
var instanceBaseDefinition = string.Empty;
var instanceBaseSetter = string.Empty;
if (firstExtends is not null)
{
extends = $"global::{firstExtends.NamespaceDot}{firstExtends.ShortMetadataName}Proxy, ";
@base = " : base(instance)";
@new = "new ";
instanceBaseDefinition = $"public {firstExtends.FullQualifiedTypeName} _Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} {{ get; }}";
instanceBaseSetter = $"_Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} = instance;";
}
var @abstract = string.Empty; // targetClassSymbol.Symbol.IsAbstract ? "abstract " : string.Empty;
var properties = GeneratePublicProperties(targetClassSymbol, pd);
var methods = GeneratePublicMethods(targetClassSymbol, pd);
var events = GenerateEvents(targetClassSymbol, pd);
var operators = GenerateOperators(targetClassSymbol, pd);
var configurationForMapster = string.Empty;
if (Context.ReplacedTypes.Count > 0)
{
configurationForMapster = GenerateMapperConfigurationForMapster();
}
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(pd.Namespace);
var accessibility = pd.Accessibility == ProxyClassAccessibility.Internal ? "internal" : "public";
return $@"//----------------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//----------------------------------------------------------------------------------------
{SupportsNullable.IIf("#nullable enable")}
using System;
{namespaceStart}
{accessibility} {@abstract}partial class {className} : {extends}{interfaceName}
{{
public {@new}{targetClassSymbol} _Instance {{ get; }}
{instanceBaseDefinition}
{events +
properties +
methods +
operators}
public {constructorName}({targetClassSymbol} instance){@base}
{{
_Instance = instance;
{instanceBaseSetter}
{configurationForMapster}
}}
}}
{namespaceEnd}
{SupportsNullable.IIf("#nullable restore")}";
}
private string GeneratePublicProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData))
{
var type = GetPropertyType(property, out var isReplaced);
var instance = !property.IsStatic ?
"_Instance" :
$"{targetClassSymbol.Symbol}";
var propertyName = property.GetSanitizedName();
var instancePropertyName = $"{instance}.{propertyName}";
if (property.IsIndexer)
{
var parameters = GetMethodParameters(property.Parameters, true);
propertyName = $"this[{string.Join(", ", parameters)}]";
var instanceParameters = GetMethodParameters(property.Parameters, false);
instancePropertyName = $"{instance}[{string.Join(", ", instanceParameters)}]";
}
var overrideOrVirtual = string.Empty;
if (property.IsOverride)
{
overrideOrVirtual = "override ";
}
else if (property.IsVirtual)
{
overrideOrVirtual = "virtual ";
}
var getIsPublic = property.GetMethod.IsPublic();
var setIsPublic = property.SetMethod.IsPublic();
if (!getIsPublic && !setIsPublic)
{
continue;
}
string get;
string set;
if (isReplaced)
{
get = getIsPublic ? $"get => Mapster.TypeAdapter.Adapt<{type}>({instancePropertyName}); " : string.Empty;
set = setIsPublic ? $"set => {instancePropertyName} = Mapster.TypeAdapter.Adapt<{property.Type}>(value); " : string.Empty;
}
else
{
get = getIsPublic ? $"get => {instancePropertyName}; " : string.Empty;
set = setIsPublic ? $"set => {instancePropertyName} = value; " : string.Empty;
}
foreach (var attribute in property.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" public {overrideOrVirtual}{type} {propertyName} {{ {get}{set}}}");
str.AppendLine();
}
return str.ToString();
}
private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
var methods = MemberHelper.GetPublicMethods(targetClassSymbol, proxyData);
foreach (var method in methods)
{
var methodParameters = new List<string>();
var invokeParameters = new List<string>();
foreach (var parameterSymbol in method.Parameters)
{
var type = GetParameterType(parameterSymbol, out _);
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
// Do not add the '_' for a 'ref' parameter.
invokeParameters.Add($"{parameterSymbol.GetRefKindPrefix()}{parameterSymbol.GetSanitizedName()}{(!parameterSymbol.IsRef()).IIf("_")}");
}
string overrideOrVirtual = string.Empty;
if (method.IsOverride && method.OverriddenMethod != null)
{
var baseType = method.OverriddenMethod.ContainingType.GetFullType();
if (TryGetNamedTypeSymbolByFullName(TypeKind.Class, baseType, Enumerable.Empty<string>(), out _))
{
overrideOrVirtual = "override ";
}
}
else if (method.IsVirtual)
{
overrideOrVirtual = "virtual ";
}
string returnTypeAsString = GetReplacedTypeAsString(method.ReturnType, out var returnIsReplaced);
var whereStatement = GetWhereStatementFromMethod(method);
foreach (var attribute in method.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.AppendLine($" public {overrideOrVirtual}{returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement}");
str.AppendLine(@" {");
foreach (var ps in method.Parameters.Where(p => !p.IsRef()))
{
var type = FixType(ps.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), ps.Type.NullableAnnotation);
string normalOrMap = $" = {ps.GetSanitizedName()}";
if (ps.RefKind == RefKind.Out)
{
normalOrMap = string.Empty;
}
else
{
_ = GetParameterType(ps, out var isReplaced); // TODO : response is not used?
if (isReplaced)
{
normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()})";
}
}
str.AppendLine($" {type} {ps.GetSanitizedName()}_{normalOrMap};");
}
var methodName = method.GetMethodNameWithOptionalTypeParameters();
var alternateReturnVariableName = $"result_{methodName.GetDeterministicHashCodeAsString()}";
string instance = method.IsStatic ? targetClassSymbol.Symbol.ToFullyQualifiedDisplayString() : "_Instance";
if (returnTypeAsString == "void")
{
str.AppendLine($" {instance}.{methodName}({string.Join(", ", invokeParameters)});");
}
else
{
str.AppendLine($" var {alternateReturnVariableName} = {instance}.{methodName}({string.Join(", ", invokeParameters)});");
}
foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out))
{
string normalOrMap = $" = {ps.GetSanitizedName()}_";
if (ps.GetTypeEnum() == TypeEnum.Complex)
{
var type = GetParameterType(ps, out var isReplaced);
if (isReplaced)
{
normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()}_)";
}
}
str.AppendLine($" {ps.GetSanitizedName()}{normalOrMap};");
}
if (returnTypeAsString != "void")
{
if (returnIsReplaced)
{
str.AppendLine($" return Mapster.TypeAdapter.Adapt<{returnTypeAsString}>({alternateReturnVariableName});");
}
else
{
str.AppendLine($" return {alternateReturnVariableName};");
}
}
str.AppendLine(" }");
str.AppendLine();
}
return str.ToString();
}
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData))
{
var name = @event.Key.GetSanitizedName();
var ps = @event.First().Parameters.First();
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
foreach (var attribute in ps.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
str.Append($" public event {type} {name} {{");
if (@event.Any(e => e.MethodKind == MethodKind.EventAdd))
{
str.Append($" add {{ _Instance.{name} += value; }}");
}
if (@event.Any(e => e.MethodKind == MethodKind.EventRemove))
{
str.Append($" remove {{ _Instance.{name} -= value; }}");
}
str.AppendLine(" }");
str.AppendLine();
}
return str.ToString();
}
private string GenerateOperators(ClassSymbol targetClassSymbol, ProxyData proxyData)
{
var str = new StringBuilder();
foreach (var @operator in MemberHelper.GetPublicStaticOperators(targetClassSymbol, proxyData))
{
foreach (var attribute in @operator.GetAttributesAsList())
{
str.AppendLine($" {attribute}");
}
if (!@operator.Parameters.Any())
{
continue;
}
var parameter = @operator.Parameters.First();
var proxyClassName = targetClassSymbol.Symbol.ResolveProxyClassName();
var operatorType = @operator.Name.ToLowerInvariant().Replace("op_", string.Empty);
if (operatorType == "explicit")
{
var returnTypeAsString = GetReplacedTypeAsString(@operator.ReturnType, out _);
str.AppendLine($" public static explicit operator {returnTypeAsString}({proxyClassName} {parameter.Name})");
str.AppendLine(@" {");
str.AppendLine($" return ({returnTypeAsString}) {parameter.Name}._Instance;");
str.AppendLine(@" }");
}
else
{
var returnTypeAsString = GetReplacedTypeAsString(parameter.Type, out _);
str.AppendLine($" public static implicit operator {proxyClassName}({returnTypeAsString} {parameter.Name})");
str.AppendLine(@" {");
str.AppendLine($" return new {proxyClassName}(({targetClassSymbol.Symbol.Name}) {parameter.Name});");
str.AppendLine(@" }");
}
str.AppendLine();
}
return str.ToString();
}
}
@@ -1,106 +1,106 @@
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using ProxyInterfaceSourceGenerator.FileGenerators;
using ProxyInterfaceSourceGenerator.Models;
using ProxyInterfaceSourceGenerator.SyntaxReceiver;
namespace ProxyInterfaceSourceGenerator;
[Generator]
#if DEBUG
public
#else
internal
#endif
class ProxyInterfaceCodeGenerator : ISourceGenerator
{
private readonly ExtraFilesGenerator _proxyAttributeGenerator = new();
public void Initialize(GeneratorInitializationContext context)
{
#if DEBUGATTACH
if (!System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Launch();
}
#endif
context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
try
{
if (context.ParseOptions is not CSharpParseOptions csharpParseOptions)
{
throw new NotSupportedException("Only C# is supported.");
}
if (context.SyntaxContextReceiver is not ProxySyntaxReceiver receiver)
{
throw new NotSupportedException($"Only {nameof(ProxySyntaxReceiver)} is supported.");
}
// https://github.com/reactiveui/refit/blob/main/InterfaceStubGenerator.Core/InterfaceStubGenerator.cs
var supportsNullable = csharpParseOptions.LanguageVersion >= LanguageVersion.CSharp8;
GenerateProxyAttribute(context, receiver);
GeneratePartialInterfaces(context, receiver, supportsNullable);
GenerateProxyClasses(context, receiver, supportsNullable);
}
catch (Exception exception)
{
GenerateError(context, exception);
}
}
private void GenerateError(GeneratorExecutionContext context, Exception exception)
{
var message = $"/*\r\n{nameof(ProxyInterfaceCodeGenerator)}\r\n\r\n[Exception]\r\n{exception}\r\n\r\n[StackTrace]\r\n{exception.StackTrace}*/";
context.AddSource("Error.g", SourceText.From(message, Encoding.UTF8));
}
private void GenerateProxyAttribute(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver)
{
var context = new Context
{
GeneratorExecutionContext = ctx,
Candidates = receiver.CandidateInterfaces
};
var attributeData = _proxyAttributeGenerator.GenerateFile();
context.GeneratorExecutionContext.AddSource(attributeData.FileName, SourceText.From(attributeData.Text, Encoding.UTF8));
}
private static void GeneratePartialInterfaces(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
{
var context = new Context
{
GeneratorExecutionContext = ctx,
Candidates = receiver.CandidateInterfaces
};
var partialInterfacesGenerator = new PartialInterfacesGenerator(context, supportsNullable);
foreach (var (fileName, text) in partialInterfacesGenerator.GenerateFiles())
{
context.GeneratorExecutionContext.AddSource(fileName, SourceText.From(text, Encoding.UTF8));
}
}
private static void GenerateProxyClasses(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
{
var context = new Context
{
GeneratorExecutionContext = ctx,
Candidates = receiver.CandidateInterfaces
};
var proxyClassesGenerator = new ProxyClassesGenerator(context, supportsNullable);
foreach (var (fileName, text) in proxyClassesGenerator.GenerateFiles())
{
context.GeneratorExecutionContext.AddSource(fileName, SourceText.From(text, Encoding.UTF8));
}
}
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using ProxyInterfaceSourceGenerator.FileGenerators;
using ProxyInterfaceSourceGenerator.Models;
using ProxyInterfaceSourceGenerator.SyntaxReceiver;
namespace ProxyInterfaceSourceGenerator;
[Generator]
#if DEBUG
public
#else
internal
#endif
class ProxyInterfaceCodeGenerator : ISourceGenerator
{
private readonly ExtraFilesGenerator _proxyAttributeGenerator = new();
public void Initialize(GeneratorInitializationContext context)
{
#if DEBUGATTACH
if (!System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Launch();
}
#endif
context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
try
{
if (context.ParseOptions is not CSharpParseOptions csharpParseOptions)
{
throw new NotSupportedException("Only C# is supported.");
}
if (context.SyntaxContextReceiver is not ProxySyntaxReceiver receiver)
{
throw new NotSupportedException($"Only {nameof(ProxySyntaxReceiver)} is supported.");
}
// https://github.com/reactiveui/refit/blob/main/InterfaceStubGenerator.Core/InterfaceStubGenerator.cs
var supportsNullable = csharpParseOptions.LanguageVersion >= LanguageVersion.CSharp8;
GenerateProxyAttribute(context, receiver);
GeneratePartialInterfaces(context, receiver, supportsNullable);
GenerateProxyClasses(context, receiver, supportsNullable);
}
catch (Exception exception)
{
GenerateError(context, exception);
}
}
private void GenerateError(GeneratorExecutionContext context, Exception exception)
{
var message = $"/*\r\n{nameof(ProxyInterfaceCodeGenerator)}\r\n\r\n[Exception]\r\n{exception}\r\n\r\n[StackTrace]\r\n{exception.StackTrace}*/";
context.AddSource("Error.g", SourceText.From(message, Encoding.UTF8));
}
private void GenerateProxyAttribute(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver)
{
var context = new Context
{
GeneratorExecutionContext = ctx,
Candidates = receiver.CandidateInterfaces
};
var attributeData = _proxyAttributeGenerator.GenerateFile();
context.GeneratorExecutionContext.AddSource(attributeData.FileName, SourceText.From(attributeData.Text, Encoding.UTF8));
}
private static void GeneratePartialInterfaces(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
{
var context = new Context
{
GeneratorExecutionContext = ctx,
Candidates = receiver.CandidateInterfaces
};
var partialInterfacesGenerator = new PartialInterfacesGenerator(context, supportsNullable);
foreach (var (fileName, text) in partialInterfacesGenerator.GenerateFiles())
{
context.GeneratorExecutionContext.AddSource(fileName, SourceText.From(text, Encoding.UTF8));
}
}
private static void GenerateProxyClasses(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
{
var context = new Context
{
GeneratorExecutionContext = ctx,
Candidates = receiver.CandidateInterfaces
};
var proxyClassesGenerator = new ProxyClassesGenerator(context, supportsNullable);
foreach (var (fileName, text) in proxyClassesGenerator.GenerateFiles())
{
context.GeneratorExecutionContext.AddSource(fileName, SourceText.From(text, Encoding.UTF8));
}
}
}
@@ -4,19 +4,20 @@
<Version>0.1.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<ProjectGuid>{12344228-91F4-4502-9595-39584E5ABB34}</ProjectGuid>
<LangVersion>10</LangVersion>
<LangVersion>Latest</LangVersion>
<Nullable>enable</Nullable>
<Authors>Stef Heyenrath</Authors>
<Authors>Speckle</Authors>
<Description></Description>
<RootNamespace>Speckle.ProxyGenerator</RootNamespace>
<Title>ProxyInterfaceGenerator</Title>
<PackageId>ProxyInterfaceGenerator</PackageId>
<PackageId>Speckle.ProxyGenerator</PackageId>
<Description>This project uses Source Generation to generate an interface and a Proxy class for classes. This makes it possible to wrap external classes which do not have an interface, in a Proxy class which makes it easier to Mock and use DI.</Description>
<PackageTags>class;interface;proxy;SourceGenerator;Analyzer;Generation;Generate;wrap</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../../PackageReleaseNotes.txt"))</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/StefH/ProxyInterfaceSourceGenerator</PackageProjectUrl>
<PackageProjectUrl>https://github.com/specklesystems/ProxyGenerator</PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/StefH/ProxyInterfaceSourceGenerator</RepositoryUrl>
<RepositoryUrl>https://github.com/specklesystems/ProxyGenerator</RepositoryUrl>
<PackageReadmeFile>PackageReadme.md</PackageReadmeFile>
<PackageIcon>icon.png</PackageIcon>
<IncludeBuildOutput>false</IncludeBuildOutput>
@@ -43,7 +44,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -79,4 +80,4 @@
</AssemblyAttribute>
</ItemGroup>
</Project>
</Project>
@@ -1,86 +1,86 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver;
internal class ProxySyntaxReceiver : ISyntaxContextReceiver
{
private const string GlobalPrefix = "global::";
private static readonly string[] GenerateProxyAttributes = { "ProxyInterfaceGenerator.Proxy", "Proxy" };
private static readonly string[] Modifiers = { "public", "partial" };
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; } = new Dictionary<InterfaceDeclarationSyntax, ProxyData>();
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
var syntaxNode = context.Node;
var semanticModel = context.SemanticModel;
if (syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax && TryGet(interfaceDeclarationSyntax, out var data, semanticModel!))
{
CandidateInterfaces.Add(interfaceDeclarationSyntax, data);
}
}
private static string CreateFullInterfaceName(string ns, BaseTypeDeclarationSyntax classDeclarationSyntax)
{
return !string.IsNullOrEmpty(ns) ? $"{ns}.{classDeclarationSyntax.Identifier}" : classDeclarationSyntax.Identifier.ToString();
}
private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, [NotNullWhen(true)] out ProxyData? data, SemanticModel semanticModel)
{
data = null;
if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Any())
{
// InterfaceDeclarationSyntax should be "public" and "partial"
return false;
}
var attributeList = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => GenerateProxyAttributes.Contains(a.Name.ToString())));
if (attributeList is null)
{
// InterfaceDeclarationSyntax should have the correct attribute
return false;
}
var usings = new List<string>();
string ns = interfaceDeclarationSyntax.GetNamespace();
if (!string.IsNullOrEmpty(ns))
{
usings.Add(ns);
}
if (interfaceDeclarationSyntax.TryGetParentSyntax(out CompilationUnitSyntax? cc))
{
foreach (var @using in cc.Usings)
{
usings.Add(@using.Name.ToString());
}
}
var fluentBuilderAttributeArguments = AttributeArgumentListParser.ParseAttributeArguments(attributeList.Attributes.FirstOrDefault()?.ArgumentList, semanticModel);
var metadataName = fluentBuilderAttributeArguments.MetadataName;
var globalNamespace = string.IsNullOrEmpty(ns) ? string.Empty : $"{GlobalPrefix}{ns}";
var namespaceDot = string.IsNullOrEmpty(ns) ? string.Empty : $"{ns}.";
data = new ProxyData(
@namespace: ns,
namespaceDot: namespaceDot,
shortInterfaceName: interfaceDeclarationSyntax.Identifier.ToString(),
fullInterfaceName: CreateFullInterfaceName(globalNamespace, interfaceDeclarationSyntax), // $"{ns}.{interfaceDeclarationSyntax.Identifier}",
fullQualifiedTypeName: fluentBuilderAttributeArguments.FullyQualifiedDisplayString,
fullMetadataTypeName: metadataName,
shortMetadataTypeName: metadataName.Split('.').Last(),
usings: usings,
proxyBaseClasses: fluentBuilderAttributeArguments.ProxyBaseClasses,
accessibility: fluentBuilderAttributeArguments.Accessibility,
membersToIgnore: fluentBuilderAttributeArguments.MembersToIgnore
);
return true;
}
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver;
internal class ProxySyntaxReceiver : ISyntaxContextReceiver
{
private const string GlobalPrefix = "global::";
private static readonly string[] GenerateProxyAttributes = { "ProxyInterfaceGenerator.Proxy", "Proxy" };
private static readonly string[] Modifiers = { "public", "partial" };
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; } = new Dictionary<InterfaceDeclarationSyntax, ProxyData>();
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
var syntaxNode = context.Node;
var semanticModel = context.SemanticModel;
if (syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax && TryGet(interfaceDeclarationSyntax, out var data, semanticModel!))
{
CandidateInterfaces.Add(interfaceDeclarationSyntax, data);
}
}
private static string CreateFullInterfaceName(string ns, BaseTypeDeclarationSyntax classDeclarationSyntax)
{
return !string.IsNullOrEmpty(ns) ? $"{ns}.{classDeclarationSyntax.Identifier}" : classDeclarationSyntax.Identifier.ToString();
}
private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, [NotNullWhen(true)] out ProxyData? data, SemanticModel semanticModel)
{
data = null;
if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Any())
{
// InterfaceDeclarationSyntax should be "public" and "partial"
return false;
}
var attributeList = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => GenerateProxyAttributes.Contains(a.Name.ToString())));
if (attributeList is null)
{
// InterfaceDeclarationSyntax should have the correct attribute
return false;
}
var usings = new List<string>();
string ns = interfaceDeclarationSyntax.GetNamespace();
if (!string.IsNullOrEmpty(ns))
{
usings.Add(ns);
}
if (interfaceDeclarationSyntax.TryGetParentSyntax(out CompilationUnitSyntax? cc))
{
foreach (var @using in cc.Usings)
{
usings.Add(@using.Name.ToString());
}
}
var fluentBuilderAttributeArguments = AttributeArgumentListParser.ParseAttributeArguments(attributeList.Attributes.FirstOrDefault()?.ArgumentList, semanticModel);
var metadataName = fluentBuilderAttributeArguments.MetadataName;
var globalNamespace = string.IsNullOrEmpty(ns) ? string.Empty : $"{GlobalPrefix}{ns}";
var namespaceDot = string.IsNullOrEmpty(ns) ? string.Empty : $"{ns}.";
data = new ProxyData(
@namespace: ns,
namespaceDot: namespaceDot,
shortInterfaceName: interfaceDeclarationSyntax.Identifier.ToString(),
fullInterfaceName: CreateFullInterfaceName(globalNamespace, interfaceDeclarationSyntax), // $"{ns}.{interfaceDeclarationSyntax.Identifier}",
fullQualifiedTypeName: fluentBuilderAttributeArguments.FullyQualifiedDisplayString,
fullMetadataTypeName: metadataName,
shortMetadataTypeName: metadataName.Split('.').Last(),
usings: usings,
proxyBaseClasses: fluentBuilderAttributeArguments.ProxyBaseClasses,
accessibility: fluentBuilderAttributeArguments.Accessibility,
membersToIgnore: fluentBuilderAttributeArguments.MembersToIgnore
);
return true;
}
}
@@ -1,125 +1,125 @@
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.Utils;
internal static class MemberHelper
{
private static readonly string[] ExcludedMethods = { "ToString", "GetHashCode" };
public static IReadOnlyList<IPropertySymbol> GetPublicProperties(
ClassSymbol classSymbol,
ProxyData proxyData,
params Func<IPropertySymbol, bool>[] filters)
{
var allFilters = new List<Func<IPropertySymbol, bool>>(filters)
{
p => p.Kind == SymbolKind.Property
};
return GetPublicMembers(classSymbol, proxyData, allFilters.ToArray()).ToArray();
}
public static IReadOnlyList<IMethodSymbol> GetPublicMethods(
ClassSymbol classSymbol,
ProxyData proxyData,
Func<IMethodSymbol, bool>? filter = null)
{
filter ??= _ => true;
return
GetPublicMembers(
classSymbol,
proxyData,
m => m.Kind == SymbolKind.Method,
m => m.MethodKind == MethodKind.Ordinary,
m => !ExcludedMethods.Contains(m.Name),
filter)
.ToArray();
}
public static IReadOnlyList<IMethodSymbol> GetPublicStaticOperators(
ClassSymbol classSymbol,
ProxyData proxyData,
Func<IMethodSymbol, bool>? filter = null)
{
filter ??= _ => true;
return
GetPublicMembers(
classSymbol,
proxyData,
m => m.Kind == SymbolKind.Method,
m => m.MethodKind == MethodKind.Conversion,
m => !ExcludedMethods.Contains(m.Name),
filter)
.ToArray();
}
public static IReadOnlyList<IGrouping<ISymbol, IMethodSymbol>> GetPublicEvents(
ClassSymbol classSymbol,
ProxyData proxyData,
Func<IMethodSymbol, bool>? filter = null)
{
filter ??= _ => true;
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
#pragma warning disable RS1024 // Compare symbols correctly
return GetPublicMembers(
classSymbol,
proxyData,
m => m.MethodKind is MethodKind.EventAdd or MethodKind.EventRemove/* || m.MethodKind == MethodKind.EventRaise*/,
filter)
.GroupBy(e => e.AssociatedSymbol)
.ToArray();
#pragma warning restore RS1024 // Compare symbols correctly
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.
}
// TODO : do we need also to check for "SanitizedName()" here?
private static IReadOnlyList<T> GetPublicMembers<T>(
ClassSymbol classSymbol,
ProxyData proxyData,
params Func<T, bool>[] filters
) where T : ISymbol
{
var membersQuery = classSymbol.Symbol.GetMembers().OfType<T>()
.Where(m => m.DeclaredAccessibility == Accessibility.Public);
var f = filters.ToList();
f.Add(x => !proxyData.MembersToIgnore.Contains(x.Name));
foreach (var filter in f)
{
membersQuery = membersQuery.Where(filter);
}
var ownMembers = membersQuery.ToList();
var ownMemberNames = ownMembers.Select(x => x.Name);
if (!proxyData.ProxyBaseClasses)
{
return ownMembers;
}
var allMembers = ownMembers;
var baseType = classSymbol.Symbol.BaseType;
while (baseType != null && baseType.SpecialType != SpecialType.System_Object)
{
var baseMembers = baseType.GetMembers().OfType<T>()
.Where(m => m.DeclaredAccessibility == Accessibility.Public)
.Where(x => !ownMemberNames.Contains(x.Name));
foreach (var filter in filters)
{
baseMembers = baseMembers.Where(filter);
}
allMembers.AddRange(baseMembers);
baseType = baseType.BaseType;
}
return allMembers;
}
using Microsoft.CodeAnalysis;
using ProxyInterfaceSourceGenerator.Models;
namespace ProxyInterfaceSourceGenerator.Utils;
internal static class MemberHelper
{
private static readonly string[] ExcludedMethods = { "ToString", "GetHashCode" };
public static IReadOnlyList<IPropertySymbol> GetPublicProperties(
ClassSymbol classSymbol,
ProxyData proxyData,
params Func<IPropertySymbol, bool>[] filters)
{
var allFilters = new List<Func<IPropertySymbol, bool>>(filters)
{
p => p.Kind == SymbolKind.Property
};
return GetPublicMembers(classSymbol, proxyData, allFilters.ToArray()).ToArray();
}
public static IReadOnlyList<IMethodSymbol> GetPublicMethods(
ClassSymbol classSymbol,
ProxyData proxyData,
Func<IMethodSymbol, bool>? filter = null)
{
filter ??= _ => true;
return
GetPublicMembers(
classSymbol,
proxyData,
m => m.Kind == SymbolKind.Method,
m => m.MethodKind == MethodKind.Ordinary,
m => !ExcludedMethods.Contains(m.Name),
filter)
.ToArray();
}
public static IReadOnlyList<IMethodSymbol> GetPublicStaticOperators(
ClassSymbol classSymbol,
ProxyData proxyData,
Func<IMethodSymbol, bool>? filter = null)
{
filter ??= _ => true;
return
GetPublicMembers(
classSymbol,
proxyData,
m => m.Kind == SymbolKind.Method,
m => m.MethodKind == MethodKind.Conversion,
m => !ExcludedMethods.Contains(m.Name),
filter)
.ToArray();
}
public static IReadOnlyList<IGrouping<ISymbol, IMethodSymbol>> GetPublicEvents(
ClassSymbol classSymbol,
ProxyData proxyData,
Func<IMethodSymbol, bool>? filter = null)
{
filter ??= _ => true;
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
#pragma warning disable RS1024 // Compare symbols correctly
return GetPublicMembers(
classSymbol,
proxyData,
m => m.MethodKind is MethodKind.EventAdd or MethodKind.EventRemove/* || m.MethodKind == MethodKind.EventRaise*/,
filter)
.GroupBy(e => e.AssociatedSymbol)
.ToArray();
#pragma warning restore RS1024 // Compare symbols correctly
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.
}
// TODO : do we need also to check for "SanitizedName()" here?
private static IReadOnlyList<T> GetPublicMembers<T>(
ClassSymbol classSymbol,
ProxyData proxyData,
params Func<T, bool>[] filters
) where T : ISymbol
{
var membersQuery = classSymbol.Symbol.GetMembers().OfType<T>()
.Where(m => m.DeclaredAccessibility == Accessibility.Public);
var f = filters.ToList();
f.Add(x => !proxyData.MembersToIgnore.Contains(x.Name));
foreach (var filter in f)
{
membersQuery = membersQuery.Where(filter);
}
var ownMembers = membersQuery.ToList();
var ownMemberNames = ownMembers.Select(x => x.Name);
if (!proxyData.ProxyBaseClasses)
{
return ownMembers;
}
var allMembers = ownMembers;
var baseType = classSymbol.Symbol.BaseType;
while (baseType != null && baseType.SpecialType != SpecialType.System_Object)
{
var baseMembers = baseType.GetMembers().OfType<T>()
.Where(m => m.DeclaredAccessibility == Accessibility.Public)
.Where(x => !ownMemberNames.Contains(x.Name));
foreach (var filter in filters)
{
baseMembers = baseMembers.Where(filter);
}
allMembers.AddRange(baseMembers);
baseType = baseType.BaseType;
}
return allMembers;
}
}
@@ -32,7 +32,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj" />
<ProjectReference Include="..\..\src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj" />
</ItemGroup>
<ItemGroup>
@@ -69,4 +69,4 @@
</Compile>
</ItemGroup>
</Project>
</Project>
@@ -1,3 +1,5 @@
using System.Diagnostics.CodeAnalysis;
namespace ProxyInterfaceSourceGeneratorTests.Source;
public class Foo
@@ -17,7 +19,8 @@ public class Foo
// return new Foo();
//}
public Foo[] Foos { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public Foo[] Foos { get; set; } = null!;
public Foo[] DoSomethingAndGetAnArrayOfFoos()
{
@@ -28,4 +31,4 @@ public class Foo
//{
// return new[] { new Foo() }.ToList();
//}
}
}
@@ -1,3 +1,5 @@
using System.Diagnostics.CodeAnalysis;
namespace ProxyInterfaceSourceGeneratorTests.Source;
public class Foo2
@@ -17,7 +19,8 @@ public class Foo2
// return new Foo();
//}
public Foo2[] Foos { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public Foo2[] Foos { get; set; }= null!;
public Foo2[] DoSomethingAndGetAnArrayOfFoos()
{
@@ -33,4 +36,4 @@ public class Foo2
//{
// return new[] { new Foo() }.ToList();
//}
}
}
@@ -1,6 +1,9 @@
using System.Diagnostics.CodeAnalysis;
namespace ProxyInterfaceSourceGeneratorTests.Source;
public class MixedVisibility
{
public string Foo { get; protected set; } //<- this will generate bad code
}
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public string Foo { get; protected set; } = null!;//<- this will generate bad code
}
@@ -29,13 +29,15 @@ namespace ProxyInterfaceSourceGeneratorTests.Source
}
[Display(ResourceType = typeof(PeriodicTimer))]
public string Name { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public string Name { get; set; }= null!;
public string? StringNullable { get; set; }
public long? NullableLong { get; }
public object @object { get; set; }
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
public object @object { get; set; }= null!;
public void Void()
{
@@ -131,4 +133,4 @@ namespace ProxyInterfaceSourceGeneratorTests.Source
return true;
}
}
}
}