diff --git a/.gitmodules b/.gitmodules index 760c2b84aeb..8882eb33f2f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,10 +10,6 @@ path = external/debugger-libs url = https://github.com/mono/debugger-libs branch = main -[submodule "external/Java.Interop"] - path = external/Java.Interop - url = https://github.com/dotnet/java-interop - branch = main [submodule "external/libunwind"] path = external/libunwind url = https://github.com/libunwind/libunwind.git @@ -37,3 +33,7 @@ [submodule "external/termux-elf-cleaner"] path = external/termux-elf-cleaner url = https://github.com/termux/termux-elf-cleaner +[submodule "external/Java.Interop/external/xamarin-android-tools"] + path = external/Java.Interop/external/xamarin-android-tools + url = https://github.com/xamarin/xamarin-android-tools.git + branch = main diff --git a/build-tools/automation/azure-pipelines-public.yaml b/build-tools/automation/azure-pipelines-public.yaml index 1d73956a3d7..535abc23b67 100644 --- a/build-tools/automation/azure-pipelines-public.yaml +++ b/build-tools/automation/azure-pipelines-public.yaml @@ -412,6 +412,19 @@ stages: parameters: condition: true +# Java.Interop Tests Stage +- template: /build-tools/automation/yaml-templates/stage-java-interop-tests.yaml@self + parameters: + windowsPool: + name: $(NetCorePublicPoolName) + demands: + - ImageOverride -equals $(WindowsPoolImageNetCorePublic) + macPool: + name: AcesShared + demands: + - ImageOverride -equals ACES_VM_SharedPool_Tahoe + os: macOS + # MAUI Tests Stage - stage: maui_tests displayName: MAUI Tests diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index 3c868ae2d18..7d2d53a1a3e 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -99,6 +99,8 @@ extends: parameters: usesCleanImages: ${{ parameters.macTestAgentsUseCleanImages }} + - template: /build-tools/automation/yaml-templates/stage-java-interop-tests.yaml@self + - stage: maui_tests displayName: MAUI Tests dependsOn: mac_build diff --git a/build-tools/automation/yaml-templates/cache-gradle.yaml b/build-tools/automation/yaml-templates/cache-gradle.yaml index 33a89b5bc8b..b10abce2bf1 100644 --- a/build-tools/automation/yaml-templates/cache-gradle.yaml +++ b/build-tools/automation/yaml-templates/cache-gradle.yaml @@ -9,14 +9,14 @@ parameters: steps: - script: | - git submodule status --cached external/Java.Interop > $(Agent.TempDirectory)/java-interop-submodule-hash.txt + git log -1 --format=%H external/Java.Interop > $(Agent.TempDirectory)/java-interop-submodule-hash.txt echo "##vso[task.setvariable variable=GRADLE_CACHE_DIR]$HOME/.gradle/caches" workingDirectory: ${{ parameters.xaSourcePath }} displayName: prepare Gradle cache variables condition: ne(variables['Agent.OS'], 'Windows_NT') - pwsh: | - git submodule status --cached external/Java.Interop > $(Agent.TempDirectory)/java-interop-submodule-hash.txt + git log -1 --format=%H external/Java.Interop > $(Agent.TempDirectory)/java-interop-submodule-hash.txt $gradleCacheDir = Join-Path $env:USERPROFILE ".gradle\caches" Write-Host "##vso[task.setvariable variable=GRADLE_CACHE_DIR]$gradleCacheDir" workingDirectory: ${{ parameters.xaSourcePath }} diff --git a/build-tools/automation/yaml-templates/stage-java-interop-tests.yaml b/build-tools/automation/yaml-templates/stage-java-interop-tests.yaml new file mode 100644 index 00000000000..05316ca44f9 --- /dev/null +++ b/build-tools/automation/yaml-templates/stage-java-interop-tests.yaml @@ -0,0 +1,107 @@ +# Java.Interop tests stage +# +# Mirrors the two jobs from +# external/Java.Interop/build-tools/automation/azure-pipelines.yaml +# (windows_dotnet_build, mac_dotnet_build) so that the Java.Interop +# build + tests continue to run as part of dotnet/android CI now that +# Java.Interop has been merged in-tree. +# +# Referenced from both: +# - build-tools/automation/azure-pipelines.yaml (official / 1ES) +# - build-tools/automation/azure-pipelines-public.yaml (public PR validation) + +parameters: +- name: stageName + type: string + default: java_interop_tests +- name: dependsOn + type: object + default: [] +- name: condition + type: string + default: succeeded() +- name: windowsPool + type: object + default: + name: Azure Pipelines + vmImage: $(HostedWinImage) +- name: macPool + type: object + default: + name: Azure Pipelines + vmImage: $(HostedMacImage) + +stages: +- stage: ${{ parameters.stageName }} + displayName: Java.Interop Tests + dependsOn: ${{ parameters.dependsOn }} + condition: ${{ parameters.condition }} + variables: + # Variables consumed by external/Java.Interop/build-tools/automation/templates/*.yaml. + # Defined at stage scope so they don't conflict with dotnet/android-wide + # variables (e.g. DotNetTargetFramework=net11.0). + DotNetCoreVersion: $(DotNetSdkVersion).x + DotNetTargetFramework: $(DotNetStableTargetFramework) + NetCoreTargetFrameworkPathSuffix: -$(DotNetStableTargetFramework) + Build.Configuration: Release + RunningOnCI: true + jobs: + + # Check - "Xamarin.Android (Java.Interop Tests Windows - .NET)" + - job: java_interop_windows_dotnet_build + displayName: Windows - .NET + pool: ${{ parameters.windowsPool }} + timeoutInMinutes: 60 + workspace: + clean: all + steps: + - checkout: self + submodules: recursive + clean: true + + - template: /external/Java.Interop/build-tools/automation/templates/install-dependencies.yaml@self + + - template: /external/Java.Interop/build-tools/automation/templates/core-build.yaml@self + + - template: /external/Java.Interop/build-tools/automation/templates/core-tests.yaml@self + parameters: + runNativeDotnetTests: true + nativeAotRid: win-x64 + platformName: .NET - Windows + + - template: /external/Java.Interop/build-tools/automation/templates/fail-on-dirty-tree.yaml@self + + - template: /external/Java.Interop/build-tools/automation/templates/fail-on-issue.yaml@self + + # Check - "Xamarin.Android (Java.Interop Tests Mac - .NET)" + - job: java_interop_mac_dotnet_build + displayName: Mac - .NET + pool: ${{ parameters.macPool }} + timeoutInMinutes: 20 + workspace: + clean: all + steps: + - checkout: self + submodules: recursive + clean: true + + - bash: | + set -e + if ! command -v cmake >/dev/null 2>&1 ; then + brew install cmake + fi + displayName: Ensure cmake is installed + + - template: /external/Java.Interop/build-tools/automation/templates/install-dependencies.yaml@self + + - template: /external/Java.Interop/build-tools/automation/templates/core-build.yaml@self + + - template: /external/Java.Interop/build-tools/automation/templates/core-tests.yaml@self + parameters: + runNativeTests: true + nativeAotRid: osx-arm64 + platformName: .NET - MacOS + + - template: /external/Java.Interop/build-tools/automation/templates/fail-on-dirty-tree.yaml@self + + - template: /external/Java.Interop/build-tools/automation/templates/fail-on-issue.yaml@self diff --git a/build-tools/scripts/XAVersionInfo.targets b/build-tools/scripts/XAVersionInfo.targets index 72cd05dcd46..5e2889a3fc7 100644 --- a/build-tools/scripts/XAVersionInfo.targets +++ b/build-tools/scripts/XAVersionInfo.targets @@ -16,9 +16,8 @@ - <_SubmoduleBranchInfo Include="external/Java.Interop"> - _BuildInfo_JavaInteropCommit - + <_SubmoduleBranchInfo Include="external/xamarin-android-tools"> _BuildInfo_XamarinAndroidToolsCommit diff --git a/external/Java.Interop b/external/Java.Interop deleted file mode 160000 index 6ec1345165f..00000000000 --- a/external/Java.Interop +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ec1345165fa7385c935f16ccaa8cc38be50a080 diff --git a/external/Java.Interop/.devcontainer/devcontainer.json b/external/Java.Interop/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..165213b119b --- /dev/null +++ b/external/Java.Interop/.devcontainer/devcontainer.json @@ -0,0 +1,34 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet +{ + "name": "Linux Universal Image", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/universal:2-linux" + + // Features to add to the dev container. More info: https://containers.dev/features. + , "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "17", + "jdkDistro": "ms" + } + } + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [5000, 5001], + // "portsAttributes": { + // "5001": { + // "protocol": "https" + // } + // } + + // Use 'postCreateCommand' to run commands after the container is created. + // Have GitHub Codespaces checkout all submodules + // https://github.com/orgs/community/discussions/25429 + , "postCreateCommand": "git submodule update --init --recursive" + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/external/Java.Interop/.editorconfig b/external/Java.Interop/.editorconfig new file mode 100644 index 00000000000..fa6269db147 --- /dev/null +++ b/external/Java.Interop/.editorconfig @@ -0,0 +1,500 @@ +############################### +# Core EditorConfig Options # +############################### + +root = true + +# All files +[*] +charset = utf-8 +trim_trailing_whitespace = true + +# MSBuild +[*.{csproj,proj,projitems,shproj,fsproj,targets,props}] +indent_style = space +indent_size = 2 + +# XML config files +[*.{xml,axml,xaml,config,nuspec,resx}] +indent_style = space +indent_size = 2 + +# RESX files +[*.resx] +trim_trailing_whitespace = false + +# JSON files +[*.json] +indent_style = space +indent_size = 2 + +# F# files +[*.{fs, fsx, fsi}] +indent_style = space +indent_size = 4 + +# Code files +[*.{cs,csx,java,vb,vbx}] +insert_final_newline = true +indent_style = tab +tab_width = 8 +indent_size = 8 +max_line_length = 180 + +############################### +# .NET Coding Conventions # +############################### + +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false + +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent + +# Avoid redundant accessibility modifiers when they're default +dotnet_style_require_accessibility_modifiers = omit_if_default:suggestion +dotnet_style_readonly_field = true:suggestion + +# Expression-level preferences +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent + +############################### +# Naming Conventions # +############################### + +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +dotnet_naming_style.underline_separator.word_separator = _ +dotnet_naming_style.underline_separator.capitalization = all_lower + +# Symbol Definitions +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.parameters.applicable_accessibilities = * + +dotnet_naming_symbols.fields.applicable_kinds = field + +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const + +# Use CamelCase for parameters +dotnet_naming_rule.method_parameters_should_be_camel_case.severity = suggestion +dotnet_naming_rule.method_parameters_should_be_camel_case.symbols = parameters +dotnet_naming_rule.method_parameters_should_be_camel_case.style = camel_case + +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style + +# Use underline separator for instance fields +dotnet_naming_rule.fields_should_be_underline_separator.severity = suggestion +dotnet_naming_rule.fields_should_be_underline_separator.symbols = fields +dotnet_naming_rule.fields_should_be_underline_separator.style = underline_separator + + +############################### +# C# Code Style Rules # +############################### + +[*.cs] +# var preferences +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent + +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent + +# Pattern-matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion + +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion + +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion + +############################### +# C# Formatting Rules # +############################### + +# Newline settings +csharp_new_line_before_open_brace = methods,types +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true + +# Indentation preferences +csharp_indent_switch_labels = false +csharp_indent_case_contents = true +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = true +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +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_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = true +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = true +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_before_open_square_brackets = true + +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true + +################################## +# Visual Basic Code Style Rules # +################################## + +[*.vb] +# Modifier preferences +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:suggestion + +################################## +# DevDiv Recommended Analyzers # +################################## + +# Code files +[*.{cs,vb}] + +dotnet_diagnostic.CA2153.severity = error # Do Not Catch Corrupted State Exceptions +dotnet_diagnostic.CA2301.severity = error # Do not call BinaryFormatter.Deserialize without first setting BinaryFormatter.Binder +dotnet_diagnostic.CA2302.severity = error # Ensure BinaryFormatter.Binder is set before calling BinaryFormatter.Deserialize +dotnet_diagnostic.CA2305.severity = error # Do not use insecure deserializer LosFormatter +dotnet_diagnostic.CA2311.severity = error # Do not deserialize without first setting NetDataContractSerializer.Binder +dotnet_diagnostic.CA2312.severity = error # Ensure NetDataContractSerializer.Binder is set before deserializing +dotnet_diagnostic.CA2315.severity = error # Do not use insecure deserializer ObjectStateFormatter +dotnet_diagnostic.CA2321.severity = error # Do not deserialize with JavaScriptSerializer using a SimpleTypeResolver +dotnet_diagnostic.CA2327.severity = error # Do not use insecure JsonSerializerSettings +dotnet_diagnostic.CA2328.severity = error # Ensure that JsonSerializerSettings are secure +dotnet_diagnostic.CA2329.severity = error # Do not deserialize with JsonSerializer using an insecure configuration +dotnet_diagnostic.CA2330.severity = error # Ensure that JsonSerializer has a secure configuration when deserializing +dotnet_diagnostic.CA3061.severity = error # Do Not Add Schema By URL +dotnet_diagnostic.CA3075.severity = error # Insecure DTD processing in XML +dotnet_diagnostic.CA3076.severity = error # Insecure XSLT script processing. +dotnet_diagnostic.CA3077.severity = error # Insecure Processing in API Design, XmlDocument and XmlTextReader +dotnet_diagnostic.CA3147.severity = error # Mark Verb Handlers With Validate Antiforgery Token +dotnet_diagnostic.CA5350.severity = error # Do Not Use Weak Cryptographic Algorithms +dotnet_diagnostic.CA5351.severity = error # Do Not Use Broken Cryptographic Algorithms +dotnet_diagnostic.CA5358.severity = error # Review cipher mode usage with cryptography experts +dotnet_diagnostic.CA5361.severity = error # Do Not Disable SChannel Use of Strong Crypto +dotnet_diagnostic.CA5364.severity = error # Do Not Use Deprecated Security Protocols +dotnet_diagnostic.CA5378.severity = error # Do not disable ServicePointManagerSecurityProtocols +dotnet_diagnostic.CA5397.severity = error # Do not use deprecated SslProtocols values +dotnet_diagnostic.IA5350.severity = error # Do Not Use Weak Cryptographic Algorithms +dotnet_diagnostic.IA5351.severity = error # Do Not Use Broken Cryptographic Algorithms +dotnet_diagnostic.IA5352.severity = error # Do Not Misuse Cryptographic APIs + +dotnet_diagnostic.CA2322.severity = suggestion # Ensure JavaScriptSerializer is not initialized with SimpleTypeResolver before deserializing +dotnet_diagnostic.CA2350.severity = suggestion # Do not use DataTable.ReadXml() with untrusted data +dotnet_diagnostic.CA2351.severity = suggestion # Do not use DataSet.ReadXml() with untrusted data +dotnet_diagnostic.CA2352.severity = suggestion # Unsafe DataSet or DataTable in serializable type can be vulnerable to remote code execution attacks +dotnet_diagnostic.CA2353.severity = suggestion # Unsafe DataSet or DataTable in serializable type +dotnet_diagnostic.CA2354.severity = suggestion # Unsafe DataSet or DataTable in deserialized object graph can be vulnerable to remote code execution attacks +dotnet_diagnostic.CA2355.severity = suggestion # Unsafe DataSet or DataTable type found in deserializable object graph +dotnet_diagnostic.CA2356.severity = suggestion # Unsafe DataSet or DataTable type in web deserializable object graph +dotnet_diagnostic.CA2361.severity = suggestion # Ensure autogenerated class containing DataSet.ReadXml() is not used with untrusted data +dotnet_diagnostic.CA2362.severity = suggestion # Unsafe DataSet or DataTable in autogenerated serializable type can be vulnerable to remote code execution attacks +dotnet_diagnostic.CA3001.severity = suggestion # Review code for SQL injection vulnerabilities +dotnet_diagnostic.CA3002.severity = suggestion # Review code for XSS vulnerabilities +dotnet_diagnostic.CA3003.severity = suggestion # Review code for file path injection vulnerabilities +dotnet_diagnostic.CA3004.severity = suggestion # Review code for information disclosure vulnerabilities +dotnet_diagnostic.CA3005.severity = suggestion # Review code for LDAP injection vulnerabilities +dotnet_diagnostic.CA3006.severity = suggestion # Review code for process command injection vulnerabilities +dotnet_diagnostic.CA3007.severity = suggestion # Review code for open redirect vulnerabilities +dotnet_diagnostic.CA3008.severity = suggestion # Review code for XPath injection vulnerabilities +dotnet_diagnostic.CA3009.severity = suggestion # Review code for XML injection vulnerabilities +dotnet_diagnostic.CA3010.severity = suggestion # Review code for XAML injection vulnerabilities +dotnet_diagnostic.CA3011.severity = suggestion # Review code for DLL injection vulnerabilities +dotnet_diagnostic.CA3012.severity = suggestion # Review code for regex injection vulnerabilities +dotnet_diagnostic.CA5359.severity = suggestion # Do Not Disable Certificate Validation +dotnet_diagnostic.CA5380.severity = suggestion # Do Not Add Certificates To Root Store +dotnet_diagnostic.CA5381.severity = suggestion # Ensure Certificates Are Not Added To Root Store +dotnet_diagnostic.CA5395.severity = suggestion # Miss HttpVerb attribute for action methods +dotnet_diagnostic.CA5396.severity = suggestion # Set HttpOnly to true for HttpCookie +dotnet_diagnostic.CA5398.severity = suggestion # Avoid hardcoded SslProtocols values +dotnet_diagnostic.CA5386.severity = suggestion # Avoid hardcoding SecurityProtocolType value +dotnet_diagnostic.CA5391.severity = suggestion # Use antiforgery tokens in ASP.NET Core MVC controllers +dotnet_diagnostic.IA6450.severity = suggestion # Custom web token handler was found +dotnet_diagnostic.IA6451.severity = suggestion # Implement required validations for app asserted actor token + +# Adding the NetAnalyzers NuGet package automatically starts analyzing code at the default +# severity levels for each rule. We're not ready for that yet, so disable all other rules. + +dotnet_diagnostic.CA2310.severity = none # Do not use insecure deserializer NetDataContractSerializer +dotnet_diagnostic.Async001.severity = none +dotnet_diagnostic.Async002.severity = none +dotnet_diagnostic.Async003.severity = none +dotnet_diagnostic.Async004.severity = none +dotnet_diagnostic.Async005.severity = none +dotnet_diagnostic.Async006.severity = none +dotnet_diagnostic.CA1000.severity = none # Do not declare static members on generic types +dotnet_diagnostic.CA1001.severity = none # Types that own disposable fields should be disposable +dotnet_diagnostic.CA1002.severity = none # Do not expose generic lists +dotnet_diagnostic.CA1003.severity = none # Use generic event handler instances +dotnet_diagnostic.CA1005.severity = none # Avoid excessive parameters on generic types +dotnet_diagnostic.CA1008.severity = none # Enums should have zero value +dotnet_diagnostic.CA1010.severity = none # Generic interface should also be implemented +dotnet_diagnostic.CA1012.severity = none # Abstract types should not have public constructors +dotnet_diagnostic.CA1014.severity = none # Mark assemblies with CLSCompliant +dotnet_diagnostic.CA1016.severity = none # Mark assemblies with assembly version +dotnet_diagnostic.CA1017.severity = none # Mark assemblies with ComVisible +dotnet_diagnostic.CA1018.severity = none # Mark attributes with AttributeUsageAttribute +dotnet_diagnostic.CA1019.severity = none # Define accessors for attribute arguments +dotnet_diagnostic.CA1021.severity = none # Avoid out parameters +dotnet_diagnostic.CA1024.severity = none # Use properties where appropriate +dotnet_diagnostic.CA1027.severity = none # Mark enums with FlagsAttribute +dotnet_diagnostic.CA1028.severity = none # Enum Storage should be Int32 +dotnet_diagnostic.CA1030.severity = none # Use events where appropriate +dotnet_diagnostic.CA1031.severity = none # Do not catch general exception types +dotnet_diagnostic.CA1032.severity = none # Implement standard exception constructors +dotnet_diagnostic.CA1033.severity = none # Interface methods should be callable by child types +dotnet_diagnostic.CA1034.severity = none # Nested types should not be visible +dotnet_diagnostic.CA1036.severity = none # Override methods on comparable types +dotnet_diagnostic.CA1040.severity = none # Avoid empty interfaces +dotnet_diagnostic.CA1041.severity = none # Provide ObsoleteAttribute message +dotnet_diagnostic.CA1043.severity = none # Use Integral Or String Argument For Indexers +dotnet_diagnostic.CA1044.severity = none # Properties should not be write only +dotnet_diagnostic.CA1045.severity = none # Do not pass types by reference +dotnet_diagnostic.CA1046.severity = none # Do not overload equality operator on reference types +dotnet_diagnostic.CA1047.severity = none # Do not declare protected member in sealed type +dotnet_diagnostic.CA1050.severity = none # Declare types in namespaces +dotnet_diagnostic.CA1051.severity = none # Do not declare visible instance fields +dotnet_diagnostic.CA1052.severity = none # Static holder types should be Static or NotInheritable +dotnet_diagnostic.CA1054.severity = none # URI-like parameters should not be strings +dotnet_diagnostic.CA1055.severity = none # URI-like return values should not be strings +dotnet_diagnostic.CA1056.severity = none # URI-like properties should not be strings +dotnet_diagnostic.CA1058.severity = none # Types should not extend certain base types +dotnet_diagnostic.CA1060.severity = none # Move pinvokes to native methods class +dotnet_diagnostic.CA1061.severity = none # Do not hide base class methods +dotnet_diagnostic.CA1062.severity = none # Validate arguments of public methods +dotnet_diagnostic.CA1063.severity = none # Implement IDisposable Correctly +dotnet_diagnostic.CA1064.severity = none # Exceptions should be public +dotnet_diagnostic.CA1065.severity = none # Do not raise exceptions in unexpected locations +dotnet_diagnostic.CA1066.severity = none # Implement IEquatable when overriding Object.Equals +dotnet_diagnostic.CA1067.severity = none # Override Object.Equals(object) when implementing IEquatable<T> +dotnet_diagnostic.CA1068.severity = none # CancellationToken parameters must come last +dotnet_diagnostic.CA1069.severity = none # Enums values should not be duplicated +dotnet_diagnostic.CA1070.severity = none # Do not declare event fields as virtual +dotnet_diagnostic.CA1200.severity = none # Avoid using cref tags with a prefix +dotnet_diagnostic.CA1303.severity = none # Do not pass literals as localized parameters +dotnet_diagnostic.CA1304.severity = none # Specify CultureInfo +dotnet_diagnostic.CA1305.severity = none # Specify IFormatProvider +#dotnet_diagnostic.CA1307.severity = none # Specify StringComparison - Controlled via Directory.Build.props +dotnet_diagnostic.CA1308.severity = none # Normalize strings to uppercase +#dotnet_diagnostic.CA1309.severity = none # Use ordinal stringcomparison - Controlled via Directory.Build.props +dotnet_diagnostic.CA1401.severity = none # P/Invokes should not be visible +dotnet_diagnostic.CA1417.severity = none # Do not use 'OutAttribute' on string parameters for P/Invokes +dotnet_diagnostic.CA1501.severity = none # Avoid excessive inheritance +dotnet_diagnostic.CA1502.severity = none # Avoid excessive complexity +dotnet_diagnostic.CA1505.severity = none # Avoid unmaintainable code +dotnet_diagnostic.CA1506.severity = none # Avoid excessive class coupling +dotnet_diagnostic.CA1507.severity = none # Use nameof to express symbol names +dotnet_diagnostic.CA1508.severity = none # Avoid dead conditional code +dotnet_diagnostic.CA1509.severity = none # Invalid entry in code metrics rule specification file +dotnet_diagnostic.CA1700.severity = none # Do not name enum values 'Reserved' +dotnet_diagnostic.CA1707.severity = none # Identifiers should not contain underscores +dotnet_diagnostic.CA1708.severity = none # Identifiers should differ by more than case +dotnet_diagnostic.CA1710.severity = none # Identifiers should have correct suffix +dotnet_diagnostic.CA1711.severity = none # Identifiers should not have incorrect suffix +dotnet_diagnostic.CA1712.severity = none # Do not prefix enum values with type name +dotnet_diagnostic.CA1713.severity = none # Events should not have 'Before' or 'After' prefix +dotnet_diagnostic.CA1714.severity = none # Flags enums should have plural names +dotnet_diagnostic.CA1715.severity = none # Identifiers should have correct prefix +dotnet_diagnostic.CA1716.severity = none # Identifiers should not match keywords +dotnet_diagnostic.CA1717.severity = none # Only FlagsAttribute enums should have plural names +dotnet_diagnostic.CA1720.severity = none # Identifier contains type name +dotnet_diagnostic.CA1721.severity = none # Property names should not match get methods +dotnet_diagnostic.CA1724.severity = none # Type names should not match namespaces +dotnet_diagnostic.CA1725.severity = none # Parameter names should match base declaration +dotnet_diagnostic.CA1801.severity = none # Review unused parameters +dotnet_diagnostic.CA1802.severity = none # Use literals where appropriate +dotnet_diagnostic.CA1805.severity = none # Do not initialize unnecessarily +dotnet_diagnostic.CA1806.severity = none # Do not ignore method results +dotnet_diagnostic.CA1810.severity = none # Initialize reference type static fields inline +dotnet_diagnostic.CA1812.severity = none # Avoid uninstantiated internal classes +dotnet_diagnostic.CA1813.severity = none # Avoid unsealed attributes +dotnet_diagnostic.CA1814.severity = none # Prefer jagged arrays over multidimensional +dotnet_diagnostic.CA1815.severity = none # Override equals and operator equals on value types +dotnet_diagnostic.CA1816.severity = none # Dispose methods should call SuppressFinalize +dotnet_diagnostic.CA1819.severity = none # Properties should not return arrays +dotnet_diagnostic.CA1820.severity = none # Test for empty strings using string length +dotnet_diagnostic.CA1821.severity = none # Remove empty Finalizers +dotnet_diagnostic.CA1822.severity = none # Mark members as static +dotnet_diagnostic.CA1823.severity = none # Avoid unused private fields +dotnet_diagnostic.CA1824.severity = none # Mark assemblies with NeutralResourcesLanguageAttribute +dotnet_diagnostic.CA1825.severity = none # Avoid zero-length array allocations +dotnet_diagnostic.CA1826.severity = none # Do not use Enumerable methods on indexable collections +dotnet_diagnostic.CA1827.severity = none # Do not use Count() or LongCount() when Any() can be used +dotnet_diagnostic.CA1828.severity = none # Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used +dotnet_diagnostic.CA1829.severity = none # Use Length/Count property instead of Count() when available +dotnet_diagnostic.CA1830.severity = none # Prefer strongly-typed Append and Insert method overloads on StringBuilder +dotnet_diagnostic.CA1831.severity = none # Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1832.severity = none # Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1833.severity = none # Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1834.severity = none # Consider using 'StringBuilder.Append(char)' when applicable +dotnet_diagnostic.CA1835.severity = none # Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' +dotnet_diagnostic.CA1836.severity = none # Prefer IsEmpty over Count +dotnet_diagnostic.CA1837.severity = none # Use 'Environment.ProcessId' +dotnet_diagnostic.CA1838.severity = none # Avoid 'StringBuilder' parameters for P/Invokes +dotnet_diagnostic.CA2000.severity = none # Dispose objects before losing scope +dotnet_diagnostic.CA2002.severity = none # Do not lock on objects with weak identity +dotnet_diagnostic.CA2007.severity = none # Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2008.severity = none # Do not create tasks without passing a TaskScheduler +dotnet_diagnostic.CA2009.severity = none # Do not call ToImmutableCollection on an ImmutableCollection value +dotnet_diagnostic.CA2010.severity = none +dotnet_diagnostic.CA2011.severity = none # Avoid infinite recursion +dotnet_diagnostic.CA2012.severity = none # Use ValueTasks correctly +dotnet_diagnostic.CA2013.severity = none # Do not use ReferenceEquals with value types +dotnet_diagnostic.CA2014.severity = none # Do not use stackalloc in loops +dotnet_diagnostic.CA2015.severity = none # Do not define finalizers for types derived from MemoryManager<T> +dotnet_diagnostic.CA2016.severity = none # Forward the 'CancellationToken' parameter to methods that take one +dotnet_diagnostic.CA2100.severity = none # Review SQL queries for security vulnerabilities +dotnet_diagnostic.CA2101.severity = none # Specify marshaling for P/Invoke string arguments +dotnet_diagnostic.CA2109.severity = none # Review visible event handlers +dotnet_diagnostic.CA2119.severity = none # Seal methods that satisfy private interfaces +dotnet_diagnostic.CA2200.severity = none # Rethrow to preserve stack details +dotnet_diagnostic.CA2201.severity = none # Do not raise reserved exception types +dotnet_diagnostic.CA2207.severity = none # Initialize value type static fields inline +dotnet_diagnostic.CA2208.severity = none # Instantiate argument exceptions correctly +dotnet_diagnostic.CA2211.severity = none # Non-constant fields should not be visible +dotnet_diagnostic.CA2213.severity = none # Disposable fields should be disposed +dotnet_diagnostic.CA2214.severity = none # Do not call overridable methods in constructors +dotnet_diagnostic.CA2215.severity = none # Dispose methods should call base class dispose +dotnet_diagnostic.CA2216.severity = none # Disposable types should declare finalizer +dotnet_diagnostic.CA2217.severity = none # Do not mark enums with FlagsAttribute +dotnet_diagnostic.CA2218.severity = none # Override GetHashCode on overriding Equals +dotnet_diagnostic.CA2219.severity = none # Do not raise exceptions in finally clauses +dotnet_diagnostic.CA2224.severity = none # Override Equals on overloading operator equals +dotnet_diagnostic.CA2225.severity = none # Operator overloads have named alternates +dotnet_diagnostic.CA2226.severity = none # Operators should have symmetrical overloads +dotnet_diagnostic.CA2227.severity = none # Collection properties should be read only +dotnet_diagnostic.CA2229.severity = none # Implement serialization constructors +dotnet_diagnostic.CA2231.severity = none # Overload operator equals on overriding value type Equals +dotnet_diagnostic.CA2234.severity = none # Pass system uri objects instead of strings +dotnet_diagnostic.CA2235.severity = none # Mark all non-serializable fields +dotnet_diagnostic.CA2237.severity = none # Mark ISerializable types with serializable +dotnet_diagnostic.CA2241.severity = none # Provide correct arguments to formatting methods +dotnet_diagnostic.CA2242.severity = none # Test for NaN correctly +dotnet_diagnostic.CA2243.severity = none # Attribute string literals should parse correctly +dotnet_diagnostic.CA2244.severity = none # Do not duplicate indexed element initializations +dotnet_diagnostic.CA2245.severity = none # Do not assign a property to itself +dotnet_diagnostic.CA2246.severity = none # Assigning symbol and its member in the same statement +dotnet_diagnostic.CA2247.severity = none # Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum instead of TaskContinuationOptions enum +dotnet_diagnostic.CA2248.severity = none # Provide correct 'enum' argument to 'Enum.HasFlag' +dotnet_diagnostic.CA2249.severity = none # Consider using 'string.Contains' instead of 'string.IndexOf' +dotnet_diagnostic.CA2300.severity = none # Do not use insecure deserializer BinaryFormatter +dotnet_diagnostic.CA2326.severity = none # Do not use TypeNameHandling values other than None +dotnet_diagnostic.CA5360.severity = none # Do Not Call Dangerous Methods In Deserialization +dotnet_diagnostic.CA5362.severity = none # Potential reference cycle in deserialized object graph +dotnet_diagnostic.CA5363.severity = none # Do Not Disable Request Validation +dotnet_diagnostic.CA5365.severity = none # Do Not Disable HTTP Header Checking +dotnet_diagnostic.CA5366.severity = none # Use XmlReader For DataSet Read Xml +dotnet_diagnostic.CA5367.severity = none # Do Not Serialize Types With Pointer Fields +dotnet_diagnostic.CA5368.severity = none # Set ViewStateUserKey For Classes Derived From Page +dotnet_diagnostic.CA5369.severity = none # Use XmlReader For Deserialize +dotnet_diagnostic.CA5370.severity = none # Use XmlReader For Validating Reader +dotnet_diagnostic.CA5371.severity = none # Use XmlReader For Schema Read +dotnet_diagnostic.CA5372.severity = none # Use XmlReader For XPathDocument +dotnet_diagnostic.CA5373.severity = none # Do not use obsolete key derivation function +dotnet_diagnostic.CA5374.severity = none # Do Not Use XslTransform +dotnet_diagnostic.CA5375.severity = none # Do Not Use Account Shared Access Signature +dotnet_diagnostic.CA5376.severity = none # Use SharedAccessProtocol HttpsOnly +dotnet_diagnostic.CA5377.severity = none # Use Container Level Access Policy +dotnet_diagnostic.CA5379.severity = none # Do Not Use Weak Key Derivation Function Algorithm +dotnet_diagnostic.CA5382.severity = none # Use Secure Cookies In ASP.Net Core +dotnet_diagnostic.CA5383.severity = none # Ensure Use Secure Cookies In ASP.Net Core +dotnet_diagnostic.CA5384.severity = none # Do Not Use Digital Signature Algorithm (DSA) +dotnet_diagnostic.CA5385.severity = none # Use Rivest–Shamir–Adleman (RSA) Algorithm With Sufficient Key Size +dotnet_diagnostic.CA5387.severity = none # Do Not Use Weak Key Derivation Function With Insufficient Iteration Count +dotnet_diagnostic.CA5388.severity = none # Ensure Sufficient Iteration Count When Using Weak Key Derivation Function +dotnet_diagnostic.CA5389.severity = none # Do Not Add Archive Item's Path To The Target File System Path +dotnet_diagnostic.CA5390.severity = none # Do not hard-code encryption key +dotnet_diagnostic.CA5392.severity = none # Use DefaultDllImportSearchPaths attribute for P/Invokes +dotnet_diagnostic.CA5393.severity = none # Do not use unsafe DllImportSearchPath value +dotnet_diagnostic.CA5394.severity = none # Do not use insecure randomness +dotnet_diagnostic.CA5399.severity = none # HttpClients should enable certificate revocation list checks +dotnet_diagnostic.CA5400.severity = none # Ensure HttpClient certificate revocation list check is not disabled +dotnet_diagnostic.CA5401.severity = none # Do not use CreateEncryptor with non-default IV +dotnet_diagnostic.CA5402.severity = none # Use CreateEncryptor with the default IV +dotnet_diagnostic.CA5403.severity = none # Do not hard-code certificate +dotnet_diagnostic.CA9999.severity = none # Analyzer version mismatch +dotnet_diagnostic.IA2989.severity = none # Do not use banned insecure deserialization APIs +dotnet_diagnostic.IA2992.severity = none # Do Not Use Banned APIs For Insecure Deserializers +dotnet_diagnostic.IA2993.severity = none # Do Not Use Banned Constructors For Insecure Deserializers +dotnet_diagnostic.IA2994.severity = none # Do Not Use ResourceSet Without ResourceReader +dotnet_diagnostic.IA2995.severity = none # Do Not Use ResourceReader +dotnet_diagnostic.IA2996.severity = none # Do Not Use ResXResourceReader Without ITypeResolutionService +dotnet_diagnostic.IA2997.severity = none # Do Not Use TypeNameHandling Other Than None +dotnet_diagnostic.IA2998.severity = none # Do Not Deserialize With BinaryFormatter Without Binder +dotnet_diagnostic.IA2999.severity = none # Do Not Set BinaryFormatter.Binder to null +dotnet_diagnostic.IA5359.severity = none # Use approved crypto libraries for the supported platform +dotnet_diagnostic.IL3000.severity = none # Avoid using accessing Assembly file path when publishing as a single-file +dotnet_diagnostic.IL3001.severity = none # Avoid using accessing Assembly file path when publishing as a single-file +dotnet_diagnostic.RS1000.severity = none +dotnet_diagnostic.RS1001.severity = none +dotnet_diagnostic.RS1002.severity = none +dotnet_diagnostic.RS1003.severity = none +dotnet_diagnostic.RS1004.severity = none +dotnet_diagnostic.RS1005.severity = none +dotnet_diagnostic.RS1006.severity = none +dotnet_diagnostic.RS1007.severity = none +dotnet_diagnostic.RS1008.severity = none +dotnet_diagnostic.RS1009.severity = none +dotnet_diagnostic.RS1010.severity = none +dotnet_diagnostic.RS1011.severity = none +dotnet_diagnostic.RS1012.severity = none +dotnet_diagnostic.RS1013.severity = none +dotnet_diagnostic.RS1014.severity = none diff --git a/external/Java.Interop/.gitattributes b/external/Java.Interop/.gitattributes new file mode 100644 index 00000000000..02cae14c35b --- /dev/null +++ b/external/Java.Interop/.gitattributes @@ -0,0 +1,45 @@ +# NOTE: this file is for git 1.6.6 (and possibly older) +# Post-1.7.2 there is eol and text, and crlf is deprecated +# but we can't depend on an unreleased version... + +# This file mainly controls line ending conversion behaviour, if +# the user has the setting core.autocrlf true. + +# The meaning of the attributes is a little odd +# -crlf means DO NOT convert line endings +# crlf means CONVERT to lf in the repo & Linux/Mac, crlf on Windows + +# sln is always CRLF, even on linux, so don't convert +*.sln eol=crlf +*.bat eol=crlf +*.cmd eol=crlf +*.rtf eol=crlf + +# Mostly generated by VS, so avoid extra noise +*.Designer.cs eol=crlf + +*.cs text +*.resx text +*.xlf text +*.xml text +*.md text +Makefile eol=lf +*.targets eol=crlf +*.proj eol=crlf +*.vcproj eol=crlf +*.vcxproj eol=crlf +*.csproj eol=crlf +*.shproj eol=crlf +*.projitems eol=crlf +*.tpnitems eol=crlf +*.wixproj eol=crlf +*.wxs eol=crlf +*.rtf eol=crlf + +# Gradle wrapper must stay LF on all platforms (executed under Bash on Unix) +gradlew eol=lf +*.properties eol=lf +*.kt eol=lf +*.kts eol=lf + +.github/workflows/*.lock.yml linguist-generated=true merge=ours \ No newline at end of file diff --git a/external/Java.Interop/.github/agents/agentic-workflows.md b/external/Java.Interop/.github/agents/agentic-workflows.md new file mode 100644 index 00000000000..9a2e0130e84 --- /dev/null +++ b/external/Java.Interop/.github/agents/agentic-workflows.md @@ -0,0 +1,224 @@ +--- +name: Agentic Workflows +description: GitHub Agentic Workflows (gh-aw) - Create, debug, and upgrade AI-powered workflows with intelligent prompt routing. +disable-model-invocation: true +--- + +# GitHub Agentic Workflows Agent + +This agent helps you work with **GitHub Agentic Workflows (gh-aw)**, a CLI extension for creating AI-powered workflows in natural language using markdown files. + +## What This Agent Does + +This is a **dispatcher agent** that routes your request to the appropriate specialized prompt based on your task: + +- **Creating new workflows**: Routes to `create` prompt +- **Updating existing workflows**: Routes to `update` prompt +- **Debugging workflows**: Routes to `debug` prompt +- **Upgrading workflows**: Routes to `upgrade-agentic-workflows` prompt +- **Creating report-generating workflows**: Routes to `report` prompt — consult this whenever the workflow posts status updates, audits, analyses, or any structured output as issues, discussions, or comments +- **Creating shared components**: Routes to `create-shared-agentic-workflow` prompt +- **Fixing Dependabot PRs**: Routes to `dependabot` prompt — use this when Dependabot opens PRs that modify generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`). Never merge those PRs directly; instead update the source `.md` files and rerun `gh aw compile --dependabot` to bundle all fixes +- **Analyzing test coverage**: Routes to `test-coverage` prompt — consult this whenever the workflow reads, analyzes, or reports on test coverage data from PRs or CI runs +- **Rendering ASCII charts in markdown**: Routes to `asciicharts` guide — consult this whenever the workflow needs compact charts that render reliably in GitHub issues, comments, or discussions +- **CLI commands and triggering workflows**: Routes to `cli-commands` guide — consult this whenever the user asks how to run, compile, debug, or manage workflows from the command line, or when they need the MCP tool equivalent of a `gh aw` command +- **Reducing token consumption / cost optimization**: Routes to `token-optimization` guide — consult this whenever the user asks how to reduce token usage, lower costs, speed up workflows, or measure the impact of prompt changes with experiments +- **Choosing workflow architectures and design patterns**: Routes to `patterns` guide — consult this whenever the user asks for strategy, architecture, operating models, or pattern selection for agentic workflows + +Workflows may optionally include: + +- **Project tracking / monitoring** (GitHub Projects updates, status reporting) +- **Orchestration / coordination** (one workflow assigning agents or dispatching and coordinating other workflows) + +## Files This Applies To + +- Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` +- Workflow lock files: `.github/workflows/*.lock.yml` +- Shared components: `.github/workflows/shared/*.md` +- Configuration: `.github/aw/github-agentic-workflows.md` + +## Problems This Solves + +- **Workflow Creation**: Design secure, validated agentic workflows with proper triggers, tools, and permissions +- **Workflow Debugging**: Analyze logs, identify missing tools, investigate failures, and fix configuration issues +- **Version Upgrades**: Migrate workflows to new gh-aw versions, apply codemods, fix breaking changes +- **Component Design**: Create reusable shared workflow components that wrap MCP servers + +## How to Use + +When you interact with this agent, it will: + +1. **Understand your intent** - Determine what kind of task you're trying to accomplish +2. **Route to the right prompt** - Load the specialized prompt file for your task +3. **Execute the task** - Follow the detailed instructions in the loaded prompt + +## Available Prompts + +### Create New Workflow +**Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet + +**Prompt file**: `.github/aw/create-agentic-workflow.md` + +**Use cases**: +- "Create a workflow that triages issues" +- "I need a workflow to label pull requests" +- "Design a weekly research automation" + +### Update Existing Workflow +**Load when**: User wants to modify, improve, or refactor an existing workflow + +**Prompt file**: `.github/aw/update-agentic-workflow.md` + +**Use cases**: +- "Add web-fetch tool to the issue-classifier workflow" +- "Update the PR reviewer to use discussions instead of issues" +- "Improve the prompt for the weekly-research workflow" + +### Debug Workflow +**Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors + +**Prompt file**: `.github/aw/debug-agentic-workflow.md` + +**Use cases**: +- "Why is this workflow failing?" +- "Analyze the logs for workflow X" +- "Investigate missing tool calls in run #12345" + +### Upgrade Agentic Workflows +**Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations + +**Prompt file**: `.github/aw/upgrade-agentic-workflows.md` + +**Use cases**: +- "Upgrade all workflows to the latest version" +- "Fix deprecated fields in workflows" +- "Apply breaking changes from the new release" + +### Create a Report-Generating Workflow +**Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment + +**Prompt file**: `.github/aw/report.md` + +**Use cases**: +- "Create a weekly CI health report" +- "Post a daily security audit to Discussions" +- "Add a status update comment to open PRs" + +### Create Shared Agentic Workflow +**Load when**: User wants to create a reusable workflow component or wrap an MCP server + +**Prompt file**: `.github/aw/create-shared-agentic-workflow.md` + +**Use cases**: +- "Create a shared component for Notion integration" +- "Wrap the Slack MCP server as a reusable component" +- "Design a shared workflow for database queries" + +### Fix Dependabot PRs +**Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) + +**Prompt file**: `.github/aw/dependabot.md` + +**Use cases**: +- "Fix the open Dependabot PRs for npm dependencies" +- "Bundle and close the Dependabot PRs for workflow dependencies" +- "Update @playwright/test to fix the Dependabot PR" + +### Analyze Test Coverage +**Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. + +**Prompt file**: `.github/aw/test-coverage.md` + +**Use cases**: +- "Create a workflow that comments coverage on PRs" +- "Analyze coverage trends over time" +- "Add a coverage gate that blocks PRs below a threshold" + +### CLI Commands Reference +**Load when**: The user asks how to run, compile, debug, or manage workflows from the command line; needs the MCP tool equivalent of a `gh aw` command; or is in a restricted environment (e.g., Copilot Cloud) without direct CLI access. + +**Reference file**: `.github/aw/cli-commands.md` + +**Use cases**: +- "How do I trigger workflow X on the main branch?" +- "What's the MCP equivalent of `gh aw logs`?" +- "I'm in Copilot Cloud — how do I compile a workflow?" +- "Show me all available gh aw commands" + +### Token Consumption Optimization +**Load when**: The user asks how to reduce token usage, lower workflow costs, make a workflow faster or cheaper, or measure the impact of prompt or configuration changes. + +**Reference file**: `.github/aw/token-optimization.md` + +**Use cases**: +- "How do I reduce the token cost of this workflow?" +- "My workflow is too expensive — how do I optimize it?" +- "How do I compare token usage between two runs?" +- "Should I use gh-proxy or the MCP server?" +- "How do I use sub-agents to reduce costs?" +- "How do I measure the impact of a prompt change?" + +### Workflow Pattern Selection +**Load when**: The user asks for architecture, strategy, operating model selection, or pattern recommendations for building agentic workflows. + +**Reference file**: `.github/aw/patterns.md` + +**Use cases**: +- "Which pattern should I use for multi-repo rollout?" +- "How should I structure this workflow architecture?" +- "What pattern fits slash-command triage?" +- "Should this be DispatchOps or DailyOps?" + +## Instructions + +When a user interacts with you: + +1. **Identify the task type** from the user's request +2. **Load the appropriate prompt** from the repository paths listed above +3. **Follow the loaded prompt's instructions** exactly +4. **If uncertain**, ask clarifying questions to determine the right prompt + +## Quick Reference + +```bash +# Initialize repository for agentic workflows +gh aw init + +# Generate the lock file for a workflow +gh aw compile [workflow-name] + +# Trigger a workflow on demand (preferred over gh workflow run) +gh aw run # interactive input collection +gh aw run --ref main # run on a specific branch + +# Debug workflow runs +gh aw logs [workflow-name] +gh aw audit + +# Upgrade workflows +gh aw fix --write +gh aw compile --validate +``` + +## Key Features of gh-aw + +- **Natural Language Workflows**: Write workflows in markdown with YAML frontmatter +- **AI Engine Support**: Copilot, Claude, Codex, or custom engines +- **MCP Server Integration**: Connect to Model Context Protocol servers for tools +- **Safe Outputs**: Structured communication between AI and GitHub API +- **Strict Mode**: Security-first validation and sandboxing +- **Shared Components**: Reusable workflow building blocks +- **Repo Memory**: Persistent git-backed storage for agents +- **Sandboxed Execution**: All workflows run in the Agent Workflow Firewall (AWF) sandbox, enabling full `bash` and `edit` tools by default + +## Important Notes + +- Always reference the instructions file at `.github/aw/github-agentic-workflows.md` for complete documentation +- Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud +- Workflows must be compiled to `.lock.yml` files before running in GitHub Actions +- **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF +- Follow security best practices: minimal permissions, explicit network access, no template injection +- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See `.github/aw/network.md` for the full list of valid ecosystem identifiers and domain patterns. +- **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself. +- **Triggering runs**: Always use `gh aw run ` to trigger a workflow on demand — not `gh workflow run .lock.yml`. `gh aw run` handles workflow resolution by short name, input parsing and validation, and correct run-tracking for agentic workflows. Use `--ref ` to run on a specific branch. +- **CLI commands reference**: For a complete guide on all `gh aw` commands and their MCP tool equivalents (for restricted environments), see `.github/aw/cli-commands.md` diff --git a/external/Java.Interop/.github/aw/actions-lock.json b/external/Java.Interop/.github/aw/actions-lock.json new file mode 100644 index 00000000000..84e3231b543 --- /dev/null +++ b/external/Java.Interop/.github/aw/actions-lock.json @@ -0,0 +1,19 @@ +{ + "entries": { + "actions/github-script@v9.0.0": { + "repo": "actions/github-script", + "version": "v9.0.0", + "sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3" + }, + "github/gh-aw-actions/setup-cli@v0.79.8": { + "repo": "github/gh-aw-actions/setup-cli", + "version": "v0.79.8", + "sha": "c0338fef4749d08c21f8f975fb0e37efa17dda47" + }, + "github/gh-aw-actions/setup@v0.79.8": { + "repo": "github/gh-aw-actions/setup", + "version": "v0.79.8", + "sha": "c0338fef4749d08c21f8f975fb0e37efa17dda47" + } + } +} diff --git a/external/Java.Interop/.github/copilot-instructions.md b/external/Java.Interop/.github/copilot-instructions.md new file mode 100644 index 00000000000..4109925d133 --- /dev/null +++ b/external/Java.Interop/.github/copilot-instructions.md @@ -0,0 +1,156 @@ +# Java.Interop Copilot Instructions + +## Project Overview + +**Java.Interop** is a .NET library that provides Java Native Interface (JNI) bindings for managed languages such as C#. It enables bidirectional interoperability between .NET's Common Language Runtime (CLR) and Java Virtual Machines (JVMs), allowing .NET code to invoke Java methods and Java code to call back into managed code. + +**Primary Use Cases**: +- .NET for Android development (successor to Xamarin.Android) +- Desktop Java interop scenarios +- Binding Java libraries for .NET consumption +- Cross-platform Java integration + +## Architecture & Core Concepts + +### JNI (Java Native Interface) +- Industry-standard interface for Java-native code interaction +- Provides type-safe bindings using structs like `JniObjectReference` instead of raw `IntPtr` +- Supports both SafeHandle-based (safer) and IntPtr-based (faster) implementations +- Reference types: Local, Global, and WeakGlobal references with proper lifecycle management + +### Type System & Marshaling +- **JavaObject**: Base class for managed wrappers of Java objects +- **JniPeerMembers**: Caches method and field IDs for efficient access +- **Value Marshaling**: Converts between Java and .NET types (e.g., `java.lang.String` ↔ `System.String`) +- **Exception Marshaling**: Translates Java exceptions to .NET exceptions + +### Code Generation Pipeline +1. **API Description**: XML files describing Java APIs +2. **Generator Tool**: Converts API descriptions to C# binding code +3. **Java Callable Wrappers (JCWs)**: Java stubs for calling managed methods +4. **Marshal Methods**: Runtime-generated or pre-compiled bridging code + +## Repository Structure + +### Core Libraries (`src/`) +- **`Java.Interop/`**: Main JNI binding library with core types and runtime +- **`Java.Interop.Export/`**: `[Export]` attribute support for exposing managed methods to Java + +### Code Generation Tools (`tools/`) +- **`generator/`**: Primary tool for generating C# bindings from Java API descriptions +- **`class-parse/`**: Parses Java `.class` files and generates API descriptions +- **`java-source-utils/`**: Utilities for processing Java source code +- **`jcw-gen/`**: Generates Java Callable Wrapper classes +- **`param-name-importer/`**: Imports parameter names from Java source + +### Supporting Libraries +- **`Java.Interop.Tools.JavaSource/`**: Javadoc parsing and XML documentation conversion +- **`Java.Interop.Tools.Maven/`**: Maven project integration and dependency resolution +- **`Xamarin.Android.Tools.Bytecode/`**: Java bytecode analysis and processing +- **`Xamarin.SourceWriter/`**: Code generation utilities + +### Testing (`tests/`) +- Unit tests for the core JNI binding and code-generation components +- Integration tests with real JVM instances where needed +- Generator tests with sample API descriptions + +### Samples (`samples/`) +- **`Hello-NativeAOT*/`**: Ahead-of-time compilation scenarios + +## Development Patterns & Conventions + +### Code Formatting + +C# code uses tabs (not spaces) and the Mono code-formatting style defined in `.editorconfig` + +* Your mission is to make diffs as absolutely as small as possible, preserving existing code formatting. + +* If you encounter additional spaces or formatting within existing code blocks, LEAVE THEM AS-IS. + +* If you encounter code comments, LEAVE THEM AS-IS. + +* Place a space prior to any parentheses `(` or `[` + +* Use `""` for empty string and *not* `string.Empty` + +* Use `[]` for empty arrays and *not* `Array.Empty()` + +Examples of properly formatted code: + +```csharp +Foo (); +Bar (1, 2, "test"); +myarray [0] = 1; + +if (someValue) { + // Code here +} + +try { + // Code here +} catch (Exception e) { + // Code here +} +``` + +### Code Comments +- Use XML documentation comments (`///`) for public APIs +- Document JNI interop behavior and threading requirements +- Include usage examples for complex scenarios + +### Error Handling +- Java exceptions are automatically converted to .NET exceptions +- Use `JniEnvironment.Errors.ExceptionOccurred()` for manual exception checking +- Wrap JNI calls in `try`/`finally` blocks for proper resource cleanup + +### Memory Management +- Local references: Automatically cleaned up by JVM +- Global references: Must be explicitly freed via `JniObjectReference.Dispose()` +- Use `using` statements or `try`/`finally` for proper cleanup + +### Threading +- JNI environments are thread-local +- Use `JniEnvironment.Current` to access the current thread's JNI environment +- Java objects can be shared across threads with proper reference management + +## Build System + +### Prerequisites +- .NET 9+ SDK +- Java Development Kit (for compiling Java test classes) +- Platform-specific JVM libraries + +### Build Commands +```bash +# Initialize submodules and prepare build +dotnet build -t:Prepare + +# Build all projects +dotnet build + +# Run specific tests +dotnet test tests/Java.Interop.Tools.Generator-Tests/Java.Interop.Tools.Generator-Tests.csproj + +# Build with specific configuration +dotnet build -c Release +``` + +### Configuration +- Use `Configuration.Override.props` for local build customization +- Set `$(JdkJvmPath)` to specify JVM library location +- Configure `$(JAVA_HOME)` for Java tooling + +## Useful Resources + +- [JNI Specification](http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html) +- [.NET for Android Documentation](https://learn.microsoft.com/en-us/dotnet/android/) +- [Android JNI Performance Guide](https://developer.android.com/training/articles/perf-jni) +- [Project Architecture Documentation](Documentation/Architecture.md) +- [Build Configuration Guide](Documentation/BuildConfiguration.md) + +## Getting Help + +- Review existing tests for usage patterns +- Check [GitHub Issues](https://github.com/dotnet/java-interop/issues) for known problems +- Consult the [.NET Discord](https://aka.ms/dotnet-discord) for community support +- Follow [Coding Guidelines](http://www.mono-project.com/community/contributing/coding-guidelines/) for contributions \ No newline at end of file diff --git a/external/Java.Interop/.github/skills/agentic-workflows/SKILL.md b/external/Java.Interop/.github/skills/agentic-workflows/SKILL.md new file mode 100644 index 00000000000..b4505045ca5 --- /dev/null +++ b/external/Java.Interop/.github/skills/agentic-workflows/SKILL.md @@ -0,0 +1,79 @@ +--- +name: agentic-workflows +description: Route gh-aw workflow design/create/debug/upgrade requests to the right prompts. +--- + +# Agentic Workflows Router + +Use this skill when a user asks to design, create, update, debug, or upgrade GitHub Agentic Workflows in this repository. + +This skill is a dispatcher: identify the task type, load the matching workflow prompt/skill file, and follow it directly. Keep responses concise and ask a clarifying question if the correct prompt is unclear. + +Read only the files you need: +Load these files from `github/gh-aw` (they are not available locally). +- `.github/aw/agentic-chat.md` +- `.github/aw/agentic-workflows-mcp.md` +- `.github/aw/asciicharts.md` +- `.github/aw/campaign.md` +- `.github/aw/charts-trending.md` +- `.github/aw/charts.md` +- `.github/aw/cli-commands.md` +- `.github/aw/context.md` +- `.github/aw/create-agentic-workflow.md` +- `.github/aw/create-shared-agentic-workflow.md` +- `.github/aw/debug-agentic-workflow.md` +- `.github/aw/dependabot.md` +- `.github/aw/deployment-status.md` +- `.github/aw/experiments.md` +- `.github/aw/github-agentic-workflows.md` +- `.github/aw/github-mcp-server.md` +- `.github/aw/llms.md` +- `.github/aw/mcp-clis.md` +- `.github/aw/memory.md` +- `.github/aw/messages.md` +- `.github/aw/network.md` +- `.github/aw/patterns.md` +- `.github/aw/pr-reviewer.md` +- `.github/aw/report.md` +- `.github/aw/reuse.md` +- `.github/aw/safe-outputs-automation.md` +- `.github/aw/safe-outputs-content.md` +- `.github/aw/safe-outputs-management.md` +- `.github/aw/safe-outputs-runtime.md` +- `.github/aw/safe-outputs.md` +- `.github/aw/serena-tool.md` +- `.github/aw/shared-safe-jobs.md` +- `.github/aw/skills.md` +- `.github/aw/subagents.md` +- `.github/aw/syntax-agentic.md` +- `.github/aw/syntax-core.md` +- `.github/aw/syntax-tools-imports.md` +- `.github/aw/syntax.md` +- `.github/aw/test-coverage.md` +- `.github/aw/test-expression.md` +- `.github/aw/token-optimization.md` +- `.github/aw/triggers.md` +- `.github/aw/update-agentic-workflow.md` +- `.github/aw/upgrade-agentic-workflows.md` +- `.github/aw/visual-regression.md` +- `.github/aw/workflow-constraints.md` +- `.github/aw/workflow-editing.md` +- `.github/aw/workflow-patterns.md` + +- `.github/skills/agentic-workflow-designer/SKILL.md` +After loading the matching workflow prompt or skill, follow it directly: +- Design workflows from scratch via interview: `skills/agentic-workflow-designer/SKILL.md` +- Create new workflows: `.github/aw/create-agentic-workflow.md` +- Update existing workflows: `.github/aw/update-agentic-workflow.md` +- Debug, audit, or investigate workflows: `.github/aw/debug-agentic-workflow.md` +- Upgrade workflows and fix deprecations: `.github/aw/upgrade-agentic-workflows.md` +- Create shared components or MCP wrappers: `.github/aw/create-shared-agentic-workflow.md` +- Create report-generating workflows: `.github/aw/report.md` +- Fix Dependabot manifest PRs: `.github/aw/dependabot.md` +- Analyze coverage workflows: `.github/aw/test-coverage.md` +- Render compact markdown charts: `.github/aw/asciicharts.md` +- Map CLI commands to MCP usage: `.github/aw/cli-commands.md` +- Choose workflow architecture and patterns: `.github/aw/patterns.md` +- Optimize token usage and cost: `.github/aw/token-optimization.md` + +When the task involves OTEL, OTLP, traces, observability backends, or telemetry-driven analysis, also read and follow `skills/otel-queries/SKILL.md` after loading the matching workflow prompt or skill. diff --git a/external/Java.Interop/.github/skills/build-and-test/SKILL.md b/external/Java.Interop/.github/skills/build-and-test/SKILL.md new file mode 100644 index 00000000000..0d7747c4e42 --- /dev/null +++ b/external/Java.Interop/.github/skills/build-and-test/SKILL.md @@ -0,0 +1,82 @@ +--- +name: build-and-test +description: Build and test the Java.Interop repository. Use when asked to build, compile, run tests, verify changes, or check for regressions. Handles submodule initialization, build preparation, compilation, test execution, and result summarization. Also use after making code changes to validate they compile and pass tests. +--- + +# Build and Test + +Build and test the Java.Interop .NET/JNI interop repository. + +## Prerequisites + +- .NET SDK (9+) +- Java Development Kit (JDK) +- Platform-specific JVM libraries + +## Workflow + +1. Initialize submodules (if needed) +2. Prepare the build +3. Build the solution +4. Run tests +5. Summarize results + +## Step 1: Initialize Submodules + +Run only if `external/xamarin-android-tools` is empty or missing: + +```bash +git submodule update --init --recursive +``` + +## Step 2: Prepare + Build + +```bash +dotnet build -t:Prepare +dotnet build Java.Interop.sln +``` + +If the user only wants to build (not test), stop here and report success/failure. + +## Step 3: Run Tests + +Run all tests: + +```bash +dotnet test Java.Interop.sln +``` + +Run a specific test project (when the user specifies one or when iterating on a focused area): + +```bash +dotnet test tests//.csproj +``` + +Common test projects: +- `Java.Interop-Tests` — core JNI binding tests (largest suite) +- `Java.Interop.Export-Tests` — export attribute tests +- `generator-Tests` — C# binding generator tests +- `Java.Interop.Tools.JavaCallableWrappers-Tests` — JCW generation tests + +## Step 4: Summarize Results + +Parse the `dotnet test` output. Extract lines matching `Passed!` or `Failed!` patterns. + +Present a summary table: + +| Test Assembly | Passed | Failed | Skipped | +|---|---|---|---| +| Assembly-Name | N | N | N | + +**Total: X passed, Y failed, Z skipped.** + +If any tests failed, show the failure details and relevant error messages. + +## Handling Failures + +**Build failures**: Show the full error output. Common issues: +- Missing submodules → run `git submodule update --init --recursive` +- Missing JDK → check `$JAVA_HOME` is set +- Missing JVM → check `$JdkJvmPath` in `Configuration.Override.props` + +**Test failures**: Show the failing test names and assertion messages. If a specific test fails, suggest re-running just that test project for faster iteration. diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/SKILL.md b/external/Java.Interop/.github/skills/java-interop-reviewer/SKILL.md new file mode 100644 index 00000000000..95e9f75a4d9 --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/SKILL.md @@ -0,0 +1,124 @@ +--- +name: java-interop-reviewer +description: >- + Review dotnet/java-interop PRs against established rules. Trigger on "review this PR", + a GitHub PR URL, or code review requests. Checks C#, JNI interop, nullable, async, + security, error handling, formatting, performance, native code, and generator codegen. +--- + +# Java.Interop PR Reviewer + +Review PRs against guidelines distilled from past reviews by senior maintainers of dotnet/java-interop. + +## Review Mindset + +Be polite but skeptical. Prioritize bugs, performance regressions, safety issues, and pattern violations over style nitpicks. **3 important comments > 15 nitpicks.** + +Flag severity clearly in every comment: +- ❌ **error** — Must fix before merge. Bugs, security issues, JNI reference leaks, broken codegen. +- ⚠️ **warning** — Should fix. Performance issues, missing validation, inconsistency with patterns. +- 💡 **suggestion** — Consider changing. Style, readability, optional improvements. + +**Every review should produce at least one inline comment.** Even clean PRs have opportunities for improvement — code consolidation, missing edge-case tests, perf micro-optimizations, or documentation gaps. Use 💡 suggestions for these. A review with zero comments appears superficial and misses the chance to share knowledge. Only omit inline comments if the PR is truly trivial (e.g., a 1-line typo fix or dependency bump). + +## Workflow + +### 1. Identify the PR + +If triggered from an agentic workflow (slash command on a PR), use the PR from the event context. Otherwise, extract `owner`, `repo`, `pr_number` from a URL or reference provided by the user. +Formats: `https://github.com/{owner}/{repo}/pull/{number}`, `{owner}/{repo}#{number}`, or bare number (defaults to `dotnet/java-interop`). + +### 2. Gather context (before reading PR description) + +``` +gh pr diff {number} --repo {owner}/{repo} +gh pr view {number} --repo {owner}/{repo} --json files +``` + +For each changed file, read the **full source file** (not just the diff) to understand surrounding invariants, call patterns, and data flow. If the change modifies a public/internal API or utility, search for callers. Check whether sibling types need the same fix. + +**Form an independent assessment** of what the change does and what problems it has *before* reading the PR description. + +### 3. Incorporate PR narrative and reconcile + +``` +gh pr view {number} --repo {owner}/{repo} --json title,body +``` + +Now read the PR description and linked issues. Treat them as claims to verify, not facts to accept. Where your independent reading disagrees with the PR description, investigate further. If the PR claims a performance improvement, require evidence (benchmarks, profiling data). If it claims a bug fix, verify the bug exists and the fix addresses root cause — not symptoms. + +### 4. Check CI status + +``` +gh pr checks {number} --repo {owner}/{repo} +``` + +Review the CI results. **Never post ✅ LGTM if any required CI check is failing or if the code doesn't build.** If CI is failing: +- Investigate the failure. +- If the failure is caused by the PR's code changes, flag it as ❌ error. +- If the failure is a known infrastructure issue or pre-existing flake unrelated to the PR, note it in the summary but still use ⚠️ Needs Changes — the PR isn't mergeable until CI is green. + +### 5. Load review rules + +Based on the file types identified in step 2, read the appropriate rule files from this skill's `references/` directory. + +**Always load:** +- `references/repo-conventions.md` — Formatting, style, and patterns specific to this repository. +- `references/ai-pitfalls.md` — Common AI-generated code mistakes. + +**Conditionally load based on changed file types:** +- `references/csharp-rules.md` — When any `.cs` files changed. Covers nullable, async, error handling, performance, and code organization. +- `references/interop-rules.md` — When the diff contains JNI interop code (e.g., `JniObjectReference`, `JniPeerMembers`, `[Register]`, `DllImport`, `[MarshalAs]`, `[StructLayout]`, `JNIEnv`), or when both C# and native files changed. +- `references/native-rules.md` — When `.c`, `.cc`, `.cpp`, `.h`, or `.hpp` files changed (e.g., files under `src/java-interop/`). +- `references/msbuild-rules.md` — When `.targets`, `.props`, `.projitems`, or `.csproj` files changed. +- `references/testing-rules.md` — When test files changed (e.g., files under `tests/`, `*-Tests/`, or test project directories). +- `references/security-rules.md` — When any code files changed (C#, C/C++, or MSBuild). + +### 6. Analyze the diff + +For each changed file, check against the review rules. Record issues as: + +```json +{ "path": "src/Example.cs", "line": 42, "side": "RIGHT", "body": "..." } +``` + +**What to look for (in priority order):** +1. **Bugs & correctness** — race conditions, null dereferences, off-by-one, logic errors, JNI reference leaks +2. **Safety** — thread safety, resource leaks, security vulnerabilities +3. **Performance** — O(n²) patterns, unnecessary allocations, startup time regressions +4. **Trimmer/NativeAOT compatibility** — reflection without annotations, `Type.GetType()` misuse +5. **Missing tests** — untested error paths, edge cases, missing regression tests for bug fixes +6. **Code duplication** — near-identical methods that should be consolidated +7. **Consistency** — patterns mixed within the same PR, API return types inconsistent with repo conventions +8. **Documentation** — misleading comments, undocumented behavioral decisions + +Constraints: +- Only comment on added/modified lines in the diff — the API rejects out-of-range lines. +- `line` = line number in the NEW file (right side). Double-check against the diff. +- One issue per comment. +- **Don't pile on.** If the same issue appears many times, flag it once with a note listing all affected files. +- **Don't flag what CI catches.** Skip compiler errors, formatting the linter will catch, etc. +- **Avoid false positives.** Verify the concern actually applies given the full context. If unsure, phrase it as a question rather than a firm claim. + +### 7. Post the review + +Post your findings directly: + +- **Inline comments** on specific lines of the diff with the severity, category, and explanation. +- **Review summary** with the overall verdict (✅ LGTM, ⚠️ Needs Changes, or ❌ Reject), issue counts by severity, and positive callouts. + +If no issues found **and CI is green**, submit with at most one or two 💡 suggestions and a positive summary. Truly trivial PRs (dependency bumps, 1-line typo fixes) may have no inline comments. + +**Copilot-authored PRs:** If the PR author is `Copilot` (the GitHub Copilot coding agent) and the verdict is ⚠️ Needs Changes or ❌ Reject, prefix the review summary with `@copilot ` so the comment automatically triggers Copilot to address the feedback. Do NOT add the prefix for ✅ LGTM verdicts. + +## Comment format + +``` +🤖 {severity} **{Category}** — {What's wrong and what to do instead.} + +_{Rule: Brief name}_ +``` + +Where `{severity}` is ❌, ⚠️, or 💡. + +**Categories:** Nullable · Async pattern · Error handling · Resource management · Security · Formatting · Performance · Code organization · Naming · JNI interop · JNI references · Generator codegen · Native C/C++ · Testing · YAGNI · API design · Trimmer/AOT · Documentation diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/ai-pitfalls.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/ai-pitfalls.md new file mode 100644 index 00000000000..c2fc5154e54 --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/ai-pitfalls.md @@ -0,0 +1,25 @@ +# AI Code Generation Pitfalls + +Patterns that AI-generated code consistently gets wrong. Always loaded during reviews. + +--- + +| Pattern | What to watch for | +|---------|------------------| +| **Reinventing the wheel** | AI creates new infrastructure instead of using existing utilities. ALWAYS check if a similar utility exists before accepting new wrapper code. This is the most expensive AI pattern — hundreds of lines of plausible code that duplicates what's already there. | +| **Over-engineering** | HttpClient injection "for testability", speculative helper classes, unused overloads. If no caller needs it today, remove it. | +| **Swallowed errors** | AI catch blocks love to eat exceptions silently. Check EVERY catch block. Also check that exit codes are checked consistently. | +| **Null-forgiving operator (`!`)** | The postfix `!` null-forgiving operator (e.g., `foo!.Bar`) is banned. If the value can be null, add a proper null check. If it can't be null, make the parameter/variable non-nullable. AI frequently sprinkles `!` to silence the compiler — this turns compile-time warnings into runtime `NullReferenceException`s. Note: this rule is about the postfix `!` operator, not the logical negation `!` (e.g., `if (!someBool)` or `if (!string.IsNullOrEmpty (s))`). | +| **Wrong formatting** | AI generates standard C# formatting (no space before parens). This repo requires Mono style: `Foo ()`, `array [0]`. | +| **`string.Empty` and `Array.Empty()`** | AI defaults to these. Use `""` and `[]` instead. | +| **Sloppy structure** | Multiple types in one file, block-scoped namespaces, `#region` directives, classes where records would do. New helpers marked `public` when `internal` suffices. | +| **Docs describe intent not reality** | AI doc comments often describe what the code *should* do, not what it *actually* does. Review doc comments against the implementation. | +| **Unused parameters** | AI adds `CancellationToken` parameters but never observes them, or accepts `additionalArgs` as a string and interpolates it into a command. Unused CancellationToken is a broken contract; string args are injection risks. | +| **Confidently wrong domain facts** | AI makes authoritative claims about JNI behavior, Java type system details, or .NET interop semantics that are wrong. Always verify domain-specific claims against official docs (JNI spec, .NET docs). | +| **Over-mocking** | Not everything needs to be mocked. Integration tests with `Assert.Ignore` on failure are fine and catch real API changes that mocks never will. | +| **`Debug.WriteLine` for logging** | AI catch blocks often log with `System.Diagnostics.Debug.WriteLine()` or `Console.WriteLine()` — neither integrates with MSBuild or codebase logger patterns. | +| **`git commit --amend`** | AI uses `--amend` on commits that are already pushed or belong to another author. Always create new commits — the maintainer will squash as needed. | +| **Commit messages omit non-obvious choices** | Behavioral decisions ("JNI local refs are not eagerly disposed in this path") and known limitations belong in the commit message, not just the code. | +| **Typos in user-visible strings** | Users copy-paste error messages into bug reports. Get them right. | +| **Filler words in docs** | "So" at the start of a sentence adds nothing. Be direct. | +| **Ignoring trimmer/AOT** | AI uses `Type.GetType()`, `Activator.CreateInstance()`, or other reflection APIs without proper `[DynamicallyAccessedMembers]` annotations. These break under trimming and NativeAOT. | diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/csharp-rules.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/csharp-rules.md new file mode 100644 index 00000000000..04d21820258 --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/csharp-rules.md @@ -0,0 +1,77 @@ +# C# Review Rules + +General C# guidance applicable to any .NET repository. + +--- + +## Nullable Reference Types + +| Check | What to look for | +|-------|-----------------| +| **`#nullable enable`** | New files should have `#nullable enable` at the top — unless nullable is already enabled at the project level via the `Nullable` MSBuild property, in which case it is not needed per-file. | +| **Never use `!` (null-forgiving operator)** | The postfix `!` null-forgiving operator (e.g., `foo!.Bar`) is banned. If the value can be null, add a proper null check. If it can't be null, make the type non-nullable. AI-generated code frequently sprinkles `!` to silence warnings — this turns compile-time safety into runtime `NullReferenceException`s. Note: this rule is about the postfix `!` operator, not the logical negation `!` (e.g., `if (!someBool)` or `if (!string.IsNullOrEmpty (s))`). | + +--- + +## Async, Cancellation & Thread Safety Patterns + +| Check | What to look for | +|-------|-----------------| +| **CancellationToken propagation** | Every `async` method that accepts a `CancellationToken` must pass it to ALL downstream async calls. A token that's accepted but never used is a broken contract. | +| **OperationCanceledException** | Catch-all blocks (`catch (Exception)`) must NOT swallow `OperationCanceledException`. Catch it explicitly first and rethrow, or use a type filter. | +| **Honor the token** | If a method accepts `CancellationToken`, it must observe it — register a callback to kill processes, check `IsCancellationRequested` in loops, pass it downstream. Don't accept it just for API completeness. | +| **Thread safety of shared state** | If a new field or property can be accessed from multiple threads (e.g., static caches, event handlers), verify thread-safe access: `ConcurrentDictionary`, `Interlocked`, or explicit locks. A `Dictionary` read concurrently with a write is undefined behavior. | +| **Lock ordering** | If code acquires multiple locks, the order must be consistent everywhere. Document the ordering. Inconsistent ordering → deadlock. | +| **Avoid double-checked locking — use `Lazy` or `LazyInitializer`** | The double-checked locking (DCL) pattern is error-prone and [discouraged by Microsoft](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/volatile). Prefer `Lazy` or `LazyInitializer.EnsureInitialized()`. If DCL is truly necessary, verify all initialization completes before the field is assigned and no thread can observe a partially-initialized instance. | +| **Singleton initialization completeness** | When a singleton is initialized behind a lock, ensure ALL setup steps (not just construction) complete before publishing the instance. If `Initialize()` does `instance = new Foo(); instance.Setup();`, another thread can see `instance != null` and use it before `Setup()` runs. | + +--- + +## Error Handling + +| Check | What to look for | +|-------|-----------------| +| **No empty catch blocks** | Every `catch` must capture the `Exception` and log it (or rethrow). No silent swallowing. | +| **Validate parameters** | Enum parameters and string-typed "mode" values must be validated — throw `ArgumentException` or `NotSupportedException` for unexpected values. | +| **Fail fast on critical ops** | If a critical operation fails, throw immediately. Silently continuing leads to confusing downstream failures. | +| **Check process exit codes** | If one operation checks the process exit code, ALL similar operations must too. Inconsistent error checking creates a false sense of safety. | +| **Log messages must have context** | A bare `"Operation failed"` could be anything. Include *what* you were doing and relevant identifiers. | +| **Differentiate similar error messages** | Two messages saying `"X failed"` for different operations are impossible to debug. Make each unique. | +| **Assert boundary invariants** | If a name=value pair array must have even length, assert `(length % 2) == 0` before indexing `[i+1]`. | +| **Include actionable details in exceptions** | Use `nameof` for parameter names. Include the unsupported value or unexpected type. Never throw empty exceptions. | +| **Initialize output parameters in all paths** | Methods with `out` parameters must initialize them in all error paths, not just the success path. | +| **Challenge exception swallowing** | When a PR adds `catch { continue; }` or `catch { return null; }`, question whether the exception is truly expected or masking a deeper problem. The default should be to let unexpected exceptions propagate. | + +--- + +## Performance + +| Check | What to look for | +|-------|-----------------| +| **Avoid unnecessary allocations** | Don't create intermediate collections when LINQ chaining or a single list would do. Char arrays for `string.Split()` should be `static readonly` fields. | +| **ArrayPool for large buffers** | Buffers ≥ 1 KB should use `ArrayPool.Shared.Rent()` with `try`/`finally` return. Large allocations go to the LOH and are expensive to GC. | +| **`HashSet.Add()` already handles duplicates** | Calling `.Contains()` before `.Add()` does the hash lookup twice. Just call `.Add()`. | +| **Don't wrap a value in an interpolated string** | `$"{someString}"` creates an unnecessary `string.Format` call when `someString` is already a string. | +| **Pre-allocate collections when size is known** | Use `new List(capacity)` or `new Dictionary(count)` when the size is known or estimable. Repeated resizing is O(n) allocation waste. | +| **Avoid closures in hot paths** | Lambdas that capture local variables allocate a closure object on every call. In loops or frequently-called methods, extract the lambda to a static method or cache the delegate. | +| **Place cheap checks before expensive ones** | In validation chains, test simple conditions (null checks, boolean flags) before allocating strings or doing I/O. Short-circuit with `&&`/`||`. | +| **Cache repeated accessor calls** | If `foo.Bar.Baz` is used multiple times in a block, assign it to a local. This avoids repeated property evaluation and makes intent clearer. | +| **Watch for O(n²)** | Nested loops over the same or related collections, repeated `.Contains()` on a `List`, or LINQ `.Where()` inside a loop are O(n²). Switch to `HashSet` or `Dictionary` for lookups. | +| **Extract throw helpers** | Code like `if (x) throw new SomeException(...)` in a frequently-called method prevents inlining. Extract into a `[DoesNotReturn]` helper so the JIT can inline the happy path. | +| **`Split()` with count parameter** | `line.Split (new char[]{'='}, 2)` prevents values containing `=` from being split incorrectly. Follow existing patterns. | + +--- + +## Code Organization + +| Check | What to look for | +|-------|-----------------| +| **One type per file** | Each public class, struct, enum, or interface must be in its own `.cs` file named after the type. | +| **Use `record` for data types** | Immutable data-carrier types should be `record` types — they get value equality, `ToString()`, and deconstruction for free. | +| **Remove unused code** | Dead methods, speculative helpers, and code "for later" should be removed. Ship only what's needed. No commented-out code — Git has history. | +| **New helpers default to `internal`** | New utility methods should be `internal` unless a confirmed external consumer needs them. Use `InternalsVisibleTo` for test access. | +| **Use interfaces over concrete types** | Fields and parameters should prefer interfaces (`IMetadataResolver`) over concrete classes. When the implementation changes, you swap the implementation — not every call site. | +| **Reduce indentation with early returns** | `foreach (var x in items ?? [])` eliminates a null-check nesting level. Invert logic for the common case with `continue` so complex cases have less nesting. | +| **Don't initialize fields to default values** | `bool flag = false;` and `int count = 0;` are noise. The CLR zero-initializes all fields. Only assign when the initial value is non-default. | +| **`sealed` classes skip full Dispose** | A `sealed` class doesn't need `Dispose(bool)` + `GC.SuppressFinalize`. Just implement `IDisposable.Dispose()` directly. The full pattern is only for unsealed base classes. | +| **Well-named constants over magic numbers** | `if (retryCount > 3)` should be `if (retryCount > MaxRetries)`. Constants document intent and make the value easy to find and change. | diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/interop-rules.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/interop-rules.md new file mode 100644 index 00000000000..a29330e7fa7 --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/interop-rules.md @@ -0,0 +1,31 @@ +# Managed ↔ Native Interop Review Rules + +Rules for the boundary between C# and C/C++ code — P/Invoke declarations, JNI +bindings, and shared structs. Load when both managed and native files change, or +when the diff contains interop markers (`JniObjectReference`, `JniPeerMembers`, +`DllImport`, `[Register]`, `JNIEnv`, `[MarshalAs]`, `[StructLayout]`). + +--- + +## JNI Interop Checks + +| Check | What to look for | +|-------|-----------------| +| **`JniObjectReference` lifecycle** | Every `JniObjectReference` obtained from JNI calls must be disposed in a `try`/`finally` block. Local references that escape their JNI frame exhaust the local reference table (default 512 entries). Global references that aren't freed are permanent leaks. | +| **`JniPeerMembers` for method/field IDs** | Method and field IDs should be cached via `JniPeerMembers.InstanceMethods`, `JniPeerMembers.StaticMethods`, or `JniPeerMembers.InstanceFields`. Looking up IDs on every call is expensive. | +| **Virtual vs non-virtual dispatch** | Default interface method implementations should use `InvokeNonvirtualVoidMethod()` (non-virtual). Class method overrides should use `InvokeVirtualVoidMethod()` (virtual). Getting this wrong changes dispatch semantics. | +| **`[Register]` attribute accuracy** | `[Register]` attributes must exactly match the Java method name and JNI signature. Mismatches cause `NoSuchMethodError` at runtime. Verify against the Java API description. | +| **`JniTransition` for native callbacks** | Entry points from Java into managed code should use `JniTransition` to properly handle exception marshaling. Without it, managed exceptions propagate into the JVM as undefined behavior. | +| **Exception checking after JNI calls** | After JNI calls that can throw (most of them), check for pending Java exceptions via `JniEnvironment.Errors.ExceptionOccurred()` or rely on the built-in checking in `JniPeerMembers` wrappers. Don't ignore JNI error return codes. | + +--- + +## P/Invoke Checks + +| Check | What to look for | +|-------|-----------------| +| **`static_cast` over C-style casts** | `static_cast(val)` is checked at compile time. `(int)val` can silently reinterpret bits. Always use C++ casts in interop boundaries. | +| **`nullptr` over `NULL`** | `NULL` is `0` in C++, which can silently convert to integral types. `nullptr` has proper pointer semantics. | +| **Struct field ordering for padding** | When defining structs shared between managed and native code, order fields largest-to-smallest to minimize padding. Explicit `[StructLayout(LayoutKind.Sequential)]` and matching C struct must be kept in sync. | +| **Bool marshalling** | Boolean marshalling is a common source of bugs. C++ `bool` is 1 byte, Windows `BOOL` is 4 bytes. When P/Invoking, explicitly specify `[MarshalAs(UnmanagedType.U1)]` or `[MarshalAs(UnmanagedType.Bool)]` (4-byte). | +| **String marshalling charset** | P/Invoke string parameters should specify `CharSet.Unicode` (UTF-16) or use `[MarshalAs(UnmanagedType.LPUTF8Str)]` for UTF-8. Don't rely on the default (ANSI on Windows). | diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/msbuild-rules.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/msbuild-rules.md new file mode 100644 index 00000000000..0dd47653f66 --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/msbuild-rules.md @@ -0,0 +1,44 @@ +# MSBuild Review Rules + +Guidance for MSBuild targets, props, and project files. Loaded when `.targets`, +`.props`, `.projitems`, or `.csproj` files change. + +--- + +## Task Logging + +| Check | What to look for | +|-------|-----------------| +| **Don't use `Debug.WriteLine` or `Console.WriteLine`** | MSBuild tasks must use the task's logging facilities (e.g., `Log.LogMessage`, `Log.LogWarning`, `Log.LogError`). `Debug.WriteLine()` only reaches attached debuggers (invisible in CI). `Console.WriteLine()` bypasses MSBuild's logging pipeline entirely. | +| **Use appropriate log levels** | Use `MessageImportance.Low` for verbose diagnostics, `MessageImportance.Normal` for progress, and `MessageImportance.High` for important status. Don't spam high-importance messages. | + +--- + +## Process Management in Tasks + +| Check | What to look for | +|-------|-----------------| +| **Don't redirect stdout/stderr without draining** | Background processes with `RedirectStandardOutput = true` must have async readers draining the output. Otherwise the OS pipe buffer fills and the child process deadlocks. For fire-and-forget processes, set `Redirect* = false`. | +| **Check exit codes consistently** | If one task operation checks the process exit code, ALL similar operations must too. Inconsistent error checking creates a false sense of safety. | +| **Include stdout in error diagnostics** | When a task captures stdout, pass it to error reporting so failure messages include all output, not just stderr. | + +--- + +## MSBuild Targets & XML + +| Check | What to look for | +|-------|-----------------| +| **Underscore prefix for private names** | Internal targets, properties, and item groups should be prefixed with `_` (e.g., `_CompileJava`, `$(_JarFile)`). MSBuild has no visibility — the underscore signals "internal." | +| **Incremental builds (`Inputs`/`Outputs`)** | Every target that *writes files* must have `Inputs` and `Outputs` so MSBuild can skip it when nothing changed. Targets that only read files, set properties, or populate item groups do NOT need them. | +| **`FileWrites` for intermediate files** | Intermediate files must be added to `@(FileWrites)` so `IncrementalClean` doesn't delete them. | +| **XML indentation** | MSBuild/XML files use 2 spaces for indentation (per `.editorconfig`), not tabs. | +| **`Condition` attribute first** | On `` and task elements, put the `Condition` attribute first — it's the most important for debugging. | + +--- + +## Downstream Coordination + +| Check | What to look for | +|-------|-----------------| +| **Port, don't rewrite** | If a downstream consumer already has working logic for the same task, port it rather than writing new code. The existing code has real-world edge cases already handled. | +| **Draft downstream PR before merging** | Shared library changes should be accompanied by a draft PR in the consuming repo (dotnet/android) that proves the API actually works. | diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/native-rules.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/native-rules.md new file mode 100644 index 00000000000..b599486f900 --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/native-rules.md @@ -0,0 +1,35 @@ +# Native Code (C/C++) Review Rules + +The native interop layer (`src/java-interop/`) provides low-level JNI and +platform integration. Bugs here cause crashes and memory leaks that are +extremely hard to diagnose. + +--- + +## Memory Management + +| Check | What to look for | +|-------|-----------------| +| **Every `new` needs a `delete` or justification** | If a `new` has no matching cleanup, document *why* the leak is acceptable and its worst-case size. | +| **Quantify leaks** | Is the leaked path hit once per process lifetime or once per invocation? The answer determines whether a leak matters. | +| **Use RAII (`std::unique_ptr`, etc.)** | Use smart pointers or RAII to ensure cleanup. Don't rely on manual `delete`. | +| **Watch for leaks in external APIs** | Functions that allocate memory for the caller must have their return values freed. Check the docs for every external API call. | + +--- + +## C++ Best Practices + +| Check | What to look for | +|-------|-----------------| +| **`nullptr` over `NULL`** | `NULL` is `0` in C++, which can silently convert to integral types. `nullptr` has proper pointer semantics. Use `!= nullptr` consistently in null checks. | +| **Use C++ standard headers** | Prefer `` over ``, `` over ``, etc. The C++ headers place names in `std::`. | +| **Virtual destructor on base classes** | Any base class with virtual methods must have a public virtual destructor. Without one, `delete`-through-base-pointer is undefined behavior. | +| **Delete copy/move constructors when inappropriate** | Types holding non-copyable resources (JNI references, file handles) must use `= delete` on copy constructor and assignment operator. | +| **Prefer `private` over `protected`** | Unless the type is explicitly designed for subclassing, use `private`. Don't speculatively make things `protected`. | +| **Use `const` where possible** | If a parameter or function argument isn't modified, declare it `const`. | +| **Handle `EINTR` for system calls** | `read()`, `write()`, and other syscalls can return `EINTR` when interrupted by a signal. Retry in a loop. | +| **Use `sizeof()` not magic numbers** | `16` should be `sizeof(some_type)` or equivalent. Magic numbers make code fragile. | +| **`static_cast` over C-style casts** | `static_cast(val)` is checked at compile time. `(int)val` can silently reinterpret bits. | +| **No commented-out code** | If it's not needed, delete it. Git has history. | +| **Don't use compiler-reserved identifiers** | Double-underscore `__` prefixed names are reserved by the C/C++ standard. | +| **Reasonable line width** | Don't combine two 80-char lines into one 160-char line. Keep code readable. | diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/repo-conventions.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/repo-conventions.md new file mode 100644 index 00000000000..85e74715d4a --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/repo-conventions.md @@ -0,0 +1,96 @@ +# Repo Conventions + +Formatting, style, and patterns specific to the dotnet/java-interop repository. +Always loaded during reviews. + +--- + +## Formatting & Style + +This project uses Mono style with tabs. Formatting violations create noisy diffs +and merge conflicts. + +| Check | What to look for | +|-------|-----------------| +| **Tabs, not spaces** | Indentation must use tabs (width 8 in `.editorconfig`). MSBuild/XML files use 2 spaces. | +| **Space before `(` and `[`** | Method calls: `Foo ()`, `Bar (1, 2)`. Array access: `array [0]`. This is Mono style — omitting the space is wrong here even though it's standard elsewhere. | +| **`""` not `string.Empty`** | Use `""` for empty strings. Use `[]` not `Array.Empty()` for empty arrays. | +| **No `#region`/`#endregion`** | Region directives hide code and make reviews harder. Remove them. | +| **`#else`/`#endif` comments** | Always annotate `#else` and `#endif` with the original expression: `#else // !NETCOREAPP` and `#endif // !NETCOREAPP`. | +| **Minimal diffs** | Don't leave random empty lines. Preserve existing formatting and comments in files you didn't write. Only format code you add or modify; never reformat existing lines. | +| **Reasonable line width** | Max 180 characters per `.editorconfig`. Don't merge two lines into a single 160-character monster. | +| **Attributes on their own line** | Long attributes like `[DynamicallyAccessedMembers (...)]` should be on their own line, not inline with the method/parameter declaration. Each parameter with long attributes should get its own line. | +| **Named parameters for many-argument calls** | When calling a method with more than 4 parameters, use named parameters for clarity. | + +--- + +## Naming + +| Check | What to look for | +|-------|-----------------| +| **Disambiguate Java vs C# names** | Terms like `FullName`, `Name`, or `ReferenceType` are ambiguous in a JNI interop context. When both Java and C# interpretations exist, prefer a prefix (`JavaFullName`, `ManagedFullName`) or clear documentation. | +| **Method names must reflect behavior** | If `CreateFoo()` sometimes returns an existing instance, rename it `GetOrCreateFoo()` or `GetFoo()`. | +| **Named constants for string lengths** | `n.Length - 7` should be `n.Length - "Invoker".Length`. Magic numbers for string suffix lengths are fragile and unreadable. | +| **No magic numbers** | Literal values like buffer sizes and permission masks should be named constants. `sizeof()` in native code, `const` or `static readonly` in C#. | +| **`KeyedCollection` for name-indexed lists** | When a `List` is frequently searched by a name property, consider `KeyedCollection` or `Dictionary` for O(1) lookups. | + +--- + +## Error Messages & Localization + +| Check | What to look for | +|-------|-----------------| +| **Error/warning codes are required** | User-facing errors/warnings in generator and other tools must have codes (e.g., `BG####`, `JM####`). Error codes must not collide with existing ones. | +| **Error messages must be actionable** | Tell the user what to do, not just what went wrong. "Unable to find type" → "Unable to find type '…'. Make sure the paths to all referenced assemblies are provided with the `-L` option." | +| **Demote non-actionable messages** | If a warning can't suggest an action, demote it to informational. Warnings that users can't act on are noise. | +| **Localization resource comments** | Include comments explaining what terms should NOT be translated: `The following terms should not be translated: Metadata.xml, -L.` | +| **Don't use internal jargon in messages** | Terms like "Cecil" or "corlib" are meaningless to users. Use "referenced assemblies" or "mscorlib" instead. | +| **Error messages in resource files** | New error/warning messages should be added to `.resx` resource files and referenced via `Properties.Resources`, not hard-coded in C# strings. | + +--- + +## JNI Interop Patterns + +| Check | What to look for | +|-------|-----------------| +| **JNI reference lifecycle** | Every `JniObjectReference` must be properly disposed. Use `try`/`finally` or `using` patterns. Local references are cleaned up by the JVM at JNI frame boundaries, but explicit cleanup prevents native reference table exhaustion. | +| **Use `JniTransition` for exception marshaling** | Native callbacks into managed code should use `JniTransition` to properly handle exception marshaling between Java and C#. | +| **`JniPeerMembers` caching** | Method and field IDs should be accessed via `JniPeerMembers` for efficient caching. Don't look up method IDs on every call. | +| **Thread-local JNI environments** | JNI environments are thread-local. Always use `JniEnvironment.Current` to access the current thread's environment. Don't cache `JNIEnv*` across threads. | +| **`[Register]` attribute correctness** | `[Register]` attributes must match the Java method signature exactly. Mismatches cause runtime `NoSuchMethodError`. | + +--- + +## Performance + +| Check | What to look for | +|-------|-----------------| +| **Startup time is critical** | Changes to `Java.Interop` core affect every .NET Android app startup. Minimize type loading, lazy-initialize where possible, avoid unnecessary allocations in hot paths. | +| **Prefer arrays over dictionaries for small lookups** | For datasets with < ~50 items, linear search through an array is faster than dictionary lookup due to hash computation overhead and initialization cost. Back assertions with benchmarks. | +| **`StringComparison.Ordinal` for identifiers** | Use `StringComparison.Ordinal` for Java/C# identifier comparisons. `string.EndsWith(string)` without a `StringComparison` is locale-aware and slower. Use `StringComparison.OrdinalIgnoreCase` only for filesystem paths. | +| **Static `readonly` for reusable fields** | Static fields like singletons or shared instances should be `readonly` when they shouldn't be reassigned. `static HttpClient` instances are mandatory (no per-use disposal). | +| **Consider trimmer/NativeAOT impact** | Use `[DynamicallyAccessedMembers]` for types accessed via reflection. Use `[UnconditionalSuppressMessage]` instead of `#pragma` for trimmer warnings. Avoid `Type.GetType()` with assembly-qualified names when a direct type reference or typemap lookup can be used. | + +--- + +## Downstream Impact + +| Check | What to look for | +|-------|-----------------| +| **Consider dotnet/android consumers** | Changes to shared types (`JniPeerMembers`, `JavaObject`, `JniRuntime`, `JniTypeManager`) affect dotnet/android. API changes should be validated with a draft downstream PR. | +| **Port, don't rewrite** | If dotnet/android already has working logic for the same task, port it rather than writing new code. Existing code has real-world edge cases already handled. | +| **Target framework compatibility** | Tools shipped to customers (e.g., `generator`, `class-parse`) must target the correct .NET version. Verify against the oldest supported target framework. | + +--- + +## Patterns & Conventions + +| Check | What to look for | +|-------|-----------------| +| **Comments explain "why", not "what"** | `// increment i` adds nothing. `// skip the BOM — XmlReader chokes on it` explains intent. If a comment restates the code, delete it. | +| **Track TODOs as issues** | A `// TODO` hidden in code will be forgotten. File an issue and reference it in the comment. | +| **Remove stale comments** | If the code changed, update the comment. Comments that describe old behavior are misleading. | +| **Use existing utilities** | Check for existing helpers before writing new ones. Duplicating existing logic is the most expensive AI pattern. | +| **Return `IReadOnlyList`** | Public methods should return `IReadOnlyList` or `IReadOnlyCollection` instead of mutable `List`. | +| **Prefer C# pattern matching** | Use `is`, `switch` expressions, and property patterns instead of `if`/`else` type-check chains. | +| **Use `record` for data types** | Immutable data-carrier types should be `record` types — they get value equality, `ToString()`, and deconstruction for free. | diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/security-rules.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/security-rules.md new file mode 100644 index 00000000000..4b7da5de353 --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/security-rules.md @@ -0,0 +1,22 @@ +# Security Review Rules + +Security checklist for code reviews. Applicable to any repository handling file +I/O, archives, or process execution. + +--- + +## Archive & Path Safety + +| Check | What to look for | +|-------|-----------------| +| **Zip Slip protection** | Archive extraction must validate that every entry path, after `Path.GetFullPath()`, resolves under the destination directory. Never use `ZipFile.ExtractToDirectory()` for untrusted archives without entry-by-entry validation. | +| **Path traversal** | `StartsWith()` checks on paths must normalize with `Path.GetFullPath()` first. A path like `C:\Program Files\..\Users\evil` bypasses naive prefix checks. Also check for directory boundary issues (`C:\Program FilesX` matching `C:\Program Files`). | + +--- + +## Process & Command Safety + +| Check | What to look for | +|-------|-----------------| +| **Command injection** | Arguments passed to `Process.Start` must be sanitized. Use `ArgumentList` (not string interpolation into command strings). Never interpolate user/external input into command strings. | +| **Elevation** | Don't auto-elevate. Don't include `IsElevated()` helpers that silently re-launch elevated. The calling tool should handle elevation prompts. The library should error if it lacks permissions. | diff --git a/external/Java.Interop/.github/skills/java-interop-reviewer/references/testing-rules.md b/external/Java.Interop/.github/skills/java-interop-reviewer/references/testing-rules.md new file mode 100644 index 00000000000..32702e3499f --- /dev/null +++ b/external/Java.Interop/.github/skills/java-interop-reviewer/references/testing-rules.md @@ -0,0 +1,18 @@ +# Testing Review Rules + +Guidance for test code in dotnet/java-interop. Loaded when test files change. + +--- + +## Testing Checks + +| Check | What to look for | +|-------|-----------------| +| **NUnit conventions** | Use `[TestFixture]`, `[Test]`, `[NonParallelizable]` (for tests that hang without it). | +| **Bug fixes need regression tests** | Every PR that fixes a bug should include a test that fails without the fix and passes with it. If the PR description says "fixes #N" but adds no test, ask for one. | +| **Test assertions must be specific** | `Assert.IsNotNull(result)` or `Assert.IsTrue(success)` don't tell you what went wrong. Prefer `Assert.AreEqual(expected, actual)` or NUnit constraints (`Assert.That` with `Does.Contain`, `Is.EqualTo`, etc.) for richer failure messages. | +| **Deterministic test data** | Tests should not depend on system locale, timezone, or current date. Use explicit `CultureInfo.InvariantCulture` and hardcoded dates when testing formatting. | +| **Test edge cases** | Empty collections, null inputs, boundary values, concurrent calls, and very large inputs should all be considered. If the PR only tests the happy path, suggest edge cases. | +| **Generator tests must include Invoker types** | Tests for generated binding code should verify both the interface/class output and the `*Invoker` type behavior. Invoker codegen has historically had subtle bugs with default interface methods and virtual dispatch. | +| **JVM-dependent tests** | Tests that require a running JVM should be in projects that configure the JVM environment (e.g., `Java.Interop-Tests`). Verify that test classes requiring a JVM are not placed in unit-test-only projects. | +| **Expected codegen output tests** | Generator tests that compare expected output should be updated when the expected output format changes. Stale expected output files cause spurious test failures. | diff --git a/external/Java.Interop/.github/workflows/java-interop-reviewer.md b/external/Java.Interop/.github/workflows/java-interop-reviewer.md new file mode 100644 index 00000000000..72c7542fabe --- /dev/null +++ b/external/Java.Interop/.github/workflows/java-interop-reviewer.md @@ -0,0 +1,64 @@ +--- +on: + slash_command: + name: review + events: [pull_request_comment] + roles: [admin, maintainer, write] +environment: copilot-pr-reviewer +permissions: + contents: read + pull-requests: read +engine: + id: copilot + model: claude-opus-4.8 +max-daily-ai-credits: -1 +max-ai-credits: -1 +network: + allowed: + - defaults + - dotnet + - github + - "aka.ms" + - "microsoft.com" +tools: + github: + github-token: ${{ secrets.GITHUB_TOKEN }} + toolsets: [pull_requests, repos] + # Allow reading PR content from external/first-time contributors. + # The /review command is gated to maintainers, so only trusted users can trigger it. + min-integrity: none +safe-outputs: + github-token: ${{ secrets.GITHUB_TOKEN }} + create-pull-request-review-comment: + max: 50 + submit-pull-request-review: + max: 1 + allowed-events: [COMMENT, REQUEST_CHANGES] +--- + +# Java.Interop PR Reviewer + +A maintainer commented `/review` on this pull request. Perform a thorough code review following the dotnet/java-interop review guidelines. + +## Instructions + +1. Read the review methodology from `.github/skills/java-interop-reviewer/SKILL.md` — this defines the review workflow, mindset, severity levels, and comment format. +2. Read the review rules from the `.github/skills/java-interop-reviewer/references/` directory — load the appropriate rule files based on the changed file types, as described in the SKILL.md workflow. +3. Follow the skill's workflow to analyze the pull request: + - Gather context: read the diff and changed files + - For each changed file, read the **full source file** to understand surrounding context + - Form an independent assessment before reading the PR description + - Read the PR title and description — treat claims as things to verify + - Check CI status + - Analyze the diff against the review rules +4. Post your findings as inline review comments and a review summary. + +## Constraints + +- Only comment on added/modified lines visible in the diff. +- One issue per inline comment. +- If the same issue appears many times, flag it once listing all affected files. +- Don't flag what CI catches (compiler errors, linter issues). +- Avoid false positives — verify concerns given the full file context. +- **Never submit an APPROVE event.** Use COMMENT for clean PRs and REQUEST_CHANGES when issues are found. +- Prioritize: bugs > safety > performance > missing tests > duplication > consistency > documentation. diff --git a/external/Java.Interop/.gitignore b/external/Java.Interop/.gitignore new file mode 100644 index 00000000000..f3996b884b5 --- /dev/null +++ b/external/Java.Interop/.gitignore @@ -0,0 +1,20 @@ +bin +Configuration.Override.props +obj +JavaDeveloper-2013005_dp__11m4609.pkg +LocalJDK +TestResult.xml +TestResult-*.xml +lib/gendarme-* +gendarme.html +gendarme.xml +packages +.vs/ +.nuget/ +*.userprefs +*.user +Resource.designer.cs +*.binlog +*.rej +*.orig +*~ diff --git a/external/Java.Interop/.gitmodules b/external/Java.Interop/.gitmodules new file mode 100644 index 00000000000..5349df98200 --- /dev/null +++ b/external/Java.Interop/.gitmodules @@ -0,0 +1,4 @@ +[submodule "external/xamarin-android-tools"] + path = external/xamarin-android-tools + url = https://github.com/xamarin/xamarin-android-tools.git + branch = main diff --git a/external/Java.Interop/.vscode/extensions.json b/external/Java.Interop/.vscode/extensions.json new file mode 100644 index 00000000000..53b2f67debc --- /dev/null +++ b/external/Java.Interop/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "ms-vscode.csharp", + "ms-vscode.cpptools", + "ms-vscode.mono-debug", + "wghats.vscode-nxunit-test-adapter", + "visualstudioexptteam.vscodeintellicode", + "zbecknell.t4-support", + ] +} \ No newline at end of file diff --git a/external/Java.Interop/.vscode/launch.json b/external/Java.Interop/.vscode/launch.json new file mode 100644 index 00000000000..6c63e562088 --- /dev/null +++ b/external/Java.Interop/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "mono", + "request": "launch", + "program": "${workspaceRoot}/packages/NUnit.ConsoleRunner.3.9.0/tools/nunit3-console.exe ${workspaceRoot}/bin/TestDebug/generator-Tests.dll", + "cwd": "${workspaceRoot}bin/TestDebug/" + }, + { + "name": "Attach", + "type": "mono", + "request": "attach", + "address": "localhost", + "port": 55555 + }, + { + "name": "Launch Generator", + "type": "mono", + "request": "launch", + "preLaunchTask": "Build Generator", + "program": "${workspaceRoot}/bin/TestDebug/generator.exe", + "args": [ + "--public", + "--product-version=7", + "--api-level=29", + "-o=obj/Debug/android-29/mcw/", + "--codegen-target=XAJavaInterop1", + "--fixup=metadata", + "--preserve-enums", + "--enumflags=enumflags", + "--enumfields=map.csv", + "--enummethods=methodmap.csv", + "--enummetadata=obj/Debug/android-29/mcw/enummetadata", + "--apiversions=${env:HOME}/android-toolchain/sdk/platforms/android-29/data/api-versions.xml", + "--annotations=${env:HOME}/android-toolchain/sdk/platforms/android-29/data/annotations.zip", + "--type-map-report=obj/Debug/android-29/mcw/type-mapping.txt", + "--enumdir=obj/Debug/android-29/mcw", + "obj/Debug/android-29/mcw/api.xml" + ], + "cwd": "${workspaceRoot}/../xamarin-android/src/Mono.Android", + } + ] +} \ No newline at end of file diff --git a/external/Java.Interop/.vscode/settings.json b/external/Java.Interop/.vscode/settings.json new file mode 100644 index 00000000000..ae48674213e --- /dev/null +++ b/external/Java.Interop/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic", + "nxunitExplorer.nunit": "packages/NUnit.ConsoleRunner.3.9.0/tools/nunit3-console.exe", + "nxunitExplorer.modules": [ + "bin/TestDebug/generator-Tests.dll", + "bin/TestDebug/Java.Interop.Tools.JavaCallableWrappers-Tests.dll", + "bin/TestDebug/LogcatParse-Tests.dll", + "bin/TestDebug/Xamarin.Android.Tools.ApiXmlAdjuster-Tests.dll", + "bin/TestDebug/Xamarin.Android.Tools.Bytecode-Tests.dll", + ] +} \ No newline at end of file diff --git a/external/Java.Interop/.vscode/tasks.json b/external/Java.Interop/.vscode/tasks.json new file mode 100644 index 00000000000..7825fd0f5d2 --- /dev/null +++ b/external/Java.Interop/.vscode/tasks.json @@ -0,0 +1,67 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build Java.Interop", + "type": "shell", + "command": "msbuild Java.Interop.sln /restore /t:Build", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$msCompile" + ] + }, + { + "label": "Clean Java.Interop", + "type": "shell", + "command": "msbuild Java.Interop.sln /restore /t:Clean", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$msCompile" + ] + }, + { + "label": "Build Generator", + "type": "shell", + "command": "msbuild tools/generator/generator.sln /restore /t:Build", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$msCompile" + ] + }, + { + "label": "Clean Generator", + "type": "shell", + "command": "msbuild tools/generator/generator.sln /restore /t:Clean", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$msCompile" + ] + }, + { + "label": "Run Generator Unit Tests", + "type": "shell", + "command": "msbuild tools/generator/generator.sln /restore /t:RunNunitTests", + "group": { + "kind": "test", + "isDefault": true + }, + "problemMatcher": [ + "$msCompile" + ] + } + ] +} diff --git a/external/Java.Interop/CODE-OF-CONDUCT.md b/external/Java.Interop/CODE-OF-CONDUCT.md new file mode 100644 index 00000000000..775f221c98e --- /dev/null +++ b/external/Java.Interop/CODE-OF-CONDUCT.md @@ -0,0 +1,6 @@ +# Code of Conduct + +This project has adopted the code of conduct defined by the Contributor Covenant +to clarify expected behavior in our community. + +For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). diff --git a/external/Java.Interop/Configuration.Override.props.in b/external/Java.Interop/Configuration.Override.props.in new file mode 100644 index 00000000000..f9421ed40ec --- /dev/null +++ b/external/Java.Interop/Configuration.Override.props.in @@ -0,0 +1,17 @@ + + + + /Library/Java/JavaVirtualMachines/microsoft-11.jdk/Contents/Home/lib/jli/libjli.dylib + /Library/Frameworks/Mono.framework/Libraries/libmonosgen-2.0.1.dylib + $(MSBuildThisFileDirectory)bin\$(Configuration)\ + + + + + + + + + + + diff --git a/external/Java.Interop/Directory.Build.props b/external/Java.Interop/Directory.Build.props new file mode 100644 index 00000000000..ad0ce48ddaa --- /dev/null +++ b/external/Java.Interop/Directory.Build.props @@ -0,0 +1,78 @@ + + + + + Debug + true + <_OutputPath>$(MSBuildThisFileDirectory)bin\Build$(Configuration)\ + true + true + + true + 10.0 + net$(DotNetTargetFrameworkVersion) + + + + + + + + + + + + true + + False + False + obj\ + + + + $(MSBuildThisFileDirectory)external\xamarin-android-tools + + + dotnet + cmake + $(MSBuildThisFileDirectory)build-tools\gradle + $(GradleHome)\gradlew + --stacktrace --no-daemon + 11 + 11 + <_BootClassPath Condition=" '$(JreRtJarPath)' != '' ">-bootclasspath "$(JreRtJarPath)" + <_JavacSourceOptions>--release $(JavacTargetVersion) $(_BootClassPath) + + + $([System.IO.Path]::GetFullPath ('$(XamarinAndroidToolsDirectory)')) + + + + + $(NoWarn);CS8981 + + + diff --git a/external/Java.Interop/Directory.Build.targets b/external/Java.Interop/Directory.Build.targets new file mode 100644 index 00000000000..2da41427e38 --- /dev/null +++ b/external/Java.Interop/Directory.Build.targets @@ -0,0 +1,54 @@ + + + + + + + + + + $(DefineConstants);INTERNAL_NULLABLE_ATTRIBUTES + + + + + 13.0 + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/external/Java.Interop/Documentation/Architecture.md b/external/Java.Interop/Documentation/Architecture.md new file mode 100644 index 00000000000..3f8035953e5 --- /dev/null +++ b/external/Java.Interop/Documentation/Architecture.md @@ -0,0 +1,276 @@ +# Architecture + +## Xamarin.Android Architecture + +For reference/comparision, The [Xamarin.Android architecture][xa-arch] and +[JNI use][xa-jni] is reasonably well documented; *how* it all fits together +isn't. + +[xa-arch]: http://developer.xamarin.com/guides/android/under_the_hood/architecture/ +[xa-jni]: http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni/ + +Within Xamarin.Android, there are four "moving parts": + +1. `Mono.Android.dll`, which contains two things: (1) a `generator`-produced + (2) binding of the Android API, and a fair bit of "glue code" to make + things actually work -- type marshaling, method invocation, helper types, + etc. + +2. [tools/generator](tools/generator), + which generates *binding assemblies*, which in turn contain + three things: (1) JNI glue code to permit managed code to invoke Java code; + (2) JNI marshal methods to facilitate Java code calling managed code; and + (3) lots of custom attributes to facilitate Android Callable Wrapper + generation. + +3. [Java Callable Wrappers][xa-acw], which are "Java stubs" containing Java + code with native method declarations for all methods overridden or + implemented from managed code. See also + [Java.Interop.Tools.JavaCallableWrappers](src/Java.Interop.Tools.JavaCallableWrappers). + +[xa-acw]: http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/ + +4. MSBuild glue code to glue various things together. See + [xamarin-android/src/Xamarin.Android.Build.Tasks][xa-tasks]. + +[xa-tasks]: https://github.com/xamarin/xamarin-android/tree/master/src/Xamarin.Android.Build.Tasks + +Furthermore, there's a matter of "time": binding assemblies (2) are emitted +at one time, while everything else (1, 3, 4) are bundled with the SDK and +thus could potentially change. Consequently, all four need to be kept in sync; +there is, in effect, an ABI between `Mono.Android.dll`, binding assemblies, +the build process, and Java callable wrappers. Any fix that involves the +boundary between these may "leak" into other areas, or otherwise not be +viable without requiring e.g. that customers rebuild binding assemblies. + +What would such a change be? + +For example, we would like Xamarin.Android to support *Ahead Of Time* (AOT) +compilation of assemblies into native code, to reduce or eliminate JIT +overheads during process startup and runtime execution. + +The problem is that, at present, *everything* needs to be wrapped in a +runtime-generated `try`/`catch` block (emitted via `System.Reflection.Emit`) +to perform Java exception marshaling duties. + +To "fully" do this for AOT, the *binding assembly* would need to contain the +exception marshaling logic, which (1) originally couldn't be *written* in C# +(it used IL fault blocks), and (2) would increase the ABI requirements. +Alternatively, we'd need to instead generate "new" marshal methods at +packaging time, resulting in *3* places using *2* different code generators +that generate marshal methods (binding assemblies, AOT, `[Export]`). + +*Then* there's the "minor" problem of the implementation of the +[`[Export]` custom attribute][xa-export], which currently *always* requires runtime +code generation. It would be nice to remove this requirement. + +[xa-export]: http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni/#ExportAttribute_and_ExportFieldAttribute + +*Finally*, none of this is *extensible*: lots of marshaling logic is hardcoded, +e.g. translating `java.io.InputStream` to `System.IO.Stream` (and back), +and there's no facility for additional types to participate in *any* of this. + +It's a big, monolithic, ball of mud. + +## Proposed Java.Interop Architecture + +Java.Interop aims to (eventually) change everything. (This is the end-game; the +commit history at the time of this writing does *not* fulfill this.) + +The problem with Xamarin.Android is a lack of flexibility: + +* Binding assemblies limit wide-scale improvements. +* Marshaling control and behavior is restricted from public use. +* Tying JNI glue code mechanics with the Android API makes it harder to reuse + JNI glue code elsewhere (the desktop JVM?). +* An incomplete binding ABI restricts fully embracing AOT + +Relatedly, there has long been a desire to embrace +[System.Linq.Expressions][System.Linq.Expressions], which supports generating IL +for execution at runtime (or saving to disk). + +[System.Linq.Expressions]: https://msdn.microsoft.com/en-us/library/system.linq.expressions.aspx + +Thus, the solution to *all our problems*? *Embrace* `System.Linq.Expressions`. +We still need a separate code generator for binding assemblies, but *instead* +of emitting "static" C# code that hardcodes all information about marshaling, +have it call into a runtime method that performs the work *at runtime*: + + // generator-emitted marshal method: + // Old-and-busted (current Xamarin.Android behavior) + static IntPtr n_Clone (IntPtr jnienv, IntPtr native__this) + { + Java.Lang.Object __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.Clone ()); + } + + // New hotness *from generator* (proposed Java.Interop behavior) + [Dynamic] + static IntPtr n_Clone (IntPtr jnienv, IntPtr native__this) + { + Func d = Delegate.CreateDelegate (...); + JniEnvironment.Runtime.InvokeMethod (jnienv, native__this, d /*, args... */); + } + +(API needs work/thinking through.) + +The idea is that the generator-emitted methods would be "shims" into +Java.Interop methods which would do the heavy lifting. + +This would, of course, result in additional runtime overhead. + +To rectify this, we could use a post-build step which would *replace* +all these shims with *real* method bodies: + + // Post-build generated code + static IntPtr n_Clone (IntPtr jnienv, IntPtr native__this) + { + JniTransition __envp = new JniTransition (jnienv); + try { + var __jvm = __envp.Runtime; + var __this = __jvm.ValueManager.GetValue(native__this); + var __mret = __this.Clone (); + var __jret = References.NewReturnToJniRef(__mret); + return __jret; + } + catch (Exception __e) { + __envp.SetPendingException (__e); + } + finally { + __envp.Dispose (); + } + } + +By making everything dynamic and then *replacing* everything of consequence +at package time, we loosen up ABI restrictions, allow marshaling bugs to +be inserted in future releases without requiring re-generation of binding +assemblies, and allow new types to participate in the marshal method code +generation. This allows for a more flexible marshaling system, with fewer +interdependencies, and could permit long-desired features such as +[value marshaling][value-marshaling] (copying Java values into managed types +which *don't* inherit from `JavaObject`, e.g. marshal a +`Android.Graphics.Point` into a `System.Drawing.Point`, eliminating the need +for a long-held, GC-tracked, JNI Global Reference.) + +[value-marshaling]: https://trello.com/c/M8zkFtR3/143-research-adding-valuetype-semantics-to-some-types + +Furthermore, by *relying* on a post-build step, this also allows for easily +supporting `[Export]`/`[JavaCallable]` annotated methods without *requiring* +runtime code generation, *and* to AOT the marshal methods for them! + +We *centralize* the *actual* value marshaling logic into `Java.Interop`, +removing code duplication from `generator`, and use that infrastructure +for as much as possible: C# 4 `dynamic`, post-build code generation, +runtime code generation (to support Debug builds so post-build steps +aren't always required). + +That said, we also want to *emphasize* the efficient path: we don't want +the "simple" path to require code generation; we want the simple path +to support and prefer the post-build AOT-supporting codegen path. +This in turn means that certain implemented features -- such as generic +argument marshaling -- need to change so that they're not inadvertently +used. + +## Type Safety + +The start of the reboot was to use strongly typed [`SafeHandle`][SafeHandle] +subclasses everywhere instead of `IntPtr`. This allows a local reference to be +type-checked and distinct from a global ref, complete with compiler +type checking. + +[SafeHandle]: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx + +Since we now have actual types in more places, we can move the current `JNIEnv` +methods into more semantically meaningful types. + +Unfortunately, various tests demonstrated that while `SafeHandle`s provided +increased type safety, they did so at a large runtime cost: + +1. `SafeHandle`s are reference types, increasing GC heap allocations and pressure. +2. [`SafeHandle`s are *thread-safe* in order to prevent race conditions and handle recycling attacks][reliability]. + +[reliability]: http://blogs.msdn.com/b/bclteam/archive/2005/03/16/396900.aspx + +Compared to a Xamarin.Android-like "use `IntPtr`s for *everything*" binding +approach, the overhead is significant: to *just* invoke +`JNIEnv::CallObjectMethod()`, using `SafeHandle`s for everything causes +execution time to take ~1.4x longer than a comparable struct-oriented approach. + +Make the test more realistic -- compared to current Xamarin.Android and +current Java.Interop -- so that `JniEnvironment.Members.CallObjectMethod()` +also calls `JniEnvironment.Errors.ExceptionOccurred()`, which also returns +a JNI local reference -- and runtime execution time *jumped to ~3.6x*: + + # SafeHandle timing: 00:00:09.9393493 + # Average Invocation: 0.00099393493ms + # JniObjectReference timing: 00:00:02.7254572 + # Average Invocation: 0.00027254572ms + +(See the [tests/invocation-overhead](tests/invocation-overhead) directory +for the invocation comparison sourcecode.) + +*This is not acceptable*. Performance is a concern with Xamarin.Android; +we can't be making it *worse*. + +Meanwhile, I *really* dislike using `IntPtr`s everywhere, as it doesn't let you +know what the value actually represents. + +To solve this issue, *avoid `SafeHandle` types* in the public API. + +Downside: this means we can't have the GC collect our garbage JNI references. + +Upside: the Java.Interop effort will actually be usable. + +Instead of using `SafeHandle` types, we introduce a +`JniObjectReference` struct type. This represents a JNI Local, Global, or +WeakGlobal object reference. The `JniObjectReference` struct also contains +the *reference type* as `JniObjectReferenceType`. +`jmethodID` and `jfieldID` become "normal" class types, permitting type safety, +but lose their `SafeHandle` status, which was never really necessary because +they don't require cleanup *anyway*. Furthermore, these values should be +*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be +a long-term problem. + +Historically, `JniObjectReference` retained an optional `SafeHandle` +implementation behind a build-time feature switch so the safer but slower +representation could be compared with the `IntPtr` representation during the +migration. That experiment is no longer active: the supported implementation is +the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership +transfer and disposal via `JniObjectReference.Dispose (ref reference)`. + + +## Naming Conventions + +Types with a `Java` prefix are "high-level" types which participate in cross-VM +object-reference semantics, e.g. you could add a `JavaObject` subclass to a +Java-side collection, perform a GC, and the instance will survive the GC. + +Types with a `Jni` prefix are "low-level" types and do *not* participate in +object-reference semantics. + + +## Notes + +### JDK and Global References + +The JDK VM supports an effectively unlimited number of global references. +While Dalvik bails out after creating ~64k GREFs, consider the following +on the JDK: + + var t = new JniType ("java/lang/Object"); + var c = t.GetConstructor ("()V"); + var o = t.NewInstance (c); + int count = 0; + while (true) { + Console.WriteLine ("count: {0}", count++); + o.NewGlobalRef (); + } + +I halted the above loop after reaching 25686556 instances. + + count: 25686556 + ^C + +I'm not sure when the JDK would stop handing out references, but it's probably +bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process). + diff --git a/external/Java.Interop/Documentation/BuildConfiguration.md b/external/Java.Interop/Documentation/BuildConfiguration.md new file mode 100644 index 00000000000..13984d29263 --- /dev/null +++ b/external/Java.Interop/Documentation/BuildConfiguration.md @@ -0,0 +1,49 @@ +# Build Configuration + +The Java.Interop build can be configured by specifying MSBuild properties to control +behavior or by overriding **make**(1) variables on the command line. + +## MSBuild Properties + +MSbuild properties may be placed into the file `Configuration.Override.props`, +which can be copied from +[`Configuration.Override.props.in`](Configuration.Override.props.in). +The `Configuration.Override.props` file is ``ed by +[`Directory.Build.props`](Directory.Build.props); there is no need to +`` it within other project files. + +Overridable MSBuild properties include: + +* `$(CecilSourceDirectory)`: If the empty string, Cecil will be obtained from + NuGet packages. Otherwise, `$(UtilityOutputFullPath)Xamarin.Android.Cecil.dll` + will be used to reference Cecil. +* `$(JdkJvmPath)`: Full path name to the JVM native library to use for + tests which require a desktop JVM. By default this is probed from the + configured JDK. +* `$(JavaCPath)`: Path to the `javac` command-line tool, by default set to `javac`. +* `$(JarPath)`: Path to the `jar` command-line tool, by default set to `jar`. + * It may be desirable to override these on Windows, depending on your `PATH`. +* `$(UtilityOutputFullPath)`: Directory to place various utilities such as + [`class-parse`](tools/class-parse), [`generator`](tools/generator), + and [`logcat-parse`](tools/logcat-parse). This value should be a full path. + By default this is `$(MSBuildThisFileDirectory)bin/$(Configuration)`. + +## **make**(1) variables + +The following **make**(1) variables may be specified: + +* `$(CONFIGURATION)`: The product configuration to build, and corresponds + to the `$(Configuration)` MSBuild property when running `$(MSBUILD)`. + Valid values are `Debug` and `Release`. Default value is `Debug`. +* `$(RUNTIME)`: The managed runtime to use to execute utilities, tests. + Default value is `mono64` if present in `$PATH`, otherwise `mono`. +* `$(TESTS)`: Which unit tests to execute. Useful in conjunction with the + `make run-tests` target: + + make run-tests TESTS=bin/Debug/Java.Interop-Tests.dll + +* `$(V)`: If set to a non-empty string, adds `/v:diag` to `$(MSBUILD_FLAGS)` + invocations. +* `$(MSBUILD)`: The MSBuild build tool to execute for builds. + Default value is `xbuild`. + diff --git a/external/Java.Interop/Documentation/EnumMappingFile.md b/external/Java.Interop/Documentation/EnumMappingFile.md new file mode 100644 index 00000000000..0b92324bc71 --- /dev/null +++ b/external/Java.Interop/Documentation/EnumMappingFile.md @@ -0,0 +1,102 @@ +# Enumeration Mapping File Documentation + +## Background + +In order to help with binding enumification (the process of converting groups +of Java constant int fields into C# enums), a file can be created that defines +a map between the fields and the enums to be created. + +There is a CSV format and an XML format of this file. In practice, users are +guided to the XML format via our [documentation][0] and templates. The CSV format +is mainly used internally for `Mono.Android.dll`, as it converts thousands of +constants into hundreds of enums. + +## CSV Format + +The basic format since the beginning of Xamarin contains up to 6 fields: + +* **API Level** - This is generally only used by `Mono.Android.dll` to denote + the Android level the constant was introduced in. For other uses this + is generally `0`. +* **Enum Type** - C# namespace and type of the enum to create. For example: + `Android.Views.WindowProgress`. +* **Enum Member** - C# name of the enum to create. For example: + `Start` +* **Enum Value** - The value of the enum. For example: `0`. +* **JNI Signature** - The JNI signature of the Java constant to convert. For example: + `android/view/Window.PROGRESS_START`. +* **Flags** - If this field contains `flags` the enum will be created with the + `[Flags]` attribute. (Any member will `flags` will make the whole enum `[Flags]`.) + +Full example: +``` +10,Android.Views.WindowProgress,Start,android/view/Window.PROGRESS_START,0,flags +``` + +--- +**NOTE** + +Our CSV files also allow comments using `//`. Lines beginning with this +sequence are ignored. + +--- + +### Transient Mode + +By default, Java constants referenced in this format are kept. However the +file can contain a line like this at any point: +``` +- ENTER TRANSIENT MODE - +``` + +Any v1 constants referenced *AFTER* this line will be removed from the bindings. +(This will not affect v2 constants.) + +## CSV Format v2 + +Over time we have found some limitations to the format, such as being able +to specify if the Java constant field should be removed. Additionally, since the +format only specifies constants that *SHOULD* be mapped, we cannot use this +to track constants that we have examined and determined *SHOULD NOT* be mapped. +This has led to various blacklists and tooling of varying success to prevent +us from needing to continually re-audit those constants. + +There is now a "v2" version of defining constants. This is a line-level change +and you can mix "v1" and "v2" lines in the same file for backwards compatibility, +but for consistency it's probably better to stick to one style. + +A "v2" line contains up to 9 fields: + +* **Action** - The action to perform. This is what denotes a "v2" line, if the first + character is not one of the following it will be treated as "v1". + * `E` - Create a C# enum from a Java constant + * `A` - Create a C# enum not mapped to a Java constant + * `R` - Remove a Java constant but do not create a C# enum + * `I` - Explicitly ignore this Java constant + * `?` - Unknown, an explicit action has not been decided yet, will be ignored +* **API Level** - This is generally only used by `Mono.Android.dll` to denote + the Android level the constant was introduced in. For other uses this + is generally `0`. +* **JNI Signature** - The JNI signature of the Java constant to convert. For example: + `android/view/Window.PROGRESS_START`. +* **Enum Value** - The value of the enum. For example: `0`. +* **Enum Type** - C# namespace and type of the enum to create. For example: + `Android.Views.WindowProgress`. +* **Enum Member** - C# name of the enum to create. For example: + `Start` +* **Field Action** - Action to take on the Java constant. (This replaces Transient mode.) + * `remove` - Remove the Java constant + * `keep` - Keeps the Java constant +* **Flags** - If this field contains `flags` the enum will be created with the + `[Flags]` attribute. (Any member will `flags` will make the whole enum `[Flags]`.) +* **Deprecated Since** - This is generally only used by `Mono.Android.dll` to denote + the Android level the constant was deprecated in. Specifying "-1" will add an obsolete + message to the effect of: "This value was incorrectly added to the enumeration and is + not a valid value". Leave blank if constant is not deprecated. + +Full example: +``` +E,10,android/view/Window.PROGRESS_START,0,Android.Views.WindowProgress,Start,remove,flags,30 +``` + +[0]: https://docs.microsoft.com/en-us/xamarin/android/platform/binding-java-library/customizing-bindings/java-bindings-metadata#enumfieldsxml-and-enummethodsxml diff --git a/external/Java.Interop/Documentation/JNI-Invocation-Overhead-Musings.md b/external/Java.Interop/Documentation/JNI-Invocation-Overhead-Musings.md new file mode 100644 index 00000000000..4ac6d62dc35 --- /dev/null +++ b/external/Java.Interop/Documentation/JNI-Invocation-Overhead-Musings.md @@ -0,0 +1,163 @@ +# JNI Invocation Overhead Musings + +[tests/PerformanceTests/TimingTests.cs](tests/PerformanceTests/TimingTests.cs) +contains various tests to investigate the overheads involved in using JNI to +invoke Java methods. In particular, see the +`Java.Interop.PerformanceTests.JniMethodInvocationOverheadTiming.MethodInvocationTiming()` +tests, invokes a JNI method `count` times and attempts to "normalize" that to +invoking an equivalent, non-inlined, C# method. + +**Update**: I believe the tests are wrong, but I don't know *how* they're +wrong. (Leaving "misleading" statements in this file until I know what's +actually going on.) + +The content below suggests that the JNI overhead is proportional with the +number of JNI invocations, e.g. when `count` is 10, JNI invocations are ~5x +that of an "equivalent" C# method invocation, while when `count` is 100000, +JNI invocations are ~808x, which makes *no sense at all*, but that was the +observed behavior. + +Further investigation suggests that this hypothesis is bunk, those numbers +are bunk, something else is going on, and I still have no idea what's going on. + +That said, consider [commit c9db386c][c9db386c], which now starts printing +the *average* invocation time in a nice, human-readable, format. +When `count` is 100,000, the `static void i3` output is: + +[c9db386c]: https://github.com/xamarin/Java.Interop/commit/c9db386c5457ff6243b3e36d919ca8669f502192 + + Method Invoke: static void i3: JNI is 94x managed + C/JNI: 2.0 ms | average: 0.002 ms + JNI: 14.3707 ms; 7x C/JNI | average: 0.01437 ms + Managed: 0.1529 ms | average: 0.00015 ms + Pinvoke: 0.1269 ms; 1x managed | average: 0.00013 ms + +(Quick aside: odd that the above run says JNI is 94x managed, while below +it's 808x managed! Numbers be *weird*.) + +Of interest here is the **C/JNI** line, which shows that the average +invocation time of the `static void i3` method is 0.002ms. + +What the description below suggests is that this average time is proportional +to `count`: when `count` is small, the C/JNI average time is smaller than +the C/JNI average time when `count` is large. + +*This cannot be independently verified.* + +In point of fact, [I cannot reproduce this behavior][art-timing-test.zip]. +No matter what `count` value I choose, the average time for invoking +`JNIEnv::CallStaticVoidMethod()` *is the same* (roughly): 0.001ms. (It differs +from the above `static void i3` value, likely because it's a `static void`). + +[art-timing-test.zip]: https://files.xamarin.com/~jonp/tests/art-timing-test.zip + +For a given Java method signature, e.g. `static void m()`, invocation time is +consistent on ART (Android M Preview 2, Nexus 5). It doesn't vary, certainly not +with the `count` value. + +Instead, JNI overhead appears to be fairly consistent (for a given signature). +At ~0.002ms per invocation, you can perform roughly 500,000 JNI method +invocations per *second* from C#, which sounds good unless you need to +manipulate raw Bitmap data... + +--- + +[Commit c60f6093][c60f6093] observed that Android appeared to be much faster +than the JVM at these tests. This observation appears to have been wrong. +More interesting is that the "JNI method invocation overhead," defined as +what this test is attempting to measure (which may be wrong!), varies +based on the number of method invocations. + +[c60f6093]: https://github.com/xamarin/Java.Interop/commit/c60f6093 + +For example, if we look at just the summary information of one test +as we vary the value of `count`, the number of times we invoke the +Java method via JNI or the C# method, we see that there is a nonlinear +relationship between the count and the overhead: + + count= 10: Method Invoke: static void i3: JNI is 5x managed + count= 100: Method Invoke: static void i3: JNI is 10x managed + count= 500: Method Invoke: static void i3: JNI is 22x managed + count= 1000: Method Invoke: static void i3: JNI is 63x managed + count= 10000: Method Invoke: static void i3: JNI is 474x managed + count=100000: Method Invoke: static void i3: JNI is 808x managed + +Particularly troubling is the *huge* jump between count=1000 and +count=10000. Count=1000000 is provided for comparison with the JVM, +which provides the following results: + + count=1000000: Method Invoke: static void i3: JNI is 413x managed [JVM] + +We don't know why there's a jump, but this is in fact somewhat encouraging: +if you're only calling methods in a one-off fashion -- as is frequently +the case in Xamarin.Android -- then the overhead isn't actually that bad, +on a per-method invoke basis. It appears to only get really bad when +invoking the same method repetitively, *a lot*, which I believe shouldn't +be *that* common a use case (outside of image manipulation?). + +### JNI and P/Invoke + +[Commit 9d2dfc5][9d2dfc5] observed that there's a fair bit of overhead +associated with using `SafeHandle`s, in large part because `SafeHandle`s +need to be [*thread safe*][cbrumme-SafeHandle] in order to prevent +[handle recycling attacks][handle-recycle]. Xamarin.Android doesn't +suffer from handle recycling attacks *only* because Mono's SGEN GC +conservatively scans the stack, prolonging the lifetime of all temporaries +found there. If/when Xamarin.Android moves to a precise GC for the stack, +this may no longer be the case and handle recycling attacks -- along +with possibly finalizing/`Dispose()`ing of instances +*while they're still being used* -- can become "a thing". + +[9d2dfc5]: https://github.com/xamarin/Java.Interop/commit/9d2dfc5 +[cbrumme-SafeHandle]: http://blogs.msdn.com/b/cbrumme/archive/2004/02/20/77460.aspx +[handle-recycle]: http://blogs.msdn.com/b/cbrumme/archive/2003/04/19/51365.aspx + +(...except that handle recycling attacks *can't* become "a thing". A working +GC bridge precludes it, because collections must *always* be delayed until +a Java-side collection has been completed, as the JVM may be keeping an +instance alive. It is thus highly unlikely, even if a precise GC were used, +that a Java bridged instance would be collected in this manner.) + +An idea that came to mind to reduce the overhead of `SafeHandle` use was to +P/Invoke to a native library to perform the `JNIEnv` function pointer +invocations instead of using `delegate` invocations alongside +`Marshal.GetDelegateForFunctionPointer()`, as is currently the case. + +This was implemented in the [pinvoke-jnienv][pinvoke-jnienv] branch, +in [commit 802842a3][802842a3]. + +[pinvoke-jnienv]: https://github.com/xamarin/Java.Interop/commits/pinvoke-jnienv +[802842a3]: https://github.com/xamarin/Java.Interop/commit/802842a361380812e290fe3585fea8c0a7a19b97 + +The result: Using P/Invoke *increases* invocation overhead: + + # "Full" Invocations: JNIEnv::CallObjectMethod() + JNIEnv::DeleteLocalRef() for 10000 iterations + Java.Interop Object.toString() Timing: 00:00:30.0774575; 3.00774575 ms/iteration -- ~386.391119190154x + Xamarin.Android Object.toString() Timing: 00:00:00.0778420; 0.0077842 ms/iteration + # JNIEnv::CallObjectMethod() for 500 iterations + Java.Interop Object.toString() Timing: 00:00:00.8041310; 1.608262 ms/CallVirtualObjectMethod() -- ~266.648207712969x + Xamarin.Android CallObjectMethod() Timing: 00:00:00.0030157; 0.0060314 ms/CallObjectMethod() + # JNIEnv::DeleteLocalRef() for 500 iterations + Java.Interop JniLocalReference.Dispose() Timing: 00:00:00.8979645; 1.795929 ms/Dispose() -- ~1661.05160932297x + Xamarin.Android DeleteLocalRef() Timing: 00:00:00.0005406; 0.0010812 ms/DeleteLocalRef() + ## Breaking down the above Object.toString() + JniLocalReference.Dispose() timings, the JNI calls: + # JNIEnv::CallObjectMethod: SafeHandle vs. IntPtr + Java.Interop safeCall() Timing: 00:00:00.0058775; 0.011755 ms/SafeHandle JNIEnv::CallObjectMethodA() -- ~2.14538618776464x + Java.Interop P/Invoke safeCall() Timing: 00:00:00.0069479; 0.0138958 ms/SafeHandle JNIEnv::CallObjectMethodA() -- ~2.53610016060739x + Java.Interop unsafeCall() Timing: 00:00:00.0027396; 0.0054792 ms/IntPtr JNIEnv::CallObjectMethodA() + # JNIEnv::DeleteLocalRef: SafeHandle vs. IntPtr + Java.Interop safeDel() Timing: 00:00:00.0006010; 0.001202 ms/SafeHandle JNIEnv::DeleteLocalRef() -- ~1.47412312975227x + Java.Interop P/Invoke safeDel() Timing: 00:00:00.0007480; 0.001496 ms/SafeHandle JNIEnv::DeleteLocalRef() -- ~1.83468236448369x + Java.Interop unsafeDel() Timing: 00:00:00.0004077; 0.0008154 ms/IntPtr JNIEnv::DeleteLocalRef + +In particular, note the `Java.Interop P/Invoke` lines: + + Java.Interop P/Invoke safeCall() Timing: 00:00:00.0069479; 0.0138958 ms/SafeHandle JNIEnv::CallObjectMethodA() -- ~2.53610016060739x + Java.Interop P/Invoke safeDel() Timing: 00:00:00.0007480; 0.001496 ms/SafeHandle JNIEnv::DeleteLocalRef() -- ~1.83468236448369x + +Compare to the `SafeHandle`-using delegate-based invocations: + + Java.Interop safeCall() Timing: 00:00:00.0058775; 0.011755 ms/SafeHandle JNIEnv::CallObjectMethodA() -- ~2.14538618776464x + Java.Interop safeDel() Timing: 00:00:00.0006010; 0.001202 ms/SafeHandle JNIEnv::DeleteLocalRef() -- ~1.47412312975227x + +Surprisingly, using delegates results in less overhead than using P/Invoke. diff --git a/external/Java.Interop/Documentation/Motivation.md b/external/Java.Interop/Documentation/Motivation.md new file mode 100644 index 00000000000..da2cc02b539 --- /dev/null +++ b/external/Java.Interop/Documentation/Motivation.md @@ -0,0 +1,29 @@ +# Motivation + +**Java.Interop** is a binding of the [Java Native Interface][jni] for use from +managed languages such as C#, and an associated set of code generators to +allow Java code to invoke managed code. It is *also* a brain-delusional +[Second System Syndrome][sss] rebuild of the monodroid/Xamarin.Android core, +intended to fix some of the shortcomings and design mistakes I've made over the years. + +[jni]: http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html +[sss]: http://en.wikipedia.org/wiki/Second-system_effect + +In particular, it attempts to fix the following issues: + +* Split out the core invocation logic so it can be used without taking an + API-level constraint. +* Make the assembly a reusable .NET library. +* Support use of the lib on "desktop" Java VMs. This would allow more testing + without an Android device, could allow using Xamarin.Android Views to be shown + in the GUI designer, etc. +* Improve type safety. +* Improve consistency. + +In particular are the last two points: Xamarin.Android currently uses `IntPtr`s +*everywhere*, and it's not at all obvious what they are (method IDs vs. +local refs vs. global refs vs. ...). This culminates in `JNIEnv.FindClass()`, +which returns a global reference while most other methods return a local ref. + +The `JNIEnv` API is also huge, unwieldy, and terrible. + diff --git a/external/Java.Interop/GitInfo.txt b/external/Java.Interop/GitInfo.txt new file mode 100644 index 00000000000..2f52450b31d --- /dev/null +++ b/external/Java.Interop/GitInfo.txt @@ -0,0 +1 @@ +10.0 diff --git a/external/Java.Interop/Java.Interop.code-workspace b/external/Java.Interop/Java.Interop.code-workspace new file mode 100644 index 00000000000..7ad00c311c1 --- /dev/null +++ b/external/Java.Interop/Java.Interop.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "java.configuration.updateBuildConfiguration": "interactive" + } + } \ No newline at end of file diff --git a/external/Java.Interop/Java.Interop.sln b/external/Java.Interop/Java.Interop.sln new file mode 100644 index 00000000000..4554dfb3a82 --- /dev/null +++ b/external/Java.Interop/Java.Interop.sln @@ -0,0 +1,296 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29424.173 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{C8F58966-94BF-407F-914A-8654F8B8AE3B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logcat-parse", "tools\logcat-parse\logcat-parse.csproj", "{7387E151-48E3-4885-B2CA-A74434A34045}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "class-parse", "tools\class-parse\class-parse.csproj", "{38C762AB-8FD1-44DE-9855-26AAE7129DC3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "generator", "tools\generator\generator.csproj", "{D14A1B5C-2060-4930-92BE-F7190256C735}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{4C173212-371D-45D8-BA83-9226194F48DC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop", "src\Java.Interop\Java.Interop.csproj", "{94BD81F7-B06F-4295-9636-F8A3B6BDC762}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-interop", "src\java-interop\java-interop.csproj", "{BB0AB9F7-0979-41A7-B7A9-877260655F94}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaSource", "src\Java.Interop.Tools.JavaSource\Java.Interop.Tools.JavaSource.csproj", "{5C0B3562-8DA0-4726-9762-75B9709ED6B7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Desktop", "Desktop", "{0998E45F-8BCE-4791-A944-962CD54E2D80}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.Bytecode", "src\Xamarin.Android.Tools.Bytecode\Xamarin.Android.Tools.Bytecode.csproj", "{B17475BC-45A2-47A3-B8FC-62F3A0959EE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.AnnotationSupport", "src\Xamarin.Android.Tools.AnnotationSupport\Xamarin.Android.Tools.AnnotationSupport.csproj", "{07BC4495-1267-4B78-9EA6-B76FEEA2A64A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.ApiXmlAdjuster", "src\Xamarin.Android.Tools.ApiXmlAdjuster\Xamarin.Android.Tools.ApiXmlAdjuster.csproj", "{1268EADF-8344-431C-81F6-FCB7CBC99F49}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.AnnotationSupport.Cecil", "src\Xamarin.Android.Tools.AnnotationSupport.Cecil\Xamarin.Android.Tools.AnnotationSupport.Cecil.csproj", "{41DFB021-F795-4EB6-8E53-0D069C0BED9F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Desktop-Tests", "Desktop-Tests", "{271C9F30-F679-4793-942B-0D9527CB3E2F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestJVM", "tests\TestJVM\TestJVM.csproj", "{A76309AB-98AC-4AE2-BA30-75481420C52F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop-Tests", "tests\Java.Interop-Tests\Java.Interop-Tests.csproj", "{04E28441-36FF-4964-ADD7-EFBB47CCE406}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logcat-parse-Tests", "tests\logcat-parse-Tests\logcat-parse-Tests.csproj", "{DB05D566-0BA0-4935-868D-689E2F03688E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.Bytecode-Tests", "tests\Xamarin.Android.Tools.Bytecode-Tests\Xamarin.Android.Tools.Bytecode-Tests.csproj", "{C9FA4492-DEB0-4932-A6B8-E2C4E0581692}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.ApiXmlAdjuster-Tests", "tests\Xamarin.Android.Tools.ApiXmlAdjuster-Tests\Xamarin.Android.Tools.ApiXmlAdjuster-Tests.csproj", "{891F2E04-5614-4A26-A78F-3778025ECF43}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "generator-Tests", "tests\generator-Tests\generator-Tests.csproj", "{4EEAB1A7-99C1-4302-9C18-01A7B481409B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build-Tools", "Build-Tools", "{172B608B-E6F3-41CC-9949-203A76BA247C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jnienv-gen", "build-tools\jnienv-gen\jnienv-gen.csproj", "{6410DA0F-5E14-4FC0-9AEE-F4C542C96C7A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaCallableWrappers", "src\Java.Interop.Tools.JavaCallableWrappers\Java.Interop.Tools.JavaCallableWrappers.csproj", "{D18FCF91-8876-48A0-A693-2DC1E7D3D80A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Cecil", "src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil.csproj", "{D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Diagnostics", "src\Java.Interop.Tools.Diagnostics\Java.Interop.Tools.Diagnostics.csproj", "{64CC4E44-CE3A-4319-BF3F-6CF8BD513870}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jcw-gen", "tools\jcw-gen\jcw-gen.csproj", "{52C7D9B6-E8C8-47D0-9471-652D278D7D77}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaCallableWrappers-Tests", "tests\Java.Interop.Tools.JavaCallableWrappers-Tests\Java.Interop.Tools.JavaCallableWrappers-Tests.csproj", "{58B564A1-570D-4DA2-B02D-25BDDB1A9F4F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.AndroidSdk", "external\xamarin-android-tools\src\Xamarin.Android.Tools.AndroidSdk\Xamarin.Android.Tools.AndroidSdk.csproj", "{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaSource-Tests", "tests\Java.Interop.Tools.JavaSource-Tests\Java.Interop.Tools.JavaSource-Tests.csproj", "{093B5E94-7FB7-499F-9C11-30944BAFEE25}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "param-name-importer", "tools\param-name-importer\param-name-importer.csproj", "{0E3AF6C1-7638-464D-9174-485D494499DC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Generator", "src\Java.Interop.Tools.Generator\Java.Interop.Tools.Generator.csproj", "{C2FD2F12-DE3B-4FB9-A0D3-FA3EF597DD04}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.Generator-Tests", "tests\Java.Interop.Tools.Generator-Tests\Java.Interop.Tools.Generator-Tests.csproj", "{7F4828AB-3908-458C-B09F-33C74A1368F9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-source-utils", "tools\java-source-utils\java-source-utils.csproj", "{F46EDFA5-C52A-4F0C-B5A2-5BB67E0D8C74}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.SourceWriter", "src\Xamarin.SourceWriter\Xamarin.SourceWriter.csproj", "{C5B732C8-7AF3-41D3-B903-AEDFC392E5BA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.SourceWriter-Tests", "tests\Xamarin.SourceWriter-Tests\Xamarin.SourceWriter-Tests.csproj", "{6CF94627-BA74-4336-88CD-7EDA20C8F292}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Localization", "src\Java.Interop.Localization\Java.Interop.Localization.csproj", "{998D178B-F4C7-48B5-BDEE-44E2F869BB22}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeTiming", "tests\NativeTiming\NativeTiming.csproj", "{BF5A4019-F2FF-45AC-949D-EF7E8C94196B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaTypeSystem", "src\Java.Interop.Tools.JavaTypeSystem\Java.Interop.Tools.JavaTypeSystem.csproj", "{B173F53B-986C-4E0D-881C-063BBB116E1D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.JavaTypeSystem-Tests", "tests\Java.Interop.Tools.JavaTypeSystem-Tests\Java.Interop.Tools.JavaTypeSystem-Tests.csproj", "{11942DE9-AEC2-4B95-87AB-CA707C37643D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Maven", "src\Java.Interop.Tools.Maven\Java.Interop.Tools.Maven.csproj", "{DA458F90-218B-4FE3-995F-AF4B27895FA2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Maven-Tests", "tests\Java.Interop.Tools.Maven-Tests\Java.Interop.Tools.Maven-Tests.csproj", "{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{40B3CE2F-B8DE-45CD-A43A-0F1A89BDB803}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.TypeNameMappings", "src\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.csproj", "{C2AF6ACF-04F6-4B41-95EA-97A372C075F9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7387E151-48E3-4885-B2CA-A74434A34045}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7387E151-48E3-4885-B2CA-A74434A34045}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7387E151-48E3-4885-B2CA-A74434A34045}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7387E151-48E3-4885-B2CA-A74434A34045}.Release|Any CPU.Build.0 = Release|Any CPU + {38C762AB-8FD1-44DE-9855-26AAE7129DC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38C762AB-8FD1-44DE-9855-26AAE7129DC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38C762AB-8FD1-44DE-9855-26AAE7129DC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38C762AB-8FD1-44DE-9855-26AAE7129DC3}.Release|Any CPU.Build.0 = Release|Any CPU + {D14A1B5C-2060-4930-92BE-F7190256C735}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D14A1B5C-2060-4930-92BE-F7190256C735}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D14A1B5C-2060-4930-92BE-F7190256C735}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D14A1B5C-2060-4930-92BE-F7190256C735}.Release|Any CPU.Build.0 = Release|Any CPU + {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Release|Any CPU.Build.0 = Release|Any CPU + {BB0AB9F7-0979-41A7-B7A9-877260655F94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB0AB9F7-0979-41A7-B7A9-877260655F94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB0AB9F7-0979-41A7-B7A9-877260655F94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB0AB9F7-0979-41A7-B7A9-877260655F94}.Release|Any CPU.Build.0 = Release|Any CPU + {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Release|Any CPU.Build.0 = Release|Any CPU + {B17475BC-45A2-47A3-B8FC-62F3A0959EE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B17475BC-45A2-47A3-B8FC-62F3A0959EE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B17475BC-45A2-47A3-B8FC-62F3A0959EE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B17475BC-45A2-47A3-B8FC-62F3A0959EE0}.Release|Any CPU.Build.0 = Release|Any CPU + {07BC4495-1267-4B78-9EA6-B76FEEA2A64A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07BC4495-1267-4B78-9EA6-B76FEEA2A64A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07BC4495-1267-4B78-9EA6-B76FEEA2A64A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07BC4495-1267-4B78-9EA6-B76FEEA2A64A}.Release|Any CPU.Build.0 = Release|Any CPU + {1268EADF-8344-431C-81F6-FCB7CBC99F49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1268EADF-8344-431C-81F6-FCB7CBC99F49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1268EADF-8344-431C-81F6-FCB7CBC99F49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1268EADF-8344-431C-81F6-FCB7CBC99F49}.Release|Any CPU.Build.0 = Release|Any CPU + {41DFB021-F795-4EB6-8E53-0D069C0BED9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41DFB021-F795-4EB6-8E53-0D069C0BED9F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41DFB021-F795-4EB6-8E53-0D069C0BED9F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41DFB021-F795-4EB6-8E53-0D069C0BED9F}.Release|Any CPU.Build.0 = Release|Any CPU + {A76309AB-98AC-4AE2-BA30-75481420C52F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A76309AB-98AC-4AE2-BA30-75481420C52F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A76309AB-98AC-4AE2-BA30-75481420C52F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A76309AB-98AC-4AE2-BA30-75481420C52F}.Release|Any CPU.Build.0 = Release|Any CPU + {04E28441-36FF-4964-ADD7-EFBB47CCE406}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04E28441-36FF-4964-ADD7-EFBB47CCE406}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04E28441-36FF-4964-ADD7-EFBB47CCE406}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04E28441-36FF-4964-ADD7-EFBB47CCE406}.Release|Any CPU.Build.0 = Release|Any CPU + {DB05D566-0BA0-4935-868D-689E2F03688E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB05D566-0BA0-4935-868D-689E2F03688E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB05D566-0BA0-4935-868D-689E2F03688E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB05D566-0BA0-4935-868D-689E2F03688E}.Release|Any CPU.Build.0 = Release|Any CPU + {C9FA4492-DEB0-4932-A6B8-E2C4E0581692}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9FA4492-DEB0-4932-A6B8-E2C4E0581692}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9FA4492-DEB0-4932-A6B8-E2C4E0581692}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9FA4492-DEB0-4932-A6B8-E2C4E0581692}.Release|Any CPU.Build.0 = Release|Any CPU + {891F2E04-5614-4A26-A78F-3778025ECF43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {891F2E04-5614-4A26-A78F-3778025ECF43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {891F2E04-5614-4A26-A78F-3778025ECF43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {891F2E04-5614-4A26-A78F-3778025ECF43}.Release|Any CPU.Build.0 = Release|Any CPU + {4EEAB1A7-99C1-4302-9C18-01A7B481409B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4EEAB1A7-99C1-4302-9C18-01A7B481409B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4EEAB1A7-99C1-4302-9C18-01A7B481409B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4EEAB1A7-99C1-4302-9C18-01A7B481409B}.Release|Any CPU.Build.0 = Release|Any CPU + {6410DA0F-5E14-4FC0-9AEE-F4C542C96C7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6410DA0F-5E14-4FC0-9AEE-F4C542C96C7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6410DA0F-5E14-4FC0-9AEE-F4C542C96C7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6410DA0F-5E14-4FC0-9AEE-F4C542C96C7A}.Release|Any CPU.Build.0 = Release|Any CPU + {D18FCF91-8876-48A0-A693-2DC1E7D3D80A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D18FCF91-8876-48A0-A693-2DC1E7D3D80A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D18FCF91-8876-48A0-A693-2DC1E7D3D80A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D18FCF91-8876-48A0-A693-2DC1E7D3D80A}.Release|Any CPU.Build.0 = Release|Any CPU + {D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}.Release|Any CPU.Build.0 = Release|Any CPU + {64CC4E44-CE3A-4319-BF3F-6CF8BD513870}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64CC4E44-CE3A-4319-BF3F-6CF8BD513870}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64CC4E44-CE3A-4319-BF3F-6CF8BD513870}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64CC4E44-CE3A-4319-BF3F-6CF8BD513870}.Release|Any CPU.Build.0 = Release|Any CPU + {52C7D9B6-E8C8-47D0-9471-652D278D7D77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52C7D9B6-E8C8-47D0-9471-652D278D7D77}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52C7D9B6-E8C8-47D0-9471-652D278D7D77}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52C7D9B6-E8C8-47D0-9471-652D278D7D77}.Release|Any CPU.Build.0 = Release|Any CPU + {58B564A1-570D-4DA2-B02D-25BDDB1A9F4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58B564A1-570D-4DA2-B02D-25BDDB1A9F4F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58B564A1-570D-4DA2-B02D-25BDDB1A9F4F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58B564A1-570D-4DA2-B02D-25BDDB1A9F4F}.Release|Any CPU.Build.0 = Release|Any CPU + {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Release|Any CPU.Build.0 = Release|Any CPU + {093B5E94-7FB7-499F-9C11-30944BAFEE25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {093B5E94-7FB7-499F-9C11-30944BAFEE25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {093B5E94-7FB7-499F-9C11-30944BAFEE25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {093B5E94-7FB7-499F-9C11-30944BAFEE25}.Release|Any CPU.Build.0 = Release|Any CPU + {0E3AF6C1-7638-464D-9174-485D494499DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E3AF6C1-7638-464D-9174-485D494499DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E3AF6C1-7638-464D-9174-485D494499DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E3AF6C1-7638-464D-9174-485D494499DC}.Release|Any CPU.Build.0 = Release|Any CPU + {C2FD2F12-DE3B-4FB9-A0D3-FA3EF597DD04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2FD2F12-DE3B-4FB9-A0D3-FA3EF597DD04}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2FD2F12-DE3B-4FB9-A0D3-FA3EF597DD04}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2FD2F12-DE3B-4FB9-A0D3-FA3EF597DD04}.Release|Any CPU.Build.0 = Release|Any CPU + {7F4828AB-3908-458C-B09F-33C74A1368F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F4828AB-3908-458C-B09F-33C74A1368F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F4828AB-3908-458C-B09F-33C74A1368F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F4828AB-3908-458C-B09F-33C74A1368F9}.Release|Any CPU.Build.0 = Release|Any CPU + {F46EDFA5-C52A-4F0C-B5A2-5BB67E0D8C74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F46EDFA5-C52A-4F0C-B5A2-5BB67E0D8C74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F46EDFA5-C52A-4F0C-B5A2-5BB67E0D8C74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F46EDFA5-C52A-4F0C-B5A2-5BB67E0D8C74}.Release|Any CPU.Build.0 = Release|Any CPU + {C5B732C8-7AF3-41D3-B903-AEDFC392E5BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5B732C8-7AF3-41D3-B903-AEDFC392E5BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5B732C8-7AF3-41D3-B903-AEDFC392E5BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5B732C8-7AF3-41D3-B903-AEDFC392E5BA}.Release|Any CPU.Build.0 = Release|Any CPU + {6CF94627-BA74-4336-88CD-7EDA20C8F292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CF94627-BA74-4336-88CD-7EDA20C8F292}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CF94627-BA74-4336-88CD-7EDA20C8F292}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CF94627-BA74-4336-88CD-7EDA20C8F292}.Release|Any CPU.Build.0 = Release|Any CPU + {998D178B-F4C7-48B5-BDEE-44E2F869BB22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {998D178B-F4C7-48B5-BDEE-44E2F869BB22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {998D178B-F4C7-48B5-BDEE-44E2F869BB22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {998D178B-F4C7-48B5-BDEE-44E2F869BB22}.Release|Any CPU.Build.0 = Release|Any CPU + {BF5A4019-F2FF-45AC-949D-EF7E8C94196B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF5A4019-F2FF-45AC-949D-EF7E8C94196B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF5A4019-F2FF-45AC-949D-EF7E8C94196B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF5A4019-F2FF-45AC-949D-EF7E8C94196B}.Release|Any CPU.Build.0 = Release|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B173F53B-986C-4E0D-881C-063BBB116E1D}.Release|Any CPU.Build.0 = Release|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11942DE9-AEC2-4B95-87AB-CA707C37643D}.Release|Any CPU.Build.0 = Release|Any CPU + {DA458F90-218B-4FE3-995F-AF4B27895FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA458F90-218B-4FE3-995F-AF4B27895FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA458F90-218B-4FE3-995F-AF4B27895FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA458F90-218B-4FE3-995F-AF4B27895FA2}.Release|Any CPU.Build.0 = Release|Any CPU + {6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}.Release|Any CPU.Build.0 = Release|Any CPU + {C2AF6ACF-04F6-4B41-95EA-97A372C075F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2AF6ACF-04F6-4B41-95EA-97A372C075F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2AF6ACF-04F6-4B41-95EA-97A372C075F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2AF6ACF-04F6-4B41-95EA-97A372C075F9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {7387E151-48E3-4885-B2CA-A74434A34045} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} + {38C762AB-8FD1-44DE-9855-26AAE7129DC3} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} + {D14A1B5C-2060-4930-92BE-F7190256C735} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} + {94BD81F7-B06F-4295-9636-F8A3B6BDC762} = {4C173212-371D-45D8-BA83-9226194F48DC} + {BB0AB9F7-0979-41A7-B7A9-877260655F94} = {4C173212-371D-45D8-BA83-9226194F48DC} + {5C0B3562-8DA0-4726-9762-75B9709ED6B7} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {B17475BC-45A2-47A3-B8FC-62F3A0959EE0} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {07BC4495-1267-4B78-9EA6-B76FEEA2A64A} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {1268EADF-8344-431C-81F6-FCB7CBC99F49} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {41DFB021-F795-4EB6-8E53-0D069C0BED9F} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {A76309AB-98AC-4AE2-BA30-75481420C52F} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {04E28441-36FF-4964-ADD7-EFBB47CCE406} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {DB05D566-0BA0-4935-868D-689E2F03688E} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {C9FA4492-DEB0-4932-A6B8-E2C4E0581692} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {891F2E04-5614-4A26-A78F-3778025ECF43} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {4EEAB1A7-99C1-4302-9C18-01A7B481409B} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {6410DA0F-5E14-4FC0-9AEE-F4C542C96C7A} = {172B608B-E6F3-41CC-9949-203A76BA247C} + {D18FCF91-8876-48A0-A693-2DC1E7D3D80A} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {64CC4E44-CE3A-4319-BF3F-6CF8BD513870} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {52C7D9B6-E8C8-47D0-9471-652D278D7D77} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} + {58B564A1-570D-4DA2-B02D-25BDDB1A9F4F} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157} = {172B608B-E6F3-41CC-9949-203A76BA247C} + {093B5E94-7FB7-499F-9C11-30944BAFEE25} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {0E3AF6C1-7638-464D-9174-485D494499DC} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} + {C2FD2F12-DE3B-4FB9-A0D3-FA3EF597DD04} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {7F4828AB-3908-458C-B09F-33C74A1368F9} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {F46EDFA5-C52A-4F0C-B5A2-5BB67E0D8C74} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} + {C5B732C8-7AF3-41D3-B903-AEDFC392E5BA} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {6CF94627-BA74-4336-88CD-7EDA20C8F292} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {998D178B-F4C7-48B5-BDEE-44E2F869BB22} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {BF5A4019-F2FF-45AC-949D-EF7E8C94196B} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {B173F53B-986C-4E0D-881C-063BBB116E1D} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {11942DE9-AEC2-4B95-87AB-CA707C37643D} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {DA458F90-218B-4FE3-995F-AF4B27895FA2} = {0998E45F-8BCE-4791-A944-962CD54E2D80} + {6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {C2AF6ACF-04F6-4B41-95EA-97A372C075F9} = {40B3CE2F-B8DE-45CD-A43A-0F1A89BDB803} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {29204E0C-382A-49A0-A814-AD7FBF9774A5} + EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{58b564a1-570d-4da2-b02d-25bddb1a9f4f}*SharedItemsImports = 5 + src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{d18fcf91-8876-48a0-a693-2dc1e7d3d80a}*SharedItemsImports = 5 + EndGlobalSection +EndGlobal diff --git a/external/Java.Interop/LICENSE b/external/Java.Interop/LICENSE new file mode 100644 index 00000000000..f0cafc60e52 --- /dev/null +++ b/external/Java.Interop/LICENSE @@ -0,0 +1,25 @@ +Xamarin SDK + +The MIT License (MIT) + +Copyright (c) .NET Foundation Contributors + +All rights reserved. + +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. diff --git a/external/Java.Interop/Localize/LocProject.json b/external/Java.Interop/Localize/LocProject.json new file mode 100644 index 00000000000..d77795d62d9 --- /dev/null +++ b/external/Java.Interop/Localize/LocProject.json @@ -0,0 +1,14 @@ +{ + "Projects": [ + { + "LanguageSet": "VS_Main_Languages", + "LocItems": [ + { + "CopyOption": "LangIDOnName", + "SourceFile": ".\\src\\Java.Interop.Localization\\Resources.resx", + "OutputPath": ".\\src\\Java.Interop.Localization" + } + ] + } + ] +} diff --git a/external/Java.Interop/Localize/loc/cs/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/cs/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..29b3dc49952 --- /dev/null +++ b/external/Java.Interop/Localize/loc/cs/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + : {0}]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + .]]> + + + + + + + '.]]> + + .]]> + + + + + + + ' child node: '<{0}>'.]]> + + : <{0}>]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/de/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/de/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..d86884dbf10 --- /dev/null +++ b/external/Java.Interop/Localize/loc/de/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ': '{0}'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ' Elemente gefunden.]]> + + + + + + + '.]]> + + ".]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' untergeordneter Knoten: "<{0}>".]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/es/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/es/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..9db115ee54e --- /dev/null +++ b/external/Java.Interop/Localize/loc/es/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ': "{0}".]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + '.]]> + + + + + + + '.]]> + + ".]]> + + + + + + + ' child node: '<{0}>'.]]> + + ": "<{0}>".]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/fr/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/fr/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..8e5844e3c39 --- /dev/null +++ b/external/Java.Interop/Localize/loc/fr/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ' : '{0}'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ' trouvé.]]> + + + + + + + '.]]> + + '.]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' inattendu : '<{0}>'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/it/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/it/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..226fa88ba25 --- /dev/null +++ b/external/Java.Interop/Localize/loc/it/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ': '{0}'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + '.]]> + + + + + + + '.]]> + + '.]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' imprevisto: '<{0}>'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/ja/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/ja/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..36fc4e6399c --- /dev/null +++ b/external/Java.Interop/Localize/loc/ja/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ' の予期しない子要素です: '{0}'。]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ' 要素が見つかりません。]]> + + + + + + + '.]]> + + '。]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' 子ノードです: '<{0}>'。]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/ko/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/ko/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..d31cb952561 --- /dev/null +++ b/external/Java.Interop/Localize/loc/ko/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + '의 예기치 않은 하위 요소: '{0}'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ' 요소를 찾을 수 없습니다.]]> + + + + + + + '.]]> + + '.]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' 하위 노드: '<{0}>'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/pl/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/pl/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..4165e406cd9 --- /dev/null +++ b/external/Java.Interop/Localize/loc/pl/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ”: „{0}”.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ”.]]> + + + + + + + '.]]> + + ”.]]> + + + + + + + ' child node: '<{0}>'.]]> + + ”: „<{0}>”.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/pt-BR/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/pt-BR/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..be4c640aa56 --- /dev/null +++ b/external/Java.Interop/Localize/loc/pt-BR/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ': '{0}'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ' foi encontrados.]]> + + + + + + + '.]]> + + '.]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' inesperado: '<{0}>'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/ru/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/ru/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..540069cf08f --- /dev/null +++ b/external/Java.Interop/Localize/loc/ru/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ": "{0}".]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + " не найдены.]]> + + + + + + + '.]]> + + ".]]> + + + + + + + ' child node: '<{0}>'.]]> + + ": "<{0}>".]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/tr/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/tr/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..fe734fbb846 --- /dev/null +++ b/external/Java.Interop/Localize/loc/tr/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ' alt öğesi: '{0}'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ' öğeleri bulunamadı.]]> + + + + + + + '.]]> + + '.]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' alt düğümü: '<{0}>'.]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/zh-Hans/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/zh-Hans/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..32ac0e20d5d --- /dev/null +++ b/external/Java.Interop/Localize/loc/zh-Hans/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ”的意外子元素:“{0}”。]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ”元素。]]> + + + + + + + '.]]> + + ”。]]> + + + + + + + ' child node: '<{0}>'.]]> + + ”子节点:“<{0}>”。]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Localize/loc/zh-Hant/src/Java.Interop.Localization/Resources.resx.lcl b/external/Java.Interop/Localize/loc/zh-Hant/src/Java.Interop.Localization/Resources.resx.lcl new file mode 100644 index 00000000000..e43717bf5aa --- /dev/null +++ b/external/Java.Interop/Localize/loc/zh-Hant/src/Java.Interop.Localization/Resources.resx.lcl @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ': '{0}'.]]> + + ' 子項目: '{0}'。]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' elements found.]]> + + ' 元素。]]> + + + + + + + '.]]> + + '。]]> + + + + + + + ' child node: '<{0}>'.]]> + + ' 子節點: '<{0}>'。]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/Makefile b/external/Java.Interop/Makefile new file mode 100644 index 00000000000..d8ede4a321f --- /dev/null +++ b/external/Java.Interop/Makefile @@ -0,0 +1,145 @@ +OS ?= $(shell uname) + +V ?= 0 +CONFIGURATION = Debug + +ifeq ($(OS),Darwin) +NATIVE_EXT = .dylib +DLLMAP_OS_NAME = osx +endif +ifeq ($(OS),Linux) +NATIVE_EXT = .so +DLLMAP_OS_NAME = linux +endif + +PREPARE_EXTERNAL_FILES = \ + external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/Xamarin.Android.Tools.AndroidSdk.csproj + +DEPENDENCIES = + +NET_SUFFIX = -net10.0 +TEST_OUTPUT = bin/Test$(CONFIGURATION)$(NET_SUFFIX) + +TESTS = + +NET_TESTS = \ + $(TEST_OUTPUT)/Java.Interop-Tests.dll \ + $(TEST_OUTPUT)/Java.Interop.Tools.JavaCallableWrappers-Tests.dll \ + $(TEST_OUTPUT)/Java.Interop.Tools.JavaSource-Tests.dll \ + $(TEST_OUTPUT)/Java.Interop.Tools.Maven-Tests.dll \ + $(TEST_OUTPUT)/Java.Interop.Tools.JavaTypeSystem-Tests.dll \ + $(TEST_OUTPUT)/Java.Interop.Tools.Generator-Tests.dll \ + $(TEST_OUTPUT)/Xamarin.Android.Tools.ApiXmlAdjuster-Tests.dll \ + $(TEST_OUTPUT)/Xamarin.Android.Tools.Bytecode-Tests.dll \ + $(TEST_OUTPUT)/Xamarin.SourceWriter-Tests.dll \ + $(TEST_OUTPUT)/generator-Tests.dll \ + $(TEST_OUTPUT)/logcat-parse-Tests.dll + +PTESTS = + +all: $(DEPENDENCIES) $(TESTS) $(NET_TESTS) + +bin/ilverify: + -mkdir bin + dotnet tool install --tool-path bin dotnet-ilverify + +run-all-tests: + r=0; \ + $(MAKE) run-tests || r=1 ; \ + $(MAKE) run-net-tests || r=1 ; \ + $(MAKE) run-ptests || r=1 ; \ + $(MAKE) run-java-source-utils-tests || r=1 ; \ + exit $$r; + +include build-tools/scripts/msbuild.mk + +prepare:: $(BUILD_PROPS) + +prepare:: + $(MSBUILD) $(MSBUILD_FLAGS) -target:Prepare + $(MSBUILD) $(MSBUILD_FLAGS) -target:Restore + +clean: + -$(MSBUILD) $(MSBUILD_FLAGS) /t:Clean + -rm -Rf bin/$(CONFIGURATION) bin/Build$(CONFIGURATION) bin/Test$(CONFIGURATION) + +include build-tools/scripts/mono.mk +-include bin/Build$(CONFIGURATION)/mono.mk +-include bin/Build$(CONFIGURATION)/JdkInfo.mk + +NATIVE_TIMING_LIB = libNativeTiming$(NATIVE_EXT) + +bin/Test$(CONFIGURATION)/$(NATIVE_TIMING_LIB): tests/NativeTiming/timing.c $(wildcard $(JI_JDK_INCLUDE_PATHS)/jni.h) + mkdir -p `dirname "$@"` + gcc -g -shared -m64 -fPIC -o $@ $< $(JI_JDK_INCLUDE_PATHS:%=-I%) + +define TestAssemblyTemplate +$(TEST_OUTPUT)/$(1)-Tests.dll: tests/$(1)-Tests/$(1)-Tests.csproj + $$(MSBUILD) $$(MSBUILD_FLAGS) + touch $$@ +endef + +$(eval $(call TestAssemblyTemplate,Java.Interop)) +$(eval $(call TestAssemblyTemplate,Java.Interop.Tools.JavaCallableWrappers)) +$(eval $(call TestAssemblyTemplate,Java.Interop.Tools.JavaSource)) +$(eval $(call TestAssemblyTemplate,Java.Interop.Tools.Maven)) +$(eval $(call TestAssemblyTemplate,Java.Interop.Tools.JavaTypeSystem)) +$(eval $(call TestAssemblyTemplate,Java.Interop.Tools.Generator)) +$(eval $(call TestAssemblyTemplate,Xamarin.Android.Tools.ApiXmlAdjuster)) +$(eval $(call TestAssemblyTemplate,Xamarin.Android.Tools.Bytecode)) +$(eval $(call TestAssemblyTemplate,Xamarin.SourceWriter)) +$(eval $(call TestAssemblyTemplate,generator)) +$(eval $(call TestAssemblyTemplate,logcat-parse)) + +bin/$(CONFIGURATION)/Java.Interop.dll: $(wildcard src/Java.Interop/*/*.cs) src/Java.Interop/Java.Interop.csproj + $(MSBUILD) $(if $(V),/v:diag,) /p:Configuration=$(CONFIGURATION) $(if $(SNK),"/p:AssemblyOriginatorKeyFile=$(SNK)",) + +CSHARP_REFS = \ + bin/$(CONFIGURATION)/Java.Interop.dll \ + bin/$(CONFIGURATION)/Java.Interop.Export.dll \ + $(PTESTS) \ + $(TESTS) + +shell: + MONO_TRACE_LISTENER=Console.Out \ + MONO_OPTIONS=--debug=casts csharp $(patsubst %,-r:%,$(CSHARP_REFS)) + +# $(call RUN_TEST,filename,log-lref?) +define RUN_TEST + $(MSBUILD) $(MSBUILD_FLAGS) build-tools/scripts/RunNUnitTests.targets /p:TestAssembly=$(1) || r=1; +endef + +run-tests: $(TESTS) + r=0; \ + $(foreach t,$(TESTS), $(call RUN_TEST,$(t),1)) \ + exit $$r; + +run-net-tests: $(NET_TESTS) + r=0; \ + $(foreach t,$(NET_TESTS), dotnet test $(t) || r=1;) \ + exit $$r; + +run-ptests: $(PTESTS) + r=0; \ + $(foreach t,$(PTESTS), $(call RUN_TEST,$(t))) \ + exit $$r; + +run-java-source-utils-tests: + $(MSBUILD) $(MSBUILD_FLAGS) tools/java-source-utils/java-source-utils.csproj /t:RunTests + +bin/Test$(CONFIGURATION)/generator.exe: bin/$(CONFIGURATION)/generator.exe + cp $<* `dirname "$@"` + +update-test-generator-nunit: + -$(MAKE) run-tests TESTS=bin/Test$(CONFIGURATION)/generator-Tests.dll + for f in `find tests/generator-Tests/expected -name \*.cs` ; do \ + source=`echo $$f | sed 's#^tests/generator-Tests/expected#bin/Test$(CONFIGURATION)/out#'` ; \ + if [ -f "$$source" ]; then \ + cp -f "$$source" "$$f" ; \ + fi; \ + done + for source in `find bin/Test$(CONFIGURATION)/out.ji -type f` ; do \ + f=`echo $$source | sed 's#^bin/Test$(CONFIGURATION)/out.ji#tests/generator-Tests/expected.ji#'` ; \ + mkdir -p `dirname $$f`; \ + cp -f "$$source" "$$f" ; \ + done diff --git a/external/Java.Interop/NuGet.Config b/external/Java.Interop/NuGet.Config new file mode 100644 index 00000000000..7d88f5852e5 --- /dev/null +++ b/external/Java.Interop/NuGet.Config @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/README.md b/external/Java.Interop/README.md new file mode 100644 index 00000000000..c8137a6edab --- /dev/null +++ b/external/Java.Interop/README.md @@ -0,0 +1,59 @@ +# Java.Interop + +**Java.Interop** is a binding of the [Java Native Interface][jni] for use from +managed languages such as C#, and an associated set of code generators to +allow Java code to invoke managed code. + +This allows one to bridge code running on .NET's CLR and code running on a Java VM. + +Note this does not mean that one can run Java code on .NET, or vice-versa. + +**Java.Interop** currently does not ship independently. It is shipped as part of Microsoft's +[.NET for Android][android] product, available via Visual Studio or .NET 6+. However, it is designed +to be fully independent of Android and should be usable by other Java implementations. +For other uses, please compile and distribute from source. + +Some additional context for this project is documented in the [Motivation][motivation] +and [Architecture][architecture] pages. + +[jni]: http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html +[motivation]: /Documentation/Motivation.md +[architecture]: /Documentation/Architecture.md +[android]: https://github.com/dotnet/android + +## Building + +- The `main` branch is configured to build with .NET 10, available [here][net-10]. +- The [`release/6.0.3xx`][net-6] branch is configured to build with .NET 6. + +`Java.Interop.sln` must first run some "preparatory" tasks before it can be built: + +```console +dotnet build -t:Prepare +``` + +Once `Java.Interop.sln` has been prepared, it can be built in Visual Studio 2022 or with `dotnet`: + +``` +dotnet build +``` + +[net-10]: https://dotnet.microsoft.com/en-us/download/dotnet/10.0 +[net-6]: https://github.com/dotnet/java-interop/tree/release/6.0.3xx + +Additional build options are documented [here][build-configuration]. + +[build-configuration]: /Documentation/BuildConfiguration.md + +## Feedback and Contributing + +This project welcomes issues and PRs. + + - File an issue in [GitHub Issues](https://github.com/dotnet/android/issues/new/choose). + - Discuss development and design on [Discord](https://aka.ms/dotnet-discord). [![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen)](https://aka.ms/dotnet-discord) + - Coding style is outlined in [Coding Guidelines](http://www.mono-project.com/community/contributing/coding-guidelines/). + +## License + +Copyright (c) .NET Foundation Contributors. All rights reserved. +Licensed under the [MIT](LICENSE) License. diff --git a/external/Java.Interop/SECURITY.md b/external/Java.Interop/SECURITY.md new file mode 100644 index 00000000000..b973bca92e6 --- /dev/null +++ b/external/Java.Interop/SECURITY.md @@ -0,0 +1,15 @@ +# Security Policy + +Java.Interop is supported as a component of Xamarin.Android. + +## Supported Versions + +The Xamarin.Android support policy, including supported versions, can be found at the [Xamarin Support Policy](https://dotnet.microsoft.com/platform/support/policy/xamarin). + +## Reporting a Vulnerability + +Security issues and bugs should be reported privately to the Microsoft Security Response Center (MSRC), either by emailing secure@microsoft.com or via the portal at https://msrc.microsoft.com. +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your +original message. Further information, including the MSRC PGP key, can be found in the [MSRC Report an Issue FAQ](https://www.microsoft.com/en-us/msrc/faqs-report-an-issue). + +Please do not open issues for anything you think might have a security implication. diff --git a/external/Java.Interop/TargetFrameworkDependentValues.props b/external/Java.Interop/TargetFrameworkDependentValues.props new file mode 100644 index 00000000000..ae7eef09c1c --- /dev/null +++ b/external/Java.Interop/TargetFrameworkDependentValues.props @@ -0,0 +1,41 @@ + + + + + True + + + + $(BaseIntermediateOutputPath)\$(Configuration)-$(DotNetTargetFramework.ToLowerInvariant())\ + $(MSBuildThisFileDirectory)bin\Build$(Configuration)\ + $(MSBuildThisFileDirectory)bin\Build$(Configuration)-$(DotNetTargetFramework.ToLowerInvariant())\ + $(MSBuildThisFileDirectory)bin\$(Configuration)-$(DotNetTargetFramework.ToLowerInvariant())\ + $(MSBuildThisFileDirectory)bin\Test$(Configuration)-$(DotNetTargetFramework.ToLowerInvariant())\ + $(UtilityOutputFullPathCoreApps) + $(ToolOutputFullPath) + <_XamarinAndroidCecilPath Condition=" '$(CecilSourceDirectory)' != '' And Exists('$(UtilityOutputFullPathCoreApps)Xamarin.Android.Cecil.dll') ">$(UtilityOutputFullPathCoreApps)Xamarin.Android.Cecil.dll + Major + $(JINetToolVersion) + $(JINetCoreLibVersion) + + + + mono + <_JNIEnvGenPath>$(BuildToolOutputFullPath)jnienv-gen.dll + <_RunJNIEnvGen>$(DotnetToolPath) "$(_JNIEnvGenPath)" + + + + AllEnabledByDefault + $(WarningsAsErrors);CA1307;CA1309;CA1310 + + + + $(NoWarn);CA1307;CA1309;CA1310 + + + + $(JIUtilityVersion) + + + diff --git a/external/Java.Interop/ThirdPartyNotices.txt b/external/Java.Interop/ThirdPartyNotices.txt new file mode 100644 index 00000000000..c8e46bb80eb --- /dev/null +++ b/external/Java.Interop/ThirdPartyNotices.txt @@ -0,0 +1,219 @@ +java.interop uses third-party libraries or other resources that may be +distributed under licenses different than the java.interop software. + +In the event that we accidentally failed to list a required notice, please +bring it to our attention. Post an issue or email us: + + dotnet@microsoft.com + +The attached notices are provided for information only. + +1. JetBrains/kotlin (https://github.com/JetBrains/kotlin/) + +%% JetBrains/kotlin NOTICES AND INFORMATION BEGIN HERE +====================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +====================================================== + +END OF JetBrains/kotlin NOTICES AND INFORMATION diff --git a/external/Java.Interop/before.Java.Interop.sln.targets b/external/Java.Interop/before.Java.Interop.sln.targets new file mode 100644 index 00000000000..6a0c004173e --- /dev/null +++ b/external/Java.Interop/before.Java.Interop.sln.targets @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj new file mode 100644 index 00000000000..f8cd822d43f --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj @@ -0,0 +1,32 @@ + + + + netstandard2.0 + false + + + + + + $(BuildToolOutputFullPathNoTF) + main + false + + + + + + + + + + + + {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157} + Xamarin.Android.Tools.AndroidSdk + + + + + + diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.sln b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.sln new file mode 100644 index 00000000000..272f06ea536 --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32104.313 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.BootstrapTasks", "Java.Interop.BootstrapTasks.csproj", "{47C54705-71BA-455D-9F72-780487DE861C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.AndroidSdk", "..\..\external\xamarin-android-tools\src\Xamarin.Android.Tools.AndroidSdk\Xamarin.Android.Tools.AndroidSdk.csproj", "{2F8744CF-C265-440A-B976-DEC021324A3E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {47C54705-71BA-455D-9F72-780487DE861C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47C54705-71BA-455D-9F72-780487DE861C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47C54705-71BA-455D-9F72-780487DE861C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47C54705-71BA-455D-9F72-780487DE861C}.Release|Any CPU.Build.0 = Release|Any CPU + {2F8744CF-C265-440A-B976-DEC021324A3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F8744CF-C265-440A-B976-DEC021324A3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F8744CF-C265-440A-B976-DEC021324A3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F8744CF-C265-440A-B976-DEC021324A3E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8C64DB4C-E064-43CA-B1AB-100760FEF870} + EndGlobalSection +EndGlobal diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.targets b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.targets new file mode 100644 index 00000000000..54db188c77e --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.targets @@ -0,0 +1,59 @@ + + + + + <_Path Include="PkgNUnit_ConsoleRunner" Destination="$(PkgNUnit_ConsoleRunner)" /> + + + <_PackagePathsLine Include="<Project>" /> + <_PackagePathsLine Include=" <PropertyGroup>" /> + <_PackagePathsLine Include="@(_Path->' <%(Identity) Condition=" %27%24(%(Identity))%27 == %27%27 ">%(Destination)</%(Identity)>', ' +')" /> + <_PackagePathsLine Include=" </PropertyGroup>" /> + <_PackagePathsLine Include="</Project>" /> + + + + + + + + <_NetToolVersion>$(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch).$(GitCommits) + <_OldToolVersion>0.2.$(GitBaseVersionPatch).$(GitCommits) + <_NetCoreLibVersion>$(GitBaseVersionMajor).$(GitBaseVersionMinor).0.0 + <_OldCoreLibVersion>0.1.0.0 + <_FileVersion>$(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch).$(GitCommits) + + + <_VersionsLine Include="<Project>" /> + <_VersionsLine Include=" <PropertyGroup>" /> + <_VersionsLine Include=" <FileVersion>$(_FileVersion)</FileVersion>" /> + <_VersionsLine Include=" <JINetToolVersion>$(_NetToolVersion)</JINetToolVersion>" /> + <_VersionsLine Include=" <JIOldToolVersion>$(_OldToolVersion)</JIOldToolVersion>" /> + <_VersionsLine Include=" <JINetCoreLibVersion>$(_NetCoreLibVersion)</JINetCoreLibVersion>" /> + <_VersionsLine Include=" <JIOldCoreLibVersion>$(_OldCoreLibVersion)</JIOldCoreLibVersion>" /> + <_VersionsLine Include=" <JIBuildBranch>$(GitBranch)</JIBuildBranch>" /> + <_VersionsLine Include=" <JIBuildCommit>$(GitCommit)</JIBuildCommit>" /> + <_VersionsLine Include=" </PropertyGroup>" /> + <_VersionsLine Include="</Project>" /> + + + + + + diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/DownloadUri.cs b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/DownloadUri.cs new file mode 100644 index 00000000000..da65dc003c2 --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/DownloadUri.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +using TTask = System.Threading.Tasks.Task; +using MTask = Microsoft.Build.Utilities.Task; + +namespace Java.Interop.BootstrapTasks { + + public class DownloadUri : MTask + { + public DownloadUri () + { + } + + [Required] + public string[] SourceUris { get; set; } + + [Required] + public ITaskItem[] DestinationFiles { get; set; } + + public override bool Execute () + { + Log.LogMessage (MessageImportance.Low, "DownloadUri:"); + Log.LogMessage (MessageImportance.Low, " SourceUris:"); + foreach (var uri in SourceUris) { + Log.LogMessage (MessageImportance.Low, " {0}", uri); + } + Log.LogMessage (MessageImportance.Low, " DestinationFiles:"); + foreach (var dest in DestinationFiles) { + Log.LogMessage (MessageImportance.Low, " {0}", dest.ItemSpec); + } + + if (SourceUris.Length != DestinationFiles.Length) { + Log.LogError ("SourceUris.Length must equal DestinationFiles.Length."); + return false; + } + + var tasks = new TTask [SourceUris.Length]; + var handler = new HttpClientHandler { + CheckCertificateRevocationList = true, + }; + using (var client = new HttpClient (handler)) { + client.Timeout = TimeSpan.FromHours (3); + for (int i = 0; i < SourceUris.Length; ++i) { + tasks [i] = DownloadFile (client, SourceUris [i], DestinationFiles [i].ItemSpec); + } + TTask.WaitAll (tasks); + } + + return !Log.HasLoggedErrors; + } + + async TTask DownloadFile (HttpClient client, string uri, string destinationFile) + { + if (File.Exists (destinationFile)) { + Log.LogMessage (MessageImportance.Normal, $"Skipping uri '{uri}' as destination file already exists '{destinationFile}'."); + return; + } + var dp = Path.GetDirectoryName (destinationFile); + var dn = Path.GetFileName (destinationFile); + var tempPath = Path.Combine (dp, "." + dn + ".download"); + Directory.CreateDirectory(dp); + + Log.LogMessage (MessageImportance.Normal, $"Downloading `{uri}` to `{tempPath}`."); + try { + using (var s = await client.GetStreamAsync (uri)) + using (var o = File.OpenWrite (tempPath)) { + await s.CopyToAsync (o); + } + Log.LogMessage (MessageImportance.Low, $"mv '{tempPath}' '{destinationFile}'."); + File.Move (tempPath, destinationFile); + } + catch (Exception e) { + Log.LogError ("Unable to download URL `{0}` to `{1}`: {2}", uri, destinationFile, e.Message); + Log.LogErrorFromException (e); + } + } + } +} diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs new file mode 100644 index 00000000000..994084afb7b --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs @@ -0,0 +1,194 @@ +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml.Linq; + +using Xamarin.Android.Tools; + +using XATInfo = Xamarin.Android.Tools.JdkInfo; + +namespace Java.Interop.BootstrapTasks +{ + public class JdkInfo : Task + { + public string JdksRoot { get; set; } + + public string PropertyNameModifier { get; set; } = ""; + public string MinimumJdkVersion { get; set; } + public string MaximumJdkVersion { get; set; } + + public string DotnetToolPath { get; set; } + + static Regex VersionExtractor = new Regex (@"(?[\d]+(\.\d+)+)", RegexOptions.Compiled); + + [Required] + public ITaskItem PropertyFile { get; set; } + + public ITaskItem MakeFragmentFile { get; set; } + + [Output] + public string JavaHomePath { get; set; } + + public override bool Execute () + { + var minVersion = GetVersion (MinimumJdkVersion); + var maxVersion = GetVersion (MaximumJdkVersion); + + var explicitJdks = GetJdkRoots (); + var defaultJdks = XATInfo.GetKnownSystemJdkInfos (CreateLogger ()) + .Where (j => minVersion != null ? j.Version >= minVersion : true) + .Where (j => maxVersion != null ? j.Version <= maxVersion : true) + .Where (j => j.IncludePath.Any ()); + var jdk = explicitJdks.Concat (defaultJdks) + .Where (j => JdkRunsOnHost (j)) + .FirstOrDefault (); + + if (jdk == null) { + Log.LogError ("Could not determine JAVA_HOME location. Please set JdksRoot or export the JAVA_HOME environment variable."); + return false; + } + + var rtJarPaths = new[]{ + Path.Combine (Path.GetDirectoryName (jdk.JavacPath), "..", "jre", "lib", "rt.jar"), + }; + var rtJarPath = rtJarPaths.FirstOrDefault (p => File.Exists (p)); + + JavaHomePath = jdk.HomePath; + + Directory.CreateDirectory (Path.GetDirectoryName (PropertyFile.ItemSpec)); + WritePropertyFile (jdk, rtJarPath); + + if (MakeFragmentFile != null) { + Directory.CreateDirectory (Path.GetDirectoryName (MakeFragmentFile.ItemSpec)); + WriteMakeFragmentFile (jdk, rtJarPath); + } + + return !Log.HasLoggedErrors; + } + + static bool JdkRunsOnHost (XATInfo jdk) + { + var cputype = RuntimeInformation.ProcessArchitecture; + if (jdk.ReleaseProperties.TryGetValue ("OS_ARCH", out var arch)) { + return (cputype, arch) switch { + (Architecture.Arm64, "aarch64") => true, + (Architecture.X64, "x86_64") => true, + _ => false, + }; + } + return true; + } + + XATInfo[] GetJdkRoots () + { + XATInfo jdk = null; + try { + if (!string.IsNullOrEmpty (JdksRoot)) + jdk = new XATInfo (JdksRoot); + } catch (Exception e) { + Log.LogWarning ($"Could not get information about JdksRoot path `{JdksRoot}`: {e.Message}"); + Log.LogMessage (MessageImportance.Low, e.ToString ()); + } + return jdk == null + ? Array.Empty() + : new[] { jdk }; + } + + Version GetVersion (string value) + { + if (string.IsNullOrEmpty (value)) + return null; + if (!value.Contains (".")) { + value += ".0"; + } + Version v; + if (Version.TryParse (value, out v)) + return v; + return null; + } + + Action CreateLogger () + { + Action logger = (level, value) => { + switch (level) { + case TraceLevel.Error: + Log.LogError ("{0}", value); + break; + case TraceLevel.Warning: + Log.LogWarning ("{0}", value); + break; + default: + Log.LogMessage (MessageImportance.Low, "{0}", value); + break; + } + }; + return logger; + } + + void WritePropertyFile (XATInfo jdk, string rtJarPath) + { + var jarPath = jdk.JarPath; + var javacPath = jdk.JavacPath; + var javaPath = jdk.JavaPath; + var jdkJvmPath = jdk.JdkJvmPath; + var includes = jdk.IncludePath; + + var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); + var jdkJvmP = $"JdkJvm{PropertyNameModifier}Path"; + var project = new XElement (msbuild + "Project", + new XElement (msbuild + "Choose", + new XElement (msbuild + "When", new XAttribute ("Condition", $" '$({jdkJvmP})' == '' "), + new XElement (msbuild + "PropertyGroup", + new XElement (msbuild + jdkJvmP, jdkJvmPath)), + new XElement (msbuild + "ItemGroup", + includes.Select (i => new XElement (msbuild + $"Jdk{PropertyNameModifier}IncludePath", new XAttribute ("Include", i)))))), + new XElement (msbuild + "PropertyGroup", + CreateProperty (msbuild, $"JavaApi{PropertyNameModifier}DefineConstants", + string.Join (";", Enumerable.Range (11, jdk.Version.Major-11+1).Select (v => $"JAVA_API_{v}"))), + CreateProperty (msbuild, $"Java{PropertyNameModifier}MajorVersion", jdk.Version.Major.ToString ()), + CreateProperty (msbuild, $"Java{PropertyNameModifier}SdkDirectory", JavaHomePath), + CreateProperty (msbuild, $"Java{PropertyNameModifier}Path", javaPath), + CreateProperty (msbuild, $"JavaC{PropertyNameModifier}Path", javacPath), + CreateProperty (msbuild, $"Jar{PropertyNameModifier}Path", jarPath), + CreateProperty (msbuild, $"Dotnet{PropertyNameModifier}ToolPath", DotnetToolPath), + CreateProperty (msbuild, $"Jre{PropertyNameModifier}RtJarPath", rtJarPath))); + project.Save (PropertyFile.ItemSpec); + } + + XElement CreateProperty (XNamespace msbuild, string propertyName, string propertyValue) + { + if (string.IsNullOrEmpty (propertyValue)) { + return null; + } + + return new XElement (msbuild + propertyName, + new XAttribute ("Condition", $" '$({propertyName})' == '' "), + propertyValue); + } + + void WriteMakeFragmentFile (XATInfo jdk, string rtJarPath) + { + var jarPath = jdk.JarPath; + var javacPath = jdk.JavacPath; + var javaPath = jdk.JavaPath; + var jdkJvmPath = jdk.JdkJvmPath; + var includes = jdk.IncludePath; + + using (var o = new StreamWriter (MakeFragmentFile.ItemSpec)) { + o.WriteLine ($"export JI_JAR_PATH := {jarPath}"); + o.WriteLine ($"export JI_JAVA_PATH := {javaPath}"); + o.WriteLine ($"export JI_JAVAC_PATH := {javacPath}"); + o.WriteLine ($"export JI_JDK_INCLUDE_PATHS := {string.Join (" ", includes)}"); + o.WriteLine ($"export JI_JVM_PATH := {jdkJvmPath}"); + o.WriteLine ($"export JI_RT_JAR_PATH := {rtJarPath}"); + } + } + } +} diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs new file mode 100644 index 00000000000..4e9d11a4fa1 --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs @@ -0,0 +1,10 @@ +using System; +using System.IO; + +namespace Java.Interop.BootstrapTasks { + class OS { + public static readonly bool IsWindows = Path.DirectorySeparatorChar == '\\'; + public static readonly bool IsMacOS = !IsWindows && Directory.Exists ("/Applications"); + public static readonly bool IsLinux = !IsWindows && !IsMacOS; + } +} diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/ParseAndroidResources.cs b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/ParseAndroidResources.cs new file mode 100644 index 00000000000..5b69a69c673 --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/ParseAndroidResources.cs @@ -0,0 +1,66 @@ +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System; +using System.Linq; +using System.IO; +using System.Collections.Generic; + + +namespace Java.Interop.BootstrapTasks +{ + public class ParseAndroidResources : Task + { + public ITaskItem AndroidResourceFile { get; set; } + public ITaskItem OutputFile { get; set; } + public string DeclaringNamespaceName { get; set; } + public string DeclaringClassName { get; set; } + + public override bool Execute () + { + using (var o = File.CreateText (OutputFile.ItemSpec)) { + o.WriteLine ($"namespace {DeclaringNamespaceName};"); + o.WriteLine (); + o.WriteLine ($"partial class {DeclaringClassName} {{"); + var resources = ParseAndroidResourceFile (AndroidResourceFile.ItemSpec); + foreach (var declType in resources.Keys.OrderBy (x => x)) { + o.WriteLine ($"\tpublic static class @{declType} {{"); + var decls = resources [declType]; + foreach (var decl in decls.Keys.OrderBy (x => x)) { + o.WriteLine ($"\t\tpublic const int {decl} = {decls [decl]};"); + } + o.WriteLine ("\t}"); + } + o.WriteLine ("}"); + o.WriteLine (); + } + + return !Log.HasLoggedErrors; + } + + Dictionary> ParseAndroidResourceFile (string file) + { + var resources = new Dictionary> (); + using (var reader = File.OpenText (file)) { + string line; + while ((line = reader.ReadLine ()) != null) { + if (line.StartsWith ("#")) + continue; + var items = line.Split (' '); + if (items.Length != 4) + continue; + var type = items [0]; + if (string.Compare (type, "int", StringComparison.Ordinal) != 0) + continue; + var decl = items [1]; + var name = items [2]; + var value = items [3]; + if (!resources.TryGetValue (decl, out var declResources)) + resources.Add (decl, declResources = new Dictionary()); + declResources.Add (name, value); + } + } + + return resources; + } + } +} diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/ReplaceFileContents.cs b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/ReplaceFileContents.cs new file mode 100644 index 00000000000..be5832170ae --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/ReplaceFileContents.cs @@ -0,0 +1,27 @@ +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System; +using System.IO; +using System.Collections.Generic; + + +namespace Java.Interop.BootstrapTasks +{ + public class ReplaceFileContents : Task + { + public ITaskItem TemplateFile { get; set; } + public ITaskItem OutputFile { get; set; } + + public ITaskItem [] Replacements { get; set; } + public override bool Execute () + { + string text = File.ReadAllText (TemplateFile.ItemSpec); + foreach (var replacement in Replacements) + { + text = text.Replace (replacement.ItemSpec, replacement.GetMetadata ("Replacement")); + } + File.WriteAllText (OutputFile.ItemSpec, text); + return !Log.HasLoggedErrors; + } + } +} diff --git a/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/SetEnvironmentVariable.cs b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/SetEnvironmentVariable.cs new file mode 100644 index 00000000000..f31036d6e76 --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/SetEnvironmentVariable.cs @@ -0,0 +1,28 @@ +using System; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Java.Interop.BootstrapTasks +{ + public class SetEnvironmentVariable : Task + { + [Required] + public string Name { get; set; } + + [Required] + public string Value { get; set; } + + public override bool Execute () + { + Log.LogMessage (MessageImportance.Low, $"Task {nameof (SetEnvironmentVariable)}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (Name)}: {Name}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (Value)}: {Value}"); + + Environment.SetEnvironmentVariable (Name, Value); + + return !Log.HasLoggedErrors; + } + } +} + diff --git a/external/Java.Interop/build-tools/Java.Interop.Sdk/Sdk/Sdk.props b/external/Java.Interop/build-tools/Java.Interop.Sdk/Sdk/Sdk.props new file mode 100644 index 00000000000..8ca46be020b --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.Sdk/Sdk/Sdk.props @@ -0,0 +1,6 @@ + + + ; + : + + diff --git a/external/Java.Interop/build-tools/Java.Interop.Sdk/Sdk/Sdk.targets b/external/Java.Interop/build-tools/Java.Interop.Sdk/Sdk/Sdk.targets new file mode 100644 index 00000000000..466fd6bd5b2 --- /dev/null +++ b/external/Java.Interop/build-tools/Java.Interop.Sdk/Sdk/Sdk.targets @@ -0,0 +1,229 @@ + + + + + True + + + True + + + + + $(AssemblyName).jar + + + + + _BuildJavaCompileForManagedBinding; + _GenerateApiDescription; + _GenerateManagedBinding; + _CleanupManagedBinding; + + + _JavaCreateJcws; + _JavaCreateOutputJar; + + + + + + + + + + + <_GeneratorPath>$(UtilityOutputFullPath)generator.dll + <_JavaIntermediateDir>$(IntermediateOutputPath)_ji\ + <_JavaManagedBindingInput>$(_JavaIntermediateDir)o.jar + <_JavaManagedBindingDir>$(_JavaIntermediateDir)mcw\ + <_JavaJcwClassesDir>$(_JavaIntermediateDir)classes\ + <_JavaJcwSourcesDir>$(_JavaIntermediateDir)java\ + <_JavaOutputJarPath>$(_JavaIntermediateDir)$(JavaOutputJarName) + + + + + + + + + <_JavaCompileForBindingInputs + Condition=" '%(JavaCompile.Bind)' == 'True' " + Include="@(JavaCompile)" + /> + + + + + + <_JavacRefs Include="$(ToolOutputFullPath)java-interop.jar" /> + <_JavacRefs Include="@(JavaReference)" /> + <_JavacRefsWithForwardSlash Include="@(_JavacRefs->Replace('%5c', '/'))" /> + + + + + + <_ClassesDir>$(_JavaIntermediateDir)\bound-classes + <_ResponseFile>$(_JavaIntermediateDir)r.txt + <_Classpath>@(_JavacRefsWithForwardSlash, '$(JavaPathSeparator)') + + + + <_Response Include="-classpath" /> + <_Response Include=""$(_Classpath)"" /> + <_Response Include="@(_JavaCompileForBindingInputs->Replace('%5c', '/'))" /> + + + + + + + + + + + + <_ClassParseInputs + Condition=" Exists($(_JavaManagedBindingInput))" + Include="$(_JavaManagedBindingInput)" + /> + <_ClassParseInputs + Condition=" '%(JavaReference.Bind)' == 'True' " + Include="@(JavaReference)" + /> + + + + + + + <_ClassParse>"$(UtilityOutputFullPath)class-parse.dll" + <_Inputs>@(_ClassParseInputs, ' ') + <_Output>"-o=$(_JavaManagedBindingDir)api.xml" + + + + + + + + "$(_GeneratorPath)" + <_GenFlags>--public --global + <_Out>-o "$(_JavaManagedBindingDir)." + <_Codegen>--codegen-target=JavaInterop1 + <_Assembly>"--assembly=$(AssemblyName)" + <_TypeMap>--type-map-report=$(_JavaManagedBindingDir)type-mapping.txt + <_Api>$(_JavaManagedBindingDir)api.xml + <_Dirs>"--enumdir=$(_JavaManagedBindingDir)." + <_FullIntermediateOutputPath>$([System.IO.Path]::GetFullPath('$(_JavaManagedBindingDir)')) + <_LangFeatures>--lang-features=nullable-reference-types,default-interface-methods,nested-interface-types,interface-constants + + + + <_RefAsmDir Include="@(ReferencePathWithRefAssemblies->'%(RootDir)%(Directory).'->Distinct())" /> + <_Lib Include="@(_RefAsmDir->'-L "%(Identity)"')" /> + + + + + + + + + + + $(DefineConstants);$([System.String]::Copy('$(_GeneratedDefineConstants)').Replace ('%24(DefineConstants);', '')) + + + + + + + + + + + <_RefAsmDirs Include="@(ReferencePathWithRefAssemblies->'%(RootDir)%(Directory).'->Distinct())" /> + + + <_JcwGen>"$(UtilityOutputFullPath)/jcw-gen.dll" + <_Target>--codegen-target JavaInterop1 + <_Output>-o "$(_JavaJcwSourcesDir)." + <_Libpath>@(_RefAsmDirs->'-L "%(Identity)"', ' ') + + + + + + + + <_JavaGeneratedJcwSource Include="$(_JavaJcwSourcesDir)**\*.java" /> + + + + + + + + <_ResponseFile>$(_JavaIntermediateDir)r.txt + <_Classpath>@(_JavacRefsWithForwardSlash, '$(JavaPathSeparator)') + + + <_Source Include="@(JavaCompile->Replace('%5c', '/'))" /> + <_Source Include="@(_JavaGeneratedJcwSource->Replace('%5c', '/'))" /> + + + + + + + + + + + + diff --git a/external/Java.Interop/build-tools/automation/templates/core-build.yaml b/external/Java.Interop/build-tools/automation/templates/core-build.yaml new file mode 100644 index 00000000000..eae7d6a3101 --- /dev/null +++ b/external/Java.Interop/build-tools/automation/templates/core-build.yaml @@ -0,0 +1,25 @@ +parameters: + condition: succeeded() + +steps: +- task: DotNetCoreCLI@2 + displayName: Prepare Solution + inputs: + projects: external/Java.Interop/Java.Interop.sln + arguments: '-c $(Build.Configuration) -target:Prepare' + workingDirectory: external/Java.Interop + +- task: DotNetCoreCLI@2 + displayName: Shut down existing build server + inputs: + command: custom + custom: build-server + arguments: shutdown + workingDirectory: external/Java.Interop + +- task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + projects: external/Java.Interop/Java.Interop.sln + arguments: '-c $(Build.Configuration)' + workingDirectory: external/Java.Interop diff --git a/external/Java.Interop/build-tools/automation/templates/core-tests.yaml b/external/Java.Interop/build-tools/automation/templates/core-tests.yaml new file mode 100644 index 00000000000..55057be5ea6 --- /dev/null +++ b/external/Java.Interop/build-tools/automation/templates/core-tests.yaml @@ -0,0 +1,94 @@ +parameters: + condition: succeeded() + runNativeTests: false + platformName: + nativeAotRid: + +steps: +- template: run-dotnet-test.yaml + parameters: + testRunTitle: generator (${{ parameters.platformName }}) + testAssemblyName: generator-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Java.Interop.Tools.JavaCallableWrappers (${{ parameters.platformName }}) + testAssemblyName: Java.Interop.Tools.JavaCallableWrappers-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: logcat-parse (${{ parameters.platformName }}) + testAssemblyName: logcat-parse-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Xamarin.Android.Tools.ApiXmlAdjuster (${{ parameters.platformName }}) + testAssemblyName: Xamarin.Android.Tools.ApiXmlAdjuster-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Xamarin.Android.Tools.JavaTypeSystem (${{ parameters.platformName }}) + testAssemblyName: Java.Interop.Tools.JavaTypeSystem-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Xamarin.Android.Tools.Bytecode (${{ parameters.platformName }}) + testAssemblyName: Xamarin.Android.Tools.Bytecode-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Java.Interop.Tools.Generator (${{ parameters.platformName }}) + testAssemblyName: Java.Interop.Tools.Generator-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Java.Interop.Tools.JavaSource (${{ parameters.platformName }}) + testAssemblyName: Java.Interop.Tools.JavaSource-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Xamarin.SourceWriter (${{ parameters.platformName }}) + testAssemblyName: Xamarin.SourceWriter-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Java.Interop.Tools.Maven (${{ parameters.platformName }}) + testAssemblyName: Java.Interop.Tools.Maven-Tests + +- template: run-dotnet-test.yaml + parameters: + testRunTitle: Java.Interop ($(DotNetTargetFramework) - ${{ parameters.platformName }}) + testAssemblyName: Java.Interop-Tests + condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) + retryCount: 1 + +- task: DotNetCoreCLI@2 + displayName: 'Tests: java-source-utils' + inputs: + command: build + arguments: -c $(Build.Configuration) tools/java-source-utils/java-source-utils.csproj -t:RunTests + workingDirectory: external/Java.Interop + continueOnError: true + +- powershell: > + dotnet publish -c $(Build.Configuration) -r ${{ parameters.nativeAotRid }} + samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj + displayName: 'Tests: publish Hello-NativeAOTFromJNI' + workingDirectory: external/Java.Interop + continueOnError: true + +- powershell: > + dotnet build -c $(Build.Configuration) -r ${{ parameters.nativeAotRid }} + -t:RunJavaSample + samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj + displayName: 'Tests: run Hello-NativeAOTFromJNI' + workingDirectory: external/Java.Interop + continueOnError: true + +- task: PublishTestResults@2 + displayName: Publish JUnit Test Results + inputs: + testResultsFormat: JUnit + testResultsFiles: 'external/Java.Interop/tools/java-source-utils/build/test-results/**/TEST-*.xml' + testRunTitle: java-source-utils (${{ parameters.platformName }}) + continueOnError: true diff --git a/external/Java.Interop/build-tools/automation/templates/fail-on-dirty-tree.yaml b/external/Java.Interop/build-tools/automation/templates/fail-on-dirty-tree.yaml new file mode 100644 index 00000000000..38b4dbc202f --- /dev/null +++ b/external/Java.Interop/build-tools/automation/templates/fail-on-dirty-tree.yaml @@ -0,0 +1,22 @@ +# Ensure the build did not produce any modified checked in files + +parameters: + condition: succeeded() + +steps: +- powershell: | + # Run this to log the output for the user + git status + + # Run this to error the build if untracked files + $process= git status --porcelain --untracked-files=no + + if ($process) + { + Write-Host "##vso[task.logissue type=error]git tree has modified tracked files." + Write-Host "##vso[task.complete result=Failed;]" + } + + git diff + displayName: Ensure no modified committed files + condition: ${{ parameters.condition }} diff --git a/external/Java.Interop/build-tools/automation/templates/fail-on-issue.yaml b/external/Java.Interop/build-tools/automation/templates/fail-on-issue.yaml new file mode 100644 index 00000000000..ad3f176f9ed --- /dev/null +++ b/external/Java.Interop/build-tools/automation/templates/fail-on-issue.yaml @@ -0,0 +1,10 @@ +parameters: + condition: succeeded() + +steps: +- powershell: | + Write-Host "Current job status is: $env:AGENT_JOBSTATUS" + if ($env:AGENT_JOBSTATUS -eq "SucceededWithIssues") { + Write-Host "##vso[task.complete result=Failed;]DONE" + } + displayName: fail if any issues occurred diff --git a/external/Java.Interop/build-tools/automation/templates/install-dependencies.yaml b/external/Java.Interop/build-tools/automation/templates/install-dependencies.yaml new file mode 100644 index 00000000000..7ead0e5a6c7 --- /dev/null +++ b/external/Java.Interop/build-tools/automation/templates/install-dependencies.yaml @@ -0,0 +1,8 @@ +parameters: + condition: succeeded() + +steps: +- task: UseDotNet@2 + displayName: Use .NET $(DotNetCoreVersion) + inputs: + version: $(DotNetCoreVersion) diff --git a/external/Java.Interop/build-tools/automation/templates/run-dotnet-test.yaml b/external/Java.Interop/build-tools/automation/templates/run-dotnet-test.yaml new file mode 100644 index 00000000000..8163d9105b6 --- /dev/null +++ b/external/Java.Interop/build-tools/automation/templates/run-dotnet-test.yaml @@ -0,0 +1,28 @@ +parameters: + testRunTitle: + testAssemblyName: + trxSuffix: '' + condition: succeededOrFailed() + retryCount: 0 + extraArguments: '' + +steps: +- task: DotNetCoreCLI@2 + displayName: 'Tests: ${{ parameters.testRunTitle }}' + condition: ${{ parameters.condition }} + inputs: + command: test + publishTestResults: false + arguments: --logger "trx;LogFileName=${{ parameters.testAssemblyName }}${{ parameters.trxSuffix }}.trx" --results-directory $(Agent.TempDirectory) ${{ parameters.extraArguments }} bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/${{ parameters.testAssemblyName }}.dll + workingDirectory: external/Java.Interop + continueOnError: true + retryCountOnTaskFailure: ${{ parameters.retryCount }} + +- task: PublishTestResults@2 + displayName: 'Publish: ${{ parameters.testRunTitle }}' + condition: ${{ parameters.condition }} + inputs: + testResultsFormat: VSTest + testResultsFiles: '$(Agent.TempDirectory)/${{ parameters.testAssemblyName }}${{ parameters.trxSuffix }}.trx' + testRunTitle: ${{ parameters.testRunTitle }} + continueOnError: true diff --git a/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.jar b/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..87b738cbd05 Binary files /dev/null and b/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.jar differ diff --git a/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties b/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..d6e308a6378 --- /dev/null +++ b/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/external/Java.Interop/build-tools/gradle/gradlew b/external/Java.Interop/build-tools/gradle/gradlew new file mode 100755 index 00000000000..af6708ff229 --- /dev/null +++ b/external/Java.Interop/build-tools/gradle/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/external/Java.Interop/build-tools/gradle/gradlew.bat b/external/Java.Interop/build-tools/gradle/gradlew.bat new file mode 100644 index 00000000000..6d57edc706c --- /dev/null +++ b/external/Java.Interop/build-tools/gradle/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/external/Java.Interop/build-tools/jnienv-gen/Generator.cs b/external/Java.Interop/build-tools/jnienv-gen/Generator.cs new file mode 100644 index 00000000000..55263908be8 --- /dev/null +++ b/external/Java.Interop/build-tools/jnienv-gen/Generator.cs @@ -0,0 +1,1392 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Xamarin.Java.Interop +{ + static class StringCoda { + public static string FixupType (this string t) + { + return t.Replace ("*", "Ptr").Replace ("[]", "Array").Replace (" ", ""); + } + } + + partial class Generator + { + static string jnienv_g_c; + static string jnienv_g_h; + static string jnienv_g_cs; + + public static int Main (string [] args) + { + jnienv_g_c = "JniEnvironment.g.c"; + jnienv_g_h = "JniEnvironment.g.h"; + jnienv_g_cs = "JniEnvironment.g.cs"; + if (args.Length > 0) + jnienv_g_cs = args [0]; + if (args.Length > 1) { + jnienv_g_c = args [1]; + if (jnienv_g_c != "-") { + jnienv_g_h = Path.Combine (Path.GetDirectoryName (jnienv_g_c), $"{Path.GetFileNameWithoutExtension(jnienv_g_c)}-api.h"); + } else { + jnienv_g_h = "-"; + } + } + if (args.Length > 2) { + jnienv_g_h = args [2]; + } + + try { + using (TextWriter w = new StringWriter ()) { + w.NewLine = Environment.NewLine; + GenerateFile (w); + string content = w.ToString (); + if (jnienv_g_cs == "-") + Console.WriteLine (content); + else + File.WriteAllText (jnienv_g_cs, content); + } + using (TextWriter sw = new StringWriter ()) { + using (TextWriter hw = new StringWriter ()) { + sw.NewLine = Environment.NewLine; + GenerateNativeLibSource (sw, hw, jnienv_g_h); + string sourceContent = sw.ToString (); + string headerContent = hw.ToString (); + if (jnienv_g_c == "-" || jnienv_g_cs == "-") { + Console.WriteLine (headerContent); + Console.WriteLine (); + Console.WriteLine (sourceContent); + } else { + File.WriteAllText (jnienv_g_h, headerContent); + File.WriteAllText (jnienv_g_c, sourceContent); + } + }} + return 0; + } catch (Exception ex) { + Console.WriteLine (ex); + return 1; + } + } + + static string Escape (string value) + { + switch (value) { + case "object": + case "string": + case "ref": + return "@" + value; + default: return value; + } + } + + static void GenerateFile (TextWriter o) + { + o.WriteLine ("// Generated file; DO NOT EDIT!"); + o.WriteLine ("//"); + o.WriteLine ("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun"); + o.WriteLine ("#nullable enable"); + o.WriteLine (); + o.WriteLine ("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + o.WriteLine ("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES"); + o.WriteLine ("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + o.WriteLine (); + o.WriteLine ("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)"); + o.WriteLine ("#define _NAMESPACE_PER_HANDLE"); + o.WriteLine ("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)"); + o.WriteLine ("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)"); + o.WriteLine ("#define _NAMESPACE_PER_HANDLE"); + o.WriteLine ("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)"); + o.WriteLine ("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + o.WriteLine ("#define _NAMESPACE_PER_HANDLE"); + o.WriteLine ("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + o.WriteLine (); + o.WriteLine ("using System;"); + o.WriteLine ("using System.Linq;"); + o.WriteLine ("using System.Runtime.ExceptionServices;"); + o.WriteLine ("using System.Runtime.InteropServices;"); + o.WriteLine ("using System.Threading;"); + o.WriteLine (); + o.WriteLine ("using Java.Interop;"); + o.WriteLine (); + o.WriteLine ("using JNIEnvPtr = System.IntPtr;"); + o.WriteLine (); + o.WriteLine ("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + o.WriteLine ("\tusing jinstanceFieldID = System.IntPtr;"); + o.WriteLine ("\tusing jstaticFieldID = System.IntPtr;"); + o.WriteLine ("\tusing jinstanceMethodID = System.IntPtr;"); + o.WriteLine ("\tusing jstaticMethodID = System.IntPtr;"); + o.WriteLine ("\tusing jobject = System.IntPtr;"); + o.WriteLine ("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + o.WriteLine (); + o.WriteLine ("namespace Java.Interop {"); + GenerateJniNativeInterface (o); + o.WriteLine ("}"); + WriteSection (o, HandleStyle.JIIntPtr, "FEATURE_JNIENVIRONMENT_JI_INTPTRS", "Java.Interop.JIIntPtrs"); + WriteSection (o, HandleStyle.JIIntPtrPinvokeWithErrors, "FEATURE_JNIENVIRONMENT_JI_PINVOKES", "Java.Interop.JIPinvokes"); + WriteSection (o, HandleStyle.XAIntPtr, "FEATURE_JNIENVIRONMENT_XA_INTPTRS", "Java.Interop.XAIntPtrs"); + WriteSection (o, HandleStyle.JIFunctionPtrWithErrors, "FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS", "Java.Interop.JIFunctionPointers"); + } + + static void WriteSection (TextWriter o, HandleStyle style, string define, string specificNamespace) + { + o.WriteLine ("#if {0}", define); + o.WriteLine ("namespace"); + o.WriteLine ("#if _NAMESPACE_PER_HANDLE"); + o.WriteLine ("\t{0}", specificNamespace); + o.WriteLine ("#else"); + o.WriteLine ("\tJava.Interop"); + o.WriteLine ("#endif"); + o.WriteLine ("{"); + o.WriteLine (); + if (style != HandleStyle.JIIntPtrPinvokeWithErrors && style != HandleStyle.JIFunctionPtrWithErrors) { + GenerateDelegates (o, style); + o.WriteLine (); + } + GenerateTypes (o, style); + o.WriteLine (); + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.XAIntPtr: + GenerateJniNativeInterfaceInvoker (o, style); + break; + } + o.WriteLine ("}"); + o.WriteLine ("#endif // {0}", define); + } + + static void GenerateDelegates (TextWriter o, HandleStyle style) + { + created_delegates = new HashSet (); + foreach (var e in JNIEnvEntries) { + CreateDelegate (o, e, style); + } + } + + static void GenerateJniNativeInterface (TextWriter o) + { + o.WriteLine ("#pragma warning disable 0649 // Field is assigned to, and will always have its default value `null`; ignore as it'll be set in native code."); + o.WriteLine ("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout."); + o.WriteLine (); + + o.WriteLine ("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS"); + o.WriteLine ("\t[StructLayout (LayoutKind.Sequential)]"); + o.WriteLine ("\tpartial struct JniNativeInterfaceStruct {"); + o.WriteLine (); + + int maxName = JNIEnvEntries.Max (e => e.Name.Length); + + for (int i = 0; i < 4; i++) + o.WriteLine ("\t\tprivate IntPtr reserved{0}; // void*", i); + + foreach (var e in JNIEnvEntries) { + o.WriteLine ("\t\tpublic IntPtr {0};{1} // {2}", e.Name, new string (' ', maxName - e.Name.Length), e.Prototype); + } + o.WriteLine ("\t}"); + o.WriteLine ("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS"); + o.WriteLine (); + + o.WriteLine ("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + o.WriteLine ("\t[StructLayout (LayoutKind.Sequential)]"); + o.WriteLine ("\tunsafe partial struct JNIEnv {"); + + for (int i = 0; i < 4; i++) + o.WriteLine ("\t\tprivate IntPtr reserved{0}; // void*", i); + + foreach (var e in JNIEnvEntries) { + if (e.Parameters.Length > 0 && + "va_list" == e.Parameters [e.Parameters.Length-1].Type.GetManagedType (HandleStyle.JIFunctionPtrWithErrors, isReturn: false, isPinvoke: true)) { + o.WriteLine ("\t\tpublic IntPtr {0};{1} // {2}", e.Name, new string (' ', maxName - e.Name.Length), e.Prototype); + continue; + } + o.Write ("\t\tpublic delegate* unmanaged {e.Name};"); + } + o.WriteLine ("\t}"); + o.WriteLine ("#endif // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS"); + + o.WriteLine (); + o.WriteLine ("#pragma warning restore 0169"); + o.WriteLine ("#pragma warning restore 0649"); + } + + static string Initialize (JniFunction e, string prefix, string delegateType) + { + return string.Format ("{0}{1} = ({2}) Marshal.GetDelegateForFunctionPointer (env.{1}, typeof ({2}));", + prefix, e.Name, delegateType); + } + + static void GenerateJniNativeInterfaceInvoker (TextWriter o, HandleStyle style) + { + o.WriteLine ("\tpartial class JniEnvironmentInvoker {"); + o.WriteLine (); + o.WriteLine ("\t\tinternal JniNativeInterfaceStruct env;"); + o.WriteLine (); + o.WriteLine ("\t\tpublic unsafe JniEnvironmentInvoker (JniNativeInterfaceStruct* p)"); + o.WriteLine ("\t\t{"); + o.WriteLine ("\t\t\tenv = *p;"); + + foreach (var e in JNIEnvEntries) { + if (!e.Prebind) + continue; + var d = e.GetDelegateTypeName (style); + if (e.GetDelegateTypeName (style) == null) + continue; + o.WriteLine ("\t\t\t{0}", Initialize (e, "", d)); + } + + o.WriteLine ("\t\t}"); + o.WriteLine (); + + foreach (var e in JNIEnvEntries) { + var d = e.GetDelegateTypeName (style); + if (d == null) + continue; + o.WriteLine (); + if (e.Prebind) + o.WriteLine ("\t\tpublic readonly {0} {1};{2}", d, e.Name, Environment.NewLine); + else { + o.WriteLine ("\t\t{0}? _{1};", d, e.Name); + o.WriteLine ("\t\tpublic {0} {1} {{", d, e.Name); + o.WriteLine ("\t\t\tget {"); + o.WriteLine ("\t\t\t\tif (_{0} == null){2}\t\t\t\t\t{1}", e.Name, Initialize (e, "_", d), Environment.NewLine); + o.WriteLine ("\t\t\t\treturn _{0};{1}\t\t\t}}", e.Name, Environment.NewLine); + o.WriteLine ("\t\t}"); + } + } + + o.WriteLine ("\t}"); + } + + + static HashSet created_delegates = new HashSet (); + + static void CreateDelegate (TextWriter o, JniFunction entry, HandleStyle style) + { + StringBuilder builder = new StringBuilder (); + bool has_char_array = false; + + string name = entry.GetDelegateTypeName (style); + if (name == null) + return; + + builder.AppendFormat ("\tunsafe delegate {0} {1} ({2} env", entry.GetMarshalReturnType (style), name, GetJniEnvironmentPointerType (style)); + for (int i = 0; i < entry.Parameters.Length; i++) { + if (i >= 0) { + builder.Append (", "); + builder.AppendFormat ("{0} {1}", + entry.Parameters [i].Type.GetMarshalType (style, isReturn: false, isPinvoke: true), + Escape (entry.Parameters [i].Name)); + } + + var ptype = entry.Parameters [i].Type.GetManagedType (style, isReturn: false, isPinvoke: true); + if (ptype == "va_list") + return; + if (ptype == "char[]") + has_char_array = true; + } + builder.Append (");"); + + if (created_delegates.Contains (name)) + return; + + created_delegates.Add (name); + if (entry.Name == "NewString" || has_char_array) + o.WriteLine ("\t[UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl, CharSet=CharSet.Unicode)]"); + o.WriteLine (builder.ToString ()); + } + + static string GetJniEnvironmentPointerType (HandleStyle style) + { + return "JNIEnvPtr"; + } + + static void GenerateTypes (TextWriter o, HandleStyle style) + { + if (style == HandleStyle.JIIntPtrPinvokeWithErrors) { + GenerateNativeMethods (o, style); + } + if (style == HandleStyle.JIFunctionPtrWithErrors) { + GenerateJniNativeMethods (o, style); + } + + var visibilities = new Dictionary { + { ArrayOperationsCategory, "public" }, + { ClassesCategory, "public" }, + { ExceptionsCategory, "public" }, + { InstanceFieldsCategory, "public" }, + { InstanceMethodsCategory, "public" }, + { MonitorOperationsCategory, "public" }, + { NIOSupportCategory, "public" }, + { ObjectOperationsCategory, "public" }, + { ReferencesCatgeory, "public" }, + { StaticFieldsCategory, "public" }, + { StaticMethodsCategory, "public" }, + { StringOperationsCategory, "public" }, + }; + o.WriteLine ("\tpartial class JniEnvironment {"); + foreach (var t in JNIEnvEntries + .Select (e => e.DeclaringType ?? "JniEnvironment") + .Distinct () + .OrderBy (t => t)) { + string visibility; + if (!visibilities.TryGetValue (t, out visibility)) + visibility = "internal"; + GenerateJniEnv (o, t, visibility, style); + } + o.WriteLine ("\t}"); + } + + static void GenerateNativeMethods (TextWriter o, HandleStyle style) + { + o.WriteLine ("\tstatic partial class NativeMethods {"); + o.WriteLine (); + o.WriteLine ("\t\tconst string JavaInteropLib = \"java-interop\";"); + foreach (var entry in JNIEnvEntries) { + if (entry.Parameters == null) + continue; + if (entry.IsPrivate || entry.CustomWrapper) + continue; + + o.WriteLine (); + o.WriteLine ("\t\t[DllImport (JavaInteropLib, CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]"); + o.WriteLine ("\t\tinternal static extern unsafe {0} {1} (IntPtr jnienv{2}{3}{4});", + entry.ReturnType.GetMarshalType (style, isReturn: true, isPinvoke: true), + GetPinvokeName (entry.Name), + entry.Throws ? ", out IntPtr thrown" : "", + entry.Parameters.Length != 0 ? ", " : "", + string.Join (", ", entry.Parameters.Select (p => string.Format ("{0} {1}", p.Type.GetMarshalType (style, isReturn: false, isPinvoke: true), Escape (p.Name))))); + } + o.WriteLine ("\t}"); + o.WriteLine (); + } + + static void GenerateJniNativeMethods (TextWriter o, HandleStyle style) + { + o.WriteLine ("\tstatic partial class JniNativeMethods {"); + o.WriteLine (); + foreach (var entry in JNIEnvEntries) { + if (entry.Parameters == null) + continue; + if (entry.IsPrivate || entry.CustomWrapper) + continue; + + var returnType = entry.ReturnType.GetMarshalType (HandleStyle.JIFunctionPtrWithErrors, isReturn: true, isPinvoke: true); + + o.WriteLine (); + o.WriteLine ("\t\t[System.Runtime.CompilerServices.MethodImpl (System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]"); + o.Write ("\t\tinternal static unsafe "); + o.Write (entry.ReturnType.GetMarshalType (HandleStyle.JIFunctionPtrWithErrors, isReturn: true, isPinvoke: true)); + o.Write ($" {entry.Name} (IntPtr env"); + foreach (var p in entry.Parameters) { + o.Write (", "); + o.Write (p.Type.GetMarshalType (HandleStyle.JIFunctionPtrWithErrors, isReturn: false, isPinvoke: true)); + o.Write ($" {Escape (p.Name)}"); + } + o.WriteLine (")"); + o.WriteLine ("\t\t{"); + o.Write ("\t\t\t"); + if (returnType != "void") { + o.Write ("return "); + } + o.Write ($"(*((JNIEnv**)env))->{entry.Name} (env"); + foreach (var p in entry.Parameters) { + o.Write (", "); + o.Write (Escape (p.Name)); + } + o.WriteLine (");"); + o.WriteLine ("\t\t}"); + } + o.WriteLine ("\t}"); + o.WriteLine (); + } + + static string GetPinvokeName (string name) + { + var sb = new StringBuilder ("java_interop_jnienv_".Length + name.Length * 2); + sb.Append ("java_interop_jnienv"); + var uc = false; + foreach (var c in name) { + if (!uc && char.IsUpper (c)) { + sb.Append ("_"); + uc = true; + } else { + uc = false; + } + sb.Append (char.ToLower (c)); + } + return sb.ToString (); + } + + static void GenerateJniEnv (TextWriter o, string type, string visibility, HandleStyle style) + { + o.WriteLine (); + + o.WriteLine ("\t{0} static partial class {1} {{", visibility, type); + foreach (JniFunction entry in JNIEnvEntries) { + if ((entry.DeclaringType ?? "JniEnvironment") != type) + continue; + if (entry.Parameters == null) + continue; + if (entry.IsPrivate || entry.CustomWrapper) + continue; + + o.WriteLine (); + o.Write ("\t\t{2} static unsafe {0} {1} (", entry.GetManagedReturnType (style), entry.ApiName, entry.Visibility); + switch (entry.ApiName) { + default: + bool is_void = entry.ReturnType.JniType == "void"; + for (int i = 0; i < entry.Parameters.Length; i++) { + if (i > 0) + o.Write (", "); + o.Write ("{0} {1}", entry.Parameters [i].Type.GetManagedType (style, isReturn: false), Escape (entry.Parameters [i].Name)); + } + o.WriteLine (")"); + o.WriteLine ("\t\t{"); + NullCheckParameters (o, entry.Parameters, style); + PrepareParameters (o, entry.Parameters, style); + if (style == HandleStyle.JIIntPtrPinvokeWithErrors) { + if (entry.Throws) + o.WriteLine ("\t\t\tIntPtr thrown;"); + } else if (style == HandleStyle.JIFunctionPtrWithErrors) { + o.WriteLine ($"\t\t\tIntPtr __env = JniEnvironment.EnvironmentPointer;"); + } else { + o.WriteLine ("\t\t\tvar __info = JniEnvironment.CurrentInfo;"); + } + o.Write ("\t\t\t"); + if (!is_void) + o.Write ("var tmp = "); + if (style == HandleStyle.JIIntPtrPinvokeWithErrors) { + o.Write ("NativeMethods.{0} (JniEnvironment.EnvironmentPointer{1}", + GetPinvokeName (entry.Name), + entry.Throws ? ", out thrown" : ""); + } else if (style == HandleStyle.JIFunctionPtrWithErrors) { + o.Write ($"JniNativeMethods.{entry.Name} (__env"); + } else { + o.Write ("__info.Invoker.{0} (__info.EnvironmentPointer", entry.Name); + } + for (int i = 0; i < entry.Parameters.Length; i++) { + var p = entry.Parameters [i]; + o.Write (", "); + var needOut = p.Type.GetManagedType (style, isReturn: false).StartsWith ("out ", StringComparison.Ordinal); + if (needOut && style == HandleStyle.JIFunctionPtrWithErrors) { + o.Write ("&"); + } else if (needOut) { + o.Write ("out "); + } + o.Write (p.Type.GetManagedToMarshalExpression (style, Escape (entry.Parameters [i].Name))); + } + o.WriteLine (");"); + if (style == HandleStyle.JIFunctionPtrWithErrors && entry.Throws) { + o.WriteLine ("\t\t\tIntPtr thrown = JniNativeMethods.ExceptionOccurred (__env);"); + } + CleanupParameters (o, entry.Parameters, style); + RaiseException (o, entry, style); + if (is_void) { + } else { + foreach (var line in entry.ReturnType.GetHandleCreationLogStatements (style, entry.Name, "tmp")) + o.WriteLine ("\t\t\t{0}", line); + foreach (var line in entry.ReturnType.GetMarshalToManagedStatements (style, "tmp", entry)) + o.WriteLine ("\t\t\t{0}", line); + } + break; + } + + o.WriteLine ("\t\t}"); + } + o.WriteLine ("\t}"); + } + + static void NullCheckParameters (TextWriter o, ParamInfo[] ps, HandleStyle style) + { + bool haveChecks = false; + for (int i = 0; i < ps.Length; i++) { + var p = ps [i]; + if (p.CanBeNull) + continue; + var pn = Escape (p.Name); + foreach (var line in p.Type.VerifyParameter (style, pn)) { + haveChecks = true; + o.WriteLine ("\t\t\t{0}", line); + } + } + if (haveChecks) + o.WriteLine (); + } + + static void PrepareParameters (TextWriter o, ParamInfo[] ps, HandleStyle style) + { + bool haveChecks = false; + foreach (var e in ps) { + foreach (var s in e.Type.GetManagedToMarshalPrepareStatements (style, Escape (e.Name))) { + haveChecks = true; + o.WriteLine ($"\t\t\t{s}"); + } + } + if (haveChecks) + o.WriteLine (); + } + + static void CleanupParameters (TextWriter o, ParamInfo[] ps, HandleStyle style) + { + foreach (var e in ps) { + foreach (var s in e.Type.GetManagedToMarshalCleanupStatements (style, Escape (e.Name))) { + o.WriteLine ($"\t\t\t{s}"); + } + } + } + + static void RaiseException (TextWriter o, JniFunction entry, HandleStyle style) + { + if (!entry.Throws) + return; + + o.WriteLine (); + o.WriteLine ("\t\t\tException? __e = JniEnvironment.GetExceptionForLastThrowable ({0});", + (style == HandleStyle.JIIntPtrPinvokeWithErrors || style == HandleStyle.JIFunctionPtrWithErrors) + ? "thrown" + : ""); + o.WriteLine ("\t\t\tif (__e != null)"); + o.WriteLine ("\t\t\t\tExceptionDispatchInfo.Capture (__e).Throw ();"); + o.WriteLine (); + } + + static void WriteNativeFileHeader (TextWriter o) + { + o.WriteLine ("/*"); + o.WriteLine (" * Generated file; DO NOT EDIT!"); + o.WriteLine (" *"); + o.WriteLine (" * To make changes, edit Java.Interop/build-tools/jnienv-gen and rerun"); + o.WriteLine (" */"); + o.WriteLine (); + } + + static void GenerateNativeLibSource (TextWriter source, TextWriter header, string headerName) + { + WriteNativeFileHeader (source); + WriteNativeFileHeader (header); + + header.WriteLine ("#if !defined (__JAVA_INTEROP_NATIVE_H)"); + header.WriteLine ("#define __JAVA_INTEROP_NATIVE_H"); + header.WriteLine (); + header.WriteLine ("#include "); + header.WriteLine (); + header.WriteLine ("typedef jmethodID jstaticmethodID;"); + header.WriteLine ("typedef jfieldID jstaticfieldID;"); + header.WriteLine ("typedef jobject jglobal;"); + header.WriteLine (); + header.WriteLine ("#if !defined(JI_NO_VISIBILITY)"); + header.WriteLine ("\t/* VS 2010 and later have stdint.h */"); + header.WriteLine ("\t#if defined(_MSC_VER)"); + header.WriteLine (); + header.WriteLine ("\t\t#define JI_API_EXPORT __declspec(dllexport)"); + header.WriteLine ("\t\t#define JI_API_IMPORT __declspec(dllimport)"); + header.WriteLine (); + header.WriteLine ("\t#else /* defined(_MSC_VER */"); + header.WriteLine (); + header.WriteLine ("\t\t#define JI_API_EXPORT __attribute__ ((visibility (\"default\")))"); + header.WriteLine ("\t\t#define JI_API_IMPORT"); + header.WriteLine (); + header.WriteLine ("\t#endif /* !defined(_MSC_VER) */"); + header.WriteLine (); + header.WriteLine ("\t#if defined(JI_DLL_EXPORT)"); + header.WriteLine ("\t\t#define JI_API JI_API_EXPORT"); + header.WriteLine ("\t#elif defined(JI_DLL_IMPORT)"); + header.WriteLine ("\t\t#define JI_API JI_API_IMPORT"); + header.WriteLine ("\t#else /* !defined(JI_DLL_IMPORT) && !defined(JI_API_IMPORT) */"); + header.WriteLine ("\t\t#define JI_API"); + header.WriteLine ("\t#endif /* JI_DLL_EXPORT... */"); + header.WriteLine ("#else // JI_NO_VISIBILITY"); + header.WriteLine ("\t#define JI_API"); + header.WriteLine ("#endif // JI_NO_VISIBILITY"); + header.WriteLine (); + + if (headerName != "-") { + source.WriteLine ($"#include \"{Path.GetFileName(headerName)}\""); + } + + foreach (JniFunction entry in JNIEnvEntries) { + if (entry.IsPrivate || entry.CustomWrapper) + continue; + + header.WriteLine ( + "JI_API {0} {1} (JNIEnv *env{2}{3}{4});", + entry.ReturnType.JniType, + GetPinvokeName (entry.Name), + entry.Throws ? ", jthrowable *_thrown" : "", + entry.Parameters.Length != 0 ? ", " : "", + string.Join (", ", entry.Parameters.Select (p => string.Format ("{0} {1}", p.Type.JniType, p.Name))) + ); + + source.WriteLine (); + source.WriteLine ("JI_API {0}", entry.ReturnType.JniType); + source.WriteLine ("{0} (JNIEnv *env{1}{2}{3})", + GetPinvokeName (entry.Name), + entry.Throws ? ", jthrowable *_thrown" : "", + entry.Parameters.Length != 0 ? ", " : "", + string.Join (", ", entry.Parameters.Select (p => string.Format ("{0} {1}", p.Type.JniType, p.Name)))); + source.WriteLine ("{"); + bool isVoid = entry.ReturnType.JniType == "void"; + if (entry.Throws) + source.WriteLine ("\t*_thrown = 0;"); + source.Write ("\t"); + if (!isVoid) + source.Write ("{0} _r_ = ", entry.ReturnType.JniType); + source.WriteLine ("(*env)->{0} (env{1}{2});", + entry.Name, + entry.Parameters.Length != 0 ? ", " : "", + string.Join (", ", entry.Parameters.Select (p => p.Name))); + if (entry.Throws) + source.WriteLine ("\t*_thrown = (*env)->ExceptionOccurred (env);"); + if (!isVoid) + source.WriteLine ("\treturn _r_;"); + source.WriteLine ("}"); + } + + header.WriteLine (); + header.WriteLine ("#endif // __JAVA_INTEROP_NATIVE_H"); + } + } + + class JniFunction { + + public string DeclaringType; + + // The java name + public string Name; + + // The name of the property/method we will generate. Defaults to the (java) name. + private string api_name; + public string ApiName + { + get { return api_name ?? Name; } + set { api_name = value; } + } + + // The C prototype that we are binding (for diagnostic purposes) + public string Prototype; + + public TypeInfo ReturnType; + public ParamInfo [] Parameters; + + // If true, then we initialize the binding on the static ctor, we dont lazy-define it + public bool Prebind = false; + + // If there is a custom wrapper in JNIEnv (so an automatic one shouldn't be generated) + public bool CustomWrapper = false; + + // If the JNI function can throw an exception (ExceptionOccurred needs to be invoked) + public bool Throws; + + private string visibility; + public string Visibility { + get { + if (visibility == null) + return "public"; + return visibility; + } + set { + visibility = value; + } + } + + public bool IsPublic { get { return Visibility == "public"; } } + public bool IsPrivate { get { return visibility == "private"; } } + + public string GetManagedReturnType (HandleStyle style) + { + if (ReturnType == null) + return "void"; + return ReturnType.GetManagedType (style, isReturn:true); + } + + public string GetMarshalReturnType (HandleStyle style) + { + if (ReturnType == null) + return "void"; + return ReturnType.GetMarshalType (style, isReturn:true); + } + + public string GetDelegateTypeName (HandleStyle style) + { + StringBuilder name = new StringBuilder (); + + if (ReturnType == null || ReturnType.JniType == "void") + name.Append ("JniAction_"); + else + name.Append ("JniFunc_"); + name.Append ("JNIEnvPtr"); + for (int i = 0; i < Parameters.Length; i++) { + var pt = Parameters [i].Type.GetMarshalType (style, isReturn: false); + if (pt == "va_list") + return null; + + name.AppendFormat ("_").Append (pt.FixupType ()); + } + + string rt = GetMarshalReturnType (style); + if (rt != "void") + name.Append ("_").Append (rt.FixupType ()); + + return name.ToString (); + } + } + + abstract class TypeInfo + { + static readonly Dictionary types = new Dictionary () { + { "jvalue*", new BuiltinTypeInfo ("jvalue*", "JniArgumentValue*") }, + { "jbyte", new BuiltinTypeInfo ("jbyte", "sbyte") }, + { "jchar", new BuiltinTypeInfo ("jchar", "char") }, + { "jchar*", new BuiltinTypeInfo ("jchar*", "char*") }, + { "jshort", new BuiltinTypeInfo ("jshort", "short") }, + { "jsize", new BuiltinTypeInfo ("jsize", "int") }, + { "jint", new BuiltinTypeInfo ("jint", "int") }, + { "jlong", new BuiltinTypeInfo ("jlong", "long") }, + { "jfloat", new BuiltinTypeInfo ("jfloat", "float") }, + { "jdouble", new BuiltinTypeInfo ("jdouble", "double") }, + { "jboolean", new BooleanTypeInfo ("jboolean") }, + { "void*", new BuiltinTypeInfo ("void*", "IntPtr") }, + { "const jchar*", new StringTypeInfo ("const jchar*") }, + { "const char*", new StringTypeInfo ("const char*") }, + { "const JNINativeMethod*", new BuiltinTypeInfo ("const JNINativeMethod*", "JniNativeMethodRegistration []") }, + { "jobjectRefType", new BuiltinTypeInfo ("jobjectRefType", "JniObjectReferenceType") }, + { "jfieldID", new InstanceFieldTypeInfo ("jfieldID") }, + { "jstaticfieldID", new StaticFieldTypeInfo ("jstaticfieldID") }, + { "jmethodID", new InstanceMethodTypeInfo ("jmethodID") }, + { "jstaticmethodID", new StaticMethodTypeInfo ("jstaticmethodID") }, + { "jstring", new LocalReferenceTypeInfo ("jstring") }, + { "jarray", new LocalReferenceTypeInfo ("jarray") }, + { "jobject", new LocalReferenceTypeInfo ("jobject") }, + { "jthrowable", new LocalReferenceTypeInfo ("jthrowable") }, + { "jclass", new LocalReferenceTypeInfo ("jclass") }, + { "jweak", new WeakGlobalReferenceTypeInfo ("jweak") }, + { "jglobal", new GlobalReferenceTypeInfo ("jglobal") }, + { "JavaVM**", new JavaVMPointerTypeInfo ("JavaVM**") }, + { "JniReleaseArrayElementsMode", new JniReleaseArrayElementsModeTypeInfo () }, + }; + + static readonly Dictionary pointerMapping = new Dictionary { + { "jboolean*", "bool*" }, + { "jbyte*", "sbyte*" }, + { "jchar*", "char*" }, + { "jdouble*", "double*" }, + { "jfloat*", "float*" }, + { "jint*", "int*" }, + { "jlong*", "long*" }, + { "jshort*", "short*" }, + }; + + public static TypeInfo Create (string type, string managedType = null) + { + if (managedType != null) + return new BuiltinTypeInfo (type, managedType); + TypeInfo t; + if (types.TryGetValue (type, out t)) + return t; + if (type.EndsWith ("Array", StringComparison.Ordinal)) + return new ArrayTypeInfo (type); + string p; + if (pointerMapping.TryGetValue (type, out p)) + return new BuiltinTypeInfo (type, p); + if (type.EndsWith ("*", StringComparison.Ordinal)) + return new BuiltinTypeInfo (type, "IntPtr"); + return new BuiltinTypeInfo (type, type); + } + + public static implicit operator TypeInfo (string jniType) + { + return Create (jniType); + } + + public readonly string JniType; + + protected TypeInfo (string jniType) + { + JniType = jniType; + } + + public abstract string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke = false); + public abstract string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke = false); + + public virtual string[] GetHandleCreationLogStatements (HandleStyle style, string method, string variable) + { + return new string [0]; + } + + public virtual string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + return variable; + } + + public virtual string[] GetMarshalToManagedStatements (HandleStyle style, string variable, JniFunction entry) + { + return new[] { + string.Format ("return {0};", variable), + }; + } + + public virtual string[] VerifyParameter (HandleStyle style, string variable) + { + return new string [0]; + } + + public virtual string[] GetManagedToMarshalPrepareStatements (HandleStyle style, string variable) => Array.Empty (); + public virtual string[] GetManagedToMarshalCleanupStatements (HandleStyle style, string variable) => Array.Empty (); + } + + class BuiltinTypeInfo : TypeInfo { + + /// + /// NOTE: .NET framework can't marshal this + /// + const string JniArgumentValue = "JniArgumentValue*"; + string managed; + + public BuiltinTypeInfo (string jni, string managed) + : base (jni) + { + this.managed = managed; + } + + public override string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke) + { + if (isPinvoke && managed == JniArgumentValue) { + return "IntPtr"; + } + return managed; + } + + public override string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke) + { + if (isPinvoke && managed == JniArgumentValue) { + return "IntPtr"; + } + return managed; + } + + public override string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + var value = base.GetManagedToMarshalExpression (style, variable); + if (managed == JniArgumentValue) { + value = "(IntPtr) " + value; + } + return value; + } + + public override string[] VerifyParameter (HandleStyle style, string variable) + { + if (managed != "IntPtr") + return new string [0]; + var variableName = variable.StartsWith ("@", StringComparison.Ordinal) + ? variable.Substring (1) + : variable; + return new[] { + string.Format ("if ({0} == IntPtr.Zero)", variable), + string.Format ("\tthrow new ArgumentException (\"'{0}' must not be IntPtr.Zero.\", \"{0}\");", variableName), + }; + } + } + + class BooleanTypeInfo : TypeInfo { + + public BooleanTypeInfo (string jni) + : base (jni) + { + } + + public override string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke) + { + return "byte"; + } + + public override string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke) + { + return "bool"; + } + + public override string[] GetMarshalToManagedStatements (HandleStyle style, string variable, JniFunction entry) + { + return new string[] { + string.Format ("return ({0} != 0) ? true : false;", variable), + }; + } + + public override string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + return string.Format ("({0} ? (byte) 1 : (byte) 0)", variable); + } + } + + class StringTypeInfo : TypeInfo { + + public StringTypeInfo (string jni) + : base (jni) + { + } + + public override string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke) + { + if (style == HandleStyle.JIFunctionPtrWithErrors && isPinvoke) { + return "IntPtr"; + } + return "string"; + } + + public override string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke) + { + return "string"; + } + + public override string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIFunctionPtrWithErrors: + return $"_{variable}_ptr"; + default: + return variable; + } + } + + public override string[] GetMarshalToManagedStatements (HandleStyle style, string variable, JniFunction entry) + { + switch (style) { + case HandleStyle.XAIntPtr: + return new [] { + string.Format ("JniEnvironment.LogCreateLocalRef ({0});", variable), + string.Format ("return {0};", variable), + }; + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return new [] { + string.Format ("JniEnvironment.LogCreateLocalRef ({0});", variable), + string.Format ("return new JniObjectReference ({0}, JniObjectReferenceType.Local);", variable), + }; + } + return null; + } + + public override string[] VerifyParameter (HandleStyle style, string variable) + { + var variableName = variable.StartsWith ("@", StringComparison.Ordinal) + ? variable.Substring (1) + : variable; + return new[] { + string.Format ("if ({0} == null)", variable), + string.Format ("\tthrow new ArgumentNullException (\"{0}\");", variableName), + }; + } + + public override string[] GetManagedToMarshalPrepareStatements (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIFunctionPtrWithErrors: + return new[]{ + $"var _{variable}_ptr = Marshal.StringToCoTaskMemUTF8 ({variable});", + }; + default: + return base.GetManagedToMarshalPrepareStatements (style, variable); + } + } + + public override string[] GetManagedToMarshalCleanupStatements (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIFunctionPtrWithErrors: + return new[]{ + $"Marshal.ZeroFreeCoTaskMemUTF8 (_{variable}_ptr);", + }; + default: + return base.GetManagedToMarshalCleanupStatements (style, variable); + } + } + } + + class JniReleaseArrayElementsModeTypeInfo : TypeInfo { + + public JniReleaseArrayElementsModeTypeInfo () + : base ("jint") + { + } + + public override string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke) + { + return "int"; + } + + public override string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke) + { + return "JniReleaseArrayElementsMode"; + } + + public override string[] GetMarshalToManagedStatements (HandleStyle style, string variable, JniFunction entry) + { + return new string[] { + string.Format ("return (JniReleaseArrayElementsMode) {0};", variable), + }; + } + + public override string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + return string.Format ("((int) {0})", variable); + } + } + + class ArrayTypeInfo : LocalReferenceTypeInfo { + + public ArrayTypeInfo (string jni) + : base (jni) + { + } + } + + class IdTypeInfo : TypeInfo { + + string type; + + public IdTypeInfo (string jni, string type) + : base (jni) + { + this.type = type; + } + + public override string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke) + { + return "IntPtr"; + } + + public override string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke) + { + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return type; + case HandleStyle.XAIntPtr: + return "IntPtr"; + } + return "TODO_" + style;; + } + + public override string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return string.Format ("{0}.ID", variable); + } + return variable; + } + + public override string[] VerifyParameter (HandleStyle style, string variable) + { + var variableName = variable.StartsWith ("@", StringComparison.Ordinal) + ? variable.Substring (1) + : variable; + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return new [] { + string.Format ("if ({0} == null)", variable), + string.Format ("\tthrow new ArgumentNullException (\"{0}\");", variableName), + string.Format ("if (!{0}.IsValid)", variable), + string.Format ("\tthrow new ArgumentException (\"Handle value is not valid.\", \"{0}\");", variableName), + string.Format ("System.Diagnostics.Debug.Assert ({0}{1}.IsStatic);", IsStatic ? "" : "!", variableName), + }; + case HandleStyle.XAIntPtr: + return new[] { + string.Format ("if ({0} == IntPtr.Zero)", variable), + string.Format ("\tthrow new ArgumentException (\"Handle value cannot be null.\", \"{0}\");", variableName), + }; + } + return new string [0]; + } + + public override string[] GetMarshalToManagedStatements (HandleStyle style, string variable, JniFunction entry) + { + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return new[] { + string.Format ("if ({0} == IntPtr.Zero)", variable), + string.Format ($"\tthrow new InvalidOperationException (\"Should not be reached; `{entry.Name}` should have thrown!\");"), + string.Format ("return new {0} ({1}, {2}, {3}, isStatic: {4});", type, entry.Parameters [1].Name, entry.Parameters [2].Name, variable, IsStatic ? "true" : "false"), + }; + case HandleStyle.XAIntPtr: + return new[]{ + string.Format ("return {0};", variable), + }; + } + return new string [0]; + } + + protected virtual bool IsStatic { + get {return false;} + } + } + + class InstanceFieldTypeInfo : IdTypeInfo { + + public InstanceFieldTypeInfo (string jni) + : base (jni, "JniFieldInfo") + { + } + } + + class InstanceMethodTypeInfo : IdTypeInfo { + + public InstanceMethodTypeInfo (string jni) + : base (jni, "JniMethodInfo") + { + } + } + + class StaticFieldTypeInfo : IdTypeInfo { + + public StaticFieldTypeInfo (string jni) + : base (jni, "JniFieldInfo") + { + } + + protected override bool IsStatic { + get {return true;} + } + } + + class StaticMethodTypeInfo : IdTypeInfo { + + public StaticMethodTypeInfo (string jni) + : base (jni, "JniMethodInfo") + { + } + + protected override bool IsStatic { + get {return true;} + } + } + + abstract class ObjectReferenceTypeInfo : TypeInfo { + + string refType; + + public ObjectReferenceTypeInfo (string jni, string refType) + : base (jni) + { + this.refType = refType; + } + + public override string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke) + { + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + case HandleStyle.XAIntPtr: + return "jobject"; + } + return null; + } + + public override string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke) + { + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return "JniObjectReference"; + case HandleStyle.XAIntPtr: + return "IntPtr"; + } + return "TODO"; + } + + public override string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return string.Format ("{0}.Handle", variable); + case HandleStyle.XAIntPtr: + return variable; + } + return null; + } + + public override string[] GetMarshalToManagedStatements (HandleStyle style, string variable, JniFunction entry) + { + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return new [] { + string.Format ("return new JniObjectReference ({0}, {1});", variable, refType), + }; + case HandleStyle.XAIntPtr: + return new[] { + string.Format ("return {0};", variable), + }; + } + return new string [0]; + } + + public override string[] VerifyParameter (HandleStyle style, string variable) + { + var variableName = variable.StartsWith ("@", StringComparison.Ordinal) + ? variable.Substring (1) + : variable; + switch (style) { + case HandleStyle.JIIntPtr: + case HandleStyle.JIIntPtrPinvokeWithErrors: + case HandleStyle.JIFunctionPtrWithErrors: + return new [] { + string.Format ("if (!{0}.IsValid)", variable), + string.Format ("\tthrow new ArgumentException (\"Handle must be valid.\", \"{0}\");", variableName), + }; + case HandleStyle.XAIntPtr: + return new [] { + string.Format ("if ({0} == IntPtr.Zero)", variable), + string.Format ("\tthrow new ArgumentException (\"`{0}` must not be IntPtr.Zero.\", \"{0}\");", variableName), + }; + } + return new string [0]; + } + } + + class LocalReferenceTypeInfo : ObjectReferenceTypeInfo { + + public LocalReferenceTypeInfo (string jni) + : base (jni, "JniObjectReferenceType.Local") + { + } + + public override string[] GetHandleCreationLogStatements (HandleStyle style, string method, string variable) + { + if (method == "NewLocalRef" || method == "ExceptionOccurred") + return base.GetHandleCreationLogStatements (style, method, variable); + return new[] { + string.Format ("JniEnvironment.LogCreateLocalRef ({0});", variable), + }; + } + } + + class WeakGlobalReferenceTypeInfo : ObjectReferenceTypeInfo { + + public WeakGlobalReferenceTypeInfo (string jni) + : base (jni, "JniObjectReferenceType.WeakGlobal") + { + } + } + + class GlobalReferenceTypeInfo : ObjectReferenceTypeInfo { + + public GlobalReferenceTypeInfo (string jni) + : base (jni, "JniObjectReferenceType.Global") + { + } + } + + class JavaVMPointerTypeInfo : TypeInfo { + + public JavaVMPointerTypeInfo (string jni) + : base (jni) + { + } + + public override string GetMarshalType (HandleStyle style, bool isReturn, bool isPinvoke) + { + if (style == HandleStyle.JIFunctionPtrWithErrors && isPinvoke) { + return "IntPtr*"; + } + return "out IntPtr"; + } + + public override string GetManagedType (HandleStyle style, bool isReturn, bool isPinvoke) + { + return "out IntPtr"; + } + + public override string GetManagedToMarshalExpression (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIFunctionPtrWithErrors: + return $"_{variable}_ptr"; + default: + return variable; + } + } + + public override string[] GetManagedToMarshalPrepareStatements (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIFunctionPtrWithErrors: + return new[]{ + $"IntPtr _{variable}_ptr = IntPtr.Zero;", + }; + default: + return base.GetManagedToMarshalPrepareStatements (style, variable); + } + } + + public override string[] GetManagedToMarshalCleanupStatements (HandleStyle style, string variable) + { + switch (style) { + case HandleStyle.JIFunctionPtrWithErrors: + return new[]{ + $"{variable} = _{variable}_ptr;", + }; + default: + return base.GetManagedToMarshalCleanupStatements (style, variable); + } + } + } + + class ParamInfo + { + public TypeInfo Type; + public string Name; + public bool IsParamArray; + public bool CanBeNull; + + public ParamInfo (TypeInfo Type, string Name, bool IsParamArray) + { + this.Type = Type; + this.Name = Name; + this.IsParamArray = IsParamArray; + } + + public ParamInfo (TypeInfo Type, string Name = null, Modifier m = 0) + { + this.Type = Type; + this.Name = Name; + IsParamArray = (m & Modifier.Params) != 0; + CanBeNull = (m & Modifier.CanBeNull) != 0; + } + } + + [Flags] + enum Modifier { + None = 0, + Params = 1, + CanBeNull = 2, + } + + enum HandleStyle { + JIIntPtr, + JIIntPtrPinvokeWithErrors, + XAIntPtr, + JIFunctionPtrWithErrors, + } +} diff --git a/external/Java.Interop/build-tools/jnienv-gen/Generator.g.cs b/external/Java.Interop/build-tools/jnienv-gen/Generator.g.cs new file mode 100644 index 00000000000..b2fbe1311a6 --- /dev/null +++ b/external/Java.Interop/build-tools/jnienv-gen/Generator.g.cs @@ -0,0 +1,2038 @@ +namespace Xamarin.Java.Interop +{ + partial class Generator + { + const string VersionsCategory = "Versions"; + const string ClassesCategory = "Types"; + const string ExceptionsCategory = "Exceptions"; + const string ReferencesCatgeory = "References"; + const string ObjectOperationsCategory = "Object"; + const string InstanceFieldsCategory = "InstanceFields"; + const string StaticFieldsCategory = "StaticFields"; + const string InstanceMethodsCategory = "InstanceMethods"; + const string StaticMethodsCategory = "StaticMethods"; + const string StringOperationsCategory = "Strings"; + const string ArrayOperationsCategory = "Arrays"; + const string NativeMethodsCategory = "Types"; + const string MonitorOperationsCategory = "Monitors"; + const string NIOSupportCategory = "IO"; + const string ReflectionSupportCategory = "Reflection"; + const string JavaVMCategory = "References"; + + static readonly JniFunction[] JNIEnvEntries = new JniFunction[]{ + new JniFunction { + DeclaringType = VersionsCategory, + Name = "GetVersion", + Visibility = "internal", + Prototype = "jint (*GetVersion)(JNIEnv*);", + ReturnType = "jint", + Parameters = new ParamInfo [] {}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "DefineClass", + Visibility = "public", + Throws = true, + Prototype = "jclass (*DefineClass)(JNIEnv*, const char, jobject, const jbyte*, jsize);", + ReturnType = "jclass", + Parameters = new ParamInfo [] {new ParamInfo ("const char*", "name"), new ParamInfo ("jobject", "loader"), new ParamInfo ("const jbyte*", "buffer"), new ParamInfo ("jsize", "bufferLength")}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "FindClass", + Visibility = "internal", + ApiName = "_FindClass", + Throws = true, + Prototype = "jclass (*FindClass)(JNIEnv*, const char*);", + ReturnType = "jclass", + Parameters = new ParamInfo [] {new ParamInfo ("const char*", "classname")}, + }, + new JniFunction { + DeclaringType = ReflectionSupportCategory, + Name = "FromReflectedMethod", + Visibility = "private", + Prototype = "jmethodID (*FromReflectedMethod)(JNIEnv*, jobject);", + ReturnType = "jmethodID", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "method")}, + }, + new JniFunction { + DeclaringType = ReflectionSupportCategory, + Name = "FromReflectedField", + Visibility = "private", + Prototype = "jfieldID (*FromReflectedField)(JNIEnv*, jobject);", + ReturnType = "jfieldID", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "field")}, + }, + new JniFunction { + DeclaringType = ReflectionSupportCategory, + Name = "ToReflectedMethod", + Visibility = "public", + Throws = true, + Prototype = "jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jboolean", "isStatic")}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "GetSuperclass", + Visibility = "public", + Prototype = "jclass (*GetSuperclass)(JNIEnv*, jclass);", + ReturnType = "jclass", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type")}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "IsAssignableFrom", + Visibility = "public", + Prototype = "jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "class1"), new ParamInfo ("jclass", "class2")}, + }, + new JniFunction { + DeclaringType = ReflectionSupportCategory, + Name = "ToReflectedField", + Visibility = "public", + Throws = true, + Prototype = "jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jboolean", "isStatic")}, + }, + new JniFunction { + DeclaringType = ExceptionsCategory, + Name = "Throw", + // CustomWrapper = true, + ApiName = "_Throw", + Visibility = "internal", + // Throws = true, + Prototype = "jint (*Throw)(JNIEnv*, jthrowable);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jthrowable", "toThrow")}, + }, + new JniFunction { + DeclaringType = ExceptionsCategory, + Name = "ThrowNew", + ApiName = "_ThrowNew", + // CustomWrapper = true, + Visibility = "internal", + // Throws = true, + Prototype = "jint (*ThrowNew)(JNIEnv*, jclass, const char*);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("const char*", "message")}, + }, + new JniFunction { + DeclaringType = ExceptionsCategory, + Name = "ExceptionOccurred", + Visibility = "public", + Prototype = "jthrowable (*ExceptionOccurred)(JNIEnv*);", + ReturnType = "jthrowable", + Parameters = new ParamInfo [] {}, + }, + new JniFunction { + DeclaringType = ExceptionsCategory, + Name = "ExceptionDescribe", + Visibility = "public", + Prototype = "void (*ExceptionDescribe)(JNIEnv*);", + ReturnType = "void", + Parameters = new ParamInfo [] {}, + }, + new JniFunction { + DeclaringType = ExceptionsCategory, + Name = "ExceptionClear", + Visibility = "public", + Prototype = "void (*ExceptionClear)(JNIEnv*);", + ReturnType = "void", + Parameters = new ParamInfo [] {}, + }, + new JniFunction { + DeclaringType = ExceptionsCategory, + Name = "FatalError", + Visibility = "public", + Prototype = "void (*FatalError)(JNIEnv*, const char*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("const char*", "message")}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "PushLocalFrame", + ApiName = "_PushLocalFrame", + // CustomWrapper = true, + Visibility = "internal", + Prototype = "jint (*PushLocalFrame)(JNIEnv*, jint);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jint", "capacity")}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "PopLocalFrame", + Visibility = "public", + Prototype = "jobject (*PopLocalFrame)(JNIEnv*, jobject);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "result", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "NewGlobalRef", + Visibility = "internal", + // Prebind = true, + Prototype = "jobject (*NewGlobalRef)(JNIEnv*, jobject);", + ReturnType = "jglobal", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "DeleteGlobalRef", + Visibility = "internal", + Prototype = "void (*DeleteGlobalRef)(JNIEnv*, jobject);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo (TypeInfo.Create ("jobject", "IntPtr"), "instance", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "DeleteLocalRef", + Visibility = "internal", + // Prebind = true, + Prototype = "void (*DeleteLocalRef)(JNIEnv*, jobject);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo (TypeInfo.Create ("jobject", "IntPtr"), "instance", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "IsSameObject", + Visibility = "public", + Prototype = "jboolean (*IsSameObject)(JNIEnv*, jobject, jobject);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "object1", Modifier.CanBeNull), new ParamInfo ("jobject", "object2", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "NewLocalRef", + Visibility = "internal", + Prototype = "jobject (*NewLocalRef)(JNIEnv*, jobject);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "EnsureLocalCapacity", + ApiName = "_EnsureLocalCapacity", + // CustomWrapper = true, + Visibility = "internal", + Prototype = "jint (*EnsureLocalCapacity)(JNIEnv*, jint);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jint", "capacity")}, + }, + new JniFunction { + DeclaringType = ObjectOperationsCategory, + Name = "AllocObject", + Visibility = "public", + Throws = true, + Prototype = "jobject (*AllocObject)(JNIEnv*, jclass);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type")}, + }, + new JniFunction { + DeclaringType = ObjectOperationsCategory, + Name = "NewObject", + ApiName = "_NewObject", + Visibility = "internal", + Throws = true, + Prototype = "jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = ObjectOperationsCategory, + Name = "NewObjectV", + Visibility = "private", + Throws = true, + Prototype = "jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = ObjectOperationsCategory, + Name = "NewObjectA", + ApiName = "_NewObject", + Visibility = "internal", + Throws = true, + Prototype = "jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "GetObjectClass", + Visibility = "public", + Prototype = "jclass (*GetObjectClass)(JNIEnv*, jobject);", + ReturnType = "jclass", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance")}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "IsInstanceOf", + Visibility = "public", + Prototype = "jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "GetMethodID", + Visibility = "public", + Throws = true, + Prototype = "jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);", + ReturnType = "jmethodID", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("const char*", "name"), new ParamInfo ("const char*", "signature")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallObjectMethod", + Visibility = "public", + Throws = true, + Prototype = "jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallObjectMethodV", + Visibility = "private", + Throws = true, + Prototype = "jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallObjectMethodA", + ApiName = "CallObjectMethod", + Throws = true, + Visibility = "public", + Prototype = "jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallBooleanMethod", + Visibility = "public", + Throws = true, + Prototype = "jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallBooleanMethodV", + Visibility = "private", + Throws = true, + Prototype = "jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallBooleanMethodA", + ApiName = "CallBooleanMethod", + Visibility = "public", + Throws = true, + Prototype = "jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallByteMethod", + Visibility = "public", + Throws = true, + Prototype = "jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallByteMethodV", + Visibility = "private", + Throws = true, + Prototype = "jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallByteMethodA", + ApiName = "CallByteMethod", + Visibility = "public", + Throws = true, + Prototype = "jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallCharMethod", + Visibility = "public", + Throws = true, + Prototype = "jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallCharMethodV", + Visibility = "private", + Throws = true, + Prototype = "jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallCharMethodA", + ApiName = "CallCharMethod", + Visibility = "public", + Throws = true, + Prototype = "jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallShortMethod", + Visibility = "public", + Throws = true, + Prototype = "jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallShortMethodV", + Visibility = "private", + Throws = true, + Prototype = "jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallShortMethodA", + ApiName = "CallShortMethod", + Visibility = "public", + Throws = true, + Prototype = "jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallIntMethod", + Visibility = "public", + Throws = true, + Prototype = "jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallIntMethodV", + Visibility = "private", + Throws = true, + Prototype = "jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallIntMethodA", + ApiName = "CallIntMethod", + Visibility = "public", + Throws = true, + Prototype = "jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallLongMethod", + Visibility = "public", + Throws = true, + Prototype = "jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallLongMethodV", + Visibility = "private", + Throws = true, + Prototype = "jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallLongMethodA", + ApiName = "CallLongMethod", + Visibility = "public", + Throws = true, + Prototype = "jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallFloatMethod", + Visibility = "public", + Throws = true, + Prototype = "jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallFloatMethodV", + Visibility = "private", + Throws = true, + Prototype = "jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallFloatMethodA", + ApiName = "CallFloatMethod", + Visibility = "public", + Throws = true, + Prototype = "jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallDoubleMethod", + Visibility = "public", + Throws = true, + Prototype = "jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallDoubleMethodV", + Visibility = "private", + Throws = true, + Prototype = "jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallDoubleMethodA", + ApiName = "CallDoubleMethod", + Visibility = "public", + Throws = true, + Prototype = "jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallVoidMethod", + Visibility = "public", + Throws = true, + Prototype = "void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallVoidMethodV", + Visibility = "private", + Throws = true, + Prototype = "void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallVoidMethodA", + ApiName = "CallVoidMethod", + Visibility = "public", + Throws = true, + Prototype = "void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualObjectMethod", + Visibility = "public", + Throws = true, + Prototype = "jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualObjectMethodV", + Visibility = "private", + Throws = true, + Prototype = "jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType ="jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualObjectMethodA", + ApiName = "CallNonvirtualObjectMethod", + Visibility = "public", + Throws = true, + Prototype = "jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualBooleanMethod", + Visibility = "public", + Throws = true, + Prototype = "jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualBooleanMethodV", + Visibility = "private", + Throws = true, + Prototype = "jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualBooleanMethodA", + ApiName = "CallNonvirtualBooleanMethod", + Visibility = "public", + Throws = true, + Prototype = "jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualByteMethod", + Visibility = "public", + Throws = true, + Prototype = "jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualByteMethodV", + Visibility = "private", + Throws = true, + Prototype = "jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualByteMethodA", + ApiName = "CallNonvirtualByteMethod", + Visibility = "public", + Throws = true, + Prototype = "jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualCharMethod", + Visibility = "public", + Throws = true, + Prototype = "jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualCharMethodV", + Visibility = "private", + Throws = true, + Prototype = "jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "obj"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualCharMethodA", + ApiName = "CallNonvirtualCharMethod", + Visibility = "public", + Throws = true, + Prototype = "jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualShortMethod", + Visibility = "public", + Throws = true, + Prototype = "jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualShortMethodV", + Visibility = "private", + Throws = true, + Prototype = "jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "obj"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualShortMethodA", + ApiName = "CallNonvirtualShortMethod", + Visibility = "public", + Throws = true, + Prototype = "jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualIntMethod", + Visibility = "public", + Throws = true, + Prototype = "jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualIntMethodV", + Visibility = "private", + Throws = true, + Prototype = "jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "obj"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualIntMethodA", + ApiName = "CallNonvirtualIntMethod", + Visibility = "public", + Throws = true, + Prototype = "jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualLongMethod", + Visibility = "public", + Throws = true, + Prototype = "jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualLongMethodV", + Visibility = "private", + Throws = true, + Prototype = "jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualLongMethodA", + ApiName = "CallNonvirtualLongMethod", + Throws = true, + Visibility = "public", + Prototype = "jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualFloatMethod", + Visibility = "public", + Throws = true, + Prototype = "jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualFloatMethodV", + Visibility = "private", + Throws = true, + Prototype = "jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualFloatMethodA", + ApiName = "CallNonvirtualFloatMethod", + Visibility = "public", + Throws = true, + Prototype = "jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualDoubleMethod", + Visibility = "public", + Throws = true, + Prototype = "jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualDoubleMethodV", + Visibility = "private", + Throws = true, + Prototype = "jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualDoubleMethodA", + ApiName = "CallNonvirtualDoubleMethod", + Visibility = "public", + Throws = true, + Prototype = "jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualVoidMethod", + Visibility = "public", + Throws = true, + Prototype = "void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass, jmethodID, ...);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualVoidMethodV", + Visibility = "private", + Throws = true, + Prototype = "void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = InstanceMethodsCategory, + Name = "CallNonvirtualVoidMethodA", + ApiName = "CallNonvirtualVoidMethod", + Visibility = "public", + Throws = true, + Prototype = "void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jclass", "type"), new ParamInfo ("jmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetFieldID", + Visibility = "public", + Throws = true, + Prototype = "jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);", + ReturnType = "jfieldID", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("const char*", "name"), new ParamInfo ("const char*", "signature")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetObjectField", + Visibility = "public", + Prototype = "jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetBooleanField", + Visibility = "public", + Prototype = "jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetByteField", + Visibility = "public", + Prototype = "jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetCharField", + Visibility = "public", + Prototype = "jchar (*GetCharField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetShortField", + Visibility = "public", + Prototype = "jshort (*GetShortField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetIntField", + Visibility = "public", + Prototype = "jint (*GetIntField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetLongField", + Visibility = "public", + Prototype = "jlong (*GetLongField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetFloatField", + Visibility = "public", + Prototype = "jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "GetDoubleField", + Visibility = "public", + Prototype = "jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field")}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetObjectField", + Visibility = "public", + Prototype = "void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jobject", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetBooleanField", + Visibility = "public", + Prototype = "void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jboolean", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetByteField", + Visibility = "public", + Prototype = "void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jbyte", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetCharField", + Visibility = "public", + Prototype = "void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jchar", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetShortField", + Visibility = "public", + Prototype = "void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jshort", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetIntField", + Visibility = "public", + Prototype = "void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jint", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetLongField", + Visibility = "public", + Prototype = "void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jlong", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetFloatField", + Visibility = "public", + Prototype = "void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jfloat", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = InstanceFieldsCategory, + Name = "SetDoubleField", + Visibility = "public", + Prototype = "void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance"), new ParamInfo ("jfieldID", "field"), new ParamInfo ("jdouble", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "GetStaticMethodID", + Visibility = "public", + Throws = true, + Prototype = "jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);", + ReturnType = "jstaticmethodID", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("const char*", "name"), new ParamInfo ("const char*", "signature")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticObjectMethod", + Visibility = "public", + Throws = true, + Prototype = "jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticObjectMethodV", + Visibility = "private", + Throws = true, + Prototype = "jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticObjectMethodA", + ApiName = "CallStaticObjectMethod", + Visibility = "public", + Throws = true, + Prototype = "jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticBooleanMethod", + Visibility = "public", + Throws = true, + Prototype = "jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticBooleanMethodV", + Visibility = "private", + Throws = true, + Prototype = "jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticBooleanMethodA", + ApiName = "CallStaticBooleanMethod", + Visibility = "public", + Throws = true, + Prototype = "jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticByteMethod", + Visibility = "public", + Throws = true, + Prototype = "jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticByteMethodV", + Visibility = "private", + Throws = true, + Prototype = "jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticByteMethodA", + ApiName = "CallStaticByteMethod", + Throws = true, + Visibility = "public", + Prototype = "jbyte (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticCharMethod", + Visibility = "public", + Throws = true, + Prototype = "jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticCharMethodV", + Visibility = "private", + Throws = true, + Prototype = "jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticCharMethodA", + ApiName = "CallStaticCharMethod", + Visibility = "public", + Throws = true, + Prototype = "jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticShortMethod", + Visibility = "public", + Throws = true, + Prototype = "jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticShortMethodV", + Visibility = "private", + Throws = true, + Prototype = "jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticShortMethodA", + ApiName = "CallStaticShortMethod", + Visibility = "public", + Throws = true, + Prototype = "jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticIntMethod", + Visibility = "public", + Throws = true, + Prototype = "jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticIntMethodV", + Visibility = "private", + Throws = true, + Prototype = "jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticIntMethodA", + ApiName = "CallStaticIntMethod", + Visibility = "public", + Throws = true, + Prototype = "jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticLongMethod", + Visibility = "public", + Throws = true, + Prototype = "jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticLongMethodV", + Visibility = "private", + Throws = true, + Prototype = "jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticLongMethodA", + ApiName = "CallStaticLongMethod", + Visibility = "public", + Throws = true, + Prototype = "jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticFloatMethod", + Visibility = "public", + Throws = true, + Prototype = "jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticFloatMethodV", + Visibility = "private", + Throws = true, + Prototype = "jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticFloatMethodA", + ApiName = "CallStaticFloatMethod", + Visibility = "public", + Throws = true, + Prototype = "jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticDoubleMethod", + Visibility = "public", + Throws = true, + Prototype = "jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticDoubleMethodV", + Visibility = "private", + Throws = true, + Prototype = "jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticDoubleMethodA", + ApiName = "CallStaticDoubleMethod", + Visibility = "public", + Throws = true, + Prototype = "jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticVoidMethod", + Visibility = "public", + Throws = true, + Prototype = "void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticVoidMethodV", + Visibility = "private", + Throws = true, + Prototype = "void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("va_list", "args")}, + }, + new JniFunction { + DeclaringType = StaticMethodsCategory, + Name = "CallStaticVoidMethodA", + ApiName = "CallStaticVoidMethod", + Visibility = "public", + Throws = true, + Prototype = "void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticmethodID", "method"), new ParamInfo ("jvalue*", "args", true)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticFieldID", + Visibility = "public", + Throws = true, + Prototype = "jstaticfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*, const char*);", + ReturnType = "jstaticfieldID", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("const char*", "name"), new ParamInfo ("const char*", "signature")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticObjectField", + Visibility = "public", + Prototype = "jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticBooleanField", + Visibility = "public", + Prototype = "jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticByteField", + Visibility = "public", + Prototype = "jbyte (*GetStaticByteField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jbyte", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticCharField", + Visibility = "public", + Prototype = "jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jchar", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticShortField", + Visibility = "public", + Prototype = "jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jshort", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticIntField", + Visibility = "public", + Prototype = "jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticLongField", + Visibility = "public", + Prototype = "jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticFloatField", + Visibility = "public", + Prototype = "jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jfloat", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "GetStaticDoubleField", + Visibility = "public", + Prototype = "jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID);", + ReturnType = "jdouble", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field")}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticObjectField", + Visibility = "public", + Prototype = "void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jobject", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticBooleanField", + Visibility = "public", + Prototype = "void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jboolean", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticByteField", + Visibility = "public", + Prototype = "void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jbyte", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticCharField", + Visibility = "public", + Prototype = "void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jchar", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticShortField", + Visibility = "public", + Prototype = "void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jshort", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticIntField", + Visibility = "public", + Prototype = "void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jint", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticLongField", + Visibility = "public", + Prototype = "void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jlong", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticFloatField", + Visibility = "public", + Prototype = "void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jfloat", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StaticFieldsCategory, + Name = "SetStaticDoubleField", + Visibility = "public", + Prototype = "void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("jstaticfieldID", "field"), new ParamInfo ("jdouble", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "NewString", + // CustomWrapper = true, + Visibility = "public", + Throws = true, + Prototype = "jstring (*NewString)(JNIEnv*, const jchar*, jsize);", + ReturnType = "jstring", + Parameters = new ParamInfo [] {new ParamInfo ("jchar*", "unicodeChars"), new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "GetStringLength", + Visibility = "public", + Prototype = "jsize (*GetStringLength)(JNIEnv*, jstring);", + ReturnType = "jsize", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "GetStringChars", + Visibility = "public", + Prototype = "const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);", + ReturnType = TypeInfo.Create ("const jchar*", "char*"), + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "ReleaseStringChars", + Visibility = "public", + Prototype = "void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo ("jchar*", "chars")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "NewStringUTF", + Visibility = "private", + Throws = true, + Prototype = "jstring (*NewStringUTF)(JNIEnv*, const char*);", + ReturnType = "jstring", + Parameters = new ParamInfo [] {new ParamInfo ("const char*", "bytes")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "GetStringUTFLength", + Visibility = "private", + Prototype = "jsize (*GetStringUTFLength)(JNIEnv*, jstring);", + ReturnType = "jsize", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "GetStringUTFChars", + Visibility = "private", + Prototype = "const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);", + ReturnType = "const char*", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "ReleaseStringUTFChars", + Visibility = "private", + Prototype = "void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo ("const char*", "utf")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetArrayLength", + // CustomWrapper = true, + Visibility = "public", + Prototype = "jsize (*GetArrayLength)(JNIEnv*, jarray);", + ReturnType = "jsize", + Parameters = new ParamInfo [] {new ParamInfo ("jarray", "array")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewObjectArray", + // ApiName = "NewArray", + // CustomWrapper = true, + Visibility = "public", + Throws = true, + Prototype = "jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);", + ReturnType = "jobjectArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length"), new ParamInfo ("jclass", "elementClass"), new ParamInfo ("jobject", "initialElement", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetObjectArrayElement", + Visibility = "public", + Throws = true, + Prototype = "jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("jobjectArray", "array"), new ParamInfo ("jsize", "index")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetObjectArrayElement", + Visibility = "public", + Throws = true, + Prototype = "void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jobjectArray", "array"), new ParamInfo ("jsize", "index"), new ParamInfo ("jobject", "value", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewBooleanArray", + Visibility = "public", + Prototype = "jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);", + ReturnType = "jbooleanArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewByteArray", + Visibility = "public", + Prototype = "jbyteArray (*NewByteArray)(JNIEnv*, jsize);", + ReturnType = "jbyteArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewCharArray", + Visibility = "public", + Prototype = "jcharArray (*NewCharArray)(JNIEnv*, jsize);", + ReturnType = "jcharArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewShortArray", + Visibility = "public", + Prototype = "jshortArray (*NewShortArray)(JNIEnv*, jsize);", + ReturnType = "jshortArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewIntArray", + Visibility = "public", + Prototype = "jintArray (*NewIntArray)(JNIEnv*, jsize);", + ReturnType = "jintArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewLongArray", + Visibility = "public", + Prototype = "jlongArray (*NewLongArray)(JNIEnv*, jsize);", + ReturnType = "jlongArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewFloatArray", + Visibility = "public", + Prototype = "jfloatArray (*NewFloatArray)(JNIEnv*, jsize);", + ReturnType = "jfloatArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "NewDoubleArray", + Visibility = "public", + Prototype = "jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize);", + ReturnType = "jdoubleArray", + Parameters = new ParamInfo [] {new ParamInfo ("jsize", "length")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetBooleanArrayElements", + Visibility = "public", + Prototype = "jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);", + ReturnType = "jboolean*", + Parameters = new ParamInfo [] {new ParamInfo ("jbooleanArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetByteArrayElements", + Visibility = "public", + Prototype = "jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);", + ReturnType = "jbyte*", + Parameters = new ParamInfo [] {new ParamInfo ("jbyteArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetCharArrayElements", + Visibility = "public", + Prototype = "jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);", + ReturnType = "jchar*", + Parameters = new ParamInfo [] {new ParamInfo ("jcharArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetShortArrayElements", + Visibility = "public", + Prototype = "jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);", + ReturnType = "jshort*", + Parameters = new ParamInfo [] {new ParamInfo ("jshortArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetIntArrayElements", + Visibility = "public", + Prototype = "jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);", + ReturnType = "jint*", + Parameters = new ParamInfo [] {new ParamInfo ("jintArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetLongArrayElements", + Visibility = "public", + Prototype = "jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);", + ReturnType = "jlong*", + Parameters = new ParamInfo [] {new ParamInfo ("jlongArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetFloatArrayElements", + Visibility = "public", + Prototype = "jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);", + ReturnType = "jfloat*", + Parameters = new ParamInfo [] {new ParamInfo ("jfloatArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetDoubleArrayElements", + Visibility = "public", + Prototype = "jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);", + ReturnType = "jdouble*", + Parameters = new ParamInfo [] {new ParamInfo ("jdoubleArray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseBooleanArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jbooleanArray", "array"), new ParamInfo ("jboolean*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseByteArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray, jbyte*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jbyteArray", "array"), new ParamInfo ("jbyte*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseCharArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseCharArrayElements)(JNIEnv*, jcharArray, jchar*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jcharArray", "array"), new ParamInfo ("jchar*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseShortArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseShortArrayElements)(JNIEnv*, jshortArray, jshort*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jshortArray", "array"), new ParamInfo ("jshort*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseIntArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseIntArrayElements)(JNIEnv*, jintArray, jint*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jintArray", "array"), new ParamInfo ("jint*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseLongArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseLongArrayElements)(JNIEnv*, jlongArray, jlong*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jlongArray", "array"), new ParamInfo ("jlong*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseFloatArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray, jfloat*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jfloatArray", "array"), new ParamInfo ("jfloat*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleaseDoubleArrayElements", + Visibility = "public", + Prototype = "void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray, jdouble*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jdoubleArray", "array"), new ParamInfo ("jdouble*", "elements"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetBooleanArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray, jsize, jsize, jboolean*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jbooleanArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jboolean*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetByteArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, jbyte*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jbyteArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jbyte*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetCharArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetCharArrayRegion)(JNIEnv*, jcharArray, jsize, jsize, jchar*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jcharArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jchar*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetShortArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetShortArrayRegion)(JNIEnv*, jshortArray, jsize, jsize, jshort*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jshortArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jshort*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetIntArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetIntArrayRegion)(JNIEnv*, jintArray, jsize, jsize, jint*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jintArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jint*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetLongArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetLongArrayRegion)(JNIEnv*, jlongArray, jsize, jsize, jlong*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jlongArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jlong*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetFloatArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetFloatArrayRegion)(JNIEnv*, jfloatArray, jsize, jsize, jfloat*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jlongArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jfloat*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetDoubleArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray, jsize, jsize, jdouble*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jdoubleArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jdouble*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetBooleanArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray, jsize, jsize, const jboolean*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jbooleanArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jboolean*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetByteArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jbyteArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jbyte*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetCharArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetCharArrayRegion)(JNIEnv*, jcharArray, jsize, jsize, const jchar*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jcharArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo (TypeInfo.Create ("const jchar*", "char*"), "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetShortArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetShortArrayRegion)(JNIEnv*, jshortArray, jsize, jsize, const jshort*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jshortArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jshort*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetIntArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetIntArrayRegion)(JNIEnv*, jintArray, jsize, jsize, const jint*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jintArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jint*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetLongArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetLongArrayRegion)(JNIEnv*, jlongArray, jsize, jsize, const jlong*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jlongArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jlong*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetFloatArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetFloatArrayRegion)(JNIEnv*, jfloatArray, jsize, jsize, const jfloat*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jfloatArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jfloat*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "SetDoubleArrayRegion", + Visibility = "public", + Throws = true, + Prototype = "void (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray, jsize, jsize, const jdouble*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jdoubleArray", "array"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jdouble*", "buffer")}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "RegisterNatives", + ApiName = "_RegisterNatives", + Visibility = "internal", + // Prebind = true, + Throws = true, + Prototype = "jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*, jint);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type"), new ParamInfo ("const JNINativeMethod*", "methods"), new ParamInfo ("jint", "numMethods")}, + }, + new JniFunction { + DeclaringType = ClassesCategory, + Name = "UnregisterNatives", + ApiName = "_UnregisterNatives", + Visibility = "internal", + Prototype = "jint (*UnregisterNatives)(JNIEnv*, jclass);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jclass", "type")}, + }, + new JniFunction { + DeclaringType = MonitorOperationsCategory, + Name = "MonitorEnter", + ApiName = "_MonitorEnter", + Visibility = "internal", + Prototype = "jint (*MonitorEnter)(JNIEnv*, jobject);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance")}, + }, + new JniFunction { + DeclaringType = MonitorOperationsCategory, + Name = "MonitorExit", + ApiName = "_MonitorExit", + Visibility = "internal", + Prototype = "jint (*MonitorExit)(JNIEnv*, jobject);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance")}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "GetJavaVM", + ApiName = "_GetJavaVM", + Visibility = "internal", + // Prebind = true, + Prototype = "jint (*GetJavaVM)(JNIEnv*, JavaVM**);", + ReturnType = "jint", + Parameters = new ParamInfo [] {new ParamInfo ("JavaVM**", "vm")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "GetStringRegion", + Visibility = "private", + Prototype = "void (*GetStringRegion)(JNIEnv*, jstring, jsize, jsize, jchar*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("jchar*", "buffer")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "GetStringUTFRegion", + Visibility = "private", + Prototype = "void (*GetStringUTFRegion)(JNIEnv*, jstring, jsize, jsize, char*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo ("jsize", "start"), new ParamInfo ("jsize", "length"), new ParamInfo ("char*", "buffer")}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "GetPrimitiveArrayCritical", + Visibility = "public", + Prototype = "void* (*GetPrimitiveArrayCritical)(JNIEnv*, jarray, jboolean*);", + ReturnType = "void*", + Parameters = new ParamInfo [] {new ParamInfo ("jarray", "array"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ArrayOperationsCategory, + Name = "ReleasePrimitiveArrayCritical", + Visibility = "public", + Prototype = "void (*ReleasePrimitiveArrayCritical)(JNIEnv*, jarray, void*, jint);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jarray", "array"), new ParamInfo ("void*", "carray"), new ParamInfo ("JniReleaseArrayElementsMode", "mode")}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "GetStringCritical", + Visibility = "private", + Prototype = "const jchar* (*GetStringCritical)(JNIEnv*, jstring, jboolean*);", + ReturnType = "const jchar*", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo (TypeInfo.Create ("jboolean*", "bool*"), "isCopy", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = StringOperationsCategory, + Name = "ReleaseStringCritical", + Visibility = "private", + Prototype = "void (*ReleaseStringCritical)(JNIEnv*, jstring, const jchar*);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo ("jstring", "stringInstance"), new ParamInfo ("const jchar*", "carray")}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "NewWeakGlobalRef", + Visibility = "internal", + Prototype = "jweak (*NewWeakGlobalRef)(JNIEnv*, jobject);", + ReturnType = "jweak", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "DeleteWeakGlobalRef", + Visibility = "internal", + Prototype = "void (*DeleteWeakGlobalRef)(JNIEnv*, jweak);", + ReturnType = "void", + Parameters = new ParamInfo [] {new ParamInfo (TypeInfo.Create ("jobject", "IntPtr"), "instance", Modifier.CanBeNull)}, + }, + new JniFunction { + DeclaringType = ExceptionsCategory, + Name = "ExceptionCheck", + Visibility = "public", + Prototype = "jboolean (*ExceptionCheck)(JNIEnv*);", + ReturnType = "jboolean", + Parameters = new ParamInfo [] {}, + }, + new JniFunction { + DeclaringType = NIOSupportCategory, + Name = "NewDirectByteBuffer", + Visibility = "public", + Throws = true, + Prototype = "jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);", + ReturnType = "jobject", + Parameters = new ParamInfo [] {new ParamInfo ("void*", "address"), new ParamInfo ("jlong", "capacity")}, + }, + new JniFunction { + DeclaringType = NIOSupportCategory, + Name = "GetDirectBufferAddress", + Visibility = "public", + Prototype = "void* (*GetDirectBufferAddress)(JNIEnv*, jobject);", + ReturnType = "void*", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "buffer")}, + }, + new JniFunction { + DeclaringType = NIOSupportCategory, + Name = "GetDirectBufferCapacity", + Visibility = "public", + Prototype = "jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject);", + ReturnType = "jlong", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "buffer")}, + }, + new JniFunction { + DeclaringType = ReferencesCatgeory, + Name = "GetObjectRefType", + Visibility = "internal", + Prototype = "jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);", + ReturnType = "jobjectRefType", + Parameters = new ParamInfo [] {new ParamInfo ("jobject", "instance")}, + }, + }; + } +} diff --git a/external/Java.Interop/build-tools/jnienv-gen/jnienv-gen.csproj b/external/Java.Interop/build-tools/jnienv-gen/jnienv-gen.csproj new file mode 100644 index 00000000000..eaa1211466a --- /dev/null +++ b/external/Java.Interop/build-tools/jnienv-gen/jnienv-gen.csproj @@ -0,0 +1,16 @@ + + + + Exe + $(DotNetTargetFramework) + false + + + + + + $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\ + $(BuildToolOutputFullPath) + + + diff --git a/external/Java.Interop/build-tools/scripts/AssemblyInfo.g.cs.in b/external/Java.Interop/build-tools/scripts/AssemblyInfo.g.cs.in new file mode 100644 index 00000000000..6e8832914f5 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/AssemblyInfo.g.cs.in @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Microsoft Corporation")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("@CONFIGURATION@")] +[assembly: System.Reflection.AssemblyCopyrightAttribute("Microsoft Corporation")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("@VERSION@")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("@INFORMATIONALVERSION@")] +[assembly: System.Reflection.AssemblyProductAttribute("@PRODUCT@")] +[assembly: System.Reflection.AssemblyTitleAttribute("@TITLE@")] +[assembly: System.Reflection.AssemblyVersionAttribute("@VERSION@")] + +// Generated by the MSBuild WriteCodeFragment class. \ No newline at end of file diff --git a/external/Java.Interop/build-tools/scripts/NativeToolchain.targets b/external/Java.Interop/build-tools/scripts/NativeToolchain.targets new file mode 100644 index 00000000000..5632946a5c7 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/NativeToolchain.targets @@ -0,0 +1,26 @@ + + + + <_VSInstallDir Condition=" '$(VsInstallRoot)' != '' ">$(VsInstallRoot) + <_VSInstallDir Condition=" '$(_VSInstallDir)' == '' And '$(VsInstallDir)' != '' ">$(VsInstallDir) + <_VcvarsallPath Condition=" '$(_VSInstallDir)' != '' ">$(_VSInstallDir)\VC\Auxiliary\Build\vcvarsall.bat + + + + True + + + + True + + + + + call "$(_VcvarsallPath)" + + + -G "NMake Makefiles" + -G "Unix Makefiles" + + + diff --git a/external/Java.Interop/build-tools/scripts/Prepare.targets b/external/Java.Interop/build-tools/scripts/Prepare.targets new file mode 100644 index 00000000000..4488ec51c5a --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/Prepare.targets @@ -0,0 +1,31 @@ + + + + Debug + + + + + + + + <_MaxJdk>$(MaxJdkVersion) + <_MaxJdk Condition=" '$(_MaxJdk)' == '' ">$(JI_MAX_JDK) + $(JAVA_HOME_17_X64) + $(JAVA_HOME_11_X64) + + + + + + diff --git a/external/Java.Interop/build-tools/scripts/RunCmake.proj b/external/Java.Interop/build-tools/scripts/RunCmake.proj new file mode 100644 index 00000000000..5ea67f6b5c6 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/RunCmake.proj @@ -0,0 +1,73 @@ + + + + + + + + + + + + + <_Prepare>$(PrepareNativeToolchain) + <_Prepare Condition=" '$(_Prepare)' != '' And !$(_Prepare.Trim().EndsWith('&&')) ">$(_Prepare) && + <_SourceDir>$(CmakeSourceDir.Replace('%5c', '/')) + <_BuildDir>$(CmakeBuildDir.Replace('%5c', '/')) + <_ExtraArgs>$(CmakeExtraArgs.Replace('%5c', '/')) + + + + <_CmakeStatus>$(MSBuildLastTaskResult) + + + + + + + + + + + + + + diff --git a/external/Java.Interop/build-tools/scripts/RunNUnitTests.targets b/external/Java.Interop/build-tools/scripts/RunNUnitTests.targets new file mode 100644 index 00000000000..2ece387e038 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/RunNUnitTests.targets @@ -0,0 +1,42 @@ + + + + + Debug + <_TopDir>$(MSBuildThisFileDirectory)..\.. + <_Runtime Condition=" '$(RUNTIME)' != '' ">$(RUNTIME) + <_Runtime Condition=" '$(RUNTIME)' == '' And '$(OS)' != 'Windows_NT' ">mono --debug + <_NUnit>$(_Runtime) $(PkgNUnit_ConsoleRunner)/tools/nunit3-console.exe + <_Run Condition=" '$(RUN)' != '' ">--run="$(RUN)" + + + + + <_TestAssembly Include="$(_TopDir)\bin\Test$(Configuration)\*-*Tests.dll" Condition=" '$(TestAssembly)' == '' " /> + <_TestAssembly Include="$(TestAssembly)" Condition=" '$(TestAssembly)' != '' " /> + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/build-tools/scripts/VersionInfo.targets b/external/Java.Interop/build-tools/scripts/VersionInfo.targets new file mode 100644 index 00000000000..c86a53c5f54 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/VersionInfo.targets @@ -0,0 +1,11 @@ + + + + + + $(Version) git-rev-head:$(JIBuildCommit) git-branch:$(JIBuildBranch) + + + + \ No newline at end of file diff --git a/external/Java.Interop/build-tools/scripts/cecil.projitems b/external/Java.Interop/build-tools/scripts/cecil.projitems new file mode 100644 index 00000000000..9dc9cac2b62 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/cecil.projitems @@ -0,0 +1,12 @@ + + + + <_XamarinAndroidCecilVersion Condition=" '$(_XamarinAndroidCecilVersion)' == '' ">0.11.6 + + + + + + + + diff --git a/external/Java.Interop/build-tools/scripts/mono.mk b/external/Java.Interop/build-tools/scripts/mono.mk new file mode 100644 index 00000000000..06d92795400 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/mono.mk @@ -0,0 +1,40 @@ +# +# Mono Path Probing +# +# Inputs: +# +# $(OS): Optional; **uname**(1) value of the host operating system +# $(CONFIGURATION): Build configuration name, e.g. Debug or Release +# $(V): Output verbosity. If != 0, then `MONO_OPTIONS` is exported with --debug. +# +# Outputs: +# +# bin/Build$(CONFIGURATION)/MonoInfo.props: +# MSBuild property file which contains: +# * `$(MonoFrameworkPath)`: `$(JI_MONO_FRAMEWORK_PATH)` value. +# * `$(MonoLibs)`: `$(JI_MONO_LIBS)` value. +# * `@(MonoIncludePath)`: `$(JI_MONO_INCLUDE_PATHS)` values. +# $(JI_MONO_LIB_PATH): +# Base path to the mono instalation, it can be used to access base class +# assemblies in $(JI_MONO_LIB_PATH)/mono// +# $(JI_MONO_FRAMEWORK_PATH): +# Path to the `libmonosgen-2.0.1.dylib` file to link against. +# $(JI_MONO_INCLUDE_PATHS): +# One or more space separated paths containing Mono headers to pass as +# -Ipath values to the compiler. +# It DOES NOT contain the -I itself; use $(JI_MONO_INCLUDE_PATHS:%=-I%) for that. +# $(JI_MONO_LIBS) +# C compiler linker arguments to link against `$(JI_MONO_FRAMEWORK_PATH)`. +# $(RUNTIME): +# The **mono**(1) program to use to execute managed code. + +OS ?= $(shell uname) +RUNTIME := $(shell if [ -f "`which mono64`" ] ; then echo mono64 ; else echo mono; fi) --debug=casts + +ifneq ($(V),0) +MONO_OPTIONS += --debug +endif # $(V) != 0 + +ifneq ($(MONO_OPTIONS),) +export MONO_OPTIONS +endif # $(MONO_OPTIONS) != '' diff --git a/external/Java.Interop/build-tools/scripts/msbuild.mk b/external/Java.Interop/build-tools/scripts/msbuild.mk new file mode 100644 index 00000000000..5819b01ed98 --- /dev/null +++ b/external/Java.Interop/build-tools/scripts/msbuild.mk @@ -0,0 +1,29 @@ +# +# MSBuild Abstraction. +# +# Makefile targets which need to invoke MSBuild should use `$(MSBUILD)`, +# not some specific MSBuild program such as `xbuild` or `msbuild`. +# +# Typical use will also include `$(MSBUILD_FLAGS)`, which provides the +# Configuration and logging verbosity, as per $(CONFIGURATION) and $(V): +# +# $(MSBUILD) $(MSBUILD_FLAGS) path/to/Project.csproj +# +# Inputs: +# +# $(CONFIGURATION): Build configuration name, e.g. Debug or Release +# $(MSBUILD): The MSBuild program to use. +# $(MSBUILD_ARGS): Extra arguments to pass to $(MSBUILD); embedded into $(MSBUILD_FLAGS) +# $(V): Build verbosity +# +# Outputs: +# +# $(MSBUILD): The MSBuild program to use. Defaults to `xbuild` unless overridden. +# $(MSBUILD_FLAGS): Additional MSBuild flags; contains $(CONFIGURATION), $(V), $(MSBUILD_ARGS). + +MSBUILD = msbuild +MSBUILD_FLAGS = /p:Configuration=$(CONFIGURATION) $(MSBUILD_ARGS) + +ifneq ($(V),0) +MSBUILD_FLAGS += /v:d +endif # $(V) != 0 diff --git a/external/Java.Interop/build-tools/trim-analyzers/trim-analyzers.props b/external/Java.Interop/build-tools/trim-analyzers/trim-analyzers.props new file mode 100644 index 00000000000..a61c10aa797 --- /dev/null +++ b/external/Java.Interop/build-tools/trim-analyzers/trim-analyzers.props @@ -0,0 +1,55 @@ + + + + + true + true + true + + true + + + $(WarningsAsErrors); + IL2000;IL2001;IL2002;IL2003;IL2004; + IL2005;IL2006;IL2007;IL2008;IL2009; + IL2010;IL2011;IL2012;IL2013;IL2014; + IL2015;IL2016;IL2017;IL2018;IL2019; + IL2020;IL2021;IL2022;IL2023;IL2024; + IL2025;IL2026;IL2027;IL2028;IL2029; + IL2030;IL2031;IL2032;IL2033;IL2034; + IL2035;IL2036;IL2037;IL2038;IL2039; + IL2040;IL2041;IL2042;IL2043;IL2044; + IL2045;IL2046;IL2047;IL2048;IL2049; + IL2050;IL2051;IL2052;IL2053;IL2054; + IL2055;IL2056;IL2057;IL2058;IL2059; + IL2060;IL2061;IL2062;IL2063;IL2064; + IL2065;IL2066;IL2067;IL2068;IL2069; + IL2070;IL2071;IL2072;IL2073;IL2074; + IL2075;IL2076;IL2077;IL2078;IL2079; + IL2080;IL2081;IL2082;IL2083;IL2084; + IL2085;IL2086;IL2087;IL2088;IL2089; + IL2090;IL2091;IL2092;IL2093;IL2094; + IL2095;IL2096;IL2097;IL2098;IL2099; + IL2100;IL2101;IL2102;IL2103;IL2104; + IL2105;IL2106;IL2107;IL2108;IL2109; + IL2110;IL2111;IL2112;IL2113;IL2114; + IL2115;IL2116;IL2117;IL2118;IL2119; + IL2120;IL2121;IL2122;IL2123;IL2124; + IL2125;IL2126;IL2127;IL2128;IL2129; + + + true + + + $(WarningsAsErrors); + IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056; + + + \ No newline at end of file diff --git a/external/Java.Interop/external/xamarin-android-tools b/external/Java.Interop/external/xamarin-android-tools new file mode 160000 index 00000000000..bcce35f51c6 --- /dev/null +++ b/external/Java.Interop/external/xamarin-android-tools @@ -0,0 +1 @@ +Subproject commit bcce35f51c67671ca4846fc8ea0dbe140ea9542a diff --git a/external/Java.Interop/external/xamarin-android-tools.override.props b/external/Java.Interop/external/xamarin-android-tools.override.props new file mode 100644 index 00000000000..d80257cce5c --- /dev/null +++ b/external/Java.Interop/external/xamarin-android-tools.override.props @@ -0,0 +1,6 @@ + + + + true + + diff --git a/external/Java.Interop/global.json b/external/Java.Interop/global.json new file mode 100644 index 00000000000..e8f86e8d7c5 --- /dev/null +++ b/external/Java.Interop/global.json @@ -0,0 +1,8 @@ +{ + "sdk": { + "allowPrerelease": true + }, + "msbuild-sdks": { + "Microsoft.Build.NoTargets": "3.7.134" + } +} \ No newline at end of file diff --git a/external/Java.Interop/product.snk b/external/Java.Interop/product.snk new file mode 100644 index 00000000000..8c04e53be9d Binary files /dev/null and b/external/Java.Interop/product.snk differ diff --git a/external/Java.Interop/samples/Hello-NativeAOTFromJNI/App.cs b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/App.cs new file mode 100644 index 00000000000..f7d0307d266 --- /dev/null +++ b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/App.cs @@ -0,0 +1,30 @@ +using System.Runtime.InteropServices; + +using Java.Interop; + +namespace Hello_NativeAOTFromJNI; + +static class App { + + [UnmanagedCallersOnly (EntryPoint="Java_net_dot_jni_hello_App_sayHello")] + static IntPtr sayHello (IntPtr jnienv, IntPtr klass) + { + var envp = new JniTransition (jnienv); + try { + const string message = "Hello from .NET NativeAOT!"; + Console.WriteLine (message); + var h = JniEnvironment.Strings.NewString (message); + var r = JniEnvironment.References.NewReturnToJniRef (h); + JniObjectReference.Dispose (ref h); + return r; + } + catch (Exception e) { + Console.Error.WriteLine ($"Error in App.sayHello(): {e}"); + envp.SetPendingException (e); + } + finally { + envp.Dispose (); + } + return IntPtr.Zero; + } +} diff --git a/external/Java.Interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj new file mode 100644 index 00000000000..a428cc4eb52 --- /dev/null +++ b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj @@ -0,0 +1,63 @@ + + + + $(DotNetTargetFramework) + + + + + + Hello_NativeAOTFromJNI + enable + enable + true + true + Shared + + AnyCPU + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets new file mode 100644 index 00000000000..1a62aef04b8 --- /dev/null +++ b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets @@ -0,0 +1,55 @@ + + + + + + <_Source Include="@(HelloNativeAOTFromJNIJar->Replace('%5c', '/'))" /> + + + + <_JavacOpt Include="$(_JavacSourceOptions)" /> + <_JavacOpt Include="-d "$(IntermediateOutputPath)h-classes" " /> + <_JavacOpt Include="-classpath "$(OutputPath)java-interop.jar" " /> + <_JavacOpt Include=""@$(IntermediateOutputPath)_java_sources.txt"" /> + <_JavacOpt Include="-h "$(IntermediateOutputPath)h-classes" " /> + + + + + + + + + + + + + + + <_Classpath Include="hello-from-java.jar" /> + <_Classpath Include="java-interop.jar" /> + + + <_CPSep Condition=" '$(OS)' == 'Windows_NT' ">; + <_CPSep Condition=" '$(_CPSep)' == '' ">: + <_CP>@(_Classpath, '$(_CPSep)') + + + + + diff --git a/external/Java.Interop/samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.cs b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.cs new file mode 100644 index 00000000000..f34730d76f5 --- /dev/null +++ b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.cs @@ -0,0 +1,174 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.InteropServices; + +using Java.Interop; + +namespace Hello_NativeAOTFromJNI; + +static class JavaInteropRuntime +{ + static JniRuntime? runtime; + + [UnmanagedCallersOnly (EntryPoint="JNI_OnLoad")] + static int JNI_OnLoad (IntPtr vm, IntPtr reserved) + { + return (int) JniVersion.v1_6; + } + + [UnmanagedCallersOnly (EntryPoint="JNI_OnUnload")] + static void JNI_OnUnload (IntPtr vm, IntPtr reserved) + { + runtime?.Dispose (); + runtime = null; + } + + [UnmanagedCallersOnly (EntryPoint="Java_net_dot_jni_hello_JavaInteropRuntime_init")] + static void init (IntPtr jnienv, IntPtr klass) + { + if (runtime != null) + return; + + try { + runtime = new ExistingJniRuntime (jnienv); + } + catch (Exception e) { + Console.Error.WriteLine ($"JavaInteropRuntime.init: error: {e}"); + } + } + + sealed class ExistingJniRuntime : JniRuntime { + + public ExistingJniRuntime (IntPtr jnienv) + : base (new CreationOptions { + EnvironmentPointer = jnienv, + TypeManager = new JniRuntime.JniTypeManager (), + ObjectReferenceManager = new ObjectReferenceManager (), + ValueManager = new ValueManager (), + }) + { + } + + public override string? GetCurrentManagedThreadName () + { + return Thread.CurrentThread.Name; + } + + public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool fNeedFileInfo) + { + return new StackTrace (skipFrames, fNeedFileInfo).ToString (); + } + } + + sealed class ObjectReferenceManager : JniRuntime.JniObjectReferenceManager { + public override int GlobalReferenceCount => 0; + + public override int WeakGlobalReferenceCount => 0; + } + + sealed class ValueManager : JniRuntime.JniValueManager { + public override void WaitForGCBridgeProcessing () + { + } + + public override void CollectPeers () + { + } + + public override void AddPeer (IJavaPeerable value) + { + } + + public override void RemovePeer (IJavaPeerable value) + { + } + + public override void FinalizePeer (IJavaPeerable value) + { + } + + public override List GetSurfacedPeers () + { + return new List (); + } + + public override IJavaPeerable? PeekPeer (JniObjectReference reference) + { + return null; + } + + public override void ActivatePeer ( + JniObjectReference reference, + Type type, + ConstructorInfo cinfo, + object?[]? argumentValues) + { + throw new NotSupportedException (); + } + + protected override void ConstructPeerCore (IJavaPeerable peer, ref JniObjectReference reference, JniObjectReferenceOptions options) + { + throw new NotSupportedException (); + } + + public override IJavaPeerable? CreatePeer ( + ref JniObjectReference reference, + JniObjectReferenceOptions transfer, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type? targetType) + { + throw new NotSupportedException (); + } + + [return: MaybeNull] + protected override T CreateValueCore<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type? targetType = null) + { + throw new NotSupportedException (); + } + + protected override object? CreateValueCore ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type? targetType = null) + { + throw new NotSupportedException (); + } + + [return: MaybeNull] + protected override T GetValueCore<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type? targetType = null) + { + throw new NotSupportedException (); + } + + protected override object? GetValueCore ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type? targetType = null) + { + throw new NotSupportedException (); + } + + protected override JniValueMarshaler GetValueMarshalerCore (Type type) + { + throw new NotSupportedException (); + } + + protected override JniValueMarshaler GetValueMarshalerCore () + { + throw new NotSupportedException (); + } + + protected override JniObjectReference CreateLocalObjectReferenceArgumentCore ( + Type type, + object? value) + { + throw new NotSupportedException (); + } + } +} diff --git a/external/Java.Interop/samples/Hello-NativeAOTFromJNI/java/net/dot/jni/hello/App.java b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/java/net/dot/jni/hello/App.java new file mode 100644 index 00000000000..9b6aef7a00c --- /dev/null +++ b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/java/net/dot/jni/hello/App.java @@ -0,0 +1,13 @@ +package net.dot.jni.hello; + +class App { + + public static void main(String[] args) { + System.out.println("Hello from Java!"); + JavaInteropRuntime.init(); + String s = sayHello(); + System.out.println("String returned to Java: " + s); + } + + static native String sayHello(); +} diff --git a/external/Java.Interop/samples/Hello-NativeAOTFromJNI/java/net/dot/jni/hello/JavaInteropRuntime.java b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/java/net/dot/jni/hello/JavaInteropRuntime.java new file mode 100644 index 00000000000..aa7f1b0d703 --- /dev/null +++ b/external/Java.Interop/samples/Hello-NativeAOTFromJNI/java/net/dot/jni/hello/JavaInteropRuntime.java @@ -0,0 +1,12 @@ +package net.dot.jni.hello; + +public class JavaInteropRuntime { + static { + System.loadLibrary("Hello-NativeAOTFromJNI"); + } + + private JavaInteropRuntime() { + } + + public static native void init(); +} diff --git a/external/Java.Interop/src/Java.Interop.Localization/Java.Interop.Localization.csproj b/external/Java.Interop/src/Java.Interop.Localization/Java.Interop.Localization.csproj new file mode 100644 index 00000000000..c9c30921cfe --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Java.Interop.Localization.csproj @@ -0,0 +1,32 @@ + + + + netstandard2.0 + enable + en + true + ..\..\product.snk + + + + + + + True + True + Resources.resx + + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.Designer.cs b/external/Java.Interop/src/Java.Interop.Localization/Resources.Designer.cs new file mode 100644 index 00000000000..12164c404f9 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.Designer.cs @@ -0,0 +1,630 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Java.Interop.Localization { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Java.Interop.Localization.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Error while loading assembly: '{0}'.. + /// + public static string CecilResolver_XA0009 { + get { + return ResourceManager.GetString("CecilResolver_XA0009", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to remove old constants: {0}.. + /// + public static string Generator_BG4000 { + get { + return ResourceManager.GetString("Generator_BG4000", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to process enum mapping. Text line: {0}.. + /// + public static string Generator_BG4100 { + get { + return ResourceManager.GetString("Generator_BG4100", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error during processing metadata fixup: {0}.. + /// + public static string Generator_BG4200 { + get { + return ResourceManager.GetString("Generator_BG4200", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid XPath specification: {0}.. + /// + public static string Generator_BG4300 { + get { + return ResourceManager.GetString("Generator_BG4300", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Target attribute name is not specified for path: {0}.. + /// + public static string Generator_BG4307 { + get { + return ResourceManager.GetString("Generator_BG4307", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected 'global::' specification. This error happens if 'global::' is specified in the Metadata.xml transform file, for example.. + /// + public static string Generator_BG4400 { + get { + return ResourceManager.GetString("Generator_BG4400", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected class child {0}.. + /// + public static string Generator_BG8101 { + get { + return ResourceManager.GetString("Generator_BG8101", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class '{0}' has unknown base type '{1}'.. + /// + public static string Generator_BG8102 { + get { + return ResourceManager.GetString("Generator_BG8102", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class '{0}' has invalid base type '{1}'.. + /// + public static string Generator_BG8103 { + get { + return ResourceManager.GetString("Generator_BG8103", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to parse assembly '{0}': {1}.. + /// + public static string Generator_BG8200 { + get { + return ResourceManager.GetString("Generator_BG8200", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to For constructor '{0}', could not find enclosing type '{1}'.. + /// + public static string Generator_BG8300 { + get { + return ResourceManager.GetString("Generator_BG8300", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected field type `{0}` ({1}).. + /// + public static string Generator_BG8400 { + get { + return ResourceManager.GetString("Generator_BG8400", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skipping '{0}.{1}' due to a duplicate method name. (Java type: '{2}'). + /// + public static string Generator_BG8401_Method { + get { + return ResourceManager.GetString("Generator_BG8401_Method", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skipping '{0}.{1}' due to a duplicate nested type name. (Java type: '{2}'). + /// + public static string Generator_BG8401_NestedType { + get { + return ResourceManager.GetString("Generator_BG8401_NestedType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skipping '{0}.{1}' due to a duplicate field or property name. (Java type: '{2}'). + /// + public static string Generator_BG8401_Property { + get { + return ResourceManager.GetString("Generator_BG8401_Property", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skipping '{0}.{1}' due to a duplicate field. (Java type: '{2}'). + /// + public static string Generator_BG8402 { + get { + return ResourceManager.GetString("Generator_BG8402", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' has a type name which matches the enclosing namespace name. See https://aka.ms/BG8403 for more information.. + /// + public static string Generator_BG8403 { + get { + return ResourceManager.GetString("Generator_BG8403", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected child element of '<interface>': '{0}'.. + /// + public static string Generator_BG8500 { + get { + return ResourceManager.GetString("Generator_BG8500", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No event name provided in '{0}.{1}'.. + /// + public static string Generator_BG8501 { + get { + return ResourceManager.GetString("Generator_BG8501", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalidating '{0}' and all its nested types because some of its interfaces were invalid.. + /// + public static string Generator_BG8502 { + get { + return ResourceManager.GetString("Generator_BG8502", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalidating '{0}' and all its nested types because some of its methods were invalid.. + /// + public static string Generator_BG8503 { + get { + return ResourceManager.GetString("Generator_BG8503", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Event name for '{0}.{1}' is invalid. A valid 'eventName' or 'argsType' can be assigned by adding a rule to the Metadata.xml transforms file.. + /// + public static string Generator_BG8504 { + get { + return ResourceManager.GetString("Generator_BG8504", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Event property name for '{0}.{1}' is invalid. A valid 'eventName' or 'argsType' can be assigned by adding a rule to the Metadata.xml transforms file.. + /// + public static string Generator_BG8506 { + get { + return ResourceManager.GetString("Generator_BG8506", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid XML file '{0}': {1}.. + /// + public static string Generator_BG8600 { + get { + return ResourceManager.GetString("Generator_BG8600", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No '<package>' elements found.. + /// + public static string Generator_BG8601 { + get { + return ResourceManager.GetString("Generator_BG8601", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected root child node: '<{0}>'.. + /// + public static string Generator_BG8602 { + get { + return ResourceManager.GetString("Generator_BG8602", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected '<package>' child node: '<{0}>'.. + /// + public static string Generator_BG8603 { + get { + return ResourceManager.GetString("Generator_BG8603", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not find top ancestor type '{0}' for nested type '{1}'.. + /// + public static string Generator_BG8604 { + get { + return ResourceManager.GetString("Generator_BG8604", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?). + /// + public static string Generator_BG8605 { + get { + return ResourceManager.GetString("Generator_BG8605", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details.. + /// + public static string Generator_BG8606 { + get { + return ResourceManager.GetString("Generator_BG8606", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown return type '{0}' for member '{1}'.. + /// + public static string Generator_BG8700 { + get { + return ResourceManager.GetString("Generator_BG8700", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid return type '{0}' for member '{1}'.. + /// + public static string Generator_BG8701 { + get { + return ResourceManager.GetString("Generator_BG8701", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown parameter type '{0}' for member '{1}'.. + /// + public static string Generator_BG8800 { + get { + return ResourceManager.GetString("Generator_BG8800", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid parameter type '{0}' for member '{1}'.. + /// + public static string Generator_BG8801 { + get { + return ResourceManager.GetString("Generator_BG8801", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata.xml element '{0}' matched no nodes.. + /// + public static string Generator_BG8A00 { + get { + return ResourceManager.GetString("Generator_BG8A00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid namespace transform '{0}'. + /// + public static string Generator_BG8A07 { + get { + return ResourceManager.GetString("Generator_BG8A07", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata.xml element '{0}' is missing the 'path' attribute.. + /// + public static string Generator_BG8A08 { + get { + return ResourceManager.GetString("Generator_BG8A08", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown generic argument constraint type '{0}' for member '{1}'.. + /// + public static string Generator_BG8B00 { + get { + return ResourceManager.GetString("Generator_BG8B00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not find base interface '{1}' for type '{0}'.. + /// + public static string Generator_BG8C00 { + get { + return ResourceManager.GetString("Generator_BG8C00", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to For type '{0}', base interface '{1}' is invalid.. + /// + public static string Generator_BG8C01 { + get { + return ResourceManager.GetString("Generator_BG8C01", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to For type '{0}', the Kotlin name-mangled method '{1}' (originally '{2}') has multiple hash-suffixed siblings that erase to the same C# signature. Only the first will be emitted; remove the duplicate via Metadata.xml to suppress this warning.. + /// + public static string Generator_BG8C02 { + get { + return ResourceManager.GetString("Generator_BG8C02", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot generate Java wrapper for type '{0}'. Only 'class' types are supported.. + /// + public static string JavaCallableWrappers_XA4200 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4200", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot determine JNI name for type '{0}'.. + /// + public static string JavaCallableWrappers_XA4201 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4201", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The 'Name' property must be a fully qualified type like 'com.example.MyClass' and no package was found for '{0}'.. + /// + public static string JavaCallableWrappers_XA4203 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4203", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to resolve interface type '{0}'. Are you missing an assembly reference?. + /// + public static string JavaCallableWrappers_XA4204 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4204", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [ExportField] can only be used on methods with 0 parameters.. + /// + public static string JavaCallableWrappers_XA4205 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4205", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [Export] cannot be used on a generic type.. + /// + public static string JavaCallableWrappers_XA4206 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4206", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [ExportField] cannot be used on a generic type.. + /// + public static string JavaCallableWrappers_XA4207 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4207", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [ExportField] cannot be used on a method returning 'void'.. + /// + public static string JavaCallableWrappers_XA4208 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4208", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot override Kotlin-generated method '{0}' because it is not a valid Java method name. This method can only be overridden from Kotlin.. + /// + public static string JavaCallableWrappers_XA4217 { + get { + return ResourceManager.GetString("JavaCallableWrappers_XA4217", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to preload reference '{0}'.. + /// + public static string JniMarshalMethodGen_JM4001 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM4001", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please specify at least one ASSEMBLY to process.. + /// + public static string JniMarshalMethodGen_JM4002 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM4002", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to create Java VM{0}{1}. + /// + public static string JniMarshalMethodGen_JM4003 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM4003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read profile file '{0}'.{1}{2}. + /// + public static string JniMarshalMethodGen_JM4004 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM4004", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path '{0}' does not exist.. + /// + public static string JniMarshalMethodGen_JM4005 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM4005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to process assembly '{0}'{1}{2}{1}{3}. + /// + public static string JniMarshalMethodGen_JM4006 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM4006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Couln't find interface {0}. + /// + public static string JniMarshalMethodGen_JM8001 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM8001", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Caught an exception while loading types. The types that cannot be loaded will not be processed. Make sure that any additional assembly references required for those types are provided using the -r option. Exception:{0}{1}. + /// + public static string JniMarshalMethodGen_JM8003 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM8003", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to find type '{0}'. The type will not be processed. Make sure the directories for all referenced assemblies are provided with the -L option.. + /// + public static string JniMarshalMethodGen_JM8004 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM8004", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Marshal methods type '{0}' already exists. Skipped generation of marshal methods in assembly '{1}'. Use -f to force regeneration when desired.. + /// + public static string JniMarshalMethodGen_JM8005 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM8005", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to find definition of method '{0}' in assembly metadata. It will not be processed. Make sure the directories for all referenced assemblies are provided with the -L option.. + /// + public static string JniMarshalMethodGen_JM8006 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM8006", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to find the System.Console.WriteLine() method. Disabling debug injection. To enable debug injection, ensure the directory containing mscorlib is provided with the -L option.. + /// + public static string JniMarshalMethodGen_JM8007 { + get { + return ResourceManager.GetString("JniMarshalMethodGen_JM8007", resourceCulture); + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.cs.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.cs.resx new file mode 100644 index 00000000000..add2298cef4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.cs.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Chyba při načítání sestavení:{0} + {0} - File name + + + Nepodařilo se odebrat staré konstanty: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Zpracování mapování výčtu se nezdařilo. Textový řádek: {0}. + {0} - The line that could not be processed. + + + Chyba při zpracování opravy metadat: {0} + {0} - The error encountered. + + + Neplatná specifikace XPath: {0} + {0} - The invalid XPath line. + + + Pro cestu {0} není zadán název cílového atributu: {0}. + {0} - The invalid XPath line. + + + Neočekávaná specifikace global::. K této chybě dochází například v případě, že je v transformačním souboru Metadata.xml zadána hodnota global::. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Neočekávaný podřízený {0} třídy. + {0} - The unexpected child class. + + + Třída {0} má neznámý základní typ {1}. + {0}, {1} - .NET types. + + + Třída {0} má neplatný základní typ {1}. + {0}, {1} - .NET types. + + + Nepovedlo se parsovat sestavení {0} : {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + Pro konstruktor{0} nebylo možné najít nadřazený typ {1}. + {0} - .NET constructor method. +{1} - .NET type. + + + Neočekávaný typ pole {0}({1}). + {0} - .NET type. +{1} - .NET field signature. + + + Přeskakuje se {0}.{1} z důvodu duplicitního názvu metody. (Typ Javy:{2}) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Přeskakuje se {0}.{1} z důvodu duplicitního názvu vnořeného typu. (Typ Javy:{2}) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Přeskakuje se {0}.{1} z důvodu duplicitního názvu pole nebo vlastnosti. (Typ Javy:{2}) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Přeskakuje se {0}.{1} kvůli duplicitnímu poli. (Typ Javy:{2}) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Typ {0} má název typu, který odpovídá názvu nadřazeného oboru názvů. Další informace najdete v https://aka.ms/BG8403. + {0} - Java type. + + + Neočekávaný podřízený element <interface>: {0} + {0} - XML element name. +<interface> should not be translated. + + + Není zadaný žádný název události v {0}.{1}. + {0} - .NET type name +{1} - .NET member. + + + Probíhá zneplatnění {0} a všech jeho vnořených typů, protože některá z jeho rozhraní byla neplatná. + {0} - .NET type name. + + + Probíhá zneplatnění {0} a všech jeho vnořených typů, protože některé z jeho metod byly neplatné. + {0} - .NET type name. + + + Název události pro {0}.{1} je neplatný. Platnou hodnotu eventName nebo argsType lze přiřadit přidáním pravidla do souboru transformací Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Název vlastnosti události pro {0}.{1} je neplatný. Platnou hodnotu eventName nebo argsType lze přiřadit přidáním pravidla do souboru transformací Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Neplatný soubor XML{0}: {1}. + {0} - File name +{1} - The error encountered. + + + Nebyly nalezeny žádné elementy <package>. + The following terms should not be translated: <package>. + + + Neočekávaný kořenový podřízený uzel: <{0}>. + {0} - XML element name. + + + Neočekávaný podřízený uzel <package>: <{0}> + {0} - XML element name. +The following terms should not be translated: <package>. + + + Nelze najít horní nadřazený typ {0} pro vnořený typ {1}. + {0}, {1} - .NET types. + + + Typ Javy{0}se nepovedlo najít (nechybí NuGet java reference jar/aar nebo java binding library?) + {0} - Java type. + + + Některé typy nebo členy nelze vázat, protože odkazované typy Java nebyly nalezeny. Podrobnosti najdete v souboru java-resolution-report.log. + The following terms should not be translated: java-resolution-report.log + + + Neznámý návratový typ {0} pro člena {1}. + {0} - Java type. +{1} - .NET member. + + + Neplatný návratový typ {0} pro člena {1}. + {0} - Java type. +{1} - .NET member. + + + Neznámý typ parametru {0} pro člena {1}. + {0} - Java type. +{1} - .NET member. + + + Neplatný typ parametru {0} pro člen {1}. + {0} - Java type. +{1} - .NET member. + + + Element Metadata.xml {0} neodpovídá žádným uzlům. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Neplatná transformace oboru názvů {0} + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + V elementu {0} souboru Metadata.xml chybí atribut path. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Neznámý typ omezení obecného argumentu {0} pro člena {1}. + {0} - .NET type name +{1} - .NET member. + + + Nelze najít základní rozhraní {1} pro typ {0}. + {0}, {1} - .NET types. + + + Pro typ {0} je základní rozhraní {1} neplatné. + {0}, {1} - .NET types. + + + Pro typ{0} nelze vygenerovat obálku Javy. Jsou podporovány pouze typy class. + {0} - Java type. +The following terms should not be translated: +class. + + + Nelze určit název JNI pro typ {0}. + {0} - Java type. +The following terms should not be translated: JNI. + + + Vlastnost Name musí být plně kvalifikovaný typ, například com.example.MyClass, a pro {0}nebyl nalezen žádný balíček. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Nelze přeložit typ rozhraní {0}. Nechybí vám odkaz na sestavení? + {0} - Java interface. + + + [ExportField] lze použít pouze u metod s 0 parametry. + The following terms should not be translated: [ExportField]. + + + [Export] nelze použít u obecného typu. + The following terms should not be translated: [Export]. + + + [ExportField] nelze použít u obecného typu. + The following terms should not be translated: [ExportField]. + + + [ExportField] se nedá použít u metody, která vrací void. + The following terms should not be translated: [ExportField], void. + + + Metodu '{0}' vygenerovanou metodou Kotlin nelze přepsat, protože se nejedná o platný název metody Java. Tuto metodu lze přepsat pouze přes Kotlin. + {0} - Kotlin method name. + + + Odkaz {0} nelze předem načíst {0}. + {0} - assembly path + + + Zadejte alespoň jedno SESTAVENÍ, které se má zpracovat. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Nepovedlo se vytvořit{0}{1}virtuálního počítače Java + {0} - newline, {1} - exception + + + Nelze přečíst soubor profilu {0}.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Cesta {0} neexistuje. + {0} - path + + + Sestavení{0}{1}{2}{1}{3} nelze zpracovat. + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Nepovedlo se najít rozhraní {0}.- + {0} - interface name + + + Při načítání typů byla zachycena výjimka. Typy, které nelze načíst, nebudou zpracovány. Ujistěte se, že všechny další odkazy na sestavení vyžadované pro tyto typy jsou k dispozici pomocí možnosti -r. Výjimka:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Nelze najít typ {0}. Typ nebude zpracován. Ujistěte se, že adresáře pro všechna odkazovaná sestavení jsou k dispozici s parametrem -L. + {0} - type +The following terms should not be translated: -L + + + Typ metody zařazování{0}již existuje. Bylo přeskočeno generování zařazování metod v sestavení{1}. Pokud chcete vynutit opakované generování, použijte -f.použití. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Nelze najít definici metody {0} v metadatech sestavení. Nebude zpracována. Ujistěte se, že adresáře pro všechna odkazovaná sestavení jsou k dispozici s parametrem -L. + {0} - method +The following terms should not be translated: -L + + + Nelze najít metodu System.Console.WriteLine(). Zakazuje se injektáž ladění. Pokud chcete povolit injektáž ladění, ujistěte se, že adresář obsahující knihovnu mscorlib je k dispozici s parametrem -L. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.de.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.de.resx new file mode 100644 index 00000000000..66123814c59 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.de.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Fehler beim Laden der Assembly: „{0}“. + {0} - File name + + + Fehler beim Entfernen alter Konstanten: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Fehler beim Verarbeiten der Enumerationszuordnung. Textzeile: {0}. + {0} - The line that could not be processed. + + + Fehler beim Verarbeiten der Metadatenkorrektur: {0}. + {0} - The error encountered. + + + Ungültige XPath-Spezifikation: {0}. + {0} - The invalid XPath line. + + + Für den Pfad wurde kein Zielattributname angegeben: {0}. + {0} - The invalid XPath line. + + + Unerwartete global::-Spezifikation. Dieser Fehler tritt auf, wenn z. B. "global::" in der Metadata.xml Transformationsdatei angegeben ist. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Unerwartetes untergeordnetes Klassenelement {0}. + {0} - The unexpected child class. + + + Die Klasse '{0}' hat einen unbekannten Basistyp '{1}'. + {0}, {1} - .NET types. + + + Die Klasse '{0}' weist einen ungültigen Basistyp '{1}' auf. + {0}, {1} - .NET types. + + + Fehler beim Analysieren der assembly-'{0}': {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + Für den Konstruktor '{0}' konnte der einschließende Typ '{1}' nicht gefunden werden. + {0} - .NET constructor method. +{1} - .NET type. + + + Unerwarteter Feldtyp "{0}" ({1}). + {0} - .NET type. +{1} - .NET field signature. + + + "{0}.{1}" wird aufgrund eines doppelten Methodennamens übersprungen. (Java-Typ: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + "{0}.{1}" wird aufgrund eines doppelten geschachtelten Typnamens übersprungen. (Java-Typ: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + "{0}.{1}" wird aufgrund eines doppelten Feld- oder Eigenschaftsnamens übersprungen. (Java-Typ: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + "{0}.{1}" wird aufgrund eines doppelten Felds übersprungen. (Java-Typ: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Der Typ '{0}' hat einen Typnamen, der mit dem einschließenden Namespacenamen übereinstimmt. Weitere Informationen finden Sie unter https://aka.ms/BG8403. + {0} - Java type. + + + Unerwartetes untergeordnetes Element von '<interface>': '{0}'. + {0} - XML element name. +<interface> should not be translated. + + + In "{0}.{1}" wurde kein Ereignisname angegeben. + {0} - .NET type name +{1} - .NET member. + + + '{0}' und alle geschachtelten Typen werden ungültig, da einige ihrer Schnittstellen ungültig waren. + {0} - .NET type name. + + + '{0}' und alle geschachtelten Typen werden ungültig, da einige ihrer Methoden ungültig waren. + {0} - .NET type name. + + + Der Ereignisname für "{0}.{1}" ist ungültig. Ein gültiger eventName- oder argsType-Wert kann zugewiesen werden, indem der Metadata.xml Transformationsdatei eine Regel hinzugefügt wird. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Der Ereigniseigenschaftsname für "{0}.{1}" ist ungültig. Ein gültiger eventName- oder argsType-Wert kann zugewiesen werden, indem der Metadata.xml Transformationsdatei eine Regel hinzugefügt wird. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Ungültige XML-Datei „{0}“: {1}. + {0} - File name +{1} - The error encountered. + + + Es wurden keine '<package>' Elemente gefunden. + The following terms should not be translated: <package>. + + + Unerwarteter untergeordneter Stammknoten: "<{0}>". + {0} - XML element name. + + + Unerwarteter '<package>' untergeordneter Knoten: "<{0}>". + {0} - XML element name. +The following terms should not be translated: <package>. + + + Der oberste Vorgängertyp '{0}' für geschachtelten Typ '{1}' wurde nicht gefunden. + {0}, {1} - .NET types. + + + Der Java-Typ '{0}' wurde nicht gefunden . (Fehlt ein Java-Verweis-JAR/AAR oder eine Java-Bindungsbibliothek, NuGet?). + {0} - Java type. + + + Einige Typen oder Member konnten nicht gebunden werden, da die referenzierten Javatypen nicht gefunden wurden. Weitere Informationen finden Sie in der Datei "java-resolution-report.log". + The following terms should not be translated: java-resolution-report.log + + + Unbekannter Rückgabetyp '{0}' für Mitglied '{1}'. + {0} - Java type. +{1} - .NET member. + + + Ungültiger Rückgabetyp '{0}' für Mitglied '{1}'. + {0} - Java type. +{1} - .NET member. + + + Unbekannter Parametertyp '{0}' für Mitglied '{1}'. + {0} - Java type. +{1} - .NET member. + + + Ungültiger Parametertyp '{0}' für Mitglied '{1}'. + {0} - Java type. +{1} - .NET member. + + + Metadata.xml Element '{0}' mit keinem Knoten übereinstimmen. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Ungültige Namespacetransformation '{0}' + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Für das Metadata.xml-Element '{0}' fehlt das Path-Attribut. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Unbekannter generischer Argumenteinschränkungstyp '{0}' für Mitglied'{1}'. + {0} - .NET type name +{1} - .NET member. + + + Die Basisschnittstelle '{1}' für den Typ '{0}' wurde nicht gefunden. + {0}, {1} - .NET types. + + + Für den Typ '{0}' ist die Basisschnittstelle '{1}' ungültig. + {0}, {1} - .NET types. + + + Für den Typ '{0}' kann kein Java Wrapper generiert werden. Es werden nur class-Typen unterstützt. + {0} - Java type. +The following terms should not be translated: +class. + + + Der JNI-Name für den Typ '{0}' kann nicht bestimmt werden. + {0} - Java type. +The following terms should not be translated: JNI. + + + Die Eigenschaft "Name" muss ein vollqualifizierter Typ wie "com.example.MyClass" sein, und es wurde kein Paket für '{0}' gefunden. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Der Schnittstellentyp '{0}' kann nicht aufgelöst werden. Fehlt ein Assemblyverweis? + {0} - Java interface. + + + [ExportField] kann nur für Methoden mit 0 Parametern verwendet werden. + The following terms should not be translated: [ExportField]. + + + [Export] kann nicht für einen generischen Typ verwendet werden. + The following terms should not be translated: [Export]. + + + [ExportField] kann nicht für einen generischen Typ verwendet werden. + The following terms should not be translated: [ExportField]. + + + [ExportField] kann nicht für eine Methode verwendet werden, die "void" zurückgibt. + The following terms should not be translated: [ExportField], void. + + + Die von Kotlin generierte Methode '{0}' kann nicht überschrieben werden, da es sich nicht um einen gültigen Java-Methodennamen handelt. Diese Methode kann nur von Kotlin überschrieben werden. + {0} - Kotlin method name. + + + Verweis '{0}' kann nicht vorab geladen werden. + {0} - assembly path + + + Geben Sie mindestens eine ASSEMBLY an, die verarbeitet werden soll. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Java-VM {0}{1} kann nicht erstellt werden. + {0} - newline, {1} - exception + + + Profildatei „{0}“ kann nicht gelesen werden.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Der Pfad „{0}“ ist nicht vorhanden. + {0} - path + + + Die Assembly '{0}'{1}{2}{1}{3} kann nicht verarbeitet werden. + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Schnittstelle {0} nicht gefunden + {0} - interface name + + + Ausnahme beim Laden von Typen. Die Typen, die nicht geladen werden können, werden nicht verarbeitet. Stellen Sie sicher, dass alle zusätzlichen Assemblyverweise, die für diese Typen erforderlich sind, mithilfe der Option "-r" bereitgestellt werden. Ausnahme:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Typ '{0}' wurde nicht gefunden. Es wird nicht verarbeitet. Stellen Sie sicher, dass die Verzeichnisse für alle Assemblys, auf die verwiesen wird, mit der Option -L bereitgestellt werden. + {0} - type +The following terms should not be translated: -L + + + Der Marshallmethodentyp '{0}' bereits vorhanden. Das Generieren von Marshallmethoden in assembly-'{1}' wurde übersprungen. Verwenden Sie -f, um bei Bedarf eine Neuerstellung zu erzwingen. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Die Definition der Methode '{0}' wurde in den Assemblymetadaten nicht gefunden. Es wird nicht verarbeitet. Stellen Sie sicher, dass die Verzeichnisse für alle Assemblys, auf die verwiesen wird, mit der Option -L bereitgestellt werden. + {0} - method +The following terms should not be translated: -L + + + Die System.Console.WriteLine()-Methode wurde nicht gefunden. Debuginjektion wird deaktiviert. Um die Debuginjektion zu aktivieren, stellen Sie sicher, dass das Verzeichnis, das mscorlib enthält, mit der Option -L bereitgestellt wird. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.es.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.es.resx new file mode 100644 index 00000000000..a56e506f882 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.es.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Error al cargar el ensamblaje: "{0}". + {0} - File name + + + Ha ocurrido un error al eliminar las constantes antiguas: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Ha ocurrido un error al procesar el mapeo del enum. Línea de texto: {0}. + {0} - The line that could not be processed. + + + Ha ocurrido un error durante el procesamiento de la corrección de metadatos: {0}. + {0} - The error encountered. + + + Especificación XPath no válida: {0}. + {0} - The invalid XPath line. + + + No se ha especificado el nombre del atributo de destino para la ruta: {0}. + {0} - The invalid XPath line. + + + Especificación inesperada de 'global::'. Este error se produce si se especifica 'global::' en el archivo de transformación Metadata.xml, por ejemplo. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Clase secundaria inesperada {0}. + {0} - The unexpected child class. + + + La clase "{0}" tiene una base desconocido de tipo "{1}". + {0}, {1} - .NET types. + + + La clase "{0}" tiene una base inválida tipo "{1}". + {0}, {1} - .NET types. + + + Ha ocurrido un error al analizar el ensamblaje "{0}": {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + Para el constructor "{0}", no se ha podido encontrar el tipo envolvente "{1}". + {0} - .NET constructor method. +{1} - .NET type. + + + Tipo de campo inesperado "{0}" ({1}). + {0} - .NET type. +{1} - .NET field signature. + + + Se ha omitido "{0}.{1}" debido a un nombre de método duplicado. (Java tipo: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + El "{0}.{1}" ha sido omitido debido a un nombre de tipo anidado duplicado. (tipo Java: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Se ha omitido "{0}.{1}" debido a un campo o nombre de propiedad duplicado. (tipo Java: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Se ha omitido "{0}.{1}" debido a un campo duplicado. (tipo Java: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + El tipo "{0}" tiene un nombre de tipo que coincide con el nombre del espacio de nombres que lo rodea. Consulte https://aka.ms/BG8403 para obtener más información. + {0} - Java type. + + + Elemento secundario inesperado de '<interface>': "{0}". + {0} - XML element name. +<interface> should not be translated. + + + No se ha proporcionado ningún nombre de evento en "{0}.{1}". + {0} - .NET type name +{1} - .NET member. + + + Invalidando "{0}" y todos sus tipos anidados porque algunas de sus interfaces no eran válidas. + {0} - .NET type name. + + + Invalidando "{0}" y todos sus tipos anidados porque algunos de sus métodos no eran válidos. + {0} - .NET type name. + + + El nombre del evento para "{0}.{1}" no es válido. Se puede asignar un 'eventName' o 'argsType' válido agregando una regla al archivo de transformaciones Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + El nombre de la propiedad del evento para "{0}.{1}" no es válido. Se puede asignar un 'eventName' o 'argsType' válido agregando una regla al archivo de transformaciones Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Archivo XML no válido "{0}": {1}. + {0} - File name +{1} - The error encountered. + + + No se han encontrado los elementos '<package>'. + The following terms should not be translated: <package>. + + + Raíz de nodo secundario inesperado: "<{0}>". + {0} - XML element name. + + + Nodo secundario inesperado de "<package>": "<{0}>". + {0} - XML element name. +The following terms should not be translated: <package>. + + + No se ha podido encontrar el tipo antecesor superior "{0}" para el tipo anidado "{1}". + {0}, {1} - .NET types. + + + No se ha podido encontrar el tipo de Java "{0}" (¿le falta un jar/aar de referencia de Java o una biblioteca de enlace de Java NuGet?) + {0} - Java type. + + + Algunos tipos o miembros no han podido ser vinculados debido a que no se han podido encontrar los tipos Java referenciados. Consulte el archivo "java-resolution-report.log" para más detalles. + The following terms should not be translated: java-resolution-report.log + + + Retorno desconocido tipo "{0}" para el miembro "{1}". + {0} - Java type. +{1} - .NET member. + + + Retorno inválido tipo "{0}" para el miembro "{1}". + {0} - Java type. +{1} - .NET member. + + + Parámetro desconocido tipo "{0}" para el miembro "{1}". + {0} - Java type. +{1} - .NET member. + + + Parámetro inválido tipo "{0}" para el miembro "{1}". + {0} - Java type. +{1} - .NET member. + + + El elemento Metadata.xml "{0}" no tiene nodos. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Transformación de espacio de nombres inválida "{0}" + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Falta el atributo 'path' en el elemento Metadata.xml '{0}'. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Tipo de restricción genérica desconocida "{0}" para el miembro "{1}". + {0} - .NET type name +{1} - .NET member. + + + No se ha podido encontrar la interfaz base "{1}" para el tipo "{0}". + {0}, {1} - .NET types. + + + Para el tipo "{0}", la interfaz base "{1}" no es válida. + {0}, {1} - .NET types. + + + No se puede generar el contenedor de Java para el tipo '{0}'. Solo se admiten tipos "class". + {0} - Java type. +The following terms should not be translated: +class. + + + No se puede determinar el nombre JNI para el tipo "{0}". + {0} - Java type. +The following terms should not be translated: JNI. + + + La propiedad "Name" debe ser un tipo completamente calificado como "com.example.MyClass" y no se encontró ningún paquete para "{0}". + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + No se puede resolver el tipo de interfaz "{0}". ¿Le falta una referencia de ensamblaje? + {0} - Java interface. + + + [ExportField] solo puede utilizarse en métodos con 0 parámetros. + The following terms should not be translated: [ExportField]. + + + No se puede utilizar [Exportar] en un tipo genérico. + The following terms should not be translated: [Export]. + + + No se puede utilizar [ExportField] en un tipo genérico. + The following terms should not be translated: [ExportField]. + + + No se puede utilizar [ExportField] en un método que devuelve "void". + The following terms should not be translated: [ExportField], void. + + + El método generado por Kotlin "{0}" no puede ser anulado debido a que no es un nombre de método Java válido. Este método sólo puede ser anulado desde Kotlin. + {0} - Kotlin method name. + + + No se ha podido precargar la referencia "{0}". + {0} - assembly path + + + Especifique al menos un ENSAMBLADO a procesar. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + No se puede crear Java VM{0}{1} + {0} - newline, {1} - exception + + + No se puede leer el archivo de perfil "{0}".{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + La ruta "{0}" no existe. + {0} - path + + + No se puede procesar el ensamblado "{0}"{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + No se encuentra la interfaz {0} + {0} - interface name + + + Se ha producido una excepción al cargar los tipos. Los tipos que no pueden ser cargados no serán procesados. Asegúrese de que las referencias de ensamblaje adicionales necesarias para esos tipos se proporcionan utilizando la opción -r. Excepción:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + No se puede encontrar el tipo "{0}". El tipo no será procesado. Asegúrese de que los directorios de todos los ensamblados referenciados se proporcionan con la opción -L. + {0} - type +The following terms should not be translated: -L + + + Los métodos Marshal de tipo "{0}" ya existen. Se ha omitido la generación de métodos Marshal en el ensamblado "{1}". Utilice -f para forzar la regeneración cuando lo desee. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + No se ha podido encontrar la definición del método "{0}" en los metadatos del ensamblado. No será procesado. Asegúrese de que los directorios de todos los ensamblajes referenciados se proporcionan con la opción -L. + {0} - method +The following terms should not be translated: -L + + + No se puede encontrar el método System.Console.WriteLine(). Desactivación de la inserción de la depuración. Para habilitar la inserción de depuración, asegúrese de que el directorio que contiene mscorlib se proporciona con la opción -L. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.fr.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.fr.resx new file mode 100644 index 00000000000..b45ab91e543 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.fr.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Erreur lors du chargement de l'assemblage : '{0}'. + {0} - File name + + + Impossible de supprimer les anciennes constantes : {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Échec du traitement du mappage enum. Ligne de texte : {0}. + {0} - The line that could not be processed. + + + Erreur lors du traitement de la correction des métadonnées : {0}. + {0} - The error encountered. + + + Spécification XPath non valide : {0}. + {0} - The invalid XPath line. + + + Le nom d'attribut cible n'est pas spécifié pour le chemin : {0}. + {0} - The invalid XPath line. + + + Spécification 'globale ::' inattendue. Cette erreur se produit si 'global ::' est spécifié dans le fichier de transformation Metadata.xml, par exemple. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Enfant de classe {0} inattendu. + {0} - The unexpected child class. + + + La classe '{0}' a un type de base inconnu '{1}'. + {0}, {1} - .NET types. + + + La classe '{0}' a un type de base '{1}' non valide. + {0}, {1} - .NET types. + + + Échec de l'analyse de l'assembly '{0}' : {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + Pour le constructeur '{0}', impossible de trouver le type englobant '{1}'. + {0} - .NET constructor method. +{1} - .NET type. + + + Type de champ `{0}` ({1}) inattendu. + {0} - .NET type. +{1} - .NET field signature. + + + Sauter '{0}.{1}' en raison d'un nom de méthode en double. (Type Java : '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Sauter '{0}.{1}' en raison d'un nom de type imbriqué en double. (Type Java : '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Sauter '{0}.{1}' en raison d'un champ ou d'un nom de propriété en double. (Type Java : '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Sauter '{0}.{1}' en raison d'un champ en double. (Type Java : '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Le type '{0}' a un nom de type qui correspond au nom de l'espace de noms englobant. Voir https://aka.ms/BG8403 pour plus d'informations. + {0} - Java type. + + + Élément enfant inattendu de '<interface>' : '{0}'. + {0} - XML element name. +<interface> should not be translated. + + + Aucun nom d'événement fourni dans '{0}.{1}'. + {0} - .NET type name +{1} - .NET member. + + + Invalidation de '{0}' et de tous ses types imbriqués car certaines de ses interfaces étaient invalides. + {0} - .NET type name. + + + Invalidation de '{0}' et de tous ses types imbriqués car certaines de ses méthodes étaient invalides. + {0} - .NET type name. + + + Nom de l'événement pour '{0}.{1}' est invalide. Un 'eventName' ou 'argsType' valide peut être attribué en ajoutant une règle au fichier de transformations Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Nom de la propriété d'événement pour '{0}.{1}' est invalide. Un 'eventName' ou 'argsType' valide peut être attribué en ajoutant une règle au fichier de transformations Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Fichier XML '{0}' non valide : {1}. + {0} - File name +{1} - The error encountered. + + + Aucun élément '<package>' trouvé. + The following terms should not be translated: <package>. + + + Nœud enfant racine inattendu : '<{0}>'. + {0} - XML element name. + + + Nœud enfant '<package>' inattendu : '<{0}>'. + {0} - XML element name. +The following terms should not be translated: <package>. + + + Impossible de trouver le type d'ancêtre supérieur '{0}' pour le type imbriqué '{1}'. + {0}, {1} - .NET types. + + + Le type Java '{0}' est introuvable (manque-t-il une référence Java jar/aar ou une bibliothèque de liaison Java NuGet ?) + {0} - Java type. + + + Certains types ou membres n'ont pas pu être liés car les types Java référencés sont introuvables. Voir le fichier 'java-resolution-report.log' pour plus de détails. + The following terms should not be translated: java-resolution-report.log + + + Type de retour inconnu '{0}' pour le membre '{1}'. + {0} - Java type. +{1} - .NET member. + + + Type de retour non valide '{0}' pour le membre '{1}'. + {0} - Java type. +{1} - .NET member. + + + Type de paramètre inconnu '{0}' pour le membre '{1}'. + {0} - Java type. +{1} - .NET member. + + + Type de paramètre '{0}' non valide pour le membre '{1}'. + {0} - Java type. +{1} - .NET member. + + + L'élément Metadata.xml '{0}' ne correspond à aucun nœud. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Transformation d'espace de noms non valide '{0}' + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Metadata.xml’attribut 'path' est manquant dans l’élément '{0}'. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Type de contrainte d'argument générique inconnu '{0}' pour le membre '{1}'. + {0} - .NET type name +{1} - .NET member. + + + Impossible de trouver l'interface de base '{1}' pour le type '{0}'. + {0}, {1} - .NET types. + + + Pour le type '{0}', l'interface de base '{1}' n'est pas valide. + {0}, {1} - .NET types. + + + Impossible de générer le wrapper Java pour le type '{0}'. Seulement les types de 'classe' sont pris en charge. + {0} - Java type. +The following terms should not be translated: +class. + + + Impossible de déterminer le nom JNI pour le type '{0}'. + {0} - Java type. +The following terms should not be translated: JNI. + + + La propriété 'Name' doit être un type complet tel que 'com.example.MyClass' et aucun package n'a été trouvé pour '{0}'. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Impossible de résoudre le type d'interface '{0}'. Il vous manque une référence d'assemblage ? + {0} - Java interface. + + + [ExportField] ne peut être utilisé que sur des méthodes avec 0 paramètres. + The following terms should not be translated: [ExportField]. + + + [Export] ne peut pas être utilisé sur un type générique. + The following terms should not be translated: [Export]. + + + [ExportField] ne peut pas être utilisé sur un type générique. + The following terms should not be translated: [ExportField]. + + + [ExportField] ne peut pas être utilisé sur une méthode retournant 'void'. + The following terms should not be translated: [ExportField], void. + + + Impossible de remplacer la méthode générée par Kotlin '{0}' car il ne s'agit pas d'un nom de méthode Java valide. Cette méthode ne peut être remplacée qu'à partir de Kotlin. + {0} - Kotlin method name. + + + Impossible de précharger la référence '{0}'. + {0} - assembly path + + + Veuillez spécifier au moins un ENSEMBLE à traiter. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Impossible de créer la machine virtuelle Java{0}{1} + {0} - newline, {1} - exception + + + Impossible de lire le fichier de profil '{0}'.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Le chemin '{0}' n'existe pas. + {0} - path + + + Impossible de traiter l'assemblage '{0}'{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Impossible de trouver l'interface {0} + {0} - interface name + + + A intercepté une exception lors du chargement des types. Les types qui ne peuvent pas être chargés ne seront pas traités. Assurez-vous que toutes les références d'assembly supplémentaires requises pour ces types sont fournies à l'aide de l'option -r. Exception : {0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Impossible de trouver le type '{0}'. Le type ne sera pas traité. Assurez-vous que les répertoires de tous les assemblys référencés sont fournis avec l'option -L. + {0} - type +The following terms should not be translated: -L + + + Le type de méthodes Marshal '{0}' existe déjà. Génération ignorée des méthodes marshal dans l'assembly '{1}'. Utilisez -f pour forcer la régénération lorsque vous le souhaitez. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Impossible de trouver la définition de la méthode '{0}' dans les métadonnées de l'assembly. Il ne sera pas traité. Assurez-vous que les répertoires de tous les assemblys référencés sont fournis avec l'option -L. + {0} - method +The following terms should not be translated: -L + + + Impossible de trouver la méthode System.Console.WriteLine(). Désactivation de l'injection de débogage. Pour activer l'injection de débogage, assurez-vous que le répertoire contenant mscorlib est fourni avec l'option -L. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.it.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.it.resx new file mode 100644 index 00000000000..a7faa8fef44 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.it.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Errore durante il caricamento dell'assembly: '{0}'. + {0} - File name + + + Impossibile rimuovere le costanti precedenti: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Impossibile elaborare il mapping dell'enumerazione. Riga di testo: {0}. + {0} - The line that could not be processed. + + + Errore durante l'elaborazione della correzione dei metadati: {0}. + {0} - The error encountered. + + + Specifica XPath non valida: {0}. + {0} - The invalid XPath line. + + + Il nome dell'attributo di destinazione non è specificato per il percorso: {0}. + {0} - The invalid XPath line. + + + Specifica 'global::' imprevista. Questo errore si verifica, ad esempio, se 'global::' è specificato nel file di trasformazione Metadata.xml. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Elemento figlio classe imprevisto {0}. + {0} - The unexpected child class. + + + La classe '{0}' contiene il tipo di base sconosciuto '{1}'. + {0}, {1} - .NET types. + + + La classe '{0}' ha un tipo di base non valido '{1}'. + {0}, {1} - .NET types. + + + Impossibile analizzare l'assembly '{0}': {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + Per il costruttore '{0}' non è stato possibile trovare il tipo di inclusione '{1}'. + {0} - .NET constructor method. +{1} - .NET type. + + + Tipo di campo '{0}' ({1}) imprevisto. + {0} - .NET type. +{1} - .NET field signature. + + + '{0}.{1}' verrà ignorato a causa di un nome di metodo duplicato. (Tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + '{0}.{1}' verrà ignorato a causa di un nome di tipo nidificato duplicato. (Tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + '{0}.{1}' verrà ignorato a causa di un nome di proprietà o campo duplicato. (tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + '{0}.{1}' verrà ignorato a causa di un campo duplicato. (Tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Il tipo '{0}' presenta un nome di tipo che corrisponde al nome dello spazio dei nomi contenitore. Per altre informazioni, vedere https://aka.ms/BG8403. + {0} - Java type. + + + Elemento figlio imprevisto di '<interface>': '{0}'. + {0} - XML element name. +<interface> should not be translated. + + + Nessun nome di evento specificato in '{0}.{1}'. + {0} - .NET type name +{1} - .NET member. + + + Convalida di '{0}' e di tutti i relativi tipi nidificati perché alcune interfacce non sono valide. + {0} - .NET type name. + + + Impossibile convalidare '{0}' e tutti i relativi tipi annidati perché alcuni dei relativi metodi non sono validi. + {0} - .NET type name. + + + Il nome dell'evento per '{0}.{1}' non è valido. È possibile assegnare un valore 'eventName' o 'argsType' valido aggiungendo una regola al file di trasformazioni Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Il nome della proprietà dell'evento per '{0}.{1}' non è valido. È possibile assegnare un valore 'eventName' o 'argsType' valido aggiungendo una regola al file di trasformazioni Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Il file XML '{0}' non è valido: {1}. + {0} - File name +{1} - The error encountered. + + + Non sono stati trovati elementi '<package>'. + The following terms should not be translated: <package>. + + + Nodo figlio radice imprevisto: '<{0}>'. + {0} - XML element name. + + + Nodo figlio '<package>' imprevisto: '<{0}>'. + {0} - XML element name. +The following terms should not be translated: <package>. + + + Non è stato possibile trovare il tipo predecessore principale '{0}' per il tipo nidificato '{1}'. + {0}, {1} - .NET types. + + + Non è stato possibile trovare il tipo Java '{0}' (manca un file jar/aar di riferimento Java o una libreria di binding Java NuGet?) + {0} - Java type. + + + Non è stato possibile associare alcuni tipi o membri perché non è stato possibile trovare i tipi Java a cui viene fatto riferimento. Per informazioni dettagliate, vedere il file 'java-resolution-report.log'. + The following terms should not be translated: java-resolution-report.log + + + Tipo restituito sconosciuto '{0}' per il membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + Tipo restituito non valido '{0}' per il membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + Tipo di parametro sconosciuto '{0}' per il membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + Tipo di parametro '{0}' non valido per il membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + L'elemento Metadata.xml '{0}' non corrisponde ad alcun nodo. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Trasformazione dello spazio dei nomi '{0}' non valida + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + L'elemento Metadata.xml '{0}' non dispone dell'attributo 'path'. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Tipo di vincolo di argomento generico sconosciuto '{0}' per il membro '{1}'. + {0} - .NET type name +{1} - .NET member. + + + Impossibile trovare l'interfaccia di base '{1}' per il tipo '{0}'. + {0}, {1} - .NET types. + + + Per il tipo '{0}', l'interfaccia di base '{1}' non è valida. + {0}, {1} - .NET types. + + + Non è possibile generare il wrapper Java per il tipo '{0}'. Sono supportati solo i tipi 'class'. + {0} - Java type. +The following terms should not be translated: +class. + + + Non è possibile determinare il nome JNI per il tipo '{0}'. + {0} - Java type. +The following terms should not be translated: JNI. + + + La proprietà 'Name' deve essere un tipo completo come 'com.example.MyClass' e non è stato trovato alcun pacchetto per '{0}'. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Impossibile risolvere il tipo di interfaccia '{0}'. Manca un riferimento all'assembly? + {0} - Java interface. + + + [ExportField] può essere utilizzato solo su metodi con 0 parametri. + The following terms should not be translated: [ExportField]. + + + [Export] non può essere utilizzato in un tipo generico. + The following terms should not be translated: [Export]. + + + [ExportField] non può essere utilizzato in un tipo generico. + The following terms should not be translated: [ExportField]. + + + impossibile utilizzare [ExportField] su un metodo che restituisce 'void'. + The following terms should not be translated: [ExportField], void. + + + Non è possibile eseguire l'override del metodo generato da Kotlin '{0}' perché non è un nome di metodo Java valido. Questo metodo può essere sostituito solo da Kotlin. + {0} - Kotlin method name. + + + Non è possibile precaricare il riferimento '{0}'. + {0} - assembly path + + + Specificare almeno un ASSEMBLY da elaborare. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Non è possibile creare la macchina virtuale Java{0}{1} + {0} - newline, {1} - exception + + + Impossibile leggere il file del profilo '{0}'.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Il percorso '{0}' non esiste. + {0} - path + + + Impossibile elaborare l'assembly '{0}'{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Non è stato possibile trovare l'interfaccia {0} + {0} - interface name + + + È stata rilevata un'eccezione durante il caricamento dei tipi. I tipi che non possono essere caricati non verranno elaborati. Assicurarsi che tutti i riferimenti ad assembly aggiuntivi necessari per questi tipi vengano forniti usando l'opzione -r. Eccezione:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Impossibile trovare il tipo '{0}'. Il tipo non verrà elaborato. Assicurarsi che le directory per tutti gli assembly a cui si fa riferimento siano fornite con l'opzione -L. + {0} - type +The following terms should not be translated: -L + + + Il tipo di metodi di marshalling '{0}' esiste già. La generazione dei metodi di marshalling nell'assembly '{1}' è stata ignorata. Usare -f per forzare la rigenerazione quando si desidera. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Impossibile trovare la definizione del metodo '{0}' nei metadati dell'assembly. Non verrà elaborato. Verificare che le directory per tutti gli assembly di riferimento siano fornite con l'opzione -L. + {0} - method +The following terms should not be translated: -L + + + Impossibile trovare il metodo System.Console.WriteLine(). Disabilitazione dell'inserimento del debug. Per abilitare l'inserimento del debug, assicurarsi che la directory contenente mscorlib sia fornita con l'opzione -L. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.ja.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.ja.resx new file mode 100644 index 00000000000..f8bab10a98e --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.ja.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + アセンブリの読み込み時のエラー: '{0}'。 + {0} - File name + + + 古い定数を削除できませんでした: {0}。 + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + 列挙型マッピングを処理できませんでした。テキスト行: {0}。 + {0} - The line that could not be processed. + + + メタデータの修正の処理中にエラーが発生しました: {0}。 + {0} - The error encountered. + + + XPath の指定が無効です: {0}。 + {0} - The invalid XPath line. + + + パスにターゲット属性名が指定されていません: {0}。 + {0} - The invalid XPath line. + + + 予期しない 'global::' 指定です。このエラーは、Metadata.xml 変換ファイルで 'global::' が指定されている場合などに発生します。 + The following are literal names and should not be translated: global::, Metadata.xml. + + + 予期しないクラスの子 {0} です。 + {0} - The unexpected child class. + + + クラス '{0}' に不明な基本型 '{1}' があります。 + {0}, {1} - .NET types. + + + クラス '{0}' に無効な基本データ型 '{1}' があります。 + {0}, {1} - .NET types. + + + アセンブリ '{0}' を解析できませんでした: {1}。 + {0} - Error .NET assembly. +{1} - The error encountered. + + + コンストラクター '{0}' について、それを囲む型 '{1}' が見つかりませんでした。 + {0} - .NET constructor method. +{1} - .NET type. + + + 予期しないフィールドの種類 '{0}' ({1}) です。 + {0} - .NET type. +{1} - .NET field signature. + + + メソッド名が重複しているため、'{0}.{1}' をスキップしています。(Java の型: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 入れ子にされた型名が重複しているため、'{0}.{1}' をスキップしています。(Java の型: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + フィールド名またはプロパティ名が重複しているため、'{0}.{1}' をスキップしています。(Java の型: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + フィールドが重複しているため、'{0}.{1}' をスキップしています。(Java の型: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 型 '{0}' に、それを囲む名前空間名と一致する型名が含まれています。詳細については、https://aka.ms/BG8403 を参照してください。 + {0} - Java type. + + + '<interface>' の予期しない子要素です: '{0}'。 + {0} - XML element name. +<interface> should not be translated. + + + '{0}.{1}' にイベント名が指定されていません。 + {0} - .NET type name +{1} - .NET member. + + + 一部のインターフェイスが無効であったため、'{0}' とその入れ子にされたすべての型を無効にしています。 + {0} - .NET type name. + + + 一部のメソッドが無効であったため、'{0}' とその入れ子にされたすべての型を無効にしています。 + {0} - .NET type name. + + + '{0}.{1}' のイベント名が無効です。Metadata.xml 変換ファイルにルールを追加すると、有効な 'eventName' または 'argsType' を割り当てることができます。 + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + '{0}.{1}' のイベント プロパティ名が無効です。Metadata.xml 変換ファイルにルールを追加すると、有効な 'eventName' または 'argsType' を割り当てることができます。 + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + XML ファイル '{0}' が無効です: {1}。 + {0} - File name +{1} - The error encountered. + + + '<package>' 要素が見つかりません。 + The following terms should not be translated: <package>. + + + 予期しないルートの子ノード: '<{0}>'。 + {0} - XML element name. + + + 予期しない '<package>' 子ノードです: '<{0}>'。 + {0} - XML element name. +The following terms should not be translated: <package>. + + + 入れ子にされた型 '{0}' の上位先祖型 '{1}' が見つかりませんでした。 + {0}, {1} - .NET types. + + + Java の型 '{0}' が見つかりませんでした (Java 参照 jar/aar または Java バインド ライブラリ NuGet が不足していないかどうかを確認してください。) + {0} - Java type. + + + 参照されている Java の型が見つからなかったため、一部の型またはメンバーをバインドできませんでした。詳細については、'java-resolution-report.log' ファイルを参照してください。 + The following terms should not be translated: java-resolution-report.log + + + メンバー '{1}' の戻り値の型 '{0}' が不明です。 + {0} - Java type. +{1} - .NET member. + + + メンバー '{1}' の戻り値の型 '{0}' が無効です。 + {0} - Java type. +{1} - .NET member. + + + メンバー '{1}' のパラメーター型 '{0}' が不明です。 + {0} - Java type. +{1} - .NET member. + + + メンバー '{1}' のパラメーター型 '{0}' が無効です。 + {0} - Java type. +{1} - .NET member. + + + Metadata.xml 要素 '{0}' と一致するノードがありませんでした。 + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + 名前空間の変換 '{0}' が無効です + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Metadata.xml 要素 '{0}' に 'path' 属性がありません。 + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + メンバー '{1}' のジェネリック引数制約型 '{0}' が不明です。 + {0} - .NET type name +{1} - .NET member. + + + 型 '{0}' の基本インターフェイス '{1}' が見つかりませんでした。 + {0}, {1} - .NET types. + + + 型'{0}' では、基本インターフェイス '{1}' が無効です。 + {0}, {1} - .NET types. + + + 型 '{0}' の Java ラッパーを生成できません。'class' 型のみがサポートされています。 + {0} - Java type. +The following terms should not be translated: +class. + + + 型 '{0}' の JNI 名を特定できません。 + {0} - Java type. +The following terms should not be translated: JNI. + + + 'Name' プロパティは 'com.example.MyClass' のような完全修飾型である必要があり、'{0}' のパッケージが見つかりませんでした。 + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + インターフェイスの型 '{0}' を解決できません。アセンブリ参照が不足していないかどうかを確認してください。 + {0} - Java interface. + + + [ExportField] は、パラメーターが 0 個のメソッドでのみ使用できます。 + The following terms should not be translated: [ExportField]. + + + [Export] はジェネリック型では使用できません。 + The following terms should not be translated: [Export]. + + + [ExportField] はジェネリック型では使用できません。 + The following terms should not be translated: [ExportField]. + + + 'void' を返すメソッドでは、[ExportField] を使用できません。 + The following terms should not be translated: [ExportField], void. + + + Kotlin で生成されたメソッド '{0}' は有効な Java メソッド名ではないため、オーバーライドできません。このメソッドは Kotlin からのみオーバーライドできます。 + {0} - Kotlin method name. + + + 参照 '{0}' を事前に読み込むことができません。 + {0} - assembly path + + + 処理する ASSEMBLY を少なくとも 1 つ指定してください。 + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Java VM{0}{1} を作成できません + {0} - newline, {1} - exception + + + プロフィール ファイル '{0}' を読み取れません。{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + パス '{0}' が存在しません。 + {0} - path + + + アセンブリ '{0}' を処理できません{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + インターフェイス {0}が見つかりませんでした + {0} - interface name + + + 型の読み込み中に例外が発生しました。読み込めない型は処理されません。これらの型に必要な追加のアセンブリ参照が -r オプションを使用して指定されていることを確認してください。例外:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + 型 '{0}' が見つかりません。この型は処理されません。参照されているすべてのアセンブリのディレクトリに -L オプションが指定されていることを確認してください。 + {0} - type +The following terms should not be translated: -L + + + マーシャリング メソッドの型 '{0}' は既に存在します。アセンブリ '{1}' でマーシャリング メソッドの生成をスキップしました。-f を使用して、必要に応じて再生成を強制してください。 + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + アセンブリ メタデータにメソッド '{0}' の定義が見つかりません。このメソッドは処理されません。参照されているすべてのアセンブリのディレクトリに -L オプションが指定されていることを確認してください。 + {0} - method +The following terms should not be translated: -L + + + System.Console.WriteLine() メソッドが見つかりません。デバッグ インジェクションを無効にしています。デバッグ インジェクションを有効にするには、mscorlib を含むディレクトリに -L オプションが指定されていることを確認してください。 + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.ko.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.ko.resx new file mode 100644 index 00000000000..de1c62eb7e4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.ko.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 어셈블리 로드 중 오류: '{0}'. + {0} - File name + + + 이전 상수를 제거하지 못했습니다: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + 열거 매핑을 처리하지 못했습니다. 텍스트 줄: {0}. + {0} - The line that could not be processed. + + + 메타데이터 수정 처리 중 오류: {0}. + {0} - The error encountered. + + + 잘못된 XPath 사양: {0}. + {0} - The invalid XPath line. + + + 대상 특성 이름이 경로 {0}에 지정되지 않았습니다. + {0} - The invalid XPath line. + + + 예기치 않은 'global::' 사양입니다. 이 오류는 예를 들어 Metadata.xml 변환 파일에 'global::'이 지정된 경우 발생합니다. + The following are literal names and should not be translated: global::, Metadata.xml. + + + 예기치 않은 클래스 하위 {0}. + {0} - The unexpected child class. + + + 클래스 '{0}'에 알 수 없는 기본 형식 '{1}'이(가) 있습니다. + {0}, {1} - .NET types. + + + 클래스 '{0}'에 잘못된 기본 형식 '{1}'이(가) 있습니다. + {0}, {1} - .NET types. + + + 어셈블리 '{0}' 구문 분석 실패: {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + 생성자 '{0}'의 경우 둘러싼 형식 '{1}'을(를) 찾을 수 없습니다. + {0} - .NET constructor method. +{1} - .NET type. + + + 예기치 않은 필드 형식 `{0}`({1})입니다. + {0} - .NET type. +{1} - .NET field signature. + + + 메소드 이름이 중복되어 '{0}.{1}'을(를) 건너뜁니다. (Java 형식: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 중첩 형식 이름이 중복되어 '{0}.{1}'을(를) 건너뜁니다. (Java 형식: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 중복 필드 또는 속성 이름으로 인해 '{0}.{1}'을(를) 건너뜁니다. (Java 형식: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 중복 필드로 인해 '{0}.{1}'을(를) 건너뜁니다. (Java 형식: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 형식 '{0}'에는 바깥쪽 네임스페이스 이름과 일치하는 형식 이름이 있습니다. 자세한 내용은 https://aka.ms/BG8403을 참조하세요. + {0} - Java type. + + + '<interface>'의 예기치 않은 하위 요소: '{0}'. + {0} - XML element name. +<interface> should not be translated. + + + '{0}.{1}'에 이벤트 이름이 제공되지 않았습니다. + {0} - .NET type name +{1} - .NET member. + + + 일부 인터페이스가 잘못되어 '{0}' 및 모든 중첩 형식을 무효화합니다. + {0} - .NET type name. + + + 일부 메서드가 잘못되어 '{0}' 및 모든 중첩 형식을 무효화합니다. + {0} - .NET type name. + + + '{0}.{1}'의 이벤트 이름이 잘못되었습니다. Metadata.xml 변환 파일에 규칙을 추가하여 유효한 'eventName' 또는 'argsType'을 할당할 수 있습니다. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + '{0}.{1}'의 이벤트 속성 이름이 잘못되었습니다. Metadata.xml 변환 파일에 규칙을 추가하여 유효한 'eventName' 또는 'argsType'을 할당할 수 있습니다. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + 잘못된 XML 파일 '{0}': {1}. + {0} - File name +{1} - The error encountered. + + + '<package>' 요소를 찾을 수 없습니다. + The following terms should not be translated: <package>. + + + 예기치 않은 루트 하위 노드: '<{0}>'. + {0} - XML element name. + + + 예기치 않은 '<package>' 하위 노드: '<{0}>'. + {0} - XML element name. +The following terms should not be translated: <package>. + + + 중첩 형식 '{1}'에 대한 상위 상위 항목 형식 '{0}'을(를) 찾을 수 없습니다. + {0}, {1} - .NET types. + + + Java 형식 '{0}'을(를) 찾을 수 없습니다(Java 참조 jar/aar 또는 Java 바인딩 라이브러리 NuGet이 누락되었습니까?) + {0} - Java type. + + + 참조된 Java 형식을 찾을 수 없기 때문에 일부 형식 또는 멤버를 바인딩할 수 없습니다. 자세한 내용은 'java-resolution-report.log' 파일을 참조하세요. + The following terms should not be translated: java-resolution-report.log + + + 멤버 '{1}'에 대한 알 수 없는 반환 형식 '{0}'. + {0} - Java type. +{1} - .NET member. + + + 멤버 '{1}'에 대한 잘못된 반환 형식 '{0}'. + {0} - Java type. +{1} - .NET member. + + + 멤버 '{1}'에 대한 알 수 없는 매개 변수 형식 '{0}'. + {0} - Java type. +{1} - .NET member. + + + '{1}' 멤버에 대한 매개 변수 형식 '{0}'이(가) 잘못되었습니다. + {0} - Java type. +{1} - .NET member. + + + Metadata.xml 요소 '{0}'이(가) 일치하는 노드가 없습니다. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + 잘못된 네임스페이스 변환 '{0}' + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Metadata.xml 요소 '{0}'에 'path' 특성이 없습니다. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + '{1}' 멤버에 대한 알 수 없는 일반 인수 제약 형식 '{0}'. + {0} - .NET type name +{1} - .NET member. + + + 형식 '{0}'에 대한 기본 인터페이스 '{1}'을(를) 찾을 수 없습니다. + {0}, {1} - .NET types. + + + 형식 '{0}'의 경우 기본 인터페이스 '{1}'이(가) 잘못되었습니다. + {0}, {1} - .NET types. + + + 형식 '{0}'에 대한 Java 래퍼를 생성할 수 없습니다. '클래스' 형식만 지원됩니다. + {0} - Java type. +The following terms should not be translated: +class. + + + 형식 '{0}'에 대한 JNI 이름을 결정할 수 없습니다. + {0} - Java type. +The following terms should not be translated: JNI. + + + '이름' 속성은 'com.example.MyClass'와 같은 정규화된 형식이어야 하며 '{0}'에 대한 패키지를 찾을 수 없습니다. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + 인터페이스 형식 '{0}'을(를) 확인할 수 없습니다. 어셈블리 참조가 누락되었습니까? + {0} - Java interface. + + + [ExportField]은(는) 매개 변수가 0인 메서드에만 사용할 수 있습니다. + The following terms should not be translated: [ExportField]. + + + [내보내기]는 제네릭 형식에 사용할 수 없습니다. + The following terms should not be translated: [Export]. + + + [ExportField]은(는) 제네릭 형식에 사용할 수 없습니다. + The following terms should not be translated: [ExportField]. + + + [ExportField]은(는) 'void'를 반환하는 메서드에 사용할 수 없습니다. + The following terms should not be translated: [ExportField], void. + + + 유효한 Java 메소드 이름이 아니기 때문에 Kotlin 생성 메소드 '{0}'을(를) 재정의할 수 없습니다. 이 메서드는 Kotlin에서만 재정의할 수 있습니다. + {0} - Kotlin method name. + + + 참조 '{0}'을(를) 미리 로드할 수 없습니다. + {0} - assembly path + + + 처리할 ASSEMBLY를 하나 이상 지정하세요. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Java VM을 생성할 수 없음{0}{1} + {0} - newline, {1} - exception + + + 프로필 파일 '{0}'을(를) 읽을 수 없습니다.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + 경로 '{0}'이(가) 존재하지 않습니다. + {0} - path + + + 어셈블리 '{0}'{1}{2}{1}{3}을(를) 처리할 수 없습니다. + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + 인터페이스 {0}을(를) 찾을 수 없습니다. + {0} - interface name + + + 형식을 로드하는 동안 예외가 발생했습니다. 로드할 수 없는 형식은 처리되지 않습니다. 해당 형식에 필요한 추가 어셈블리 참조가 -r 옵션을 사용하여 제공되었는지 확인하세요. 예외:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + 형식 '{0}'을(를) 찾을 수 없습니다. 형식이 처리되지 않습니다. 참조된 모든 어셈블리의 디렉터리에 -L 옵션이 제공되었는지 확인합니다. + {0} - type +The following terms should not be translated: -L + + + 마샬 메소드 형식 '{0}'이(가) 이미 존재합니다. 어셈블리 '{1}'에서 마샬 메서드 생성을 건너뛰었습니다. 원하는 경우 -f를 사용하여 재생성을 강제 실행합니다. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + 어셈블리 메타데이터에서 '{0}' 메서드의 정의를 찾을 수 없습니다. 처리되지 않습니다. 참조된 모든 어셈블리의 디렉터리에 -L 옵션이 제공되었는지 확인합니다. + {0} - method +The following terms should not be translated: -L + + + System.Console.WriteLine() 메서드를 찾을 수 없습니다. 디버그 주입을 비활성화합니다. 디버그 삽입을 활성화하려면 mscorlib가 포함된 디렉터리에 -L 옵션이 제공되었는지 확인합니다. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.pl.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.pl.resx new file mode 100644 index 00000000000..f580ed50d47 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.pl.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Błąd podczas ładowania motywu: „{0}” + {0} - File name + + + Nie można usunąć starych stałych: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Nie można przetworzyć mapowania wyliczenia. Wiersz tekstu: {0}. + {0} - The line that could not be processed. + + + Błąd podczas przetwarzania poprawki metadanych: {0}. + {0} - The error encountered. + + + Nieprawidłowa specyfikacja XPath: {0}. + {0} - The invalid XPath line. + + + Nie określono nazwy atrybutu docelowego dla ścieżki: {0}. + {0} - The invalid XPath line. + + + Nieoczekiwana specyfikacja „global::”. Ten błąd występuje, jeśli w pliku przekształcenia Metadata.xml określono na przykład wartość „global::”. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Nieoczekiwana klasa podrzędna {0}. + {0} - The unexpected child class. + + + Klasa „{0}” ma nieznany typ podstawowy „{1}”. + {0}, {1} - .NET types. + + + Klasa „{0}” ma nieprawidłowy typ podstawowy „{1}”. + {0}, {1} - .NET types. + + + Nie można przeanalizować zestawu „{0}”: {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + W przypadku konstruktora „{0}” nie można odnaleźć otaczającego typu „{1}”. + {0} - .NET constructor method. +{1} - .NET type. + + + Nieoczekiwany typ pola „{0}” ({1}). + {0} - .NET type. +{1} - .NET field signature. + + + Pomijanie typu „{0}.{1}” z powodu zduplikowanej nazwy metody. (Typ java: „{2}”) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Pomijanie elementu „{0}.{1}” z powodu zduplikowanej nazwy typu zagnieżdżonego. (Typ java: „{2}”) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Pomijanie elementu „{0}.{1}” z powodu zduplikowanej nazwy pola lub właściwości. (Typ java: „{2}”) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Pomijanie elementu „{0}.{1}” z powodu zduplikowanego pola. (Typ java: „{2}”) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + „{0}” ma nazwę typu zgodną z otaczającą nazwą przestrzeni nazw. Aby uzyskać więcej informacji, zobacz https://aka.ms/BG8403. + {0} - Java type. + + + Nieoczekiwany element podrzędny „<interface>”: „{0}”. + {0} - XML element name. +<interface> should not be translated. + + + Nie podano nazwy zdarzenia w typie „{0}.{1}”. + {0} - .NET type name +{1} - .NET member. + + + Unieważnienie elementu „{0}” i wszystkich jego typów zagnieżdżonych, ponieważ niektóre z jego interfejsów były nieprawidłowe. + {0} - .NET type name. + + + Unieważnienie elementu „{0}” i wszystkich jego typów zagnieżdżonych, ponieważ niektóre z jego metod były nieprawidłowe. + {0} - .NET type name. + + + Nazwa zdarzenia „{0}.{1}” jest nieprawidłowa. Prawidłowy element „eventName” lub „argsType” można przypisać, dodając regułę do pliku przekształceń Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Nazwa właściwości zdarzenia „{0}.{1}” jest nieprawidłowa. Prawidłowy element „eventName” lub „argsType” można przypisać, dodając regułę do pliku przekształceń Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Nieprawidłowy plik XML „{0}”: {1}. + {0} - File name +{1} - The error encountered. + + + Nie znaleziono elementów „<package>”. + The following terms should not be translated: <package>. + + + Nieoczekiwany główny węzeł podrzędny: „<{0}>”. + {0} - XML element name. + + + Nieoczekiwany węzeł podrzędny „<package>”: „<{0}>”. + {0} - XML element name. +The following terms should not be translated: <package>. + + + Nie można odnaleźć typu elementu nadrzędnego „{0}” dla zagnieżdżonego typu „{1}”. + {0}, {1} - .NET types. + + + Nie można odnaleźć typu języka Java „{0}” (czy brakuje pliku jar/aar odwołania Java lub NuGet biblioteki powiązań Java?) + {0} - Java type. + + + Nie można powiązać niektórych typów lub elementów członkowskich, ponieważ nie można odnaleźć przywoływanych typów języka Java. Aby uzyskać szczegółowe informacje, zobacz plik „java-resolution-report.log”. + The following terms should not be translated: java-resolution-report.log + + + Nieznany zwracany typ „{0}” dla elementu członkowskiego „{1}”. + {0} - Java type. +{1} - .NET member. + + + Nieprawidłowy zwracany typ „{0}” dla elementu członkowskiego „{1}”. + {0} - Java type. +{1} - .NET member. + + + Nieznany typ parametru „{0}” dla elementu członkowskiego „{1}”. + {0} - Java type. +{1} - .NET member. + + + Nieprawidłowy typ parametru „{0}” dla elementu członkowskiego „{1}”. + {0} - Java type. +{1} - .NET member. + + + Element Metadata.xml „{0}” nie pasuje do węzłów. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Nieprawidłowe przekształcenie przestrzeni nazw „{0}” + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + W elemencie Metadata.xml „{0}” brakuje atrybutu „path”. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Nieznany typ ograniczenia argumentu ogólnego „{0}” dla elementu członkowskiego „{1}”. + {0} - .NET type name +{1} - .NET member. + + + Nie można odnaleźć interfejsu podstawowego „{1}” dla typu „{0}”. + {0}, {1} - .NET types. + + + W przypadku typu „{0}” interfejs podstawowy „{1}” jest nieprawidłowy. + {0}, {1} - .NET types. + + + Nie można wygenerować otoki Języka Java dla typu „{0}”. Obsługiwane są tylko typy „class”. + {0} - Java type. +The following terms should not be translated: +class. + + + Nie można określić nazwy JNI dla typu „{0}”. + {0} - Java type. +The following terms should not be translated: JNI. + + + Właściwość „Name” musi być w pełni kwalifikowanym typem, takim jak „com.example.MyClass”, i nie znaleziono pakietu dla elementu „{0}”. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Nie można rozpoznać typu interfejsu „{0}”. Czy brakuje odwołania do zestawu? + {0} - Java interface. + + + Elementu [ExportField] można używać tylko w metodach z parametrami 0. + The following terms should not be translated: [ExportField]. + + + Nie można użyć elementu [Export] dla typu ogólnego. + The following terms should not be translated: [Export]. + + + Nie można użyć elementu [ExportField] dla typu ogólnego. + The following terms should not be translated: [ExportField]. + + + Nie można użyć elementu [ExportField] w metodzie zwracającej wartość „void”. + The following terms should not be translated: [ExportField], void. + + + Nie można przesłonić metody wygenerowanej przez metodę Kotlin „{0}”, ponieważ nie jest to prawidłowa nazwa metody Java. Tę metodę można zastąpić tylko za pomocą języka Kotlin. + {0} - Kotlin method name. + + + Nie można wstępnie załadować odwołania „{0}”. + {0} - assembly path + + + Określ co najmniej jeden ZESTAW do przetworzenia. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Nie można utworzyć maszyny wirtualnej Java{0}{1} + {0} - newline, {1} - exception + + + Nie można odczytać pliku profilu „{0}”.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Ścieżka „{0}” nie istnieje. + {0} - path + + + Nie można przetworzyć zestawu „{0}”{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Nie znaleziono interfejsu {0} + {0} - interface name + + + Przechwycono wyjątek podczas ładowania typów. Typy, których nie można załadować, nie zostaną przetworzone. Upewnij się, że wszelkie dodatkowe odwołania do zestawów wymagane dla tych typów są dostarczane przy użyciu opcji -r. Wyjątek:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Nie można odnaleźć typu „{0}”. Typ nie zostanie przetworzony. Upewnij się, że katalogi dla wszystkich przywoływanych zestawów są dostarczane z opcją -L. + {0} - type +The following terms should not be translated: -L + + + Typ metod marshalingu „{0}” już istnieje. Pominięto generowanie metod marshalingu w zestawie „{1}”. Użyj -f, aby wymusić ponowne wygenerowanie w razie potrzeby. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Nie można odnaleźć definicji metody „{0}” w metadanych zestawu. Nie zostanie on przetworzony. Upewnij się, że katalogi dla wszystkich przywoływanych zestawów są dostarczane z opcją -L. + {0} - method +The following terms should not be translated: -L + + + Nie można odnaleźć metody System.Console.WriteLine(). Wyłączanie iniekcji debugowania. Aby włączyć iniekcję debugowania, upewnij się, że katalog zawierający plik mscorlib jest dostarczany z opcją -L. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.pt-BR.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.pt-BR.resx new file mode 100644 index 00000000000..22f77b675af --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.pt-BR.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Erro ao carregar o assembly: '{0}'. + {0} - File name + + + Ocorreu um erro ao remover as constantes antigas: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Não foi possível processar o mapeamento de enumeração. Linha de texto: {0}. + {0} - The line that could not be processed. + + + Erro durante o processamento da correção dos metadados: {0}. + {0} - The error encountered. + + + Especificação de XPath inválida: {0}. + {0} - The invalid XPath line. + + + O nome do atributo de destino não foi especificado para o caminho: {0}. + {0} - The invalid XPath line. + + + Especificação 'global::' inesperada. Esse erro ocorre se 'global::' for especificado no arquivo de transformação Metadata.xml, por exemplo. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Classe filho inesperada {0}. + {0} - The unexpected child class. + + + A classe '{0}' tem tipo base desconhecido '{1}'. + {0}, {1} - .NET types. + + + A classe '{0}' tem o tipo base '{1}' inválido. + {0}, {1} - .NET types. + + + Ocorreu um erro ao analisar o assembly '{0}': {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + Para o construtor '{0}', não foi possível encontrar o tipo de delimitação '{1}'. + {0} - .NET constructor method. +{1} - .NET type. + + + Tipo de campo inesperado `{0}` ({1}). + {0} - .NET type. +{1} - .NET field signature. + + + Ignorando '{0}.{1}' devido a um nome de método duplicado. (Tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Ignorando '{0}.{1}' devido a um nome de tipo aninhado duplicado. (Tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Ignorando '{0}.{1}' devido a um campo duplicado ou nome da propriedade. (Tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Ignorando '{0}.{1}' devido a um campo duplicado. (Tipo Java: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + O tipo '{0}' tem um nome de tipo que corresponde ao nome do namespace incluído. Visite https://aka.ms/BG8403 para obter mais informações. + {0} - Java type. + + + Elemento filho inesperado de '<interface>': '{0}'. + {0} - XML element name. +<interface> should not be translated. + + + Nenhum nome de evento fornecido em '{0}.{1}'. + {0} - .NET type name +{1} - .NET member. + + + Invalidando '{0}' e todos os seus tipos aninhados, pois algumas das suas interfaces eram inválidas. + {0} - .NET type name. + + + Invalidando '{0}' e todos os seus tipos aninhados, pois alguns de seus métodos eram inválidos. + {0} - .NET type name. + + + O nome do evento para '{0}.{1}' é inválido. Um 'eventName' ou 'argsType' válido pode ser atribuído adicionando uma regra ao arquivo de transformações Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + O nome da propriedade do evento para '{0}.{1}' é inválido. Um 'eventName' ou 'argsType' válido pode ser atribuído adicionando uma regra ao arquivo de transformações Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Arquivo XML inválido '{0}': {1}. + {0} - File name +{1} - The error encountered. + + + Nenhum elemento '<package>' foi encontrados. + The following terms should not be translated: <package>. + + + Nó filho raiz inesperado: '<{0}>'. + {0} - XML element name. + + + Nó filho '<package>' inesperado: '<{0}>'. + {0} - XML element name. +The following terms should not be translated: <package>. + + + Não foi possível encontrar o tipo de ancestral superior '{0}' para o tipo aninhado '{1}'. + {0}, {1} - .NET types. + + + Não foi possível encontrar o tipo Java '{0}' (está faltando um jar/aar de referência Java ou uma biblioteca de vinculação Java NuGet?) + {0} - Java type. + + + Alguns tipos ou membros não puderam ser vinculados porque os tipos Java referenciados não puderam ser encontrados. Consulte o arquivo 'java-resolution-report.log' para obter detalhes. + The following terms should not be translated: java-resolution-report.log + + + Tipo de retorno desconhecido '{0}' para o membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + Tipo de retorno inválido '{0}' para o membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + Tipo de parâmetro desconhecido '{0}' para o membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + Tipo de parâmetro inválido '{0}' para o membro '{1}'. + {0} - Java type. +{1} - .NET member. + + + O elemento Metadata.xml '{0}' não correspondeu a nenhum nó. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Transformação do namespace inválida '{0}' + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + O elemento Metadata.xml '{0}' não tem o atributo 'path'. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Tipo de restrição de argumento genérico desconhecido '{0}' para o membro '{1}'. + {0} - .NET type name +{1} - .NET member. + + + Não foi possível localizar a interface base '{1}' para o tipo '{0}'. + {0}, {1} - .NET types. + + + Para o tipo '{0}', a interface base '{1}' é inválida. + {0}, {1} - .NET types. + + + Não é possível gerar o wrapper Java para o tipo '{0}'. Somente tipos de 'classe' são suportados. + {0} - Java type. +The following terms should not be translated: +class. + + + Não é possível determinar o nome JNI para o tipo '{0}'. + {0} - Java type. +The following terms should not be translated: JNI. + + + A propriedade 'Name' deve ser um tipo totalmente qualificado como 'com.example.MyClass' e nenhum pacote foi encontrado para '{0}'. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Não é possível resolver o tipo de interface '{0}'. Uma referência de assembly está ausente? + {0} - Java interface. + + + [ExportField] só pode ser usado em métodos com parâmetros 0. + The following terms should not be translated: [ExportField]. + + + [Export] não pode ser usado em um tipo genérico. + The following terms should not be translated: [Export]. + + + [ExportField] não pode ser usado em um tipo genérico. + The following terms should not be translated: [ExportField]. + + + [ExportField] não pode ser usado em um método que retorna 'void'. + The following terms should not be translated: [ExportField], void. + + + Não é possível substituir o método gerado pelo Kotlin '{0}' porque ele não é um nome de método Java válido. Esse método só pode ser substituído a partir do Kotlin. + {0} - Kotlin method name. + + + Não é possível pré-carregar a referência '{0}'. + {0} - assembly path + + + Especifique pelo menos um ASSEMBLY para processar. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Não é possível criar a VM Java{0}{1} + {0} - newline, {1} - exception + + + Não é possível ler o arquivo de perfil '{0}'.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Caminho '{0}' inexistente. + {0} - path + + + Não é possível processar o assembly '{0}'{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Não foi possível encontrar a interface {0} + {0} - interface name + + + Capturou uma exceção ao carregar tipos. Os tipos que não podem ser carregados não serão processados. Verifique se todas as referências de assembly adicionais necessárias para esses tipos foram fornecidas usando a opção -r. Exceção:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Não é possível localizar o tipo '{0}'. O tipo não será processado. Verifique se os diretórios de todos os assemblies referenciados foram fornecidos com a opção -L. + {0} - type +The following terms should not be translated: -L + + + O tipo de métodos marshaling '{0}' já existe. Foi ignorada a geração de métodos marshaling no assembly '{1}'. Use -f para forçar a regeneração quando desejar. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Não é possível encontrar a definição do método '{0}' nos metadados do assembly. Não será processado. Verifique se os diretórios de todos os assemblies referenciados foram fornecidos com a opção -L. + {0} - method +The following terms should not be translated: -L + + + Não é possível encontrar o método System.Console.WriteLine(). Desativando a injeção de depuração. Para habilitar a injeção de depuração, verifique se o diretório que contém o mscorlib foi fornecido com a opção -L. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.resx new file mode 100644 index 00000000000..084f94f502b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.resx @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Error while loading assembly: '{0}'. + {0} - File name + + + Failed to remove old constants: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Failed to process enum mapping. Text line: {0}. + {0} - The line that could not be processed. + + + Error during processing metadata fixup: {0}. + {0} - The error encountered. + + + Invalid XPath specification: {0}. + {0} - The invalid XPath line. + + + Target attribute name is not specified for path: {0}. + {0} - The invalid XPath line. + + + Unexpected 'global::' specification. This error happens if 'global::' is specified in the Metadata.xml transform file, for example. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Unexpected class child {0}. + {0} - The unexpected child class. + + + Class '{0}' has unknown base type '{1}'. + {0}, {1} - .NET types. + + + Class '{0}' has invalid base type '{1}'. + {0}, {1} - .NET types. + + + Failed to parse assembly '{0}': {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + For constructor '{0}', could not find enclosing type '{1}'. + {0} - .NET constructor method. +{1} - .NET type. + + + Unexpected field type `{0}` ({1}). + {0} - .NET type. +{1} - .NET field signature. + + + Skipping '{0}.{1}' due to a duplicate method name. (Java type: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Skipping '{0}.{1}' due to a duplicate nested type name. (Java type: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Skipping '{0}.{1}' due to a duplicate field or property name. (Java type: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Skipping '{0}.{1}' due to a duplicate field. (Java type: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Type '{0}' has a type name which matches the enclosing namespace name. See https://aka.ms/BG8403 for more information. + {0} - Java type. + + + Unexpected child element of '<interface>': '{0}'. + {0} - XML element name. +<interface> should not be translated. + + + No event name provided in '{0}.{1}'. + {0} - .NET type name +{1} - .NET member. + + + Invalidating '{0}' and all its nested types because some of its interfaces were invalid. + {0} - .NET type name. + + + Invalidating '{0}' and all its nested types because some of its methods were invalid. + {0} - .NET type name. + + + Event name for '{0}.{1}' is invalid. A valid 'eventName' or 'argsType' can be assigned by adding a rule to the Metadata.xml transforms file. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Event property name for '{0}.{1}' is invalid. A valid 'eventName' or 'argsType' can be assigned by adding a rule to the Metadata.xml transforms file. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Invalid XML file '{0}': {1}. + {0} - File name +{1} - The error encountered. + + + No '<package>' elements found. + The following terms should not be translated: <package>. + + + Unexpected root child node: '<{0}>'. + {0} - XML element name. + + + Unexpected '<package>' child node: '<{0}>'. + {0} - XML element name. +The following terms should not be translated: <package>. + + + Could not find top ancestor type '{0}' for nested type '{1}'. + {0}, {1} - .NET types. + + + The Java type '{0}' could not be found (are you missing a Java reference jar/aar or a Java binding library NuGet?) + {0} - Java type. + + + Some types or members could not be bound because referenced Java types could not be found. See the 'java-resolution-report.log' file for details. + The following terms should not be translated: java-resolution-report.log + + + Unknown return type '{0}' for member '{1}'. + {0} - Java type. +{1} - .NET member. + + + Invalid return type '{0}' for member '{1}'. + {0} - Java type. +{1} - .NET member. + + + Unknown parameter type '{0}' for member '{1}'. + {0} - Java type. +{1} - .NET member. + + + Invalid parameter type '{0}' for member '{1}'. + {0} - Java type. +{1} - .NET member. + + + Metadata.xml element '{0}' matched no nodes. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Invalid namespace transform '{0}' + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Metadata.xml element '{0}' is missing the 'path' attribute. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Unknown generic argument constraint type '{0}' for member '{1}'. + {0} - .NET type name +{1} - .NET member. + + + Could not find base interface '{1}' for type '{0}'. + {0}, {1} - .NET types. + + + For type '{0}', base interface '{1}' is invalid. + {0}, {1} - .NET types. + + + For type '{0}', the Kotlin name-mangled method '{1}' (originally '{2}') has multiple hash-suffixed siblings that erase to the same C# signature. Only the first will be emitted; remove the duplicate via Metadata.xml to suppress this warning. + {0} - .NET type. {1} - C# method name. {2} - Original (mangled) JVM method name. + + + Cannot generate Java wrapper for type '{0}'. Only 'class' types are supported. + {0} - Java type. +The following terms should not be translated: +class. + + + Cannot determine JNI name for type '{0}'. + {0} - Java type. +The following terms should not be translated: JNI. + + + The 'Name' property must be a fully qualified type like 'com.example.MyClass' and no package was found for '{0}'. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Unable to resolve interface type '{0}'. Are you missing an assembly reference? + {0} - Java interface. + + + [ExportField] can only be used on methods with 0 parameters. + The following terms should not be translated: [ExportField]. + + + [Export] cannot be used on a generic type. + The following terms should not be translated: [Export]. + + + [ExportField] cannot be used on a generic type. + The following terms should not be translated: [ExportField]. + + + [ExportField] cannot be used on a method returning 'void'. + The following terms should not be translated: [ExportField], void. + + + Cannot override Kotlin-generated method '{0}' because it is not a valid Java method name. This method can only be overridden from Kotlin. + {0} - Kotlin method name. + + + Unable to preload reference '{0}'. + {0} - assembly path + + + Please specify at least one ASSEMBLY to process. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Unable to create Java VM{0}{1} + {0} - newline, {1} - exception + + + Unable to read profile file '{0}'.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Path '{0}' does not exist. + {0} - path + + + Unable to process assembly '{0}'{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Couln't find interface {0} + {0} - interface name + + + Caught an exception while loading types. The types that cannot be loaded will not be processed. Make sure that any additional assembly references required for those types are provided using the -r option. Exception:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Unable to find type '{0}'. The type will not be processed. Make sure the directories for all referenced assemblies are provided with the -L option. + {0} - type +The following terms should not be translated: -L + + + Marshal methods type '{0}' already exists. Skipped generation of marshal methods in assembly '{1}'. Use -f to force regeneration when desired. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Unable to find definition of method '{0}' in assembly metadata. It will not be processed. Make sure the directories for all referenced assemblies are provided with the -L option. + {0} - method +The following terms should not be translated: -L + + + Unable to find the System.Console.WriteLine() method. Disabling debug injection. To enable debug injection, ensure the directory containing mscorlib is provided with the -L option. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.ru.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.ru.resx new file mode 100644 index 00000000000..d9cd71eaab6 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.ru.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Ошибка при загрузке сборки: "{0}". + {0} - File name + + + Сбой удаления старых констант: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Сбой обработки сопоставления перечисления. Текстовая строка: {0}. + {0} - The line that could not be processed. + + + Ошибка при обработке исправления метаданных: {0}. + {0} - The error encountered. + + + Недопустимая спецификация XPath: {0}. + {0} - The invalid XPath line. + + + Имя целевого атрибута не указано для пути: {0}. + {0} - The invalid XPath line. + + + Неожиданная спецификация "global::". Эта ошибка происходит, если, например, "global::" указан в файле преобразования Metadata.xml. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Непредвиденный дочерний класс {0}. + {0} - The unexpected child class. + + + Класс "{0}" имеет неизвестный базовый тип "{1}". + {0}, {1} - .NET types. + + + Класс "{0}" имеет недопустимый базовый тип "{1}". + {0}, {1} - .NET types. + + + Не удалось проанализировать сборку "{0}": {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + Для конструктора "{0}" не удалось найти вложенный тип "{1}". + {0} - .NET constructor method. +{1} - .NET type. + + + Непредвиденный тип поля "{0}" ({1}). + {0} - .NET type. +{1} - .NET field signature. + + + Пропуск "{0}.{1}" из-за дублирования имени метода. (Тип Java: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Пропуск "{0}.{1}" из-за дублирования имени вложенного типа. (Тип Java: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Пропуск "{0}.{1}" из-за дублирования имени поля или свойства. (Тип Java: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Пропуск "{0}.{1}" из-за дублирования поля. (Тип Java: "{2}") + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Тип "{0}" имеет имя типа, соответствующее имени вложенного пространства имен. Подробнее см. https://aka.ms/BG8403. + {0} - Java type. + + + Непредвиденный элемент "<interface>": "{0}". + {0} - XML element name. +<interface> should not be translated. + + + Имя события не указано в "{0}.{1}". + {0} - .NET type name +{1} - .NET member. + + + Аннулирование "{0}" и всех его вложенных типов из-за недопустимости некоторых его интерфейсов. + {0} - .NET type name. + + + Аннулирование "{0}" и всех его вложенных типов из-за недопустимых методов. + {0} - .NET type name. + + + Недопустимое имя события для "{0}.{1}". Допустимые "eventName" или "argsType" можно назначить, добавив правило в файл преобразований Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Недопустимое имя свойства события для "{0}.{1}". Допустимое значение "eventName" или "argsType" можно назначить, добавив правило в файл преобразований Metadata.xml. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + Недопустимый XML-файл "{0}": {1}. + {0} - File name +{1} - The error encountered. + + + Элементы "<package>" не найдены. + The following terms should not be translated: <package>. + + + Непредвиденный корневой дочерний узел: "<{0}>". + {0} - XML element name. + + + Непредвиденный дочерний узел "<package>": "<{0}>". + {0} - XML element name. +The following terms should not be translated: <package>. + + + Не удалось найти тип верхнего предка "{0}" для вложенного типа "{1}". + {0}, {1} - .NET types. + + + Не удалось найти тип Java "{0}" (может быть, вам не хватает справочного файла jar/aar Java или библиотеки привязки Java NuGet?) + {0} - Java type. + + + Некоторые типы или элементы не могут быть связаны, так как не удается найти ссылочные типы Java. Подробности в файле java-resolution-report.log. + The following terms should not be translated: java-resolution-report.log + + + Неизвестный тип возврата "{0}" для элемента "{1}". + {0} - Java type. +{1} - .NET member. + + + Недопустимый тип возврата "{0}" для элемента "{1}". + {0} - Java type. +{1} - .NET member. + + + Неизвестный тип параметра "{0}" для элемента "{1}". + {0} - Java type. +{1} - .NET member. + + + Недопустимый тип параметра "{0}" для элемента "{1}". + {0} - Java type. +{1} - .NET member. + + + Для элемента Metadata.xml "{0}" нет соответствующего узла. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + Недопустимое преобразование пространства имен "{0}" + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + В элементе Metadata.xml "{0}" отсутствует атрибут "path". + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + Неизвестный универсальный тип ограничения аргумента "{0}" для элемента "{1}". + {0} - .NET type name +{1} - .NET member. + + + Не удалось найти базовый интерфейс "{1}" для типа "{0}". + {0}, {1} - .NET types. + + + Для типа "{0}" базовый интерфейс "{1}" является недопустимым. + {0}, {1} - .NET types. + + + Не удается создать оболочку Java для типа "{0}". Поддерживаются только типы "class". + {0} - Java type. +The following terms should not be translated: +class. + + + Не удается определить имя JNI для типа "{0}". + {0} - Java type. +The following terms should not be translated: JNI. + + + Свойство "Name" должно иметь полный тип, например "com.example.MyClass", и пакет для "{0}" не найден. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + Не удалось разрешить тип интерфейса "{0}". Отсутствует ссылка на сборку? + {0} - Java interface. + + + [ExportField] можно использовать только для методов с 0 параметрами. + The following terms should not be translated: [ExportField]. + + + [Export] нельзя использовать для универсального типа. + The following terms should not be translated: [Export]. + + + [ExportField] нельзя использовать для универсального типа. + The following terms should not be translated: [ExportField]. + + + [ExportField] нельзя использовать для метода, возвращающего "void". + The following terms should not be translated: [ExportField], void. + + + Невозможно переопределить сгенерированный Kotlin метод "{0}", так как это недопустимое имя метода Java. Этот метод можно переопределить только из Kotlin. + {0} - Kotlin method name. + + + Не удалось предварительно загрузить ссылку "{0}". + {0} - assembly path + + + Укажите по крайней мере одну СБОРКУ для обработки. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Не удалось создать Java VM{0}{1} + {0} - newline, {1} - exception + + + Не удалось прочитать файл профиля "{0}".{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + Путь "{0}" не существует + {0} - path + + + Не удалось обработать сборку "{0}"{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + Не удается найти интерфейс {0} + {0} - interface name + + + Перехвачено исключение при загрузке типов. Типы, которые невозможно загрузить, не будут обработаны. Убедитесь, что любые дополнительные ссылки на сборки, необходимые для этих типов, предоставляются с помощью параметра -r. Исключение:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + Не удалось найти тип "{0}". Тип не будет обработан. Убедитесь, что каталоги для всех сборок, на которые есть ссылки, предоставляются с параметром -L. + {0} - type +The following terms should not be translated: -L + + + Тип методов маршалирования "{0}" уже существует. Пропущено поколение методов маршалирования в сборке "{1}". При желании используйте -f для принудительного повторного создания. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Не удалось найти определение метода "{0}" в метаданных сборки. Он не будет обработан. Убедитесь, что каталоги для всех сборок, на которые есть ссылки, предоставляются с параметром -L. + {0} - method +The following terms should not be translated: -L + + + Не удалось найти метод System.Console.WriteLine(). Отключение внедрения отладки. Чтобы включить внедрение отладки, убедитесь, что каталог, содержащий mscorlib, указан с параметром -L. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.tr.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.tr.resx new file mode 100644 index 00000000000..9582d46d249 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.tr.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Derleme yüklenirken hata oluştu: '{0}'. + {0} - File name + + + Eski sabitler kaldırılamadı: {0}. + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + Sabit listesi eşlemesi işlenemedi. Metin satırı: {0}. + {0} - The line that could not be processed. + + + Meta veri düzeltmesi işlenirken hata oluştu: {0}. + {0} - The error encountered. + + + Geçersiz XPath belirtimi: {0}. + {0} - The invalid XPath line. + + + Yol için hedef öznitelik adı belirtilmedi: {0}. + {0} - The invalid XPath line. + + + Beklenmeyen 'global::' belirtimi. Bu hata, örneğin Metadata.xml dönüşüm dosyasında 'global::' belirtilirse oluşur. + The following are literal names and should not be translated: global::, Metadata.xml. + + + Beklenmeyen sınıf alt öğesi: {0}. + {0} - The unexpected child class. + + + '{0}' sınıfı, bilinmeyen '{1}' temel türüne sahip. + {0}, {1} - .NET types. + + + '{0}' sınıfı, geçersiz '{1}' temel türüne sahip. + {0}, {1} - .NET types. + + + '{0}' derlemesi ayrıştırılamadı: {1}. + {0} - Error .NET assembly. +{1} - The error encountered. + + + '{0}' oluşturucusu için, '{1}' kapsayan türü bulunamadı. + {0} - .NET constructor method. +{1} - .NET type. + + + Beklenmeyen alan türü `{0}` ({1}). + {0} - .NET type. +{1} - .NET field signature. + + + Yinelenen bir yöntem adı nedeniyle '{0}.{1}' atlanıyor. (Java türü: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Yinelenen bir içe geçmiş tür adı nedeniyle '{0}.{1}' atlanıyor. (Java türü: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Yinelenen bir alan veya özellik adı nedeniyle '{0}.{1}' atlanıyor. (Java türü: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + Yinelenen bir alan nedeniyle '{0}.{1}' atlanıyor. (Java türü: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + '{0}' türü, kapsayan ad alanı adıyla eşleşen bir tür adına sahip. Daha fazla bilgi edinmek için bkz. https://aka.ms/BG8403. + {0} - Java type. + + + Beklenmeyen '<interface>' alt öğesi: '{0}'. + {0} - XML element name. +<interface> should not be translated. + + + '{0}.{1}' içinde sağlanmış olay adı yok. + {0} - .NET type name +{1} - .NET member. + + + Bazı arabirimleri geçersiz olduğundan '{0}' ve tüm içe geçmiş türleri geçersiz kılınıyor. + {0} - .NET type name. + + + Bazı yöntemleri geçersiz olduğundan '{0}' ve tüm içe geçmiş türleri geçersiz kılınıyor. + {0} - .NET type name. + + + '{0}.{1}' için olay adı geçersiz. Metadata.xml dönüşümleri dosyasına bir kural eklenerek geçerli bir 'eventName' veya 'argsType' atanabilir. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + '{0}.{1}' için olay özelliği adı geçersiz. Metadata.xml dönüşümleri dosyasına bir kural eklenerek geçerli bir 'eventName' veya 'argsType' atanabilir. + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + '{0}' XML dosyası geçersiz: {1}. + {0} - File name +{1} - The error encountered. + + + '<package>' öğeleri bulunamadı. + The following terms should not be translated: <package>. + + + Beklenmeyen kök alt düğüm: '<{0}>'. + {0} - XML element name. + + + Beklenmeyen '<package>' alt düğümü: '<{0}>'. + {0} - XML element name. +The following terms should not be translated: <package>. + + + '{1}' iç içe geçmiş türü için '{0}' üst türü bulunamadı. + {0}, {1} - .NET types. + + + '{0}' Java türü bulunamadı (Java başvuru JAR/AAR veya Java bağlama kitaplığı NuGet paketleri eksik mi?) + {0} - Java type. + + + Başvurulan Java türleri bulunamadığından bazı türler veya üyeler bağlanamadı. Ayrıntılar için 'java-resolution-report.log' dosyasına bakın. + The following terms should not be translated: java-resolution-report.log + + + '{1}' üyesi için '{0}' dönüş türü bilinmiyor. + {0} - Java type. +{1} - .NET member. + + + '{1}' üyesi için '{0}' dönüş türü geçersiz. + {0} - Java type. +{1} - .NET member. + + + '{1}' üyesi için '{0}' parametre türü bilinmiyor. + {0} - Java type. +{1} - .NET member. + + + '{1}' üyesi için '{0}' parametre türü geçersiz. + {0} - Java type. +{1} - .NET member. + + + '{0}' Metadata.xml öğesi hiçbir düğümle eşleşmedi. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + '{0}' ad alanı dönüşümü geçersiz. + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + '{0}' Metadata.xml öğesinde 'path' özniteliği yok. + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + '{1}' üyesi için '{0}' genel bağımsız değişken kısıtlama türü bilinmiyor. + {0} - .NET type name +{1} - .NET member. + + + '{0}' türü için '{1}' temel arabirimi bulunamadı. + {0}, {1} - .NET types. + + + '{0}' türü için '{1}' temel arabirimi geçersiz. + {0}, {1} - .NET types. + + + '{0}' türü için Java sarmalayıcı oluşturulamıyor. Yalnızca 'class' türleri desteklenir. + {0} - Java type. +The following terms should not be translated: +class. + + + '{0}' türü için JNI adı belirlenemiyor. + {0} - Java type. +The following terms should not be translated: JNI. + + + 'Name' özelliği 'com.example.MyClass' gibi tam bir tür olmalıdır ve '{0}' için paket bulunamadı. + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + '{0}' arabirim türü çözümlenemiyor. Derleme başvurusu eksik mi? + {0} - Java interface. + + + [ExportField] yalnızca 0 parametreli yöntemlerde kullanılabilir. + The following terms should not be translated: [ExportField]. + + + [Export] genel türde kullanılamaz. + The following terms should not be translated: [Export]. + + + [ExportField] genel türde kullanılamaz. + The following terms should not be translated: [ExportField]. + + + [ExportField] 'void' döndüren bir yöntemde kullanılamaz. + The following terms should not be translated: [ExportField], void. + + + Geçerli bir Java yöntem adı olmadığından Kotlin’de oluşturulan '{0}' yöntemi geçersiz kılınamıyor. Bu yöntem yalnızca Kotlin'den geçersiz kılınabilir. + {0} - Kotlin method name. + + + '{0}' başvurusu önceden yüklenemiyor. + {0} - assembly path + + + Lütfen işlemek için en az bir ASSEMBLY belirtin. + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + Java VM hesabı oluşturulamıyor{0}{1} + {0} - newline, {1} - exception + + + '{0}' profil dosyası okunamıyor.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + '{0}' yolu yok. + {0} - path + + + '{0}' derlemesi işlenemiyor{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + {0} arabirimi bulunamadı. + {0} - interface name + + + Türler yüklenirken bir özel durum yakalandı. Yüklenemeyen türler işlenmeyecek. Bu türler için gereken ek derleme başvurularının -r seçeneği kullanılarak sağlanmış olduğundan emin olun. Özel durum:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + '{0}' türü bulunamıyor. Tür işlenmeyecek. Başvurulan tüm derlemelere ait dizinlerin -L seçeneğiyle sağlanmış olduğundan emin olun. + {0} - type +The following terms should not be translated: -L + + + '{0}' türü sıralama yöntemleri zaten var. '{1}' adlı derlemede sıralama yöntemlerinin oluşturulması atlandı. İstendiğinde yeniden oluşturmayı zorlamak için -f kullanın. + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + Derleme meta verilerinde '{0}' yönteminin tanımı bulunamıyor. İşlenmeyecek. Başvurulan tüm derlemelere ait dizinlerin -L seçeneğiyle sağlanmış olduğundan emin olun. + {0} - method +The following terms should not be translated: -L + + + System.Console.WriteLine() yöntemi bulunamıyor. Hata ayıklama ekleme devre dışı bırakılıyor. Hata ayıklama eklemeyi etkinleştirmek için mscorlib içeren dizinin -L seçeneğiyle sağlanmış olduğundan emin olun. + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.zh-Hans.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.zh-Hans.resx new file mode 100644 index 00000000000..edb4705ffa6 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.zh-Hans.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 加载程序集“{0}”时出错。 + {0} - File name + + + 无法删除旧常量: {0}。 + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + 无法处理枚举映射。文本行: {0}。 + {0} - The line that could not be processed. + + + 处理元数据修复期间出错: {0}。 + {0} - The error encountered. + + + XPath 规范无效: {0}。 + {0} - The invalid XPath line. + + + 没有为路径 {0} 指定目标属性名称。 + {0} - The invalid XPath line. + + + 意外的 “global::” 规范。例如,如果在 Metadata.xml 转换文件中指定了 “global::”,则会发生此错误。 + The following are literal names and should not be translated: global::, Metadata.xml. + + + 意外的类子级 {0}。 + {0} - The unexpected child class. + + + 类“{0}”具有未知的基类型“{1}”。 + {0}, {1} - .NET types. + + + 类“{0}”具有无效的基类型“{1}”。 + {0}, {1} - .NET types. + + + 无法分析程序集“{0}”: {1}。 + {0} - Error .NET assembly. +{1} - The error encountered. + + + 对于构造函数“{0}”,找不到封闭类型“{1}”。 + {0} - .NET constructor method. +{1} - .NET type. + + + 意外的字段类型 `{0}` ({1})。 + {0} - .NET type. +{1} - .NET field signature. + + + 由于方法名称重复,正在跳过“{0}.{1}”。(Java 类型:“{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 由于嵌套类型名称重复,正在跳过“{0}.{1}”。(Java 类型:“{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 由于字段或属性名称重复,正在跳过“{0}.{1}”。(Java 类型:“{2}”) + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 由于字段重复,正在跳过“{0}.{1}”。(Java 类型:“{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 类型“{0}”具有与封闭命名空间名称匹配的类型名称。有关详细信息,请参阅 https://aka.ms/BG8403。 + {0} - Java type. + + + “<interface>”的意外子元素:“{0}”。 + {0} - XML element name. +<interface> should not be translated. + + + “{0}.{1}”中未提供任何事件名称。 + {0} - .NET type name +{1} - .NET member. + + + 正在使“{0}”及其所有嵌套类型失效,因为其某些接口无效。 + {0} - .NET type name. + + + 正在使“{0}”及其所有嵌套类型失效,因为其某些方法无效。 + {0} - .NET type name. + + + “{0}.{1}”的事件名称无效。可以通过将规则添加到 Metadata.xml 转换文件来分配有效的 “eventName” 或 “argsType”。 + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + “{0}.{1}”的事件属性名称无效。可以通过将规则添加到 Metadata.xml 转换文件来分配有效的 “eventName” 或 “argsType”。 + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + XML 文件“{0}”无效: {1}。 + {0} - File name +{1} - The error encountered. + + + 找不到“<package>”元素。 + The following terms should not be translated: <package>. + + + 意外的根子节点:“<{0}>”。 + {0} - XML element name. + + + 意外的“<package>”子节点:“<{0}>”。 + {0} - XML element name. +The following terms should not be translated: <package>. + + + 找不到嵌套类型“{1}”的顶级上级类型“{0}”。 + {0}, {1} - .NET types. + + + 找不到 Java 类型“{0}”(是否缺少 Java 引用 jar/aar 或 Java 绑定库 NuGet?) + {0} - Java type. + + + 无法绑定某些类型或成员,因为找不到引用的 Java 类型。有关详细信息,请参阅 “java-resolution-report.log” 文件。 + The following terms should not be translated: java-resolution-report.log + + + 成员“{1}”的返回类型“{0}”未知。 + {0} - Java type. +{1} - .NET member. + + + 成员“{1}”的返回类型“{0}”无效。 + {0} - Java type. +{1} - .NET member. + + + 成员“{1}”的参数类型“{0}”未知。 + {0} - Java type. +{1} - .NET member. + + + 成员“{1}”的参数类型“{0}”无效。 + {0} - Java type. +{1} - .NET member. + + + Metadata.xml 元素“{0}”不匹配任何节点。 + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + 命名空间转换“{0}”无效 + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Metadata.xml 元素 "{0}" 缺少 "path" 属性。 + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + 成员“{1}”的泛型参数约束类型“{0}”未知。 + {0} - .NET type name +{1} - .NET member. + + + 找不到类型“{0}”的基接口“{1}”。 + {0}, {1} - .NET types. + + + 对于类型“{0}”,基接口“{1}”无效。 + {0}, {1} - .NET types. + + + 无法为类型“{0}”生成 Java 包装器。仅支持 “class” 类型。 + {0} - Java type. +The following terms should not be translated: +class. + + + 无法确定类型“{0}”的 JNI 名称。 + {0} - Java type. +The following terms should not be translated: JNI. + + + “Name” 属性必须是完全限定的类型,如 “com.example.MyClass”,并且找不到“{0}”的包。 + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + 无法解析接口类型“{0}”。是否缺少程序集引用? + {0} - Java interface. + + + [ExportField] 只能用于具有 0 个参数的方法。 + The following terms should not be translated: [ExportField]. + + + [Export] 不能用于泛型类型。 + The following terms should not be translated: [Export]. + + + [ExportField] 不能用于泛型类型。 + The following terms should not be translated: [ExportField]. + + + [ExportField] 不能用于返回 “void” 的方法。 + The following terms should not be translated: [ExportField], void. + + + 无法替代 Kotlin 生成的方法“{0}”,因为它不是有效的 Java 方法名称。只能从 Kotlin 替代此方法。 + {0} - Kotlin method name. + + + 无法预加载引用“{0}”。 + {0} - assembly path + + + 请至少指定一个要处理的程序集。 + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + 无法创建 Java VM{0}{1} + {0} - newline, {1} - exception + + + 无法读取配置文件“{0}”。{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + 路径“{0}”不存在。 + {0} - path + + + 无法处理程序集“{0}”{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + 找不到接口 {0} + {0} - interface name + + + 加载类型时捕获到异常。将不处理无法加载的类型。请确保使用 -r 选项提供这些类型所需的任何其他程序集引用。异常:{0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + 找不到类型“{0}”。将不会处理该类型。确保使用 -L 选项提供所有引用的程序集的目录。 + {0} - type +The following terms should not be translated: -L + + + 封送方法类型“{0}”已存在。已跳过程序集“{1}”中封送方法的生成。在需要时使用 -f 强制重新生成。 + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + 在程序集元数据中找不到方法“{0}”的定义。将不会处理它。确保使用 -L 选项提供所有引用的程序集的目录。 + {0} - method +The following terms should not be translated: -L + + + 找不到 System.Console.WriteLine() 方法。正在禁用调试注入。要启用调试注入,请确保使用 -L 选项提供包含 mscorlib 的目录。 + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Localization/Resources.zh-Hant.resx b/external/Java.Interop/src/Java.Interop.Localization/Resources.zh-Hant.resx new file mode 100644 index 00000000000..900a23bb780 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Localization/Resources.zh-Hant.resx @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 載入組件: '{0}' 時發生錯誤。 + {0} - File name + + + 無法移除舊的常數: {0}。 + {0} - The list of constants that could not be removed. +In this message, the term "constants" refers to class or interface members that have constant values. + + + 無法處理列舉對應。文字行: {0}。 + {0} - The line that could not be processed. + + + 處理中繼資料修復期間發生錯誤: {0}。 + {0} - The error encountered. + + + 無效的 XPath 規格: {0}。 + {0} - The invalid XPath line. + + + 未指定路徑的目標屬性名稱: {0}。 + {0} - The invalid XPath line. + + + 未預期的 'global::' 規格。例如,如果在 Metadata.xml 轉換檔案中指定了 'global::',就會發生此錯誤。 + The following are literal names and should not be translated: global::, Metadata.xml. + + + 未預期的類別子系 {0}。 + {0} - The unexpected child class. + + + 類別 '{0}' 具有未知的基底型別 '{1}'。 + {0}, {1} - .NET types. + + + 類別 '{0}' 的基底型別 '{1}' 無效。 + {0}, {1} - .NET types. + + + 無法剖析組件 '{0}': {1}。 + {0} - Error .NET assembly. +{1} - The error encountered. + + + 對於建構函式 '{0}',找不到封閉型別 '{1}'。 + {0} - .NET constructor method. +{1} - .NET type. + + + 未預期的欄位型別 '{0}' ({1})。 + {0} - .NET type. +{1} - .NET field signature. + + + 因為方法名稱重複,所以略過 '{0}.{1}'。(JAVA 型別: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 因為巢狀類型名稱重複,所以略過 '{0}.{1}'。(JAVA 型別: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 因為欄位或屬性名稱重複,所以略過 '{0}.{1}'。(JAVA 型別: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 因為欄位重複,所以略過 '{0}.{1}'。(JAVA 型別: '{2}') + {0} - .NET type. +{1} - .NET field name. +{2} - Java type. + + + 型別 '{0}' 具有符合封閉命名空間名稱的型別名稱。如需詳細資訊,請參閱 https://aka.ms/BG8403。 + {0} - Java type. + + + 未預期的 '<interface>' 子項目: '{0}'。 + {0} - XML element name. +<interface> should not be translated. + + + '{0}.{1}' 中未提供事件名稱。 + {0} - .NET type name +{1} - .NET member. + + + 正在使 '{0}' 及其所有巢狀型別失效,因為其某些介面無效。 + {0} - .NET type name. + + + 正在使 '{0}' 及其所有巢狀型別失效,因為其某些方法無效。 + {0} - .NET type name. + + + '{0}.{1}' 的事件名稱無效。將規則新增至 Metadata.xml 轉換檔案,即可指派有效的 'eventName' 或 'argsType'。 + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + '{0}.{1}' 的事件屬性名稱無效。將規則新增至 Metadata.xml 轉換檔案,即可指派有效的 'eventName' 或 'argsType'。 + {0} - .NET type name +{1} - .NET member. +The following terms should not be translated: eventName, argsType, Metadata.xml. + + + 無效的 XML 檔案'{0}': {1}。 + {0} - File name +{1} - The error encountered. + + + 找不到 '<package>' 元素。 + The following terms should not be translated: <package>. + + + 未預期的根子節點: '<{0}>'。 + {0} - XML element name. + + + 未預期的 '<package>' 子節點: '<{0}>'。 + {0} - XML element name. +The following terms should not be translated: <package>. + + + 找不到巢狀型別 '{1}' 的上階型別 '{0}'。 + {0}, {1} - .NET types. + + + 找不到 JAVA 型別 '{0}' (您是否遺漏 JAVA 參考 jar/aar 或 JAVA 繫結程式庫 NuGet?) + {0} - Java type. + + + 因為找不到參照的 JAVA 型別,所以無法繫結某些型別或成員。如需詳細資料,請參閱 'java-resolution-report.log' 檔案。 + The following terms should not be translated: java-resolution-report.log + + + 成員 '{1}' 的傳回型別 '{0}' 未知。 + {0} - Java type. +{1} - .NET member. + + + 成員 '{1}' 的傳回型別 '{0}' 無效。 + {0} - Java type. +{1} - .NET member. + + + 成員 '{1}' 的參數型別 '{0}' 未知。 + {0} - Java type. +{1} - .NET member. + + + 成員 '{1}' 的參數型別 '{0}' 無效。 + {0} - Java type. +{1} - .NET member. + + + Metadata.xml 元素 '{0}' 與節點相符。 + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml. + + + 命名空間轉換 '{0}' 無效 + {0} - XML transform. (example: '<ns-replace source="example" replacement="Example" />') + + + Metadata.xml 元素 '{0}' 遺漏 'path' 屬性。 + {0} - XML transform. (example: '<remove-node path="/api/package[@name='javax.sql']"') +The following terms should not be translated: Metadata.xml, path. + + + 成員 '{1}' 的未知泛型引數限制式型別 '{0}'。 + {0} - .NET type name +{1} - .NET member. + + + 找不到型別 '{0}' 的基底介面 '{1}'。 + {0}, {1} - .NET types. + + + 針對型別 '{0}',基底介面 '{1}' 無效。 + {0}, {1} - .NET types. + + + 無法產生型別 '{0}' 的 JAVA 包裝函式。只支援 'class' 型別。 + {0} - Java type. +The following terms should not be translated: +class. + + + 無法判斷型別 '{0}' 的 JNI 名稱。 + {0} - Java type. +The following terms should not be translated: JNI. + + + 'Name' 屬性必須是如 'com.example.MyClass' 的完整型別,但找不到 '{0}' 的套件。 + {0} - Java type. +The following terms should not be translated: +Name, com.example.MyClass. + + + 無法解析介面型別 '{0}'。您是否遺失組件參考? + {0} - Java interface. + + + [ExportField] 只能在具有 0 個參數的方法上使用。 + The following terms should not be translated: [ExportField]. + + + [Export] 無法用於泛型型別。 + The following terms should not be translated: [Export]. + + + [Export] 無法用於泛型型別。 + The following terms should not be translated: [ExportField]. + + + [ExportField] 無法用於傳回 'void' 的方法。 + The following terms should not be translated: [ExportField], void. + + + 無法覆寫 Kotlin 產生的方法 '{0}',因為它不是有效的 JAVA 方法名稱。此方法只能從 Kotlin 覆寫。 + {0} - Kotlin method name. + + + 無法預先載入參考 '{0}'。 + {0} - assembly path + + + 請至少指定一個要處理的組件。 + The following terms should not be translated or have any capitalization changes: ASSEMBLY. This is a special case for this particular message. In most messages, "assembly" would be translated. + + + 無法建立 JAVA VM{0}{1} + {0} - newline, {1} - exception + + + 無法讀取設定檔檔案 '{0}'.{1}{2} + {0} - path, {1} - newline, {2} - exception. In this message, the term "profile" refers to a customized list of types to process. + + + 路徑 '{0}' 不存在。 + {0} - path + + + 無法處理組件 '{0}'{1}{2}{1}{3} + {0} - assembly, {1} - newline, {2} - exception message, {3} exception + + + 找不到介面 {0} + {0} - interface name + + + 載入型別時發生例外狀況。將不會處理無法載入的型別。請確定已使用 -r 選項提供這些型別所需的任何其他組件參考。例外狀況: {0}{1} + {0} - newline, {1} - exception. The following terms should not be translated: -r + + + 找不到型別 '{0}'。型別將不會處理。請確定所有參考組件的目錄都是以 -L 選項提供。 + {0} - type +The following terms should not be translated: -L + + + 封送處理方法型別 '{0}' 已存在。已略過在組件 '{1}' 中產生封送處理方法。使用 -f 在需要時強制重新產生。 + {0} - type, {1} - assembly name. The following terms should not be translated: -f. In this message, the term "marshal methods" refers to methods that allow interaction between the managed methods and Java methods, similar to the methods of the .NET System.Runtime.InteropServices.Marshal class. + + + 在組件中繼資料中找不到方法 '{0}' 的定義。將不會處理。請確定所有參考組件的目錄都是以 -L 選項提供。 + {0} - method +The following terms should not be translated: -L + + + 找不到 System.Console.WriteLine() 方法。正在停用偵錯插入。若要啟用偵錯插入,請確認已使用 -L 選項提供包含 mscorlib 的目錄。 + The following terms should not be translated: -L + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs new file mode 100644 index 00000000000..caa417936e8 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs @@ -0,0 +1,65 @@ +#nullable enable + +using System; + +using Mono.Cecil; + +namespace Android.Runtime { + + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Property)] +#if !JCW_ONLY_TYPE_NAMES + public +#endif // !JCW_ONLY_TYPE_NAMES + sealed class RegisterAttribute : Attribute, Java.Interop.IJniNameProviderAttribute { + + string? connector; + string name; + string? signature; + + public RegisterAttribute (string name) + { + this.name = name; + } + + public RegisterAttribute (string name, string signature, string connector) + : this (name) + { + this.connector = connector; + this.signature = signature; + } +#if HAVE_CECIL + public RegisterAttribute (string name, CustomAttribute? originAttribute) + : this (name) + { + OriginAttribute = originAttribute; + } + + public RegisterAttribute (string name, string signature, string connector, CustomAttribute? originAttribute) + : this (name, signature, connector) + { + OriginAttribute = originAttribute; + } + + public CustomAttribute? OriginAttribute { get; } +#endif // HAVE_CECIL + + public string? Connector { + get { return connector; } + set { connector = value; } + } + + public string Name { + get { return name; } + set { name = value; } + } + + public string? Signature { + get { return signature; } + set { signature = value; } + } + + public bool DoNotGenerateAcw {get; set;} + + public int ApiSince {get; set;} + } +} diff --git a/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop.NamingCustomAttributes.projitems b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop.NamingCustomAttributes.projitems new file mode 100644 index 00000000000..42892e984ea --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop.NamingCustomAttributes.projitems @@ -0,0 +1,22 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {FE789F04-5E95-42C5-AEF1-E33F8DF06B3F} + + + Java.Interop.NamingCustomAttributes + + + + + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportAttribute.cs b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportAttribute.cs new file mode 100644 index 00000000000..c2ef7ce00b4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportAttribute.cs @@ -0,0 +1,32 @@ +#nullable enable + +using System; + +namespace Java.Interop { + + [Serializable] + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor, + AllowMultiple=false, + Inherited=false)] +#if !JCW_ONLY_TYPE_NAMES + public +#endif // !JCW_ONLY_TYPE_NAMES + partial class ExportAttribute : Attribute { + + public ExportAttribute () + { + } + + public ExportAttribute (string? name) + { + Name = name; + } + + public string? Name {get; private set;} + public string? SuperArgumentsString {get; set;} + public Type []? Throws {get; set;} + internal string []? ThrownNames {get; set;} // msbuild internal use + } +} + + diff --git a/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportFieldAttribute.cs b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportFieldAttribute.cs new file mode 100644 index 00000000000..753406e2633 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportFieldAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace Java.Interop { + + [Serializable] + [AttributeUsage (AttributeTargets.Method, + AllowMultiple=false, + Inherited=false)] +#if !JCW_ONLY_TYPE_NAMES + public +#endif // !JCW_ONLY_TYPE_NAMES + partial class ExportFieldAttribute : Attribute { + + public ExportFieldAttribute (string name) + { + Name = name; + } + + public string Name {get; set;} + } +} + + diff --git a/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportParameterAttribute.cs b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportParameterAttribute.cs new file mode 100644 index 00000000000..ea6ceb6199d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportParameterAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace Java.Interop { + + [Serializable] + [AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue, + AllowMultiple=false, + Inherited=false)] +#if !JCW_ONLY_TYPE_NAMES + public +#endif // !JCW_ONLY_TYPE_NAMES + partial class ExportParameterAttribute : Attribute { + + public ExportParameterAttribute (ExportParameterKind kind) + { + Kind = kind; + } + + public ExportParameterKind Kind { get; private set; } + } +} + + diff --git a/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportParameterKind.cs b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportParameterKind.cs new file mode 100644 index 00000000000..b3c9b5e2b37 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/ExportParameterKind.cs @@ -0,0 +1,12 @@ +namespace Java.Interop { +#if !JCW_ONLY_TYPE_NAMES + public +#endif // !JCW_ONLY_TYPE_NAMES + enum ExportParameterKind { + Unspecified, + InputStream, + OutputStream, + XmlPullParser, + XmlResourceParser + } +} diff --git a/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/IJniNameProviderAttribute.cs b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/IJniNameProviderAttribute.cs new file mode 100644 index 00000000000..fb8e3c6babe --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.NamingCustomAttributes/Java.Interop/IJniNameProviderAttribute.cs @@ -0,0 +1,11 @@ +using System; +namespace Java.Interop +{ +#if !JCW_ONLY_TYPE_NAMES + public +#endif // !JCW_ONLY_TYPE_NAMES + interface IJniNameProviderAttribute + { + string Name { get; } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil.csproj b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil.csproj new file mode 100644 index 00000000000..949defc3ba9 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil.csproj @@ -0,0 +1,27 @@ + + + + netstandard2.0 + enable + true + ..\..\product.snk + + + + + + $(ToolOutputFullPath) + + + + + + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/CustomAttributeProviderRocks.cs b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/CustomAttributeProviderRocks.cs new file mode 100644 index 00000000000..11b49859397 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/CustomAttributeProviderRocks.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Mono.Cecil; + +namespace Java.Interop.Tools.Cecil { + + public static class CustomAttributeProviderRocks + { + public static bool AnyCustomAttributes (this ICustomAttributeProvider item, Type attribute) => + item.AnyCustomAttributes (attribute.FullName); + + public static IEnumerable GetCustomAttributes (this ICustomAttributeProvider item, Type attribute) + { + return item.GetCustomAttributes (attribute.FullName); + } + + public static bool AnyCustomAttributes (this ICustomAttributeProvider item, string attribute_fullname) + { + foreach (CustomAttribute custom_attribute in item.CustomAttributes) { + if (custom_attribute.Constructor.DeclaringType.FullName == attribute_fullname) + return true; + } + return false; + } + + public static IEnumerable GetCustomAttributes (this ICustomAttributeProvider item, string attribute_fullname) + { + foreach (CustomAttribute custom_attribute in item.CustomAttributes) { + if (custom_attribute.Constructor.DeclaringType.FullName != attribute_fullname) + continue; + + yield return custom_attribute; + } + } + + public static IEnumerable GetCustomAttributes (this IEnumerable items, Type attribute) + { + return items.GetCustomAttributes (attribute.FullName); + } + + public static IEnumerable GetCustomAttributes (this IEnumerable items, string attribute_fullname) + { + return items.SelectMany (e => e.GetCustomAttributes (attribute_fullname)); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs new file mode 100644 index 00000000000..0fd3c37e516 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs @@ -0,0 +1,354 @@ +// +// AssemblyResolver.cs +// +// Author: +// Jb Evain (jbevain@novell.com) +// Jonathan Pryor (jpryor@novell.com) +// +// (C) 2010 Novell, Inc. +// +// 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. +// + +using System; +using System.Diagnostics; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.IO.MemoryMappedFiles; +using System.Linq; +using System.Reflection; + +using Java.Interop.Tools.Diagnostics; + +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Java.Interop.Tools.Cecil { + + public static class AssemblyResolverCoda { + + public static AssemblyDefinition GetAssembly (this IAssemblyResolver resolver, string fileName) + { + return resolver.Resolve (AssemblyNameReference.Parse (Path.GetFileNameWithoutExtension (fileName))); + } + } + + /* + * IAssemblyResolver which looks for assembly references within + * DirectoryAssemblyResolver.SearchDirectories, in SearchDirectories order. + * + * Can't use Mono.Cecil.BaseAssemblyResolver as that special-cases + * mscorlib.dll and tries a directory based on + * `typeof (object).Module.FullyQualifiedName`, which will never be valid. + */ + public class DirectoryAssemblyResolver : IAssemblyResolver { + + public ICollection SearchDirectories {get; private set;} + + readonly List viewStreams = new List (); + Dictionary cache; + bool loadDebugSymbols; + Action logger; + + ReaderParameters loadReaderParameters; + + static readonly ReaderParameters DefaultLoadReaderParameters = new ReaderParameters { + }; + + [Obsolete ("Use DirectoryAssemblyResolver(Action, bool, ReaderParameters)")] + public DirectoryAssemblyResolver (Action logWarnings, bool loadDebugSymbols, ReaderParameters? loadReaderParameters = null) + : this ((TraceLevel level, string value) => logWarnings?.Invoke ("{0}", new[]{value}), loadDebugSymbols, loadReaderParameters) + { + if (logWarnings == null) + throw new ArgumentNullException (nameof (logWarnings)); + } + + public DirectoryAssemblyResolver (Action logger, bool loadDebugSymbols, ReaderParameters? loadReaderParameters = null) + { + if (logger == null) + throw new ArgumentNullException (nameof (logger)); + cache = new Dictionary (); + this.loadDebugSymbols = loadDebugSymbols; + this.logger = logger; + SearchDirectories = new List (); + this.loadReaderParameters = loadReaderParameters ?? DefaultLoadReaderParameters; + } + + public void Dispose () + { + Dispose (disposing: true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose (bool disposing) + { + if (!disposing || cache == null) + return; + foreach (var e in cache) { + e.Value?.Dispose (); + } + cache.Clear (); + foreach (var viewStream in viewStreams) { + viewStream.Dispose (); + } + viewStreams.Clear (); + } + + public Dictionary ToResolverCache () + { + return new Dictionary(cache); + } + + public bool AddToCache (AssemblyDefinition assembly) + { + var name = Path.GetFileNameWithoutExtension (assembly.MainModule.FileName); + + if (cache.ContainsKey (name)) + return false; + + cache [name] = assembly; + + return true; + } + + public virtual AssemblyDefinition? Load (string fileName, bool forceLoad = false) + { + AssemblyDefinition? assembly = null; + var name = Path.GetFileNameWithoutExtension (fileName); + if (!forceLoad && cache.TryGetValue (name, out assembly)) + return assembly; + + try { + assembly = ReadAssembly (fileName); + } catch (Exception e) when (e is FileNotFoundException || e is DirectoryNotFoundException) { + // These are ok, we can return null + return null; + } catch (Exception e) { + Diagnostic.Error (9, e, Localization.Resources.CecilResolver_XA0009, fileName); + } + cache [name] = assembly; + return assembly; + } + + protected virtual AssemblyDefinition ReadAssembly (string file) + { + var reader_parameters = new ReaderParameters () { + ApplyWindowsRuntimeProjections = loadReaderParameters.ApplyWindowsRuntimeProjections, + AssemblyResolver = this, + MetadataImporterProvider = loadReaderParameters.MetadataImporterProvider, + InMemory = loadReaderParameters.InMemory, + MetadataResolver = loadReaderParameters.MetadataResolver, + ReadingMode = loadReaderParameters.ReadingMode, + ReadWrite = loadReaderParameters.ReadWrite, + ReflectionImporterProvider = loadReaderParameters.ReflectionImporterProvider, + SymbolReaderProvider = loadReaderParameters.SymbolReaderProvider, + }; + try { + return LoadFromMemoryMappedFile (file, reader_parameters, loadDebugSymbols); + } catch (Exception ex) { + if (!loadDebugSymbols) + throw; + logger ( + TraceLevel.Verbose, + $"Failed to read '{file}' with debugging symbols. Retrying to load it without it. Error details are logged below."); + logger (TraceLevel.Verbose, ex.ToString ()); + reader_parameters.ReadSymbols = false; + return LoadFromMemoryMappedFile (file, reader_parameters, loadSymbols: false); + } finally { + reader_parameters.SymbolStream?.Dispose (); + } + } + + AssemblyDefinition LoadFromMemoryMappedFile (string file, ReaderParameters options, bool loadSymbols) + { + // We can't use MemoryMappedFile when ReadWrite is true + if (options.ReadWrite) { + if (loadSymbols) { + LoadSymbols (file, options, File.OpenRead); + } + return AssemblyDefinition.ReadAssembly (file, options); + } + + // We know the capacity for disposables + var disposables = new List ( + (1 + (loadSymbols ? 1 : 0)) * OpenMemoryMappedViewStream_disposables_Add_calls); + try { + if (loadSymbols) { + LoadSymbols (file, options, f => OpenMemoryMappedViewStream (f, disposables)); + } + + var viewStream = OpenMemoryMappedViewStream (file, disposables); + AssemblyDefinition result = ModuleDefinition.ReadModule (viewStream, options).Assembly; + + // Transfer ownership to `viewStreams` collection + viewStreams.Add (viewStream); + disposables.Remove (viewStream); + if (options.SymbolStream is MemoryMappedViewStream m) { + viewStreams.Add (m); + disposables.Remove (m); + options.SymbolStream = null; // Prevents caller from disposing + } + return result; + } finally { + for (int i = disposables.Count - 1; i >= 0; i--) { + disposables [i].Dispose (); + } + } + } + + static void LoadSymbols (string assemblyPath, ReaderParameters options, Func getStream) + { + var symbolStream = options.SymbolStream; + if (symbolStream == null) { + var symbolPath = Path.ChangeExtension (assemblyPath, ".pdb"); + if (File.Exists (symbolPath)) { + symbolStream = getStream (symbolPath); + } + } + options.ReadSymbols = symbolStream != null; + options.SymbolStream = symbolStream; + } + + /// + /// Number of times OpenMemoryMappedViewStream() calls disposables.Add() + /// + const int OpenMemoryMappedViewStream_disposables_Add_calls = 3; + + static MemoryMappedViewStream OpenMemoryMappedViewStream (string file, List disposables) + { + // Create stream because CreateFromFile(string, ...) uses FileShare.None which is too strict + var fileStream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, useAsync: false); + disposables.Add (fileStream); + + var mappedFile = MemoryMappedFile.CreateFromFile ( + fileStream, null, fileStream.Length, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: true); + disposables.Add (mappedFile); + + var viewStream = mappedFile.CreateViewStream (0, 0, MemoryMappedFileAccess.Read); + disposables.Add (viewStream); + + return viewStream; + } + + public AssemblyDefinition GetAssembly (string fileName) + { + return Resolve (Path.GetFileNameWithoutExtension (fileName)); + } + + public AssemblyDefinition Resolve (string fullName) + { + return Resolve (fullName, null); + } + + public AssemblyDefinition Resolve (string fullName, ReaderParameters? parameters) + { + return Resolve (AssemblyNameReference.Parse (fullName), parameters); + } + + public AssemblyDefinition Resolve (AssemblyNameReference reference) + { + return Resolve (reference, null); + } + + public string FindAssemblyFile (string fullName) + { + return FindAssemblyFile (AssemblyNameReference.Parse (fullName)); + } + + public string FindAssemblyFile (AssemblyNameReference reference) + { + var name = reference.Name; + + string? assembly; + foreach (var dir in SearchDirectories) + if ((assembly = SearchDirectory (name, dir)) != null) + return assembly; + + throw new System.IO.FileNotFoundException ( + string.Format ("Could not load assembly '{0}, Version={1}, Culture={2}, PublicKeyToken={3}'. Perhaps it doesn't exist in the Mono for Android profile?", + name, + reference.Version, + string.IsNullOrEmpty (reference.Culture) ? "neutral" : reference.Culture, + reference.PublicKeyToken == null + ? "null" + : string.Join ("", reference.PublicKeyToken.Select(b => b.ToString ("x2")))), + name + ".dll"); + } + + public AssemblyDefinition Resolve (AssemblyNameReference reference, ReaderParameters? parameters) + { + var name = reference.Name; + + AssemblyDefinition? assembly; + if (cache.TryGetValue (name, out assembly)) { + if (assembly is null) + throw CreateLoadException (reference); + + return assembly; + } + + string? assemblyFile; + AssemblyDefinition? candidate = null; + foreach (var dir in SearchDirectories) { + if ((assemblyFile = SearchDirectory (name, dir)) != null) { + var loaded = Load (assemblyFile); + if (Array.Equals (loaded?.Name.MetadataToken, reference.MetadataToken)) + return loaded; + candidate = candidate ?? loaded; + } + } + // signature mismatch, but return it as it used to do. + if (candidate != null) + return candidate; + + throw CreateLoadException (reference); + } + + static FileNotFoundException CreateLoadException (AssemblyNameReference reference) + { + return new System.IO.FileNotFoundException ( + string.Format ("Could not load assembly '{0}, Version={1}, Culture={2}, PublicKeyToken={3}'. Perhaps it doesn't exist in the Mono for Android profile?", + reference.Name, + reference.Version, + string.IsNullOrEmpty (reference.Culture) ? "neutral" : reference.Culture, + reference.PublicKeyToken == null + ? "null" + : string.Join ("", reference.PublicKeyToken.Select (b => b.ToString ("x2")))), + reference.Name + ".dll"); + } + + string? SearchDirectory (string name, string directory) + { + if (Path.IsPathRooted (name) && File.Exists (name)) + return name; + + var file = Path.Combine (directory, name + ".dll"); + if (File.Exists (file)) + return file; + + file = Path.Combine (directory, name + ".exe"); + if (File.Exists (file)) + return file; + + return null; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs new file mode 100644 index 00000000000..cdbdcaf0210 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace Java.Interop.Tools.Cecil { + + public static class MethodDefinitionRocks + { + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static MethodDefinition GetBaseDefinition (this MethodDefinition method) => throw new NotSupportedException (); + + public static MethodDefinition GetBaseDefinition (this MethodDefinition method, TypeDefinitionCache cache) => + GetBaseDefinition (method, (IMetadataResolver) cache); + + public static MethodDefinition GetBaseDefinition (this MethodDefinition method, IMetadataResolver resolver) + { + if (method.IsStatic || method.IsNewSlot || !method.IsVirtual) + return method; + + foreach (var baseType in method.DeclaringType.GetBaseTypes (resolver)) { + foreach (var m in baseType.Methods) { + if (!m.IsConstructor && + m.Name == method.Name && + (m.IsVirtual || m.IsAbstract) && + AreParametersCompatibleWith (m.Parameters, method.Parameters, resolver)) { + return m; + } + } + } + return method; + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static IEnumerable GetOverriddenMethods (MethodDefinition method, bool inherit) => throw new NotSupportedException (); + + public static IEnumerable GetOverriddenMethods (MethodDefinition method, bool inherit, TypeDefinitionCache cache) => + GetOverriddenMethods (method, inherit, (IMetadataResolver) cache); + + public static IEnumerable GetOverriddenMethods (MethodDefinition method, bool inherit, IMetadataResolver resolver) + { + yield return method; + if (inherit) { + MethodDefinition baseMethod = method; + while ((baseMethod = method.GetBaseDefinition (resolver)) != null && baseMethod != method) { + yield return method; + method = baseMethod; + } + } + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static bool AreParametersCompatibleWith (this Collection a, Collection b) => throw new NotSupportedException (); + + public static bool AreParametersCompatibleWith (this Collection a, Collection b, TypeDefinitionCache cache) => + AreParametersCompatibleWith (a, b, (IMetadataResolver) cache); + + public static bool AreParametersCompatibleWith (this Collection a, Collection b, IMetadataResolver resolver) + { + if (a.Count != b.Count) + return false; + + if (a.Count == 0) + return true; + + for (int i = 0; i < a.Count; i++) + if (!IsParameterCompatibleWith (a [i].ParameterType, b [i].ParameterType, resolver)) + return false; + + return true; + } + + static bool IsParameterCompatibleWith (IModifierType a, IModifierType b, IMetadataResolver cache) + { + if (!IsParameterCompatibleWith (a.ModifierType, b.ModifierType, cache)) + return false; + + return IsParameterCompatibleWith (a.ElementType, b.ElementType, cache); + } + + static bool IsParameterCompatibleWith (TypeSpecification a, TypeSpecification b, IMetadataResolver cache) + { + if (a is GenericInstanceType) + return IsParameterCompatibleWith ((GenericInstanceType) a, (GenericInstanceType) b, cache); + + if (a is IModifierType) + return IsParameterCompatibleWith ((IModifierType) a, (IModifierType) b, cache); + + return IsParameterCompatibleWith (a.ElementType, b.ElementType, cache); + } + + static bool IsParameterCompatibleWith (GenericInstanceType a, GenericInstanceType b, IMetadataResolver cache) + { + if (!IsParameterCompatibleWith (a.ElementType, b.ElementType, cache)) + return false; + + if (a.GenericArguments.Count != b.GenericArguments.Count) + return false; + + if (a.GenericArguments.Count == 0) + return true; + + for (int i = 0; i < a.GenericArguments.Count; i++) + if (!IsParameterCompatibleWith (a.GenericArguments [i], b.GenericArguments [i], cache)) + return false; + + return true; + } + + static bool IsParameterCompatibleWith (TypeReference a, TypeReference b, IMetadataResolver cache) + { + if (a is TypeSpecification || b is TypeSpecification) { + if (a.GetType () != b.GetType ()) + return false; + + return IsParameterCompatibleWith ((TypeSpecification) a, (TypeSpecification) b, cache); + } + + if (a.IsGenericParameter) { + if (b.IsGenericParameter && a.Name == b.Name) + return true; + var gpa = (GenericParameter) a; + foreach (var c in gpa.Constraints) { + if (!c.ConstraintType.IsAssignableFrom (b, cache)) + return false; + } + return true; + } + + return a.FullName == b.FullName; + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/NullableReferenceTypesRocks.cs b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/NullableReferenceTypesRocks.cs new file mode 100644 index 00000000000..d9cf70f36de --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/NullableReferenceTypesRocks.cs @@ -0,0 +1,121 @@ +using System; +using System.Linq; +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace Java.Interop.Tools.Cecil +{ + // Partial support for determining NRT status of method and field types. + // Reference: https://github.com/dotnet/roslyn/blob/main/docs/features/nullable-metadata.md + // The basics are supported, but advanced annotations like array elements, + // type parameters, and tuples are not supported. Our use case doesn't really need them. + public static class NullableReferenceTypesRocks + { + public static Nullability GetTypeNullability (this FieldDefinition field) + { + if (field.FieldType.FullName == "System.Void") + return Nullability.NotNull; + + // Look for explicit annotation on field + var metadata = NullableMetadata.FromAttributeCollection (field.CustomAttributes); + + if (metadata != null) + return (Nullability) metadata.Data [0]; + + // Default nullability status for type + return GetNullableContext (field.DeclaringType.CustomAttributes); + } + + public static Nullability GetReturnTypeNullability (this MethodDefinition method) + { + if (method.MethodReturnType.ReturnType.FullName == "System.Void") + return Nullability.NotNull; + + // Look for explicit annotation on return type + var metadata = NullableMetadata.FromAttributeCollection (method.MethodReturnType.CustomAttributes); + + if (metadata != null) + return (Nullability) metadata.Data [0]; + + // Default nullability status for method + var nullable = GetNullableContext (method.CustomAttributes); + + if (nullable != Nullability.Oblivous) + return nullable; + + // Default nullability status for type + return GetNullableContext (method.DeclaringType.CustomAttributes); + } + + public static Nullability GetTypeNullability (this ParameterDefinition parameter, MethodDefinition method) + { + if (parameter.ParameterType.FullName == "System.Void") + return Nullability.NotNull; + + // Look for explicit annotation on parameter + var metadata = NullableMetadata.FromAttributeCollection (parameter.CustomAttributes); + + if (metadata != null) + return (Nullability) metadata.Data [0]; + + // Default nullability status for method + var nullable = GetNullableContext (method.CustomAttributes); + + if (nullable != Nullability.Oblivous) + return nullable; + + // Default nullability status for type + return GetNullableContext (method.DeclaringType.CustomAttributes); + } + + static Nullability GetNullableContext (Collection attrs) + { + var attribute = attrs.FirstOrDefault (t => t.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute"); + + if (attribute != null) + return (Nullability) (byte) attribute.ConstructorArguments.First ().Value; + + return Nullability.Oblivous; + } + } + + public enum Nullability + { + Oblivous, + NotNull, + Nullable + } + + class NullableMetadata + { + public byte [] Data { get; private set; } + + NullableMetadata (byte [] data) => Data = data; + + NullableMetadata (byte data) => Data = new [] { data }; + + public static NullableMetadata? FromAttributeCollection (Collection attrs) + { + if (attrs is null) + return null; + + var attribute = attrs.FirstOrDefault (t => t.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute"); + + if (attribute is null) + return null; + + var ctor_arg = attribute.ConstructorArguments.First (); + + if (ctor_arg.Value is CustomAttributeArgument [] caa) + ctor_arg = caa [0]; + + if (ctor_arg.Value is byte b) + return new NullableMetadata (b); + + if (ctor_arg.Value is byte [] b2) + return new NullableMetadata (b2); + + return null; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionCache.cs b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionCache.cs new file mode 100644 index 00000000000..c402b44e578 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionCache.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Mono.Cecil; + +namespace Java.Interop.Tools.Cecil +{ + /// + /// A class for caching lookups from TypeReference -> TypeDefinition. + /// Generally its lifetime should match an AssemblyResolver instance. + /// + public class TypeDefinitionCache : IMetadataResolver + { + readonly Dictionary types = new Dictionary (); + readonly Dictionary fields = new Dictionary (); + readonly Dictionary methods = new Dictionary (); + + public virtual TypeDefinition? Resolve (TypeReference typeReference) + { + if (types.TryGetValue (typeReference, out var typeDefinition)) + return typeDefinition; + return types [typeReference] = typeReference.Resolve (); + } + + public virtual FieldDefinition? Resolve (FieldReference field) + { + if (fields.TryGetValue (field, out var fieldDefinition)) + return fieldDefinition; + return fields [field] = field.Resolve (); + } + + public virtual MethodDefinition? Resolve (MethodReference method) + { + if (methods.TryGetValue (method, out var methodDefinition)) + return methodDefinition; + return methods [method] = method.Resolve (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs new file mode 100644 index 00000000000..2873b4b7d6a --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; + +using Mono.Cecil; + +namespace Java.Interop.Tools.Cecil { + + public static class TypeDefinitionRocks { + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static TypeDefinition? GetBaseType (this TypeDefinition type) => throw new NotSupportedException (); + + public static TypeDefinition? GetBaseType (this TypeDefinition type, TypeDefinitionCache cache) => + GetBaseType (type, (IMetadataResolver) cache); + + public static TypeDefinition? GetBaseType (this TypeDefinition type, IMetadataResolver resolver) + { + var bt = type.BaseType; + if (bt == null) + return null; + return resolver.Resolve (bt); + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static IEnumerable GetTypeAndBaseTypes (this TypeDefinition type) => throw new NotSupportedException (); + + public static IEnumerable GetTypeAndBaseTypes (this TypeDefinition type, TypeDefinitionCache cache) => + GetTypeAndBaseTypes (type, (IMetadataResolver) cache); + + public static IEnumerable GetTypeAndBaseTypes (this TypeDefinition type, IMetadataResolver resolver) + { + TypeDefinition? t = type; + + while (t != null) { + yield return t; + t = t.GetBaseType (resolver); + } + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static IEnumerable GetBaseTypes (this TypeDefinition type) => throw new NotSupportedException(); + + public static IEnumerable GetBaseTypes (this TypeDefinition type, TypeDefinitionCache cache) => + GetBaseTypes (type, (IMetadataResolver) cache); + + public static IEnumerable GetBaseTypes (this TypeDefinition type, IMetadataResolver resolver) + { + TypeDefinition? t = type; + + while ((t = t.GetBaseType (resolver)) != null) { + yield return t; + } + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static bool IsAssignableFrom (this TypeReference type, TypeReference c) => throw new NotSupportedException (); + + public static bool IsAssignableFrom (this TypeReference type, TypeReference c, TypeDefinitionCache cache) => + IsAssignableFrom (type, c, (IMetadataResolver) cache); + + public static bool IsAssignableFrom (this TypeReference type, TypeReference c, IMetadataResolver resolver) + { + if (type.FullName == c.FullName) + return true; + var d = resolver.Resolve (c); + if (d == null) + return false; + foreach (var t in d.GetTypeAndBaseTypes (resolver)) { + if (type.FullName == t.FullName) + return true; + foreach (var ifaceImpl in t.Interfaces) { + var i = ifaceImpl.InterfaceType; + if (IsAssignableFrom (type, i, resolver)) + return true; + } + } + return false; + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static bool IsSubclassOf (this TypeDefinition type, string typeName) => throw new NotSupportedException (); + + public static bool IsSubclassOf (this TypeDefinition type, string typeName, TypeDefinitionCache cache) => + IsSubclassOf (type, typeName, (IMetadataResolver) cache); + public static bool IsSubclassOf (this TypeDefinition type, string typeName, IMetadataResolver resolver) + { + foreach (var t in type.GetTypeAndBaseTypes (resolver)) { + if (t.FullName == typeName) { + return true; + } + } + return false; + } + + public static bool HasJavaPeer (this TypeDefinition type, IMetadataResolver resolver) + { + if (type.IsInterface && type.ImplementsInterface ("Java.Interop.IJavaPeerable", resolver)) + return true; + + foreach (var t in type.GetTypeAndBaseTypes (resolver)) { + switch (t.FullName) { + case "Java.Lang.Object": + case "Java.Lang.Throwable": + case "Java.Interop.JavaObject": + case "Java.Interop.JavaException": + return true; + default: + break; + } + } + return false; + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static bool ImplementsInterface (this TypeDefinition type, string interfaceName) => throw new NotSupportedException (); + + public static bool ImplementsInterface (this TypeDefinition type, string interfaceName, TypeDefinitionCache cache) => + ImplementsInterface (type, interfaceName, (IMetadataResolver) cache); + + public static bool ImplementsInterface (this TypeDefinition type, string interfaceName, IMetadataResolver resolver) + { + foreach (var t in type.GetTypeAndBaseTypes (resolver)) { + foreach (var i in t.Interfaces) { + if (i.InterfaceType.FullName == interfaceName) { + return true; + } + } + } + return false; + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string GetPartialAssemblyName (this TypeReference type) => throw new NotSupportedException (); + + public static string GetPartialAssemblyName (this TypeReference type, TypeDefinitionCache cache) => + GetPartialAssemblyName (type, (IMetadataResolver) cache); + + public static string GetPartialAssemblyName (this TypeReference type, IMetadataResolver resolver) + { + TypeDefinition? def = resolver.Resolve (type); + return (def ?? type).Module.Assembly.Name.Name; + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string GetPartialAssemblyQualifiedName (this TypeReference type) => throw new NotSupportedException (); + + public static string GetPartialAssemblyQualifiedName (this TypeReference type, TypeDefinitionCache cache) => + GetPartialAssemblyQualifiedName (type, (IMetadataResolver) cache); + + public static string GetPartialAssemblyQualifiedName (this TypeReference type, IMetadataResolver resolver) + { + return string.Format ("{0}, {1}", + // Cecil likes to use '/' as the nested type separator, while + // Reflection uses '+' as the nested type separator. Use Reflection. + CecilTypeNameToReflectionTypeName (type.FullName), + type.GetPartialAssemblyName (resolver)); + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string GetAssemblyQualifiedName (this TypeReference type) => throw new NotSupportedException (); + + public static string GetAssemblyQualifiedName (this TypeReference type, TypeDefinitionCache cache) => + GetAssemblyQualifiedName (type, (IMetadataResolver) cache); + + public static string GetAssemblyQualifiedName (this TypeReference type, IMetadataResolver resolver) + { + TypeDefinition? def = resolver.Resolve (type); + return string.Format ("{0}, {1}", + // Cecil likes to use '/' as the nested type separator, while + // Reflection uses '+' as the nested type separator. Use Reflection. + CecilTypeNameToReflectionTypeName (type.FullName), + (def ?? type).Module.Assembly.Name.FullName); + } + + public static TypeDefinition? GetNestedType (this TypeDefinition type, string name) + { + if (type == null) + return null; + + foreach (TypeDefinition t in type.NestedTypes) + if (t.Name == name || t.FullName == name) + return t; + + return null; + } + + // Note: this is not recursive, so it will not find nested types. + public static TypeDefinition? FindType (this ModuleDefinition module, string name) + { + if (module == null) + return null; + + foreach (TypeDefinition t in module.Types) + if (t.Name == name || t.FullName == name) + return t; + + return null; + } + + public static string? CecilTypeNameToReflectionTypeName (string? typeName) => typeName?.Replace ('/', '+'); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics.csproj b/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics.csproj new file mode 100644 index 00000000000..8e4c99f324b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0 + enable + true + ..\..\product.snk + + + + + + $(ToolOutputFullPath) + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs b/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs new file mode 100644 index 00000000000..a260ba98f42 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs @@ -0,0 +1,198 @@ +// Copyright 2012, Xamarin Inc. All rights reserved, + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Mono.Cecil.Cil; + +namespace Java.Interop.Tools.Diagnostics { + + // Error allocation (not all used; values from MonoTouch) + // + // FIXME: THOSE CODE COMMENTS ARE VERY INACCURATE. Any MT-specific numbers should be removed. + // XA0xxx mtouch itself, e.g. parameters, environment (e.g. missing tools) + // XA0000 Unexpected error - Please fill a bug report at http://bugzilla.xamarin.com + // XA0001 Invalid or unsupported $(TargetFrameworkVersion) value of '{0}'. + // XA0002 Could not parse the environment variable '{0}'. + // XA0003 Application name '{0}.exe' conflicts with an SDK or product assembly (.dll) name. + // XA0004 New refcounting logic requires sgen to be enabled too + // XA0005 The output directory '{0}' does not exist + // XA0006 There is no devel platform at '{0}', use --platform=PLAT to specify the SDK + // XA0007 The root assembly '{0}' does not exist + // XA0008 You should provide one root assembly only + // XA0009 Error while loading assemblies: {0} + // XA0010 Could not parse the command line arguments: {0} + // XA0011 {0} was built against a more recent runtime ({1}) than MonoTouch supports + // XA0012 Incomplete data is provided to complete `{0}`. + // XA0013 Profiling support requires sgen to be enabled too + // XA0014 iOS {0} does not support building applications targeting ARMv6 + // XA0020 Could not launch mandroid daemon. + + // XA0100 EmbeddedNativeLibrary '{0}' is invalid in Android Application project. Please use AndroidNativeLibrary instead. + // XA0101 @(Content) build action is not supported + // XA0102 Lint Warning + // XA0103 Lint Error + // XA0104 Invalid Sequence Point mode + // XA0105 The TargetFrameworkVersion for {0} (v{1}) is greater than the TargetFrameworkVersion for your project (v{2}). You need to increase the TargetFrameworkVersion for your project. + + // XA1xxx file copy / symlinks (project related) + // XA10xx installer.cs / mtouch.cs + // XA1001 Could not find an application at the specified directory + // XA1002 Could not create symlinks, files were copied + // XA1003 Could not kill the application '{0}'. You may have to kill the application manually. + // XA1004 Could not get the list of installed applications. + // XA1005 Could not kill the application '{0}' on the device '{1}': {2}. You may have to kill the application manually. + // XA1006 Could not install the application '{0}' on the device '{1}': {2}. + // XA1007 Failed to launch the application '{0}' on the device '{1}': {2}. You can still launch the application manually by tapping on it. + // XA1008 Failed to launch the simulator: {0} + // XA1009 Could not copy the assembly '{0}' to '{1}': {2} + // XA1010 Could not load the assembly '{0}': {1} + // XA1011 Could not add missing resource file: '{0}' + // XA11xx DebugService.cs + // XA1101 Could not start app + // XA1102 Could not attach to the app (to kill it): {0} + // XA1103 Could not detach + // XA1104 Failed to send packet: {0} + // XA1105 Unexpected response type + // XA1106 Could not get list of applications on the device: Request timed out. + // XA1107 Application failed to launch + // XA12xx simcontroller.cs + // XA1201 Could not load the simulator: {0} + // XA13xx [LinkWith] + // XA1301 Native library `{0}` ({1}) was ignored since it does not match the current build architecture(s) ({2}) + // XA2xxx Linker + // XA20xx Linker (general) errors + // XA2001 Could not link assemblies + // XA2002 Can not resolve reference: {0} + // XA2003 Option '{0}' will be ignored since linking is disabled + // XA2004 Extra linker definitions file '{0}' could not be located. + // XA2005 Definitions from '{0}' could not be parsed. + // XA2006 Reference to metadata item '{0}' (defined in '{1}') from '{2}' could not be resolved. + // XA3xxx AOT + // XA30xx AOT (general) errors + // XA3001 Could not AOT the assembly '{0}' + // XA3002 AOT restriction: Method '{0}' must be static since it is decorated with [MonoPInvokeCallback]. See http://ios.xamarin.com/Documentation/Limitations#Reverse_Callbacks # this error message comes from the AOT compiler + // XA3003 Conflicting --debug and --llvm options. Soft-debugging is disabled. + // XA3004 Incompatible AOT configuration: '{0}'. + // XA4xxx code generation + // XA40xx main.m + // XA4001 The main template could not be expansed to `{0}`. + // XA41xx registrar.m + // XA4101 The registrar cannot build a signature for type `{0}`. + // XA4102 The registrar found an invalid type `{0}` in signature for method `{2}`. Use `{1}` instead. + // XA4103 The registrar found an invalid type `{0}` in signature for method `{2}`: The type implements INativeObject, but does not have a constructor that takes two (IntPtr, bool) arguments + // XA4104 The registrar cannot marshal the return value for type `{0}` in signature for method `{1}`. + // XA4105 The registrar cannot marshal the parameter of type `{0}` in signature for method `{1}`. + // XA4106 The registrar cannot marshal the return value for structure `{0}` in signature for method `{1}`. + // XA4107 The registrar cannot marshal the parameter of type `{0}` in signature for method `{1}`. + // XA4108 The registrar cannot get the ObjectiveC type for managed type `{0}`." + // XA4109 Failed to compile the generated registrar code. Please file a bug report at http://bugzilla.xamarin.com + // XA4110 The registrar cannot marshal the out parameter of type `{0}` in signature for method `{1}`. + // XA4111 The registrar cannot build a signature for type `{0}' in method `{1}`. + // XA42xx ACW generation + // XA4200 Can only generate ACW's for `claas` types. + // XA4201 Unable to determine JNI name for type {0}. + // XA4203 The specified type name must be fully qualified. + // XA4204 Unable to resolve interface type '{0}'. Are you missing an assembly reference? + // XA4205 [ExportField] can only be used on methods with 0 parameters. + // XA4206 [Export] cannot be used on a generic type. + // XA4207 [ExportField] cannot be used on a generic type. + // XA4208 [Java.Interop.ExportFieldAttribute] cannot be used on a method returning void. + // XA4209 Failed to create JavaTypeInfo for class: {0} due to {1} + // XA4210 "You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute." + // XA4211 AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than $(TargetFrameworkVersion) '{1}'. Using API-{1} for ACW compilation. + // XA4212 Type `{0}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported. + // XA4217 Cannot override Kotlin-generated method '{0}' because it is not a valid Java method name. This method can only be overridden from Kotlin." + // XA5xxx GCC and toolchain + // XA32xx .apk generation + // XA4300 Unsupported $(AndroidSupportedAbis) value '{0}'; ignoring. + // XA4301 Apk already contains the item {0}; ignoring. + // XA51xx compilation + // XA5101 Missing '{0}' compiler. Please install Android NDK. + // XA5102 Conversion from assembly to native code failed. Please file a bug report at http://bugzilla.xamarin.com + // XA5103 Failed to compile the file '{0}'. Please file a bug report at http://bugzilla.xamarin.com + // XA52xx linking + // XA5201 Native linking failed. Please review user flags provided to gcc: {0} + // XA5202 Native linking failed. Please review the build log. + // XA5203 Failed to generate the debug symbols (dSYM directory). Please review the build log. + // XA5204 Failed to strip the final binary. Please review the build log. + // XA52xx other tools + // XA5205 Missing 'aapt' tool. Please install the Android SDK Build-tools package. + // XA5206 {0}. Android resource directory {1} doesn't exist. + // XA5207 {0}. Java library file {1} doesn't exist. + // XA5208 Download failed. Please download {0} and put it to the {1} directory. + // XA5209 Unzipping failed. Please download {0} and extract it to the {1} directory. + // XA5210 {0}. Native library file {1} doesn't exist. + // XA5211 Embedded wear app package name differs from handheld app package name ({0} != {1}). + // XA5212 The Minimum Sdk Version ({0}) in AndroidManifest is invalid. + // XA5213 Java.Lang.OutOfMemory Excption. Consider increasing the value of $(JavaMaximumHeapSize). + // XA5214 Duplicate resource file. + // XA5215 Duplicate "values" Resource found + // XA5216 Duplicate Resource found for + // XA53xx linking + // XA5303 Native linking warning: {0} + // XA53xx other tools + // XA5300 Andorid SDK not found or not fully installed. + // XA5301 Missing 'strip' tool. Please install Xcode 'Command-Line Tools' component + // XA5302 Missing 'dsymutil' tool. Please install Xcode 'Command-Line Tools' component + // XA6xxx mtouch internal tools + // XA600x Stripper + // XA6001 Running version of Cecil doesn't support assembly stripping + // XA6002 Could not strip assembly `{0}`. + // XA6003 [UnauthorizedAccessException message] + // XA7xxx reserved + // XA8xxx reserved + // XA9xxx Licensing + // --- these are listed in activation/src/utils/activation.cs --- + // + + public static class Diagnostic { + [DoesNotReturn] + public static void Error (int code, SequencePoint? location, string message, params object[] args) + { + throw new XamarinAndroidException (code, message, args) { + Location = location, + }; + } + + + [DoesNotReturn] + public static void Error (int code, string message, params object[] args) + { + throw new XamarinAndroidException (code, message, args); + } + + [DoesNotReturn] + public static void Error (int code, Exception innerException, string message, params object[] args) + { + throw new XamarinAndroidException (code, innerException, message, args); + } + + public static void WriteTo (System.IO.TextWriter destination, Exception message, bool verbose = false) + { + var xae = message as XamarinAndroidException; + if (xae != null) { + destination.WriteLine ("monodroid: {0}", xae.Message); + if (verbose && xae.Code < 9000) + destination.WriteLine ("monodroid: {0}", xae.ToString ()); + return; + } + + destination.WriteLine ("monodroid: error XA0000: Unexpected error - Please file a bug report at http://bugzilla.xamarin.com. Reason: {0}", + verbose ? message.Message : message.ToString ()); + } + + public static Action CreateConsoleLogger () + { + Action logger = (level, value) => { + if (level == TraceLevel.Error) + Console.Error.WriteLine (value); + else + Console.WriteLine (value); + }; + return logger; + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/XamarinAndroidException.cs b/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/XamarinAndroidException.cs new file mode 100644 index 00000000000..7cea2dfa12b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/XamarinAndroidException.cs @@ -0,0 +1,49 @@ +using System; +using System.Text; + +using Mono.Cecil.Cil; + +namespace Java.Interop.Tools.Diagnostics { + + public class XamarinAndroidException : Exception + { + + public XamarinAndroidException (int code, string message, params object [] args) + : this (code, null, message, args) + { + } + + // http://blogs.msdn.com/b/msbuild/archive/2006/11/03/msbuild-visual-studio-aware-error-messages-and-message-formats.aspx + static string GetMessage (int code, string message, object [] args) + { + var m = new StringBuilder (); + m.Append ("error "); + m.AppendFormat ("XA{0:0000}", code); + m.Append (": "); + m.AppendFormat (message, args); + return m.ToString (); + } + + public XamarinAndroidException (int code, Exception? innerException, string message, params object [] args) + : base (GetMessage (code, message, args), innerException) + { + Code = code; + MessageWithoutCode = string.Format (message, args); + } + + public string MessageWithoutCode { get; private set; } + + public int Code { get; private set; } + + public SequencePoint? Location { get; set; } + + public string? SourceFile { + get { return Location?.Document.Url; } + } + + public int SourceLine { + get { return Location == null ? 0 : Location.StartLine; } + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantAction.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantAction.cs new file mode 100644 index 00000000000..ab7c6a11824 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantAction.cs @@ -0,0 +1,11 @@ +namespace Java.Interop.Tools.Generator.Enumification +{ + public enum ConstantAction + { + None, + Ignore, + Enumify, + Add, + Remove + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantEntry.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantEntry.cs new file mode 100644 index 00000000000..6838e36c29a --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantEntry.cs @@ -0,0 +1,231 @@ +using System; +using System.Xml.Linq; + +namespace Java.Interop.Tools.Generator.Enumification +{ + /// + /// This represents a Java int constant and/or a C# enum entry. + /// + public class ConstantEntry + { + public ConstantAction Action { get; set; } + public AndroidSdkVersion ApiLevel { get; set; } + public string? JavaSignature { get; set; } + public string? Value { get; set; } + public string? EnumFullType { get; set; } + public string? EnumMember { get; set; } + public FieldAction FieldAction { get; set; } + public bool IsFlags { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } + + public string EnumNamespace { + get { + if (!EnumFullType.HasValue ()) + return string.Empty; + + var index = EnumFullType.LastIndexOf ('.'); + + // There is no namespace, only a type + if (index == -1) + return string.Empty; + + return EnumFullType.Substring (0, index); + } + } + + public string EnumType { + get { + if (!EnumFullType.HasValue ()) + return string.Empty; + + var index = EnumFullType.LastIndexOf ('.'); + + // There is no namespace, only a type + if (index == -1) + return EnumFullType; + + return EnumFullType.Substring (index + 1); + } + } + + public string JavaPackage { + get { + if (!JavaSignature.HasValue ()) + return string.Empty; + + var index = JavaSignature.LastIndexOf ('/'); + + // There is no namespace, only a type + if (index == -1) + return string.Empty; + + return JavaSignature.Substring (0, index); + } + } + + public string JavaType { + get { + if (!JavaSignature.HasValue ()) + return string.Empty; + + var index = JavaSignature.LastIndexOf ('/'); + var dot_index = JavaSignature.LastIndexOf ('.'); + + return JavaSignature.Substring (index + 1, dot_index - index - 1); + } + } + + public string JavaName { + get { + if (!JavaSignature.HasValue ()) + return string.Empty; + + var index = JavaSignature.LastIndexOf ('.'); + + return JavaSignature.Substring (index + 1); + } + } + + public static ConstantEntry FromString (string line, bool transientMode = false) + { + var parser = new CsvParser (line); + + if (parser.GetField (0).In ("?", "I", "E", "A", "R")) + return FromVersion2String (parser); + + return FromVersion1String (parser, transientMode); + } + + static ConstantEntry FromVersion1String (CsvParser parser, bool transientMode) + { + var entry = new ConstantEntry { + Action = ConstantAction.Enumify, + ApiLevel = parser.GetFieldAsAndroidSdkVersion (0), + EnumFullType = parser.GetField (1), + EnumMember = parser.GetField (2), + JavaSignature = parser.GetField (3), + Value = parser.GetField (4), + IsFlags = parser.GetField (5).ToLowerInvariant () == "flags", + FieldAction = transientMode ? FieldAction.Remove : FieldAction.Keep + }; + + if (!entry.EnumNamespace.HasValue ()) { + // This is a line that only deletes a const, not maps it to an enum + entry.Action = ConstantAction.Remove; + entry.FieldAction = FieldAction.Remove; + } else if (!entry.JavaSignature.HasValue ()) { + // This is a line that adds an unmapped enum member + entry.Action = ConstantAction.Add; + entry.FieldAction = transientMode ? FieldAction.Remove : FieldAction.None; + } + + entry.NormalizeJavaSignature (); + + return entry; + } + + static ConstantEntry FromVersion2String (CsvParser parser) + { + var entry = new ConstantEntry { + Action = FromConstantActionString (parser.GetField (0)), + ApiLevel = parser.GetFieldAsAndroidSdkVersion (1), + JavaSignature = parser.GetField (2), + Value = parser.GetField (3), + EnumFullType = parser.GetField (4), + EnumMember = parser.GetField (5), + FieldAction = FromFieldActionString (parser.GetField (6)), + IsFlags = parser.GetField (7).ToLowerInvariant () == "flags", + DeprecatedSince = parser.GetFieldAsNullableAndroidSdkVersion (8) + }; + + entry.NormalizeJavaSignature (); + + return entry; + } + + public static ConstantEntry FromElement (XElement elem) + { + var entry = new ConstantEntry { + Action = ConstantAction.None, + ApiLevel = NamingConverter.ParseApiLevel (elem), + JavaSignature = elem.Parent?.Parent?.Attribute ("name")?.Value, + Value = elem.Attribute ("value")?.Value, + }; + + var java_package = elem.Parent?.Parent?.Attribute ("name")?.Value.Replace ('.', '/'); + var java_type = elem.Parent?.Attribute ("name")?.Value.Replace ('.', '$'); + var java_member = elem.Attribute ("name")?.Value; + + entry.JavaSignature = $"{java_package}/{java_type}.{java_member}".TrimStart ('/'); + + // Interfaces get an "I:" prefix + if (elem.Parent?.Name.LocalName == "interface") + entry.JavaSignature = "I:" + entry.JavaSignature; + + return entry; + } + + public override string ToString () => $"[{EnumMember}, {Value}]"; + + public string ToVersion2String () + { + var fields = new [] { + Action == ConstantAction.None ? "?" : Action.ToString ().Substring (0, 1), + ApiLevel.ToString (), + JavaSignature, + Value, + EnumFullType, + EnumMember, + ToConstantFieldActionString (FieldAction), + IsFlags ? "flags" : string.Empty, + DeprecatedSince.HasValue ? DeprecatedSince.Value.ToString () : string.Empty, + }; + + return string.Join (",", fields); + } + + static string ToConstantFieldActionString (FieldAction value) + { + return value switch + { + FieldAction.None => string.Empty, + FieldAction.Remove => "remove", + FieldAction.Keep => "keep", + _ => string.Empty + }; + + } + + static ConstantAction FromConstantActionString (string value) + { + return value switch + { + "?" => ConstantAction.None, + "I" => ConstantAction.Ignore, + "E" => ConstantAction.Enumify, + "A" => ConstantAction.Add, + "R" => ConstantAction.Remove, + _ => throw new ArgumentOutOfRangeException (nameof (value), $"Specified action '{value}' is not valid"), + }; + } + + static FieldAction FromFieldActionString (string value) + { + return value.ToLowerInvariant () switch + { + "" => FieldAction.None, + "remove" => FieldAction.Remove, + "keep" => FieldAction.Keep, + _ => throw new ArgumentOutOfRangeException (nameof (value), $"Specified field action '{value}' is not valid"), + }; + } + + void NormalizeJavaSignature () + { + // Somehow we got a mix of using dollar signs and periods + // for nested classes. Normalize to dollar signs. + if (JavaSignature.HasValue ()) + JavaSignature = $"{JavaPackage}/{JavaType.Replace ('.', '$')}.{JavaName}"; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantsParser.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantsParser.cs new file mode 100644 index 00000000000..cdc499e711e --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/ConstantsParser.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; + +namespace Java.Interop.Tools.Generator.Enumification +{ + public static class ConstantsParser + { + public static List FromEnumMapCsv (string filename) + { + using (var sr = new StreamReader (filename)) + return FromEnumMapCsv (sr); + } + + public static List FromEnumMapCsv (TextReader reader) + { + var constants = new List (); + var transient = false; + + string? s; + + // Read the enum csv file + while ((s = reader.ReadLine ()) != null) { + // Skip empty lines and comments + if (string.IsNullOrEmpty (s) || s.StartsWith ("//", StringComparison.Ordinal)) + continue; + + // Transient mode means remove the original field + if (s == "- ENTER TRANSIENT MODE -") { + transient = true; + continue; + } + + constants.Add (ConstantEntry.FromString (s, transient)); + } + + return constants; + } + + public static void SaveEnumMapCsv (List constants, string filename) + { + using (var sw = new StreamWriter (filename)) + SaveEnumMapCsv (constants, sw); + } + + public static void SaveEnumMapCsv (List constants, TextWriter writer) + { + var column_names = new [] { + "Action", + "API Level", + "JNI Signature", + "Enum Value", + "C# Enum Type", + "C# Member Name", + "Field Action", + "Is Flags", + "Deprecated Since", + }; + + writer.WriteLine ("// " + string.Join (",", column_names)); + + foreach (var c in Sort (constants)) + writer.WriteLine (c.ToVersion2String ()); + } + + public static List FromApiXml (string filename) => FromApiXml (XDocument.Load (filename)); + + public static List FromApiXml (XDocument doc) + { + var int_fields = doc.XPathSelectElements ("//field[@type='int']"); + + return int_fields.Select (f => ConstantEntry.FromElement (f)).Where (c => c.Value.HasValue ()).ToList (); + } + + public static List Sort (List constants) + { + // We want a well-defined sort to reduce diffs, but it's not as easy as just + // using the JavaSignature, because there may be added enum members that do not + // have a JavaSignature, and we would like them to be with their other members. + // For example: + // - A,0,,0,Java.MyEnum,None + // - E,1,java/class/member1,1,Java.MyEnum,Member1 + // - E,1,java/class/member2,2,Java.MyEnum,Member2 + var sorted = constants.Where (c => c.JavaSignature.HasValue ()).OrderBy (c => c.JavaSignature).ToList (); + + // Try to put members without signatures at the beginning of the section with + // their fellow enum members. If not, put them at the end of the list. + foreach (var c in constants.Where (c => !c.JavaSignature.HasValue ()).OrderBy (c => $"{c.EnumFullType}.{c.EnumMember}")) { + var sibling_index = sorted.FindIndex (c2 => c2.EnumFullType == c.EnumFullType); + + if (sibling_index >= 0) + sorted.Insert (sibling_index, c); + else + sorted.Add (c); + } + + return sorted; + } + } + + public class JavaSignatureComparer : IEqualityComparer + { + public static JavaSignatureComparer Instance { get; } = new JavaSignatureComparer (); + + public bool Equals (ConstantEntry? x, ConstantEntry? y) => x?.JavaSignature == y?.JavaSignature; + public int GetHashCode (ConstantEntry obj) => 0; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/FieldAction.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/FieldAction.cs new file mode 100644 index 00000000000..03e5c5ce2db --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/FieldAction.cs @@ -0,0 +1,9 @@ +namespace Java.Interop.Tools.Generator.Enumification +{ + public enum FieldAction + { + None, + Remove, + Keep + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodAction.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodAction.cs new file mode 100644 index 00000000000..05af02ae98f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodAction.cs @@ -0,0 +1,9 @@ +namespace Java.Interop.Tools.Generator.Enumification +{ + public enum MethodAction + { + None, + Ignore, + Enumify, + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodMapEntry.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodMapEntry.cs new file mode 100644 index 00000000000..52e26e3d721 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodMapEntry.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using Xamarin.Android.Tools; + +namespace Java.Interop.Tools.Generator.Enumification +{ + public class MethodMapEntry + { + public MethodAction Action { get; set; } + public AndroidSdkVersion ApiLevel { get; set; } + public string? JavaPackage { get; set; } + public string? JavaType { get; set; } + public string? JavaName { get; set; } + public string? ParameterName { get; set; } + public string? EnumFullType { get; set; } + public string JavaSignature => $"{JavaPackage}/{JavaType}.{JavaName}.{ParameterName}"; + public bool IsInterface { get; set; } + + public static IEnumerable FromXml (XElement element) + { + // Handle fields first + if (element.Name == "field") { + yield return FromElement (element, element.XGetAttribute ("name")!); + yield break; + } + + // Now methods and constructors + // There could be multiple entries, from the return type and multiple parameters + if (element.XGetAttribute ("return") == "int") + yield return FromElement (element, "return"); + + foreach (var p in element.Elements ("parameter")) + if (p.XGetAttribute ("type") == "int") + yield return FromElement (element, p.XGetAttribute ("name")!); + } + + static MethodMapEntry FromElement (XElement element, string parameterName) + { + var entry = new MethodMapEntry { + JavaPackage = element.Parent?.Parent?.XGetAttribute ("name")?.Replace ('.', '/'), + JavaType = element.Parent?.XGetAttribute ("name")?.Replace ('.', '$'), + JavaName = element.XGetAttribute ("name"), + ParameterName = parameterName, + ApiLevel = NamingConverter.ParseApiLevel (element), + IsInterface = element.Parent?.Name == "interface" + }; + + if (element.Name == "constructor") + entry.JavaName = "ctor"; + + return entry; + } + + public static MethodMapEntry FromString (string line) + { + var parser = new CsvParser (line); + + if (parser.GetField (0).In ("?", "I", "E")) + return FromVersion2String (parser); + + return FromVersion1String (parser); + } + + static MethodMapEntry FromVersion1String (CsvParser parser) + { + var entry = new MethodMapEntry { + Action = MethodAction.Enumify, + ApiLevel = parser.GetFieldAsAndroidSdkVersion (0), + JavaPackage = parser.GetField (1), + JavaType = parser.GetField (2), + JavaName = parser.GetField (3), + ParameterName = parser.GetField (4), + EnumFullType = parser.GetField (5) + }; + + if (entry.JavaType.StartsWith ("[Interface]", StringComparison.Ordinal)) { + entry.IsInterface = true; + entry.JavaType = entry.JavaType.Substring ("[Interface]".Length); + } + + return entry; + } + + static MethodMapEntry FromVersion2String (CsvParser parser) + { + var entry = new MethodMapEntry { + Action = FromMethodActionString (parser.GetField (0)), + ApiLevel = parser.GetFieldAsAndroidSdkVersion (1), + JavaPackage = parser.GetField (2), + JavaType = parser.GetField (3), + JavaName = parser.GetField (4), + ParameterName = parser.GetField (5), + EnumFullType = parser.GetField (6) + }; + + if (entry.JavaType.StartsWith ("[Interface]", StringComparison.Ordinal)) { + entry.IsInterface = true; + entry.JavaType = entry.JavaType.Substring ("[Interface]".Length); + } + + return entry; + } + + static MethodAction FromMethodActionString (string value) + { + return value switch { + "?" => MethodAction.None, + "I" => MethodAction.Ignore, + "E" => MethodAction.Enumify, + _ => throw new ArgumentOutOfRangeException (nameof (value), $"Specified action '{value}' is not valid"), + }; + } + + public string ToVersion1String () + { + var fields = new [] { + ApiLevel.ToString (), + JavaPackage, + (IsInterface ? "I:" : string.Empty) + JavaType, + JavaName, + ParameterName, + EnumFullType, + }; + + return string.Join (",", fields); + } + + public string ToVersion2String () + { + var fields = new [] { + Action == MethodAction.None ? "?" : Action.ToString ().Substring (0, 1), + ApiLevel.ToString (), + JavaPackage, + (IsInterface ? "[Interface]" : string.Empty) + JavaType, + JavaName, + ParameterName, + EnumFullType, + }; + + return string.Join (",", fields); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodMapParser.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodMapParser.cs new file mode 100644 index 00000000000..781625cbcf6 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Enumification/MethodMapParser.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; + +namespace Java.Interop.Tools.Generator.Enumification +{ + public class MethodMapParser + { + public static List FromMethodMapCsv (string filename) + { + using (var sr = new StreamReader (filename)) + return FromMethodMapCsv (sr); + } + + public static List FromMethodMapCsv (TextReader reader) + { + var entries = new List (); + + string? s; + + // Read the enum csv file + while ((s = reader.ReadLine ()) != null) { + // Skip empty lines and comments + if (string.IsNullOrEmpty (s) || s.StartsWith ("//", StringComparison.Ordinal)) + continue; + + entries.Add (MethodMapEntry.FromString (s)); + } + + return entries; + } + + public static void SaveMethodMapCsv (IEnumerable entries, string filename, bool version2) + { + using (var sw = new StreamWriter (filename)) + SaveMethodMapCsv (entries, sw, version2); + } + + public static void SaveMethodMapCsv (IEnumerable entries, TextWriter writer, bool version2) + { + foreach (var entry in entries.OrderBy (e => e.JavaSignature)) + writer.WriteLine (version2 ? entry.ToVersion2String () : entry.ToVersion1String ()); + } + + public static List FromApiXml (string filename) => FromApiXml (XDocument.Load (filename)); + + public static List FromApiXml (XDocument doc) + { + var results = new List (); + + // Methods that return int or have an int parameter + results.AddRange (doc.XPathSelectElements ("//method[@return='int'] | //method[parameter/@type='int']").SelectMany (x => MethodMapEntry.FromXml (x))); + + // Constructors with an int parameter + results.AddRange (doc.XPathSelectElements ("//constructor[parameter/@type='int']").SelectMany (x => MethodMapEntry.FromXml (x))); + + // Fields that are a non-constant int + results.AddRange (doc.XPathSelectElements ("//field[@type='int' and @final='false']").SelectMany (x => MethodMapEntry.FromXml (x))); + + return results; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Extensions/UtilityExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Extensions/UtilityExtensions.cs new file mode 100644 index 00000000000..a20b2833f64 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Extensions/UtilityExtensions.cs @@ -0,0 +1,75 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +namespace Java.Interop.Tools.Generator +{ + public static class UtilityExtensions + { + public static bool In (this T enumeration, params T [] values) + { + if (enumeration is null) + return false; + + foreach (var en in values) + if (enumeration.Equals (en)) + return true; + + return false; + } + + public static bool StartsWithAny (this string value, params string [] values) + { + foreach (var en in values) + if (value.StartsWith (en, StringComparison.OrdinalIgnoreCase)) + return true; + + return false; + } + + public static bool HasValue ([NotNullWhen (true)]this string? str) => !string.IsNullOrEmpty (str); + + public static XDocument? LoadXmlDocument (string filename) + { + try { + return XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + } catch (XmlException e) { + Report.Verbose (0, "Exception: {0}", e); + Report.LogCodedWarning (0, Report.WarningInvalidXmlFile, e, filename, e.Message); + } + + return null; + } + + // A case-insensitive Replace doesn't exist in classic .NET Framework. Loosely based on: + // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs + public static string ReplaceOrdinalIgnoreCase (this string source, string oldValue, string newValue) + { + var result = new StringBuilder (); + var pos = 0; + + while (true) { + var index = source.IndexOf (oldValue, pos, StringComparison.OrdinalIgnoreCase); + + // Not found, bail + if (index < 0) + break; + + // Append the unmodified portion of search space + result.Append (source.Substring (pos, index)); + + // Append the replacement + result.Append (newValue); + + pos = index + oldValue.Length; + } + + // Append what remains of the search space, then allocate the new string. + result.Append (source.Substring (pos)); + return result.ToString (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs new file mode 100644 index 00000000000..cf115d06f66 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Extensions/XmlExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Globalization; +using System.Xml.Linq; +using System.Xml.XPath; + +using Java.Interop.Tools.Generator; + +namespace Xamarin.Android.Tools +{ + static class XmlExtensions + { + public static string? XGetAttribute (this XElement element, string name) + => element.Attribute (name)?.Value.Trim (); + + public static string? XGetAttribute (this XPathNavigator nav, string name, string ns) + => nav.GetAttribute (name, ns)?.Trim (); + + public static AndroidSdkVersion? XGetAttributeAsAndroidSdkVersion (this XElement element, string name) + { + var value = element.XGetAttribute (name); + + if (AndroidSdkVersion.TryParse (value, out var result)) + return result; + + return null; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Java.Interop.Tools.Generator.csproj b/external/Java.Interop/src/Java.Interop.Tools.Generator/Java.Interop.Tools.Generator.csproj new file mode 100644 index 00000000000..adaa4943033 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Java.Interop.Tools.Generator.csproj @@ -0,0 +1,22 @@ + + + + $(DotNetTargetFramework) + enable + + + + + + $(UtilityOutputFullPath) + + + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs new file mode 100644 index 00000000000..3c169f9ae3c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Metadata/FixupXmlDocument.cs @@ -0,0 +1,232 @@ +using System; +using System.Linq; +using System.Xml.XPath; +using System.Xml.Linq; + +using Xamarin.Android.Tools; +using System.Collections.Generic; + +namespace Java.Interop.Tools.Generator +{ + public class FixupXmlDocument + { + public XDocument FixupDocument { get; } + + public FixupXmlDocument (XDocument fixupDocument) + { + FixupDocument = fixupDocument; + } + + public static FixupXmlDocument? Load (string filename) + { + if (UtilityExtensions.LoadXmlDocument (filename) is XDocument doc) + return new FixupXmlDocument (doc); + + return null; + } + + public void Apply (ApiXmlDocument apiDocument, string apiLevelString, int productVersion) + { + // Defaulting to 0 here is fine + AndroidSdkVersion.TryParse (apiLevelString, out var apiLevel); + + var metadataChildren = FixupDocument.XPathSelectElements ("/metadata/*"); + + string? prev_path = null; + XElement? attr_last_cache = null; + + foreach (var metaitem in metadataChildren) { + if (ShouldSkip (metaitem, apiLevel, productVersion)) + continue; + if (!ShouldApply (metaitem, apiDocument)) + continue; + + // Namespace replacements are handled elsewhere + if (metaitem.Name.LocalName == "ns-replace") + continue; + + var path = metaitem.XGetAttribute ("path"); + + if (path != prev_path) + attr_last_cache = null; + + prev_path = path; + + if (path is null) { + Report.LogCodedWarning (0, Report.WarningNodeMissingPathAttribute, null, metaitem, metaitem.ToString ()); + continue; + } + + switch (metaitem.Name.LocalName) { + case "remove-node": + try { + var nodes = apiDocument.ApiDocument.XPathSelectElements (path).ToArray (); + + if (nodes.Any ()) + foreach (var node in nodes) + node.Remove (); + else + // BG8A00 + Report.LogCodedWarning (0, Report.WarningRemoveNodeMatchedNoNodes, null, metaitem, $""); + } catch (XPathException) { + // BG4301 + Report.LogCodedError (Report.ErrorRemoveNodeInvalidXPath, metaitem, path); + } + break; + case "add-node": + try { + var nodes = apiDocument.ApiDocument.XPathSelectElements (path); + + if (!nodes.Any ()) + // BG8A01 + Report.LogCodedWarning (0, Report.WarningAddNodeMatchedNoNodes, null, metaitem, $""); + else { + foreach (var node in nodes) + node.Add (metaitem.Nodes ()); + } + } catch (XPathException) { + // BG4302 + Report.LogCodedError (Report.ErrorAddNodeInvalidXPath, metaitem, path); + } + break; + case "change-node": + try { + var nodes = apiDocument.ApiDocument.XPathSelectElements (path); + var matched = false; + + foreach (var node in nodes) { + var newChild = new XElement (metaitem.Value); + newChild.Add (node.Attributes ()); + newChild.Add (node.Nodes ()); + node.ReplaceWith (newChild); + matched = true; + } + + if (!matched) + // BG8A03 + Report.LogCodedWarning (0, Report.WarningChangeNodeTypeMatchedNoNodes, null, metaitem, $""); + } catch (XPathException) { + // BG4303 + Report.LogCodedError (Report.ErrorChangeNodeInvalidXPath, metaitem, path); + } + break; + case "attr": + try { + var attr_name = metaitem.XGetAttribute ("name"); + + if (string.IsNullOrEmpty (attr_name)) { + // BG4307 + Report.LogCodedError (Report.ErrorMissingAttrName, metaitem, path); + continue; + } + + var nodes = attr_last_cache != null ? new XElement [] { attr_last_cache } : apiDocument.ApiDocument.XPathSelectElements (path); + var attr_matched = 0; + + foreach (var n in nodes) { + n.SetAttributeValue (attr_name, metaitem.Value); + attr_matched++; + } + if (attr_matched == 0) + // BG8A04 + Report.LogCodedWarning (0, Report.WarningAttrMatchedNoNodes, null, metaitem, $""); + if (attr_matched != 1) + attr_last_cache = null; + } catch (XPathException) { + // BG4304 + Report.LogCodedError (Report.ErrorAttrInvalidXPath, metaitem, path); + } + break; + case "move-node": + try { + var parent = metaitem.Value; + var parents = apiDocument.ApiDocument.XPathSelectElements (parent); + var matched = false; + + foreach (var parent_node in parents) { + var nodes = parent_node.XPathSelectElements (path).ToArray (); + foreach (var node in nodes) + node.Remove (); + parent_node.Add (nodes); + matched = true; + } + if (!matched) + // BG8A05 + Report.LogCodedWarning (0, Report.WarningMoveNodeMatchedNoNodes, null, metaitem, $""); + } catch (XPathException) { + // BG4305 + Report.LogCodedError (Report.ErrorMoveNodeInvalidXPath, metaitem, path); + } + break; + case "remove-attr": + try { + var name = metaitem.XGetAttribute ("name"); + var nodes = apiDocument.ApiDocument.XPathSelectElements (path); + var matched = false; + + foreach (var node in nodes) { + node.Attributes (name).Remove (); + matched = true; + } + + if (!matched) + // BG8A06 + Report.LogCodedWarning (0, Report.WarningRemoveAttrMatchedNoNodes, null, metaitem, $""); + } catch (XPathException) { + // BG4306 + Report.LogCodedError (Report.ErrorRemoveAttrInvalidXPath, metaitem, path); + } + break; + } + } + } + + public IList GetNamespaceTransforms () + { + var list = new List (); + + foreach (var xe in FixupDocument.XPathSelectElements ("/metadata/ns-replace")) { + if (NamespaceTransform.TryParse (xe, out var transform)) + list.Add (transform); + } + + return list; + } + + bool ShouldSkip (XElement node, AndroidSdkVersion apiLevel, int productVersion) + { + if (apiLevel > 0) { + var since = node.XGetAttributeAsAndroidSdkVersion ("api-since"); + var until = node.XGetAttributeAsAndroidSdkVersion ("api-until"); + + if (since is AndroidSdkVersion since_int && since_int > apiLevel) + return true; + else if (until is AndroidSdkVersion until_int && until_int < apiLevel) + return true; + } + + if (productVersion > 0) { + var product_version = node.XGetAttributeAsAndroidSdkVersion ("product-version"); + + if (product_version is AndroidSdkVersion version && version > productVersion) + return true; + + } + return false; + } + + bool ShouldApply (XElement node, ApiXmlDocument apiDocument) + { + if (apiDocument.ApiSource.HasValue ()) { + var targetsource = node.XGetAttribute ("api-source"); + + if (!targetsource.HasValue ()) + return true; + + return targetsource == apiDocument.ApiSource; + } + + return true; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Metadata/NamespaceTransform.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Metadata/NamespaceTransform.cs new file mode 100644 index 00000000000..4db92796e75 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Metadata/NamespaceTransform.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Xml.Linq; +using Xamarin.Android.Tools; + +namespace Java.Interop.Tools.Generator +{ + public class NamespaceTransform + { + public string OldValue { get; } + public string NewValue { get; } + public bool IsStartsWith { get; } + public bool IsEndsWith { get; } + + public NamespaceTransform (string oldValue, string newValue) + { + OldValue = oldValue; + NewValue = newValue; + + if (OldValue.EndsWith (".", StringComparison.Ordinal)) { + IsStartsWith = true; + OldValue = OldValue.Substring (0, OldValue.Length - 1); + } + + if (OldValue.StartsWith (".", StringComparison.Ordinal)) { + IsEndsWith = true; + OldValue = OldValue.Substring (1); + } + } + + public string ApplyInternal (string value) + { + string result; + + while (true) { + result = ApplyInternal (value); + + if (result == value) + return result; + + value = result; + } + } + + public string Apply (string value) + { + // Handle a "starts with" and "ends with" transform + if (IsStartsWith && IsEndsWith) { + if (value.Equals (OldValue, StringComparison.OrdinalIgnoreCase)) + return NewValue; + + // Don't let this fall through + return value; + } + + // Handle a "starts with" transform + if (IsStartsWith) { + if (value.StartsWith (OldValue, StringComparison.OrdinalIgnoreCase)) + return (NewValue + value.Substring (OldValue.Length)).TrimStart ('.'); + + return value; + } + + // Handle an "ends with" transform + if (IsEndsWith) { + if (value.EndsWith (OldValue, StringComparison.OrdinalIgnoreCase)) + return (value.Substring (0, value.Length - OldValue.Length) + NewValue).TrimEnd ('.'); + + return value; + } + + // Handle an "anywhere" transform + var value_tokens = value.Split ('.'); + var match_tokens = OldValue.Split ('.'); + + var results = new List (); + + for (var i = 0; i < value_tokens.Length; i++) { + if (AtMatch (value_tokens, i, match_tokens, 0)) { + if (NewValue.HasValue ()) + results.Add (NewValue); + + i += match_tokens.Length - 1; + } else { + results.Add (value_tokens [i]); + } + } + + return string.Join (".", results); + } + + public static bool TryParse (XElement element, [NotNullWhen (true)] out NamespaceTransform? transform) + { + var source = element.XGetAttribute ("source"); + var replacement = element.XGetAttribute ("replacement"); + + if (!source.HasValue () || replacement is null) { + Report.LogCodedWarning (0, Report.WarningInvalidNamespaceTransform, null, element, element.ToString ()); + transform = null; + return false; + } + + transform = new NamespaceTransform (source, replacement); + return true; + } + + private bool AtMatch (string [] valueTokens, int valueIndex, string [] matchTokens, int matchIndex) + { + if (matchIndex >= matchTokens.Length) + return true; + + if (valueIndex >= valueTokens.Length) + return false; + + if (string.Compare (valueTokens [valueIndex], matchTokens [matchIndex], StringComparison.OrdinalIgnoreCase) == 0) + return AtMatch (valueTokens, valueIndex + 1, matchTokens, matchIndex + 1); + + return false; + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/AndroidSdkVersion.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/AndroidSdkVersion.cs new file mode 100644 index 00000000000..b78de05b621 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/AndroidSdkVersion.cs @@ -0,0 +1,126 @@ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop.Tools.Generator; + +public struct AndroidSdkVersion : IComparable, IComparable, IEquatable +{ + public int ApiLevel { get; private set; } + public int MinorRelease { get; private set; } + + public AndroidSdkVersion (int major, int minor = 0) + { + ApiLevel = major; + MinorRelease = minor; + } + + int IComparable.CompareTo (object? value) + { + var other = value as AndroidSdkVersion?; + if (other == null) { + return 1; + } + return CompareTo (other.Value); + } + + public int CompareTo (AndroidSdkVersion value) + { + int r = ApiLevel.CompareTo (value.ApiLevel); + if (r == 0) { + r = MinorRelease.CompareTo (value.MinorRelease); + } + return r; + } + + public override int GetHashCode () + => ApiLevel ^ MinorRelease; + + public override bool Equals (object? value) + { + var other = value as AndroidSdkVersion?; + if (other == null) { + return false; + } + return Equals (other.Value); + } + + public bool Equals (AndroidSdkVersion value) + { + return value.ApiLevel == ApiLevel && value.MinorRelease == MinorRelease; + } + + public override string ToString () + => MinorRelease == 0 + ? ApiLevel.ToString () + : $"{ApiLevel}.{MinorRelease}"; + + // public static implicit operator ApiLevel (int value) + // => new ApiLevel (value); + + public static bool operator < (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) < 0; + public static bool operator <= (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) <= 0; + public static bool operator > (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) > 0; + public static bool operator >= (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs) >= 0; + public static bool operator == (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => lhs.Equals (rhs); + public static bool operator != (AndroidSdkVersion lhs, AndroidSdkVersion rhs) + => !lhs.Equals (rhs); + + public static bool operator < (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) < 0; + public static bool operator <= (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) <= 0; + public static bool operator > (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) > 0; + public static bool operator >= (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.CompareTo (rhs) >= 0; + public static bool operator == (AndroidSdkVersion lhs, int rhs) + => lhs.ApiLevel.Equals (rhs); + public static bool operator != (AndroidSdkVersion lhs, int rhs) + => !lhs.ApiLevel.Equals (rhs); + + public static bool operator < (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) < 0; + public static bool operator <= (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) <= 0; + public static bool operator > (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) > 0; + public static bool operator >= (int lhs, AndroidSdkVersion rhs) + => lhs.CompareTo (rhs.ApiLevel) >= 0; + public static bool operator == (int lhs, AndroidSdkVersion rhs) + => lhs.Equals (rhs.ApiLevel); + public static bool operator != (int lhs, AndroidSdkVersion rhs) + => !lhs.Equals (rhs.ApiLevel); + + public static bool TryParse (string? value, out AndroidSdkVersion apiLevel) + { + if (value == null) { + apiLevel = default; + return false; + } + if (Version.TryParse (value, out var v)) { + apiLevel = new AndroidSdkVersion (v.Major, v.Minor); + return true; + } + if (int.TryParse (value, out var major)) { + apiLevel = new AndroidSdkVersion (major); + return true; + } + apiLevel = default; + return false; + } + + public static AndroidSdkVersion Parse (string? value) + { + AndroidSdkVersion v; + if (TryParse (value, out v)) { + return v; + } + throw new NotSupportedException ($"Could not parse `{value}` as an ApiLevel."); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs new file mode 100644 index 00000000000..42f6a4f1b8c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/ApiXmlDocument.cs @@ -0,0 +1,47 @@ +using System; +using System.Xml; +using System.Xml.Linq; +using Xamarin.Android.Tools; + +namespace Java.Interop.Tools.Generator +{ + public class ApiXmlDocument + { + public XDocument ApiDocument { get; } + public string ApiLevel { get; } + public int ProductVersion { get; } + + public string? ApiSource => ApiDocument.Root?.XGetAttribute ("api-source"); + + public ApiXmlDocument (XDocument document, string apiLevel, int productVersion) + { + ApiDocument = document; + ApiLevel = apiLevel; + ProductVersion = productVersion; + } + + public static ApiXmlDocument? Load (string filename, string apiLevel, int productVersion) + { + if (UtilityExtensions.LoadXmlDocument (filename) is XDocument doc) + return new ApiXmlDocument (doc, apiLevel, productVersion); + + return null; + } + + public void ApplyFixupFile (string filename) + { + if (FixupXmlDocument.Load (filename) is FixupXmlDocument fixup) + ApplyFixupFile (fixup); + } + + public void ApplyFixupFile (FixupXmlDocument fixup) + { + try { + fixup.Apply (this, ApiLevel, ProductVersion); + } catch (XmlException ex) { + // BG4200 + Report.LogCodedErrorAndExit (Report.ErrorFailedToProcessMetadata, null, fixup.FixupDocument, ex.Message); + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/CsvParser.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/CsvParser.cs new file mode 100644 index 00000000000..31228131636 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/CsvParser.cs @@ -0,0 +1,37 @@ +using System; + +namespace Java.Interop.Tools.Generator +{ + public class CsvParser + { + readonly string [] fields; + + public CsvParser (string line) + { + fields = line.Split (','); + } + + public string GetField (int index) + { + if (index >= fields.Length) + return string.Empty; + + return fields [index].Trim (); + } + + public AndroidSdkVersion GetFieldAsAndroidSdkVersion (int index) + { + return AndroidSdkVersion.Parse (GetField (index)); + } + + public AndroidSdkVersion? GetFieldAsNullableAndroidSdkVersion (int index) + { + var value = GetField (index); + + if (AndroidSdkVersion.TryParse (value, out var val)) + return val; + + return default; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs new file mode 100644 index 00000000000..2cd96537d03 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/ISourceLineInfo.cs @@ -0,0 +1,27 @@ +using System; + +namespace Java.Interop.Tools.Generator +{ + public interface ISourceLineInfo + { + int LineNumber { get; set; } + int LinePosition { get; set; } + string SourceFile { get; set; } + } + + public class SourceLineInfo : ISourceLineInfo + { + public int LineNumber { get; set; } + public int LinePosition { get; set; } + public string SourceFile { get; set; } + + public SourceLineInfo (string sourceFile) : this (sourceFile, 0, 0) { } + + public SourceLineInfo (string sourceFile, int lineNumber, int linePosition) + { + SourceFile = sourceFile; + LineNumber = lineNumber; + LinePosition = linePosition; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/NamingConverter.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/NamingConverter.cs new file mode 100644 index 00000000000..17b4d769946 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/NamingConverter.cs @@ -0,0 +1,100 @@ +using System; +using System.Linq; +using System.Xml.Linq; + +namespace Java.Interop.Tools.Generator +{ + public static class NamingConverter + { + /// + /// Converts a 'merge.SourceFile' attribute to an API level. (ex. "..\..\bin\BuildDebug\api\api-28.xml.in") + /// + public static AndroidSdkVersion ParseApiLevel (string? value) + { + var result = ExtractApiLevel (value); + if (!result.HasValue ()) + return default; + + return result switch { + "R" => new AndroidSdkVersion (30), + "S" => new AndroidSdkVersion (31), + _ => AndroidSdkVersion.Parse (result) + }; + } + + static string? ExtractApiLevel (string? value) + { + if (!value.HasValue ()) + return null; + + const string ApiFilenamePrefix = "api-"; + + var hyphen = value.LastIndexOf (ApiFilenamePrefix); + if (hyphen < 0 || checked (hyphen + 1 + ApiFilenamePrefix.Length) >= value.Length) + return null; + hyphen += ApiFilenamePrefix.Length; + + int end = hyphen; + if (char.IsAsciiDigit (value [end++])) { + for ( ; end < value.Length; ++end) { + var n = value [end + 1]; + if (!char.IsAsciiDigit (n) && n != '.') + break; + } + } else { + // codename; expect ALLCAPS + for ( ; end < value.Length; ++end) { + if (!char.IsAsciiLetterUpper (value [end])) + break; + } + } + + return value.Substring (hyphen, end - hyphen); + } + + // The 'merge.SourceFile' attribute may be on the element, or only on its parent. For example, + // a new 'class' added will only put the attribute on the '' element and not its children s. + public static AndroidSdkVersion ParseApiLevel (XElement element) + { + var loop = element; + + while (loop != null) { + if (loop.Attribute ("merge.SourceFile") is XAttribute attr) + return ParseApiLevel (attr.Value); + + loop = loop.Parent; + } + + return default; + } + + public static string ConvertNamespaceToCSharp (string v) + { + return string.Join (".", v.Split ('.').Select (s => Capitalize (s))); + } + + public static string ConvertClassToCSharp (string javaType) + { + return javaType; + } + + public static string ConvertFieldToCSharp (string javaName) + { + // EX: FOREGROUND_SERVICE_IMMEDIATE + return string.Join ("", javaName.Split ('_').Select (s => SentenceCase (s))); + } + + public static string Capitalize (this string value) + { + if (value.Length < 1) + return value; + + return char.ToUpperInvariant (value[0]) + value.Substring (1); + } + + public static string SentenceCase (this string value) + { + return Capitalize (value.ToLowerInvariant ()); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/Report.cs b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/Report.cs new file mode 100644 index 00000000000..4485049669b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Generator/Utilities/Report.cs @@ -0,0 +1,208 @@ +using System; +using System.Diagnostics; +using System.Xml; +using System.Xml.Linq; + +namespace Java.Interop.Tools.Generator +{ + public class Report + { + public static int? Verbosity { get; set; } + public static Action? OutputDelegate { get; set; } + + public class LocalizedMessage + { + public int Code { get; set; } + public string Value { get; set; } + + public LocalizedMessage (int code, string value) + { + Code = code; + Value = value; + } + } + + public static LocalizedMessage ErrorFailedToRemoveConstants => new LocalizedMessage (0x4000, Localization.Resources.Generator_BG4000); + public static LocalizedMessage ErrorFailedToProcessEnumMap => new LocalizedMessage (0x4100, Localization.Resources.Generator_BG4100); + public static LocalizedMessage ErrorFailedToProcessMetadata => new LocalizedMessage (0x4200, Localization.Resources.Generator_BG4200); + public static LocalizedMessage ErrorRemoveNodeInvalidXPath => new LocalizedMessage (0x4301, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorAddNodeInvalidXPath => new LocalizedMessage (0x4302, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorChangeNodeInvalidXPath => new LocalizedMessage (0x4303, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorAttrInvalidXPath => new LocalizedMessage (0x4304, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorMoveNodeInvalidXPath => new LocalizedMessage (0x4305, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorRemoveAttrInvalidXPath => new LocalizedMessage (0x4306, Localization.Resources.Generator_BG4300); + public static LocalizedMessage ErrorMissingAttrName => new LocalizedMessage (0x4307, Localization.Resources.Generator_BG4307); + public static LocalizedMessage ErrorUnexpectedGlobal => new LocalizedMessage (0x4400, Localization.Resources.Generator_BG4400); + + public static LocalizedMessage WarningUnexpectedChild => new LocalizedMessage (0x8101, Localization.Resources.Generator_BG8101); + public static LocalizedMessage WarningUnknownBaseType => new LocalizedMessage (0x8102, Localization.Resources.Generator_BG8102); + public static LocalizedMessage WarningInvalidBaseType => new LocalizedMessage (0x8103, Localization.Resources.Generator_BG8103); + public static LocalizedMessage WarningAssemblyParseFailure => new LocalizedMessage (0x8200, Localization.Resources.Generator_BG8200); + public static LocalizedMessage WarningMissingClassForConstructor => new LocalizedMessage (0x8300, Localization.Resources.Generator_BG8300); + public static LocalizedMessage WarningUnexpectedFieldType => new LocalizedMessage (0x8400, Localization.Resources.Generator_BG8400); + public static LocalizedMessage WarningFieldNameCollision_Property => new LocalizedMessage (0x8401, Localization.Resources.Generator_BG8401_Property); + public static LocalizedMessage WarningFieldNameCollision_Method => new LocalizedMessage (0x8401, Localization.Resources.Generator_BG8401_Method); + public static LocalizedMessage WarningFieldNameCollision_NestedType => new LocalizedMessage (0x8401, Localization.Resources.Generator_BG8401_NestedType); + public static LocalizedMessage WarningDuplicateField => new LocalizedMessage (0x8402, Localization.Resources.Generator_BG8402); + public static LocalizedMessage WarningTypeNameMatchesEnclosingNamespace => new LocalizedMessage (0x8403, Localization.Resources.Generator_BG8403); + public static LocalizedMessage WarningUnexpectedInterfaceChild => new LocalizedMessage (0x8500, Localization.Resources.Generator_BG8500); + public static LocalizedMessage WarningEmptyEventName => new LocalizedMessage (0x8501, Localization.Resources.Generator_BG8501); + public static LocalizedMessage WarningInvalidDueToInterfaces => new LocalizedMessage (0x8502, Localization.Resources.Generator_BG8502); + public static LocalizedMessage WarningInvalidDueToMethods => new LocalizedMessage (0x8503, Localization.Resources.Generator_BG8503); + public static LocalizedMessage WarningInvalidEventName => new LocalizedMessage (0x8504, Localization.Resources.Generator_BG8504); + public static LocalizedMessage WarningInvalidEventName2 => new LocalizedMessage (0x8505, Localization.Resources.Generator_BG8504); + public static LocalizedMessage WarningInvalidEventPropertyName => new LocalizedMessage (0x8506, Localization.Resources.Generator_BG8506); + public static LocalizedMessage WarningInvalidXmlFile => new LocalizedMessage (0x8600, Localization.Resources.Generator_BG8600); + public static LocalizedMessage WarningNoPackageElements => new LocalizedMessage (0x8601, Localization.Resources.Generator_BG8601); + public static LocalizedMessage WarningUnexpectedRootChildNode => new LocalizedMessage (0x8602, Localization.Resources.Generator_BG8602); + public static LocalizedMessage WarningUnexpectedPackageChildNode => new LocalizedMessage (0x8603, Localization.Resources.Generator_BG8603); + public static LocalizedMessage WarningNestedTypeAncestorNotFound => new LocalizedMessage (0x8604, Localization.Resources.Generator_BG8604); + public static LocalizedMessage WarningJavaTypeNotResolved => new LocalizedMessage (0x8605, Localization.Resources.Generator_BG8605); + public static LocalizedMessage WarningTypesNotBoundDueToMissingJavaTypes => new LocalizedMessage (0x8606, Localization.Resources.Generator_BG8606); + public static LocalizedMessage WarningUnknownReturnType => new LocalizedMessage (0x8700, Localization.Resources.Generator_BG8700); + public static LocalizedMessage WarningInvalidReturnType => new LocalizedMessage (0x8701, Localization.Resources.Generator_BG8701); + public static LocalizedMessage WarningUnknownParameterType => new LocalizedMessage (0x8800, Localization.Resources.Generator_BG8800); + public static LocalizedMessage WarningInvalidParameterType => new LocalizedMessage (0x8801, Localization.Resources.Generator_BG8801); + public static LocalizedMessage WarningRemoveNodeMatchedNoNodes => new LocalizedMessage (0x8A00, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningAddNodeMatchedNoNodes => new LocalizedMessage (0x8A01, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningChangeNodeTypeMatchedNoNodes => new LocalizedMessage (0x8A03, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningAttrMatchedNoNodes => new LocalizedMessage (0x8A04, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningMoveNodeMatchedNoNodes => new LocalizedMessage (0x8A05, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningRemoveAttrMatchedNoNodes => new LocalizedMessage (0x8A06, Localization.Resources.Generator_BG8A00); + public static LocalizedMessage WarningInvalidNamespaceTransform => new LocalizedMessage (0x8A07, Localization.Resources.Generator_BG8A07); + public static LocalizedMessage WarningNodeMissingPathAttribute => new LocalizedMessage (0x8A08, Localization.Resources.Generator_BG8A08); + public static LocalizedMessage WarningUnknownGenericConstraint => new LocalizedMessage (0x8B00, Localization.Resources.Generator_BG8B00); + public static LocalizedMessage WarningBaseInterfaceNotFound => new LocalizedMessage (0x8C00, Localization.Resources.Generator_BG8C00); + public static LocalizedMessage WarningBaseInterfaceInvalid => new LocalizedMessage (0x8C01, Localization.Resources.Generator_BG8C01); + public static LocalizedMessage WarningKotlinNameMangledCollision => new LocalizedMessage (0x8C02, Localization.Resources.Generator_BG8C02); + + public static void LogCodedErrorAndExit (LocalizedMessage message, params string [] args) + => LogCodedErrorAndExit (message, null, null, args); + + public static void LogCodedErrorAndExit (LocalizedMessage message, Exception? innerException, params string [] args) + => LogCodedErrorAndExit (message, innerException, null, args); + + public static void LogCodedErrorAndExit (LocalizedMessage message, Exception? innerException, XNode? node, params string? [] args) + { + LogCodedError (message, node, args); + + // Throwing a BindingGeneratorException will cause generator to terminate + throw new BindingGeneratorException (message.Code, string.Format (message.Value, args), innerException); + } + + public static void LogCodedError (LocalizedMessage message, XNode? node, params string? [] args) + { + var (file, line, col) = GetLineInfo (node); + + LogCodedError (message, file, line, col, args); + } + + public static void LogCodedError (LocalizedMessage message, string? sourceFile, int line, int column, params string? [] args) + { + WriteOutput (TraceLevel.Error, Format (true, message.Code, sourceFile, line, column, message.Value, args)); + } + + public static void LogCodedWarning (int verbosity, LocalizedMessage message, params string? [] args) + => LogCodedWarning (verbosity, message, null, null, -1, -1, args); + + public static void LogCodedWarning (int verbosity, LocalizedMessage message, ISourceLineInfo sourceInfo, params string? [] args) + => LogCodedWarning (verbosity, message, null, sourceInfo.SourceFile, sourceInfo.LineNumber, sourceInfo.LinePosition, args); + + public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception? innerException, params string? [] args) + => LogCodedWarning (verbosity, message, innerException, null, -1, -1, args); + + public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception? innerException, XNode node, params string? [] args) + { + var (file, line, col) = GetLineInfo (node); + + LogCodedWarning (verbosity, message, innerException, file, line, col, args); + } + + public static void LogCodedWarning (int verbosity, LocalizedMessage message, Exception? innerException, string? sourceFile, int line, int column, params string? [] args) + { + if (verbosity > (Verbosity ?? 0)) + return; + + var supp = innerException != null ? " For details, see verbose output." : null; + WriteOutput (TraceLevel.Warning, Format (false, message.Code, sourceFile, line, column, message.Value, args) + supp); + + if (innerException != null) + WriteOutput (TraceLevel.Warning, innerException.ToString ()); + } + + public static void Verbose (int verbosity, string format, params object?[] args) + { + if (verbosity > (Verbosity ?? 0)) + return; + WriteOutput (TraceLevel.Verbose, format, args); + } + + public static string FormatCodedMessage (bool error, LocalizedMessage message, params object? [] args) + => Format (error, message.Code, null, -1, -1, message.Value, args); + + public static string Format (bool error, int errorCode, string? sourceFile, int line, int column, string format, params object?[] args) + { + var origin = FormatOrigin (sourceFile, line, column); + + return $"{origin}{(error ? "error" : "warning")} BG{errorCode:X04}: " + string.Format (format, args); + } + + static string? FormatOrigin (string? sourceFile, int line, int column) + { + if (string.IsNullOrWhiteSpace (sourceFile)) + return null; + + var ret = sourceFile; + + if (line == 0) + return ret + ": "; + + if (column > 0) + return ret + $"({line},{column}): "; + + return ret + $"({line}): "; + } + + static (string? file, int line, int col) GetLineInfo (XNode? node) + { + if (node is null) + return (null, -1, -1); + + var file = Uri.TryCreate (node.BaseUri, UriKind.Absolute, out var uri) ? uri.LocalPath : null; + var pos = (node as IXmlLineInfo)?.HasLineInfo () == true ? node as IXmlLineInfo : null; + + return (file, pos?.LineNumber ?? -1, pos?.LinePosition ?? -1); + } + + static void WriteOutput (TraceLevel traceLevel, string format, params object?[] args) + { + // Write to overridden output if requested + if (OutputDelegate != null) { + OutputDelegate (traceLevel, string.Format (format, args)); + return; + } + + // Write to Console.Error + Console.Error.WriteLine (format, args); + } + } + + /// + /// Throwing this exception will cause generator to exit gracefully. + /// + public class BindingGeneratorException : Exception + { + public BindingGeneratorException (int errorCode, string message) + : this (errorCode, message, null) + { + } + public BindingGeneratorException (int errorCode, string message, Exception? innerException) + : this (errorCode, null, -1, -1, message, innerException) + { + } + public BindingGeneratorException (int errorCode, string? sourceFile, int line, int column, string message, Exception? innerException) + : base (Report.Format (true, errorCode, sourceFile, line, column, message), innerException) + { + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Extensions/XmlExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Extensions/XmlExtensions.cs new file mode 100644 index 00000000000..b70f24aae8e --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Extensions/XmlExtensions.cs @@ -0,0 +1,41 @@ +using System; +using System.Xml; +using System.Xml.Linq; + +namespace Java.Interop.Tools.JavaCallableWrappers.Extensions; + +static class XmlExtensions +{ + public static T GetAttributeOrDefault (this XElement xml, string name, T defaultValue) + { + var value = xml.Attribute (name)?.Value; + + if (string.IsNullOrWhiteSpace (value)) + return defaultValue; + + return (T) Convert.ChangeType (value, typeof (T)); + } + + public static string GetRequiredAttribute (this XElement xml, string name) + { + var value = xml.Attribute (name)?.Value; + + if (string.IsNullOrWhiteSpace (value)) + throw new InvalidOperationException ($"Missing required attribute '{name}' within element `{xml.ToString()}`."); + + return value!; // NRT - Guarded by IsNullOrWhiteSpace check above + } + + public static void WriteAttributeStringIfNotNull (this XmlWriter xml, string name, string? value) + { + if (value is not null) + xml.WriteAttributeString (name, value); + } + + public static void WriteAttributeStringIfNotFalse (this XmlWriter xml, string name, bool value) + { + // If value is false, don't write the attribute, we'll default to false on import + if (value) + xml.WriteAttributeString (name, value.ToString ()); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs new file mode 100644 index 00000000000..c60045c0103 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs @@ -0,0 +1,570 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Android.Runtime; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Diagnostics; +using Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; +using Java.Interop.Tools.JavaCallableWrappers.Utilities; +using Java.Interop.Tools.TypeNameMappings; +using Mono.Cecil; + +namespace Java.Interop.Tools.JavaCallableWrappers.Adapters; + +public class CecilImporter +{ + // Don't expose internal "outerType" parameter to the public API + public static CallableWrapperType CreateType (TypeDefinition type, IMetadataResolver resolver, CallableWrapperReaderOptions? options = null) + => CreateType (type, resolver, options, null); + + static CallableWrapperType CreateType (TypeDefinition type, IMetadataResolver resolver, CallableWrapperReaderOptions? options = null, string? outerType = null) + { + if (type.IsEnum || type.IsInterface || type.IsValueType) + Diagnostic.Error (4200, CecilExtensions.LookupSource (type), Localization.Resources.JavaCallableWrappers_XA4200, type.FullName); + + var jniName = JavaNativeTypeManager.ToJniName (type, resolver); + + if (jniName is null) + Diagnostic.Error (4201, CecilExtensions.LookupSource (type), Localization.Resources.JavaCallableWrappers_XA4201, type.FullName); + + if (outerType != null && !string.IsNullOrEmpty (outerType)) { + jniName = jniName.Substring (outerType.Length + 1); + ExtractJavaNames (outerType, out var p, out outerType); + } + + ExtractJavaNames (jniName, out var package, out var name); + + options ??= new CallableWrapperReaderOptions (); + + if (string.IsNullOrEmpty (package) && + (type.IsSubclassOf ("Android.App.Activity", resolver) || + type.IsSubclassOf ("Android.App.Application", resolver) || + type.IsSubclassOf ("Android.App.Service", resolver) || + type.IsSubclassOf ("Android.Content.BroadcastReceiver", resolver) || + type.IsSubclassOf ("Android.Content.ContentProvider", resolver))) + Diagnostic.Error (4203, CecilExtensions.LookupSource (type), Localization.Resources.JavaCallableWrappers_XA4203, jniName); + + var cwt = new CallableWrapperType (name, package, type.GetPartialAssemblyQualifiedName (resolver)) { + IsApplication = JavaNativeTypeManager.IsApplication (type, resolver), + IsInstrumentation = JavaNativeTypeManager.IsInstrumentation (type, resolver), + IsAbstract = type.IsAbstract, + ApplicationJavaClass = options.DefaultApplicationJavaClass, + GenerateOnCreateOverrides = options.DefaultGenerateOnCreateOverrides, + MonoRuntimeInitialization = options.DefaultMonoRuntimeInitialization, + }; + + // Type annotations + cwt.Annotations.AddRange (CreateAnnotations (type, resolver)); + + // Extends + cwt.ExtendsType = GetJavaTypeName (type.BaseType, resolver); + + // Implemented interfaces + foreach (var ifaceInfo in type.Interfaces) { + var iface = resolver.Resolve (ifaceInfo.InterfaceType); + if (iface is null) + continue; + + if (!CecilExtensions.GetTypeRegistrationAttributes (iface).Any ()) + continue; + + cwt.ImplementedInterfaces.Add (GetJavaTypeName (iface, resolver)); + } + + // Application constructor + if (CreateApplicationConstructor (cwt.Name, type, resolver) is CallableWrapperApplicationConstructor app_ctor) + cwt.ApplicationConstructor = app_ctor; + + // Methods + foreach (var minfo in type.Methods.Where (m => !m.IsConstructor)) { + var baseRegisteredMethod = CecilExtensions.GetBaseRegisteredMethod (minfo, resolver); + + if (baseRegisteredMethod is not null) + AddMethod (cwt, type, baseRegisteredMethod, minfo, options.MethodClassifier, resolver); + else if (minfo.AnyCustomAttributes ("Java.Interop.JavaCallableAttribute")) { + AddMethod (cwt, type, null, minfo, options.MethodClassifier, resolver); + cwt.HasExport = true; + } else if (minfo.AnyCustomAttributes ("Java.Interop.JavaCallableConstructorAttribute")) { + AddMethod (cwt, type, null, minfo, options.MethodClassifier, resolver); + cwt.HasExport = true; + } else if (minfo.AnyCustomAttributes (typeof (ExportFieldAttribute))) { + AddMethod (cwt, type, null, minfo, options.MethodClassifier, resolver); + cwt.HasExport = true; + } else if (minfo.AnyCustomAttributes (typeof (ExportAttribute))) { + AddMethod (cwt, type, null, minfo, options.MethodClassifier, resolver); + cwt.HasExport = true; + } + } + + // Methods from interfaces + foreach (InterfaceImplementation ifaceInfo in type.Interfaces) { + var typeReference = ifaceInfo.InterfaceType; + var typeDefinition = resolver.Resolve (typeReference); + + if (typeDefinition is null) { + Diagnostic.Error (4204, + CecilExtensions.LookupSource (type), + Localization.Resources.JavaCallableWrappers_XA4204, + typeReference.FullName); + continue; + } + + if (!CecilExtensions.GetTypeRegistrationAttributes (typeDefinition).Any ()) + continue; + + foreach (MethodDefinition imethod in typeDefinition.Methods) { + if (imethod.IsStatic) + continue; + + AddMethod (cwt, type, imethod, imethod, options.MethodClassifier, resolver); + } + } + + // Constructors + var ctorTypes = new List () { + type, + }; + + foreach (var bt in type.GetBaseTypes (resolver)) { + ctorTypes.Add (bt); + var rattr = CecilExtensions.GetTypeRegistrationAttributes (bt).FirstOrDefault (); + + if (rattr != null && rattr.DoNotGenerateAcw) + break; + } + + ctorTypes.Reverse (); + + var curCtors = new List (); + + foreach (var minfo in type.Methods) { + if (minfo.IsConstructor && minfo.AnyCustomAttributes (typeof (ExportAttribute))) { + if (minfo.IsStatic) { + // Diagnostic.Warning (log, "ExportAttribute does not work on static constructor"); + } else { + if (CreateConstructor (cwt, minfo, ctorTypes [0], type, outerType, null, curCtors, false, true, resolver) is CallableWrapperConstructor c) + cwt.Constructors.Add (c); + + cwt.HasExport = true; + } + } + } + + AddConstructors (cwt, ctorTypes [0], type, outerType, null, curCtors, true, resolver); + + for (var i = 1; i < ctorTypes.Count; ++i) { + var baseCtors = curCtors; + curCtors = new List (); + AddConstructors (cwt, ctorTypes [i], type, outerType, baseCtors, curCtors, false, resolver); + } + + AddNestedTypes (cwt, type, resolver, options); + + return cwt; + } + + static CallableWrapperField CreateField (MethodDefinition method, string fieldName, IMetadataResolver resolver) + { + var visibility = GetJavaAccess (method.Attributes & MethodAttributes.MemberAccessMask); + var type_name = JavaNativeTypeManager.ReturnTypeFromSignature (JavaNativeTypeManager.GetJniSignature (method, resolver))?.Type + ?? throw new ArgumentException ($"Could not get JNI signature for method `{method.Name}`", nameof (method)); + + var field = new CallableWrapperField (fieldName, type_name, visibility, method.Name) { + IsStatic = method.IsStatic, + }; + + field.Annotations.AddRange (CreateAnnotations (method, resolver)); + + return field; + } + + // Constructor with [Register] attribute + static CallableWrapperConstructor CreateConstructor (MethodDefinition methodDefinition, CallableWrapperType type, RegisterAttribute register, string? managedParameters, string? outerType, IMetadataResolver cache, bool shouldBeDynamicallyRegistered = true) + { + var method = CreateConstructor (methodDefinition.Name, type, register.Signature, register.Connector, managedParameters, outerType, null); + + method.Annotations.AddRange (CreateAnnotations (methodDefinition, cache)); + method.IsDynamicallyRegistered = shouldBeDynamicallyRegistered; + + return method; + } + + // Constructor with [Export] attribute + static CallableWrapperConstructor CreateConstructor (MethodDefinition methodDefinition, CallableWrapperType type, ExportAttribute export, string? managedParameters, IMetadataResolver resolver) + { + var method = CreateConstructor (methodDefinition.Name, type, JavaNativeTypeManager.GetJniSignature (methodDefinition, resolver), "__export__", null, null, export.SuperArgumentsString); + + method.IsExport = true; + method.IsStatic = methodDefinition.IsStatic; + method.JavaAccess = GetJavaAccess (methodDefinition.Attributes & MethodAttributes.MemberAccessMask); + method.ThrownTypeNames = export.ThrownNames; + method.JavaNameOverride = export.Name; + method.ManagedParameters = managedParameters; + method.Annotations.AddRange (CreateAnnotations (methodDefinition, resolver)); + + return method; + } + + // Common constructor creation code + static CallableWrapperConstructor CreateConstructor (string name, CallableWrapperType type, string? signature, string? connector, string? managedParameters, string? outerType, string? superCall) + { + signature = signature ?? throw new ArgumentNullException ("`connector` cannot be null.", nameof (connector)); + var method_name = "n_" + name + ":" + signature + ":" + connector; + + var method = new CallableWrapperConstructor (type, name, method_name, signature); + + PopulateMethod (method, signature, managedParameters, outerType, superCall); + + method.Name = type.Name; + + return method; + } + + // Method with a [Register] attribute + static CallableWrapperMethod CreateMethod (MethodDefinition methodDefinition, CallableWrapperType declaringType, RegisterAttribute register, string? managedParameters, string? outerType, IMetadataResolver resolver, bool shouldBeDynamicallyRegistered = true) + { + var method = CreateMethod (register.Name, declaringType, register.Signature, register.Connector, managedParameters, outerType, null); + + method.Annotations.AddRange (CreateAnnotations (methodDefinition, resolver)); + method.IsDynamicallyRegistered = shouldBeDynamicallyRegistered; + + return method; + } + + // Method with an [Export] attribute + static CallableWrapperMethod CreateMethod (MethodDefinition methodDefinition, CallableWrapperType declaringType, ExportAttribute export, string? managedParameters, IMetadataResolver resolver) + { + var method = CreateMethod (methodDefinition.Name, declaringType, JavaNativeTypeManager.GetJniSignature (methodDefinition, resolver), "__export__", null, null, export.SuperArgumentsString); + + method.IsExport = true; + method.IsStatic = methodDefinition.IsStatic; + method.JavaAccess = GetJavaAccess (methodDefinition.Attributes & MethodAttributes.MemberAccessMask); + method.ThrownTypeNames = export.ThrownNames; + method.JavaNameOverride = export.Name; + method.ManagedParameters = managedParameters; + method.Annotations.AddRange (CreateAnnotations (methodDefinition, resolver)); + + return method; + } + + // Method with an [ExportField] attribute + static CallableWrapperMethod CreateMethod (MethodDefinition methodDefinition, CallableWrapperType declaringType, IMetadataResolver resolver) + { + var method = CreateMethod (methodDefinition.Name, declaringType, JavaNativeTypeManager.GetJniSignature (methodDefinition, resolver), "__export__", null, null, null); + + if (methodDefinition.HasParameters) + Diagnostic.Error (4205, CecilExtensions.LookupSource (methodDefinition), Localization.Resources.JavaCallableWrappers_XA4205); + if (methodDefinition.ReturnType.MetadataType == MetadataType.Void) + Diagnostic.Error (4208, CecilExtensions.LookupSource (methodDefinition), Localization.Resources.JavaCallableWrappers_XA4208); + + method.IsExport = true; + method.IsStatic = methodDefinition.IsStatic; + method.JavaAccess = GetJavaAccess (methodDefinition.Attributes & MethodAttributes.MemberAccessMask); + + // Annotations are processed within CallableWrapperField, not the initializer method. So we don't generate them here. + + return method; + } + + // Common method creation code + static CallableWrapperMethod CreateMethod (string name, CallableWrapperType declaringType, string? signature, string? connector, string? managedParameters, string? outerType, string? superCall) + { + signature = signature ?? throw new ArgumentNullException ("`connector` cannot be null.", nameof (connector)); + var method_name = "n_" + name + ":" + signature + ":" + connector?.Replace ('/', '+'); + + var method = new CallableWrapperMethod (declaringType, name, method_name, signature); + + PopulateMethod (method, signature, managedParameters, outerType, superCall); + + return method; + } + + // This is done this way to allow sharing between CallableWrapperMethod and CallableWrapperConstructor + static void PopulateMethod (CallableWrapperMethod method, string signature, string? managedParameters, string? outerType, string? superCall) + { + method.ManagedParameters = managedParameters; + + var jnisig = signature; + var closer = jnisig.IndexOf (')'); + var ret = jnisig.Substring (closer + 1); + + method.Retval = JavaNativeTypeManager.Parse (ret)?.Type; + + var jniparms = jnisig.Substring (1, closer - 1); + + if (string.IsNullOrEmpty (jniparms) && string.IsNullOrEmpty (superCall)) + return; + + var parms = new StringBuilder (); + var scall = new StringBuilder (); + var acall = new StringBuilder (); + var first = true; + var i = 0; + + foreach (var jti in JavaNativeTypeManager.FromSignature (jniparms)) { + if (outerType != null) { + acall.Append (outerType).Append (".this"); + outerType = null; + continue; + } + + var parmType = jti.Type; + + if (!first) { + parms.Append (", "); + scall.Append (", "); + acall.Append (", "); + } + + first = false; + parms.Append (parmType).Append (" p").Append (i); + scall.Append ("p").Append (i); + acall.Append ("p").Append (i); + ++i; + } + + method.Params = parms.ToString (); + method.SuperCall = superCall ?? scall.ToString (); + method.ActivateCall = acall.ToString (); + } + + static void AddConstructors (CallableWrapperType declaringType, TypeDefinition type, TypeDefinition rootType, string? outerType, List? baseCtors, List curCtors, bool onlyRegisteredOrExportedCtors, IMetadataResolver cache) + { + foreach (var ctor in type.Methods) + if (ctor.IsConstructor && !ctor.IsStatic && !ctor.AnyCustomAttributes (typeof (ExportAttribute))) + if (CreateConstructor (declaringType, ctor, type, rootType, outerType, baseCtors, curCtors, onlyRegisteredOrExportedCtors, false, cache) is CallableWrapperConstructor c) + declaringType.Constructors.Add (c); + } + + static CallableWrapperConstructor? CreateConstructor (CallableWrapperType declaringType, MethodDefinition ctor, TypeDefinition type, TypeDefinition rootType, string? outerType, List? baseCtors, List curCtors, bool onlyRegisteredOrExportedCtors, bool skipParameterCheck, IMetadataResolver cache) + { + // We create a parameter-less constructor for the application class, so don't use the imported one + if (!ctor.HasParameters && JavaNativeTypeManager.IsApplication (rootType, cache)) + return null; + + var managedParameters = GetManagedParameters (ctor, outerType, type, cache); + + if (!skipParameterCheck && (managedParameters == null || declaringType.Constructors.Any (c => c.ManagedParameters == managedParameters))) + return null; + + // Constructor with [Export] attribute + var eattr = CecilExtensions.GetExportAttributes (ctor, cache).FirstOrDefault (); + + if (eattr != null) { + if (!string.IsNullOrEmpty (eattr.Name)) { + // Diagnostic.Warning (log, "Use of ExportAttribute.Name property is invalid on constructors"); + } + + curCtors.Add (ctor); + return CreateConstructor (ctor, declaringType, eattr, managedParameters, cache); + } + + // Constructor with [Register] attribute + var rattr = CecilExtensions.GetMethodRegistrationAttributes (ctor).FirstOrDefault (); + + if (rattr != null) { + if (declaringType.Constructors.Any (c => c.JniSignature == rattr.Signature)) + return null; + + curCtors.Add (ctor); + return CreateConstructor (ctor, declaringType, rattr, managedParameters, outerType, cache); + } + + if (onlyRegisteredOrExportedCtors) + return null; + + // Constructors without [Export] or [Register] attributes + var jniSignature = JavaNativeTypeManager.GetJniSignature (ctor, cache); + + if (jniSignature is null) + return null; + + if (declaringType.Constructors.Any (c => c.JniSignature == jniSignature)) + return null; + + if (baseCtors is null) + throw new InvalidOperationException ("`baseCtors` should not be null!"); + + if (baseCtors.Any (m => m.Parameters.AreParametersCompatibleWith (ctor.Parameters, cache))) { + curCtors.Add (ctor); + return CreateConstructor (".ctor", declaringType, jniSignature, "", managedParameters, outerType, null); + } + + if (baseCtors.Any (m => !m.HasParameters)) { + curCtors.Add (ctor); + return CreateConstructor (".ctor", declaringType, jniSignature, "", managedParameters, outerType, ""); + } + + return null; + } + + static string GetManagedParameters (MethodDefinition ctor, string? outerType, TypeDefinition type, IMetadataResolver cache) + { + var sb = new StringBuilder (); + + foreach (var pdef in ctor.Parameters) { + if (sb.Length > 0) + sb.Append (':'); + if (outerType != null && sb.Length == 0) + sb.Append (type.DeclaringType.GetPartialAssemblyQualifiedName (cache)); + else + sb.Append (pdef.ParameterType.GetPartialAssemblyQualifiedName (cache)); + } + + return sb.ToString (); + } + + static CallableWrapperApplicationConstructor? CreateApplicationConstructor (string name, TypeDefinition type, IMetadataResolver resolver) + { + if (!JavaNativeTypeManager.IsApplication (type, resolver)) + return null; + + return new CallableWrapperApplicationConstructor (name); + } + + static void AddNestedTypes (CallableWrapperType declaringType, TypeDefinition type, IMetadataResolver cache, CallableWrapperReaderOptions? options) + { + if (!type.HasNestedTypes) + return; + + foreach (var nt in type.NestedTypes) { + if (!nt.HasJavaPeer (cache)) + continue; + if (!JavaNativeTypeManager.IsNonStaticInnerClass (nt, cache)) + continue; + + declaringType.NestedTypes.Add (CreateType (nt, cache, options, JavaNativeTypeManager.ToJniName (type, cache))); + AddNestedTypes (declaringType, nt, cache, options); + } + + declaringType.HasExport |= declaringType.NestedTypes.Any (t => t.HasExport); + } + + static void AddMethod (CallableWrapperType declaringType, TypeDefinition type, MethodDefinition? registeredMethod, MethodDefinition implementedMethod, JavaCallableMethodClassifier? methodClassifier, IMetadataResolver cache) + { + if (registeredMethod != null) + foreach (RegisterAttribute attr in CecilExtensions.GetMethodRegistrationAttributes (registeredMethod)) { + // Check for Kotlin-mangled methods that cannot be overridden + if (attr.Name.Contains ("-impl") || (attr.Name.Length > 7 && attr.Name [attr.Name.Length - 8] == '-')) + Diagnostic.Error (4217, CecilExtensions.LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4217, attr.Name); + + var shouldBeDynamicallyRegistered = methodClassifier?.ShouldBeDynamicallyRegistered (type, registeredMethod, implementedMethod, attr.OriginAttribute) ?? true; + var method = CreateMethod (implementedMethod, declaringType, attr, null, null, cache, shouldBeDynamicallyRegistered); + + if (!registeredMethod.IsConstructor && !declaringType.Methods.Any (m => m.Name == method.Name && m.Params == method.Params)) + declaringType.Methods.Add (method); + } + foreach (ExportAttribute attr in CecilExtensions.GetExportAttributes (implementedMethod, cache)) { + if (type.HasGenericParameters) + Diagnostic.Error (4206, CecilExtensions.LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4206); + + var method = CreateMethod (implementedMethod, declaringType, attr, null, cache); + + if (!string.IsNullOrEmpty (attr.SuperArgumentsString)) { + // Diagnostic.Warning (log, "Use of ExportAttribute.SuperArgumentsString property is invalid on methods"); + } + + if (!implementedMethod.IsConstructor && !declaringType.Methods.Any (m => m.Name == method.Name && m.Params == method.Params)) + declaringType.Methods.Add (method); + } + foreach (ExportFieldAttribute attr in CecilExtensions.GetExportFieldAttributes (implementedMethod)) { + if (type.HasGenericParameters) + Diagnostic.Error (4207, CecilExtensions.LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4207); + + var method = CreateMethod (implementedMethod, declaringType, cache); + + if (!implementedMethod.IsConstructor && !declaringType.Methods.Any (m => m.Name == method.Name && m.Params == method.Params)) { + declaringType.Methods.Add (method); + declaringType.Fields.Add (CreateField (implementedMethod, attr.Name, cache)); + } + } + } + + static void ExtractJavaNames (string jniName, out string package, out string type) + { + var i = jniName.LastIndexOf ('/'); + + if (i < 0) { + type = jniName; + package = string.Empty; + } else { + type = jniName.Substring (i + 1); + package = jniName.Substring (0, i).Replace ('/', '.'); + } + } + + static string GetJavaTypeName (TypeReference r, IMetadataResolver cache) + { + var d = cache.Resolve (r); + var jniName = JavaNativeTypeManager.ToJniName (d, cache); + + if (jniName is null) { + Diagnostic.Error (4201, Localization.Resources.JavaCallableWrappers_XA4201, r.FullName); + throw new InvalidOperationException ("--nrt:jniName-- Should not be reached"); + } + + return jniName.Replace ('/', '.').Replace ('$', '.'); + } + + static IEnumerable CreateAnnotations (ICustomAttributeProvider type, IMetadataResolver resolver) + { + foreach (var ca in type.CustomAttributes) { + var annotation = CreateAnnotation (ca, resolver); + + if (annotation is not null) + yield return annotation; + } + } + + static CallableWrapperTypeAnnotation? CreateAnnotation (CustomAttribute ca, IMetadataResolver resolver) + { + var catype = resolver.Resolve (ca.AttributeType); + var tca = catype.CustomAttributes.FirstOrDefault (a => a.AttributeType.FullName == "Android.Runtime.AnnotationAttribute"); + + if (tca is null) + return null; + + var name_object = tca.ConstructorArguments [0].Value; + + // Should never be hit + if (name_object is not string name) + throw new ArgumentException ($"Expected a string for the first argument of the {nameof (RegisterAttribute)} constructor.", nameof (ca)); + + var annotation = new CallableWrapperTypeAnnotation (name); + + foreach (var p in ca.Properties) { + var pd = catype.Properties.FirstOrDefault (pp => pp.Name == p.Name); + var reg = pd?.CustomAttributes.FirstOrDefault (pdca => pdca.AttributeType.FullName == "Android.Runtime.RegisterAttribute"); + var key = reg != null ? (string) reg.ConstructorArguments [0].Value : p.Name; + var value = ManagedValueToJavaSource (p.Argument.Value); + + annotation.Properties.Add (new KeyValuePair (key, value)); + } + + return annotation; + } + + // FIXME: this is hacky. Is there any existing code for value to source conversion? + static string ManagedValueToJavaSource (object value) + { + if (value is string) + return "\"" + value.ToString ()?.Replace ("\"", "\"\"") + '"'; + else if (value.GetType ().FullName == "Java.Lang.Class") + return value.ToString () + ".class"; + else if (value is bool v) + return v ? "true" : "false"; + else + return value.ToString () ?? ""; + } + + static string GetJavaAccess (MethodAttributes access) + { + return access switch { + MethodAttributes.Public => "public", + MethodAttributes.FamORAssem => "protected", + MethodAttributes.Family => "protected", + _ => "private", + }; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/XmlExporter.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/XmlExporter.cs new file mode 100644 index 00000000000..748270142f0 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/XmlExporter.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; +using Java.Interop.Tools.JavaCallableWrappers.Extensions; + +namespace Java.Interop.Tools.JavaCallableWrappers.Adapters; + +public static class XmlExporter +{ + static XmlWriterSettings settings = new XmlWriterSettings { + Indent = true, + NewLineOnAttributes = false, + OmitXmlDeclaration = true, + }; + + public static void Export (string filename, IEnumerable types) + { + using (var sw = new StreamWriter (filename, false, Encoding.UTF8)) + Export (sw, types); + } + + public static void Export (TextWriter sw, IEnumerable types) + { + using (var xml = XmlWriter.Create (sw, settings)) + Export (xml, types); + } + + public static void Export (XmlWriter xml, IEnumerable types) + { + ExportTypes (xml, types); + } + + static void ExportTypes (XmlWriter xml, IEnumerable types) + { + foreach (var type in types) + ExportType (xml, type); + } + + public static void ExportType (XmlWriter xml, CallableWrapperType type) + { + xml.WriteStartElement ("type"); + xml.WriteAttributeString ("name", type.Name); + xml.WriteAttributeString ("package", type.Package); + xml.WriteAttributeStringIfNotFalse ("is_abstract", type.IsAbstract); + xml.WriteAttributeStringIfNotNull ("application_java_class", type.ApplicationJavaClass); + xml.WriteAttributeStringIfNotFalse ("generate_on_create_overrides", type.GenerateOnCreateOverrides); + xml.WriteAttributeStringIfNotNull ("mono_runtime_initialization", type.MonoRuntimeInitialization); + xml.WriteAttributeStringIfNotNull ("extends_type", type.ExtendsType); + xml.WriteAttributeStringIfNotFalse ("is_application", type.IsApplication); + xml.WriteAttributeStringIfNotFalse ("is_instrumentation", type.IsInstrumentation); + xml.WriteAttributeString ("partial_assembly_qualified_name", type.PartialAssemblyQualifiedName); + xml.WriteAttributeStringIfNotFalse ("has_export", type.HasExport); + + if (type.ApplicationConstructor is not null) + xml.WriteAttributeString ("application_constructor", type.ApplicationConstructor.Name); + + ExportAnnotations (xml, type.Annotations); + ExportImplementedInterfaces (xml, type.ImplementedInterfaces); + ExportConstructors (xml, type.Constructors); + ExportFields (xml, type.Fields); + ExportMethods (xml, type.Methods); + ExportNestedTypes (xml, type.NestedTypes); + + xml.WriteEndElement (); + } + + static void ExportAnnotations (XmlWriter writer, IEnumerable annotations) + { + if (annotations.Count () == 0) + return; + + writer.WriteStartElement ("annotations"); + + foreach (var annotation in annotations) { + writer.WriteStartElement ("annotation"); + writer.WriteAttributeString ("name", annotation.Name); + + foreach (var property in annotation.Properties) { + writer.WriteStartElement ("property"); + writer.WriteAttributeString ("name", property.Key); + writer.WriteAttributeString ("value", property.Value); + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + static void ExportImplementedInterfaces (XmlWriter writer, List interfaces) + { + if (interfaces.Count == 0) + return; + + writer.WriteStartElement ("implemented_interfaces"); + + foreach (var @interface in interfaces) { + writer.WriteStartElement ("interface"); + writer.WriteAttributeString ("name", @interface); + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + static void ExportConstructors (XmlWriter xml, IEnumerable constructors) + { + if (constructors.Count () == 0) + return; + + xml.WriteStartElement ("constructors"); + + foreach (var constructor in constructors) + ExportMethod (xml, constructor); + + xml.WriteEndElement (); + } + + static void ExportFields (XmlWriter xml, IEnumerable fields) + { + if (fields.Count () == 0) + return; + + xml.WriteStartElement ("fields"); + + foreach (var field in fields) { + xml.WriteStartElement ("field"); + xml.WriteAttributeString ("name", field.FieldName); + xml.WriteAttributeString ("type", field.TypeName); + xml.WriteAttributeString ("visibility", field.Visibility); + xml.WriteAttributeStringIfNotFalse ("is_static", field.IsStatic); + xml.WriteAttributeString ("initializer_name", field.InitializerName); + ExportAnnotations (xml, field.Annotations); + xml.WriteEndElement (); + } + + xml.WriteEndElement (); + } + + static void ExportMethods (XmlWriter xml, IEnumerable methods) + { + if (methods.Count () == 0) + return; + + xml.WriteStartElement ("methods"); + + foreach (var method in methods) + ExportMethod (xml, method); + + xml.WriteEndElement (); + } + + static void ExportMethod (XmlWriter xml, CallableWrapperMethod method) + { + xml.WriteStartElement (method is CallableWrapperConstructor ? "constructor" : "method"); + xml.WriteAttributeString ("name", method.Name); + xml.WriteAttributeString ("method", method.Method); + xml.WriteAttributeString ("jni_signature", method.JniSignature); + xml.WriteAttributeStringIfNotNull ("managed_parameters", method.ManagedParameters); + xml.WriteAttributeStringIfNotNull ("java_name_override", method.JavaNameOverride); + xml.WriteAttributeStringIfNotNull ("params", method.Params); + xml.WriteAttributeStringIfNotNull ("retval", method.Retval); + xml.WriteAttributeStringIfNotNull ("java_access", method.JavaAccess); + xml.WriteAttributeStringIfNotFalse ("is_export", method.IsExport); + xml.WriteAttributeStringIfNotFalse ("is_static", method.IsStatic); + xml.WriteAttributeStringIfNotFalse ("is_dynamically_registered", method.IsDynamicallyRegistered); + xml.WriteAttributeStringIfNotNull ("thrown_type_names", method.ThrownTypeNames != null ? string.Join (", ", method.ThrownTypeNames) : null); + xml.WriteAttributeStringIfNotNull ("super_call", method.SuperCall); + xml.WriteAttributeStringIfNotNull ("activate_call", method.ActivateCall); + + ExportAnnotations (xml, method.Annotations); + + xml.WriteEndElement (); + } + + static void ExportNestedTypes (XmlWriter xml, IEnumerable nestedTypes) + { + if (nestedTypes.Count () == 0) + return; + + xml.WriteStartElement ("nested_types"); + + foreach (var nestedType in nestedTypes) + ExportType (xml, nestedType); + + xml.WriteEndElement (); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/XmlImporter.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/XmlImporter.cs new file mode 100644 index 00000000000..32702c75013 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/XmlImporter.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; +using Java.Interop.Tools.JavaCallableWrappers.Extensions; +using Java.Interop.Tools.TypeNameMappings; + +namespace Java.Interop.Tools.JavaCallableWrappers.Adapters; + +public static class XmlImporter +{ + public static List Import (string filename) + { + using (var sr = new StreamReader (filename, Encoding.UTF8)) + return Import (sr); + } + + public static List Import (TextReader sr) + { + using (var xml = XmlReader.Create (sr)) + return Import (xml); + } + + public static List Import (XmlReader xml) + { + var doc = XDocument.Load (xml); + + var types = new List (); + + foreach (var type in doc.Root.Elements ("type")) + types.Add (ImportType (type)); + + return types; + } + + + public static List Import (XElement xml) + { + var types = new List (); + + foreach (var type in xml.Elements ("type")) + types.Add (ImportType (type)); + + return types; + } + + public static CallableWrapperType ImportType (XElement xml) + { + var name = xml.GetRequiredAttribute ("name"); + var package = xml.GetAttributeOrDefault ("package", (string?) ""); + var partial_assembly_qualified_name = xml.GetRequiredAttribute ("partial_assembly_qualified_name"); + + // If package is empty, generate a crc64 package name from the assembly qualified name + if (string.IsNullOrEmpty (package)) + package = GeneratePackageFromAssemblyQualifiedName (partial_assembly_qualified_name); + + var type = new CallableWrapperType (name, package ?? "", partial_assembly_qualified_name) { + ApplicationJavaClass = xml.GetAttributeOrDefault ("application_java_class", (string?) null), + ExtendsType = xml.GetAttributeOrDefault ("extends_type", (string?) null), + GenerateOnCreateOverrides = xml.GetAttributeOrDefault ("generate_on_create_overrides", false), + HasExport = xml.GetAttributeOrDefault ("has_export", false), + IsAbstract = xml.GetAttributeOrDefault ("is_abstract", false), + IsApplication = xml.GetAttributeOrDefault ("is_application", false), + IsInstrumentation = xml.GetAttributeOrDefault ("is_instrumentation", false), + MonoRuntimeInitialization = xml.GetAttributeOrDefault ("mono_runtime_initialization", (string?) null), + }; + + if (xml.GetAttributeOrDefault ("application_constructor", (string?) null) is string applicationConstructor) + type.ApplicationConstructor = new CallableWrapperApplicationConstructor (applicationConstructor); + + ImportAnnotations (type.Annotations, xml.Element ("annotations")); + ImportImplementedInterfaces (type, xml.Element ("implemented_interfaces")); + ImportConstructors (type, xml.Element ("constructors")); + ImportMethods (type, xml.Element ("methods")); + ImportFields (type, xml.Element ("fields")); + + foreach (var nestedType in xml.Elements ("nested_type")) + type.NestedTypes.Add (ImportType (nestedType)); + + return type; + } + + static void ImportAnnotations (List annotations, XElement? xml) + { + foreach (var annotation in xml?.Elements ("annotation") ?? []) { + var a = ImportAnnotation (annotation); + annotations.Add (a); + } + } + + static CallableWrapperTypeAnnotation ImportAnnotation (XElement xml) + { + var name = xml.GetRequiredAttribute ("name"); + var annotation = new CallableWrapperTypeAnnotation (name); + + foreach (var property in xml.Elements ("property")) { + var p = ImportAnnotationProperty (property); + annotation.Properties.Add (p); + } + + return annotation; + } + + static KeyValuePair ImportAnnotationProperty (XElement xml) + { + var name = xml.GetRequiredAttribute ("name"); + var value = xml.GetRequiredAttribute ("value"); + + return new KeyValuePair (name, value); + } + + static void ImportImplementedInterfaces (CallableWrapperType type, XElement? xml) + { + foreach (var iface in xml?.Elements ("interface") ?? []) { + var name = iface.GetRequiredAttribute ("name"); + type.ImplementedInterfaces.Add (name); + } + } + + static void ImportConstructors (CallableWrapperType type, XElement? xml) + { + foreach (var ctor in xml?.Elements ("constructor") ?? []) { + var c = ImportConstructor (type, ctor); + type.Constructors.Add (c); + } + } + + static void ImportMethods (CallableWrapperType type, XElement? xml) + { + foreach (var method in xml?.Elements ("method") ?? []) { + var m = ImportMethod (type, method); + type.Methods.Add (m); + } + } + + static CallableWrapperConstructor ImportConstructor (CallableWrapperType type, XElement xml) + { + var name = xml.GetRequiredAttribute ("name"); + var method = xml.GetRequiredAttribute ("method"); + var jniSig = xml.GetRequiredAttribute ("jni_signature"); + + var ctor = new CallableWrapperConstructor (type, name, method, jniSig); + FillInMethodDetails (ctor, xml); + + return ctor; + } + + static CallableWrapperMethod ImportMethod (CallableWrapperType type, XElement xml) + { + var name = xml.GetRequiredAttribute ("name"); + var method = xml.GetRequiredAttribute ("method"); + var jniSig = xml.GetRequiredAttribute ("jni_signature"); + + var m = new CallableWrapperMethod (type, name, method, jniSig); + FillInMethodDetails (m, xml); + + return m; + } + + static void FillInMethodDetails (CallableWrapperMethod method, XElement xml) + { + // Common between constructors and methods + method.ManagedParameters = xml.GetAttributeOrDefault ("managed_parameters", (string?) null); + method.JavaNameOverride = xml.GetAttributeOrDefault ("java_name_override", (string?) null); + method.Params = xml.GetAttributeOrDefault ("params", (string?) null); + method.Retval = xml.GetAttributeOrDefault ("retval", (string?) null); + method.JavaAccess = xml.GetAttributeOrDefault ("java_access", (string?) null); + method.IsExport = xml.GetAttributeOrDefault ("is_export", false); + method.IsStatic = xml.GetAttributeOrDefault ("is_static", false); + method.IsDynamicallyRegistered = xml.GetAttributeOrDefault ("is_dynamically_registered", false); + method.SuperCall = xml.GetAttributeOrDefault ("super_call", (string?) null); + method.ActivateCall = xml.GetAttributeOrDefault ("activate_call", (string?) null); + + if (xml.GetAttributeOrDefault ("thrown_type_names", (string?) null) is string thrownTypeNames) + method.ThrownTypeNames = thrownTypeNames.Split (new [] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + ImportAnnotations (method.Annotations, xml.Element ("annotations")); + } + + static void ImportFields (CallableWrapperType type, XElement? xml) + { + foreach (var field in xml?.Elements ("field") ?? []) { + var f = ImportField (field); + type.Fields.Add (f); + } + } + + static CallableWrapperField ImportField (XElement xml) + { + var name = xml.GetRequiredAttribute ("name"); + var type = xml.GetRequiredAttribute ("type"); + var visibility = xml.GetRequiredAttribute ("visibility"); + var initializer_name = xml.GetRequiredAttribute ("initializer_name"); + + var field = new CallableWrapperField (name, type, visibility, initializer_name) { + IsStatic = xml.GetAttributeOrDefault ("is_static", false), + }; + + ImportAnnotations (field.Annotations, xml.Element ("annotations")); + + return field; + } + + /// + /// Generates a package name from a partial assembly qualified name. + /// This is used when the package attribute is missing or empty in the XML. + /// + /// The partial assembly qualified name in format "Namespace.TypeName, AssemblyName" + /// A package name based on the current + static string GeneratePackageFromAssemblyQualifiedName (string partialAssemblyQualifiedName) + { + // Format: "Namespace.TypeName, AssemblyName" or "Namespace.TypeName+NestedType, AssemblyName" + var commaIndex = partialAssemblyQualifiedName.IndexOf (','); + if (commaIndex < 0) + return ""; + + var fullTypeName = partialAssemblyQualifiedName.Substring (0, commaIndex).Trim (); + var assemblyName = partialAssemblyQualifiedName.Substring (commaIndex + 1).Trim (); + + // Extract namespace from full type name + // Handle nested types by using '+' as separator + var plusIndex = fullTypeName.IndexOf ('+'); + var typeNameWithoutNested = plusIndex >= 0 ? fullTypeName.Substring (0, plusIndex) : fullTypeName; + + var lastDotIndex = typeNameWithoutNested.LastIndexOf ('.'); + var ns = lastDotIndex >= 0 ? typeNameWithoutNested.Substring (0, lastDotIndex) : ""; + + // If no namespace, return empty (will use default package) + if (string.IsNullOrEmpty (ns)) + return ""; + + return JavaNativeTypeManager.GetPackageName (ns, assemblyName); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperApplicationConstructor.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperApplicationConstructor.cs new file mode 100644 index 00000000000..2d8c40938d2 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperApplicationConstructor.cs @@ -0,0 +1,26 @@ +using System.IO; + +namespace Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; + +public class CallableWrapperApplicationConstructor +{ + public string Name { get; set; } + + public CallableWrapperApplicationConstructor (string name) + { + Name = name; + } + + public void Generate (TextWriter sw, CallableWrapperWriterOptions options) + { + sw.WriteLine (); + + sw.Write ("\tpublic "); + sw.Write (Name); + sw.WriteLine (" ()"); + + sw.WriteLine ("\t{"); + sw.WriteLine ("\t\tmono.MonoPackageManager.setContext (this);"); + sw.WriteLine ("\t}"); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperConstructor.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperConstructor.cs new file mode 100644 index 00000000000..59ef048ae7a --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperConstructor.cs @@ -0,0 +1,72 @@ +using System.IO; + +namespace Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; + +public class CallableWrapperConstructor : CallableWrapperMethod +{ + public CallableWrapperConstructor (CallableWrapperType declaringType, string name, string method, string jniSignature) : base (declaringType, name, method, jniSignature) + { + } + + public override void Generate (TextWriter sw, CallableWrapperWriterOptions options) + { + // TODO: we only generate constructors so that Android types w/ no + // default constructor can be subclasses by our generated code. + // + // This does NOT currently allow creating managed types from Java. + sw.WriteLine (); + + foreach (var annotation in Annotations) + annotation.Generate (sw, "", options); + + sw.Write ("\tpublic "); + sw.Write (Name); + + sw.Write (" ("); + sw.Write (Params); + sw.Write (')'); + + sw.WriteLine (ThrowsDeclaration); + + sw.WriteLine ("\t{"); + sw.Write ("\t\tsuper ("); + sw.Write (SuperCall); + sw.WriteLine (");"); + +#if MONODROID_TIMING + sw.WriteLine ("\t\tandroid.util.Log.i(\"MonoDroid-Timing\", \"{0}..ctor({1}): time: \"+java.lang.System.currentTimeMillis());", Name, Params); +#endif + + if (!DeclaringType.CannotRegisterInStaticConstructor) { + + sw.Write ("\t\tif (getClass () == "); + sw.Write (Name); + sw.WriteLine (".class) {"); + + sw.Write ("\t\t\t"); + + switch (options.CodeGenerationTarget) { + case JavaPeerStyle.JavaInterop1: + sw.Write ("net.dot.jni.ManagedPeer.construct (this, \""); + sw.Write (JniSignature); + sw.Write ("\", new java.lang.Object[] { "); + sw.Write (ActivateCall); + sw.WriteLine (" });"); + break; + default: + sw.Write ("mono.android.TypeManager.Activate (\""); + sw.Write (DeclaringType.PartialAssemblyQualifiedName); + sw.Write ("\", \""); + sw.Write (ManagedParameters); + sw.Write ("\", this, new java.lang.Object[] { "); + sw.Write (ActivateCall); + sw.WriteLine (" });"); + break; + } + + sw.WriteLine ("\t\t}"); + } + + sw.WriteLine ("\t}"); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperField.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperField.cs new file mode 100644 index 00000000000..043dedc9ee1 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperField.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.IO; + +namespace Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; + +public class CallableWrapperField +{ + public string FieldName { get; set; } + public string TypeName { get; set; } + public string Visibility { get; set; } + public bool IsStatic { get; set; } + public string InitializerName { get; set; } + public List Annotations { get; } = new List (); + + public CallableWrapperField (string fieldName, string typeName, string visibility, string initializerName) + { + FieldName = fieldName; + TypeName = typeName; + Visibility = visibility; + InitializerName = initializerName; + } + + public void Generate (TextWriter sw, CallableWrapperWriterOptions options) + { + sw.WriteLine (); + + foreach (var annotation in Annotations) + annotation.Generate (sw, "", options); + + sw.Write ("\t"); + sw.Write (Visibility); + sw.Write (' '); + + if (IsStatic) + sw.Write ("static "); + + sw.Write (TypeName); + sw.Write (' '); + + sw.Write (FieldName); + sw.Write (" = "); + + sw.Write (InitializerName); + sw.WriteLine (" ();"); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperMethod.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperMethod.cs new file mode 100644 index 00000000000..9b9e692d5f1 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperMethod.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; + +public class CallableWrapperMethod +{ + public string Name { get; set; } + public string Method { get; set; } + public string JniSignature { get; set; } + public string? ManagedParameters { get; set; } + public string? JavaNameOverride { get; set; } + public string? Params { get; set; } + public string? Retval { get; set; } + public string? JavaAccess { get; set; } + public bool IsExport { get; set; } + public bool IsStatic { get; set; } + public bool IsDynamicallyRegistered { get; set; } = true; + public string []? ThrownTypeNames { get; set; } + public string? SuperCall { get; set; } + public string? ActivateCall { get; set; } + public string JavaName => JavaNameOverride ?? Name; + public List Annotations { get; } = new List (); + public CallableWrapperType DeclaringType { get; } + + public string? ThrowsDeclaration => ThrownTypeNames?.Length > 0 ? $" throws {string.Join (", ", ThrownTypeNames)}" : null; + + public CallableWrapperMethod (CallableWrapperType declaringType, string name, string method, string jniSignature) + { + DeclaringType = declaringType; + Name = name; + Method = method; + JniSignature = jniSignature; + } + + public virtual void Generate (TextWriter sw, CallableWrapperWriterOptions options) + { + sw.WriteLine (); + + foreach (var annotation in Annotations) + annotation.Generate (sw, "", options); + + sw.Write ("\t"); + + sw.Write (IsExport ? JavaAccess : "public"); + sw.Write (' '); + + if (IsStatic) + sw.Write ("static "); + + sw.Write (Retval); + sw.Write (' '); + + sw.Write (JavaName); + + sw.Write (" ("); + sw.Write (Params); + sw.Write (')'); + + sw.WriteLine (ThrowsDeclaration); + sw.WriteLine ("\t{"); + +#if MONODROID_TIMING + sw.WriteLine ("\t\tandroid.util.Log.i(\"MonoDroid-Timing\", \"{0}.{1}: time: \"+java.lang.System.currentTimeMillis());", Name, Method); +#endif + + sw.Write ("\t\t"); + sw.Write (Retval == "void" ? string.Empty : "return "); + + sw.Write ("n_"); + sw.Write (Name); + + sw.Write (" ("); + sw.Write (ActivateCall); + sw.WriteLine (");"); + + sw.WriteLine ("\t}"); + sw.WriteLine (); + + sw.Write ("\tprivate "); + + if (IsStatic) + sw.Write ("static "); + + sw.Write ("native "); + + sw.Write (Retval); + + sw.Write (" n_"); + sw.Write (Name); + + sw.Write (" ("); + sw.Write (Params); + sw.WriteLine (");"); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperType.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperType.cs new file mode 100644 index 00000000000..720a90d6e0d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperType.cs @@ -0,0 +1,322 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; + +public class CallableWrapperType +{ + public string Name { get; set; } + public string Package { get; set; } + public bool IsAbstract { get; set; } + public string? ApplicationJavaClass { get; set; } + public bool GenerateOnCreateOverrides { get; set; } + /// + /// The Java source code to be included in Instrumentation.onCreate + /// + /// Originally came from MonoRuntimeProvider.java delimited by: + /// // Mono Runtime Initialization {{{ + /// // }}} + /// + public string? MonoRuntimeInitialization { get; set; } + public string? ExtendsType { get; set; } + public CallableWrapperApplicationConstructor? ApplicationConstructor { get; set; } + public bool IsApplication { get; set; } + public bool IsInstrumentation { get; set; } + public string PartialAssemblyQualifiedName { get; set; } + public bool HasExport { get; set; } + + public List Annotations { get; } = new List (); + public List ImplementedInterfaces { get; } = new List (); + public List Constructors { get; } = new List (); + public List Fields { get; } = new List (); + public List Methods { get; } = new List (); + public List NestedTypes { get; } = new List (); + + public bool CannotRegisterInStaticConstructor => IsApplication || IsInstrumentation; + + public CallableWrapperType (string name, string package, string partialAssemblyQualifiedName) + { + Name = name; + Package = package; + PartialAssemblyQualifiedName = partialAssemblyQualifiedName; + } + + // example of java target to generate for a type + // + // package mono.droid; + // + // import android.app.Activity; + // import android.os.Bundle; + // + // public class MonoActivity extends android.app.Activity + // { + // static final String __md_methods; + // static { + // __md_methods = + // "n_OnCreate:(Landroid/os/Bundle;)V:GetOnCreate_Landroid_os_Bundle_Handler\n" + + // ""; + // mono.android.Runtime.register ("Mono.Droid.MonoActivity, AssemblyName", MonoActivity.class, __md_methods); + // } + // + // public void onCreate(android.os.Bundle savedInstanceState) + // { + // n_onCreate (savedInstanceState); + // } + // + // private native void n_onCreate (android.os.Bundle bundle); + // } + public void Generate (TextWriter writer, CallableWrapperWriterOptions options, bool isNested = false) + { + if (!isNested && !string.IsNullOrEmpty (Package)) { + writer.WriteLine ("package " + Package + ";"); + writer.WriteLine (); + } + + GenerateHeader (writer, options); + + if (!isNested) + GenerateInfrastructure (writer, options); + + GenerateBody (writer, options); + + foreach (var nested in NestedTypes) + nested.Generate (writer, options, true); + + GenerateFooter (writer, options); + } + + void GenerateHeader (TextWriter sw, CallableWrapperWriterOptions options) + { + sw.WriteLine (); + + // Type annotations + foreach (var annotation in Annotations) + annotation.Generate (sw, "", options); + + sw.WriteLine ("public " + (IsAbstract ? "abstract " : "") + "class " + Name); + + var extends = ExtendsType; + + // Do this check here rather than the constructor because it can be set after the constructor is called + if (extends == "android.app.Application" && ApplicationJavaClass != null && !string.IsNullOrEmpty (ApplicationJavaClass)) + extends = ApplicationJavaClass; + + sw.WriteLine ("\textends " + extends); + + sw.WriteLine ("\timplements"); + sw.Write ("\t\t"); + + switch (options.CodeGenerationTarget) { + case JavaPeerStyle.JavaInterop1: + sw.Write ("net.dot.jni.GCUserPeerable"); + break; + default: + sw.Write ("mono.android.IGCUserPeer"); + break; + } + + foreach (var iface in ImplementedInterfaces) { + sw.WriteLine (","); + sw.Write ("\t\t"); + sw.Write (iface); + } + + sw.WriteLine (); + sw.WriteLine ("{"); + } + + void GenerateInfrastructure (TextWriter writer, CallableWrapperWriterOptions options) + { + var needCtor = false; + + if (HasDynamicallyRegisteredMethods) { + needCtor = true; + writer.WriteLine ("/** @hide */"); + writer.WriteLine ("\tpublic static final String __md_methods;"); + } + + for (var i = 0; i < NestedTypes.Count; i++) { + if (!NestedTypes [i].HasDynamicallyRegisteredMethods) + continue; + + needCtor = true; + writer.Write ("\tstatic final String __md_"); + writer.Write (i + 1); + writer.WriteLine ("_methods;"); + } + + if (needCtor) { + writer.WriteLine ("\tstatic {"); + + if (HasDynamicallyRegisteredMethods) + GenerateRegisterType (writer, this, "__md_methods", options); + + for (var i = 0; i < NestedTypes.Count; ++i) + GenerateRegisterType (writer, NestedTypes [i], $"__md_{i + 1}_methods", options); + + writer.WriteLine ("\t}"); + } + } + + void GenerateBody (TextWriter sw, CallableWrapperWriterOptions options) + { + foreach (var ctor in Constructors) + ctor.Generate (sw, options); + + ApplicationConstructor?.Generate (sw, options); + + foreach (var field in Fields) + field.Generate (sw, options); + + foreach (var method in Methods) + method.Generate (sw, options); + + if (GenerateOnCreateOverrides && IsApplication && !Methods.Any (m => m.Name == "onCreate")) + WriteApplicationOnCreate (sw, options); + + if (GenerateOnCreateOverrides && IsInstrumentation && !Methods.Any (m => m.Name == "onCreate")) + WriteInstrumentationOnCreate (sw, options); + + var addRef = options.CodeGenerationTarget == JavaPeerStyle.JavaInterop1 ? "jiAddManagedReference" : "monodroidAddReference"; + var clearRefs = options.CodeGenerationTarget == JavaPeerStyle.JavaInterop1 ? "jiClearManagedReferences" : "monodroidClearReferences"; + + sw.WriteLine (); + sw.WriteLine ("\tprivate java.util.ArrayList refList;"); + + sw.WriteLine ($"\tpublic void {addRef} (java.lang.Object obj)"); + sw.WriteLine ("\t{"); + sw.WriteLine ("\t\tif (refList == null)"); + sw.WriteLine ("\t\t\trefList = new java.util.ArrayList ();"); + sw.WriteLine ("\t\trefList.add (obj);"); + sw.WriteLine ("\t}"); + sw.WriteLine (); + + sw.WriteLine ($"\tpublic void {clearRefs} ()"); + sw.WriteLine ("\t{"); + sw.WriteLine ("\t\tif (refList != null)"); + sw.WriteLine ("\t\t\trefList.clear ();"); + sw.WriteLine ("\t}"); + } + + void GenerateFooter (TextWriter sw, CallableWrapperWriterOptions options) + { + sw.WriteLine ("}"); + } + + void WriteApplicationOnCreate (TextWriter sw, CallableWrapperWriterOptions options) + { + sw.WriteLine (); + + sw.WriteLine ("\tpublic void onCreate ()"); + sw.WriteLine ("\t{"); + + sw.Write ("\t\tmono.android.Runtime.register (\""); + sw.Write (PartialAssemblyQualifiedName); + sw.Write ("\", "); + sw.Write (Name); + sw.WriteLine (".class, __md_methods);"); + + sw.WriteLine ("\t\tsuper.onCreate ();"); + sw.WriteLine ("\t}"); + } + + void WriteInstrumentationOnCreate (TextWriter sw, CallableWrapperWriterOptions options) + { + sw.WriteLine (); + sw.WriteLine ("\tpublic void onCreate (android.os.Bundle arguments)"); + sw.WriteLine ("\t{"); + +#if MONODROID_TIMING + sw.WriteLine ("\t\tandroid.util.Log.i(\"MonoDroid-Timing\", \"{0}.onCreate(Bundle): time: \"+java.lang.System.currentTimeMillis());", Name); + sw.WriteLine (); +#endif + + sw.WriteLine ("\t\tandroid.content.Context context = getContext ();"); + sw.WriteLine (); + + if (!string.IsNullOrEmpty (MonoRuntimeInitialization)) { + sw.WriteLine (MonoRuntimeInitialization); + sw.WriteLine (); + } + + sw.Write ("\t\tmono.android.Runtime.register (\""); + sw.Write (PartialAssemblyQualifiedName); + sw.Write ("\", "); + sw.Write (Name); + sw.WriteLine (".class, __md_methods);"); + + sw.WriteLine ("\t\tsuper.onCreate (arguments);"); + sw.WriteLine ("\t}"); + } + + void GenerateRegisterType (TextWriter sw, CallableWrapperType self, string field, CallableWrapperWriterOptions options) + { + if (!self.HasDynamicallyRegisteredMethods) + return; + + sw.Write ("\t\t"); + sw.Write (field); + sw.WriteLine (" = "); + + foreach (var method in self.Methods) { + if (method.IsDynamicallyRegistered) { + sw.Write ("\t\t\t\"", method.Method); + sw.Write (method.Method); + sw.WriteLine ("\\n\" +"); + } + } + + sw.WriteLine ("\t\t\t\"\";"); + + if (CannotRegisterInStaticConstructor) + return; + + sw.Write ("\t\t"); + + switch (options.CodeGenerationTarget) { + case JavaPeerStyle.JavaInterop1: + sw.Write ("net.dot.jni.ManagedPeer.registerNativeMembers ("); + sw.Write (self.Name); + sw.Write (".class, "); + sw.Write (field); + sw.WriteLine (");"); + break; + default: + sw.Write ("mono.android.Runtime.register (\""); + sw.Write (self.PartialAssemblyQualifiedName); + sw.Write ("\", "); + sw.Write (self.Name); + sw.Write (".class, "); + sw.Write (field); + sw.WriteLine (");"); + break; + } + } + + // If there are no methods, we need to generate "empty" registration because of backward compatibility + public bool HasDynamicallyRegisteredMethods => Methods.Count == 0 || Methods.Any (sig => sig.IsDynamicallyRegistered); + + /// + /// Returns a destination file path based on the package name of this Java type + /// + public string GetDestinationPath (string outputPath) + { + var dir = Package.Replace ('.', Path.DirectorySeparatorChar); + return Path.Combine (outputPath, dir, Name + ".java"); + } + + public void Generate (string outputPath, CallableWrapperWriterOptions options) + { + using (StreamWriter sw = OpenStream (outputPath)) + Generate (sw, options, false); + } + + StreamWriter OpenStream (string outputPath) + { + var destination = GetDestinationPath (outputPath); + Directory.CreateDirectory (Path.GetDirectoryName (destination)!); + + return new StreamWriter (new FileStream (destination, FileMode.Create, FileAccess.Write)); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperTypeAnnotation.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperTypeAnnotation.cs new file mode 100644 index 00000000000..e605eee62e7 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers/CallableWrapperTypeAnnotation.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers; + +public class CallableWrapperTypeAnnotation +{ + public string Name { get; set; } + public List> Properties { get; } = new (); + + public CallableWrapperTypeAnnotation (string name) + { + Name = name; + } + + public void Generate (TextWriter sw, string indent, CallableWrapperWriterOptions options) + { + sw.Write (indent); + sw.Write ('@'); + sw.Write (Name); + + var properties = string.Join (", ", Properties.Select (p => $"{p.Key} = {p.Value}")); + + if (!string.IsNullOrEmpty (properties)) { + sw.Write (" ("); + sw.Write (properties); + sw.Write (")"); + } + + sw.WriteLine (); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj new file mode 100644 index 00000000000..07d9f770589 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj @@ -0,0 +1,39 @@ + + + + netstandard2.0 + enable + true + true + true + ..\..\product.snk + $(DefineConstants);JCW_ONLY_TYPE_NAMES;HAVE_CECIL + + + + + + $(ToolOutputFullPath) + + + + + + + JavaNativeTypeManager.cs + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CallableWrapperReaderOptions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CallableWrapperReaderOptions.cs new file mode 100644 index 00000000000..acd5a9633ab --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CallableWrapperReaderOptions.cs @@ -0,0 +1,9 @@ +namespace Java.Interop.Tools.JavaCallableWrappers; + +public class CallableWrapperReaderOptions +{ + public string? DefaultApplicationJavaClass { get; set; } + public bool DefaultGenerateOnCreateOverrides { get; set; } + public string? DefaultMonoRuntimeInitialization { get; set; } + public JavaCallableMethodClassifier? MethodClassifier { get; set; } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CallableWrapperWriterOptions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CallableWrapperWriterOptions.cs new file mode 100644 index 00000000000..e0bd76c0878 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CallableWrapperWriterOptions.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Java.Interop.Tools.JavaCallableWrappers; + +public class CallableWrapperWriterOptions +{ + public JavaPeerStyle CodeGenerationTarget { get; set; } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CecilExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CecilExtensions.cs new file mode 100644 index 00000000000..74e10e08c22 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/CecilExtensions.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Android.Runtime; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.TypeNameMappings; +using Mono.Cecil; +using Mono.Cecil.Cil; +using static Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager; + +namespace Java.Interop.Tools.JavaCallableWrappers.Utilities; + +static class CecilExtensions +{ + public static IEnumerable GetExportFieldAttributes (Mono.Cecil.ICustomAttributeProvider p) + { + return GetAttributes (p, a => ToExportFieldAttribute (a)); + } + + public static IEnumerable GetAttributes (Mono.Cecil.ICustomAttributeProvider p, Func selector) + where TAttribute : class + { + return GetAttributes (p, typeof (TAttribute).FullName!, selector); + } + + public static IEnumerable GetAttributes (Mono.Cecil.ICustomAttributeProvider p, string attributeName, Func selector) + where TAttribute : class + { + return p.GetCustomAttributes (attributeName) + .Select (selector) + .Where (v => v != null) + .Select (v => v!); + } + + internal static ExportFieldAttribute ToExportFieldAttribute (CustomAttribute attr) + { + return new ExportFieldAttribute ((string) attr.ConstructorArguments [0].Value); + } + + public static MethodDefinition? GetBaseRegisteredMethod (MethodDefinition method, IMetadataResolver cache) + { + MethodDefinition bmethod; + while ((bmethod = method.GetBaseDefinition (cache)) != method) { + method = bmethod; + + if (HasMethodRegistrationAttributes (method)) { + return method; + } + } + return null; + } + + internal static RegisterAttribute? ToRegisterAttribute (CustomAttribute attr) + { + // attr.Resolve (); + RegisterAttribute? r = null; + if (attr.ConstructorArguments.Count == 1) + r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr); + else if (attr.ConstructorArguments.Count == 3) + r = new RegisterAttribute ( + (string) attr.ConstructorArguments [0].Value, + (string) attr.ConstructorArguments [1].Value, + (string) attr.ConstructorArguments [2].Value, + attr); + if (r != null) { + var v = attr.Properties.FirstOrDefault (p => p.Name == "DoNotGenerateAcw"); + r.DoNotGenerateAcw = v.Name == null ? false : (bool) v.Argument.Value; + } + return r; + } + + + internal static RegisterAttribute? RegisterFromJniTypeSignatureAttribute (CustomAttribute attr) + { + // attr.Resolve (); + RegisterAttribute? r = null; + if (attr.ConstructorArguments.Count == 1) + r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr); + if (r != null) { + var v = attr.Properties.FirstOrDefault (p => p.Name == "GenerateJavaPeer"); + if (v.Name == null) { + r.DoNotGenerateAcw = false; + } else if (v.Name == "GenerateJavaPeer") { + r.DoNotGenerateAcw = !(bool) v.Argument.Value; + } + var isKeyProp = attr.Properties.FirstOrDefault (p => p.Name == "IsKeyword"); + var isKeyword = isKeyProp.Name != null && ((bool) isKeyProp.Argument.Value) == true; + var arrRankProp = attr.Properties.FirstOrDefault (p => p.Name == "ArrayRank"); + if (arrRankProp.Name != null && arrRankProp.Argument.Value is int rank) { + r.Name = new string ('[', rank) + (isKeyword ? r.Name : "L" + r.Name + ";"); + } + } + return r; + } + + internal static RegisterAttribute? RegisterFromJniConstructorSignatureAttribute (CustomAttribute attr) + { + // attr.Resolve (); + RegisterAttribute? r = null; + if (attr.ConstructorArguments.Count == 1) + r = new RegisterAttribute ( + name: ".ctor", + signature: (string) attr.ConstructorArguments [0].Value, + connector: "", + originAttribute: attr); + return r; + } + + internal static RegisterAttribute? RegisterFromJniMethodSignatureAttribute (CustomAttribute attr) + { + // attr.Resolve (); + RegisterAttribute? r = null; + if (attr.ConstructorArguments.Count == 2) + r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, + (string) attr.ConstructorArguments [1].Value, + "", + attr); + return r; + } + + static ExportAttribute ToExportAttribute (CustomAttribute attr, IMemberDefinition declaringMember, IMetadataResolver cache) + { + var name = attr.ConstructorArguments.Count > 0 ? (string) attr.ConstructorArguments [0].Value : declaringMember.Name; + if (attr.Properties.Count == 0) + return new ExportAttribute (name); + var typeArgs = (CustomAttributeArgument []) attr.Properties.FirstOrDefault (p => p.Name == "Throws").Argument.Value; + var thrown = typeArgs != null && typeArgs.Any () + ? (from caa in typeArgs select JavaNativeTypeManager.Parse (GetJniTypeName ((TypeReference) caa.Value, cache))?.Type) + .Where (v => v != null) + .ToArray () + : null; + var superArgs = (string) attr.Properties.FirstOrDefault (p => p.Name == "SuperArgumentsString").Argument.Value; + return new ExportAttribute (name) { ThrownNames = thrown, SuperArgumentsString = superArgs }; + } + + static ExportAttribute ToExportAttributeFromJavaCallableAttribute (CustomAttribute attr, IMemberDefinition declaringMember) + { + var name = attr.ConstructorArguments.Count > 0 + ? (string) attr.ConstructorArguments [0].Value + : declaringMember.Name; + return new ExportAttribute (name); + } + + static ExportAttribute ToExportAttributeFromJavaCallableConstructorAttribute (CustomAttribute attr, IMemberDefinition declaringMember) + { + var superArgs = (string) attr.Properties + .FirstOrDefault (p => p.Name == "SuperConstructorExpression") + .Argument + .Value; + return new ExportAttribute (".ctor") { + SuperArgumentsString = superArgs, + }; + } + + internal static IEnumerable GetTypeRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p) + { + foreach (var a in CecilExtensions.GetAttributes (p, a => CecilExtensions.ToRegisterAttribute (a))) { + yield return a; + } + foreach (var c in p.GetCustomAttributes ("Java.Interop.JniTypeSignatureAttribute")) { + var r = RegisterFromJniTypeSignatureAttribute (c); + if (r == null) { + continue; + } + yield return r; + } + } + + // Keep in sync w/ HasMethodRegistrationAttributes() + public static IEnumerable GetMethodRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p) + { + foreach (var a in CecilExtensions.GetAttributes (p, a => CecilExtensions.ToRegisterAttribute (a))) { + yield return a; + } + foreach (var c in p.GetCustomAttributes ("Java.Interop.JniConstructorSignatureAttribute")) { + var r = RegisterFromJniConstructorSignatureAttribute (c); + if (r == null) { + continue; + } + yield return r; + } + foreach (var c in p.GetCustomAttributes ("Java.Interop.JniMethodSignatureAttribute")) { + var r = RegisterFromJniMethodSignatureAttribute (c); + if (r == null) { + continue; + } + yield return r; + } + } + + static readonly string[] MethodRegistrationAttributes = new[]{ + typeof (RegisterAttribute).FullName, + "Java.Interop.JniConstructorSignatureAttribute", + "Java.Interop.JniMethodSignatureAttribute", + }; + + // Keep in sync w/ GetMethodRegistrationAttributes() + public static bool HasMethodRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p) + { + foreach (CustomAttribute custom_attribute in p.CustomAttributes) { + var customAttrType = custom_attribute.Constructor.DeclaringType.FullName; + foreach (var t in MethodRegistrationAttributes) { + if (customAttrType == t) + return true; + } + } + return false; + } + + public static IEnumerable GetExportAttributes (IMemberDefinition p, IMetadataResolver cache) + { + return CecilExtensions.GetAttributes (p, a => CecilExtensions.ToExportAttribute (a, p, cache)) + .Concat (CecilExtensions.GetAttributes (p, "Java.Interop.JavaCallableAttribute", + a => CecilExtensions.ToExportAttributeFromJavaCallableAttribute (a, p))) + .Concat (CecilExtensions.GetAttributes (p, "Java.Interop.JavaCallableConstructorAttribute", + a => CecilExtensions.ToExportAttributeFromJavaCallableConstructorAttribute (a, p))); + } + + public static SequencePoint? LookupSource (MethodDefinition method) + { + if (!method.HasBody) + return null; + + foreach (var ins in method.Body.Instructions) { + var seqPoint = method.DebugInformation.GetSequencePoint (ins); + if (seqPoint != null) + return seqPoint; + } + + return null; + } + + public static SequencePoint? LookupSource (TypeDefinition type) + { + SequencePoint? candidate = null; + foreach (var method in type.Methods) { + if (!method.HasBody) + continue; + + foreach (var ins in method.Body.Instructions) { + var seq = method.DebugInformation.GetSequencePoint (ins); + if (seq == null) + continue; + + if (Regex.IsMatch (seq.Document.Url, ".+\\.(g|designer)\\..+")) + break; + if (candidate == null || seq.StartLine < candidate.StartLine) + candidate = seq; + break; + } + } + + return candidate; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64.Table.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64.Table.cs new file mode 100644 index 00000000000..c82097ed5b0 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64.Table.cs @@ -0,0 +1,536 @@ +namespace Java.Interop.Tools.JavaCallableWrappers +{ + partial class Crc64Helper + { + static readonly ulong[,] table = { + { + 0x0000000000000000, 0x7ad870c830358979, 0xf5b0e190606b12f2, 0x8f689158505e9b8b, + 0xc038e5739841b68f, 0xbae095bba8743ff6, 0x358804e3f82aa47d, 0x4f50742bc81f2d04, + 0xab28ecb46814fe75, 0xd1f09c7c5821770c, 0x5e980d24087fec87, 0x24407dec384a65fe, + 0x6b1009c7f05548fa, 0x11c8790fc060c183, 0x9ea0e857903e5a08, 0xe478989fa00bd371, + 0x7d08ff3b88be6f81, 0x07d08ff3b88be6f8, 0x88b81eabe8d57d73, 0xf2606e63d8e0f40a, + 0xbd301a4810ffd90e, 0xc7e86a8020ca5077, 0x4880fbd87094cbfc, 0x32588b1040a14285, + 0xd620138fe0aa91f4, 0xacf86347d09f188d, 0x2390f21f80c18306, 0x594882d7b0f40a7f, + 0x1618f6fc78eb277b, 0x6cc0863448deae02, 0xe3a8176c18803589, 0x997067a428b5bcf0, + 0xfa11fe77117cdf02, 0x80c98ebf2149567b, 0x0fa11fe77117cdf0, 0x75796f2f41224489, + 0x3a291b04893d698d, 0x40f16bccb908e0f4, 0xcf99fa94e9567b7f, 0xb5418a5cd963f206, + 0x513912c379682177, 0x2be1620b495da80e, 0xa489f35319033385, 0xde51839b2936bafc, + 0x9101f7b0e12997f8, 0xebd98778d11c1e81, 0x64b116208142850a, 0x1e6966e8b1770c73, + 0x8719014c99c2b083, 0xfdc17184a9f739fa, 0x72a9e0dcf9a9a271, 0x08719014c99c2b08, + 0x4721e43f0183060c, 0x3df994f731b68f75, 0xb29105af61e814fe, 0xc849756751dd9d87, + 0x2c31edf8f1d64ef6, 0x56e99d30c1e3c78f, 0xd9810c6891bd5c04, 0xa3597ca0a188d57d, + 0xec09088b6997f879, 0x96d1784359a27100, 0x19b9e91b09fcea8b, 0x636199d339c963f2, + 0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416, 0x2aca3b2d1a053f9d, 0x50124be52a30b6e4, + 0x1f423fcee22f9be0, 0x659a4f06d21a1299, 0xeaf2de5e82448912, 0x902aae96b271006b, + 0x74523609127ad31a, 0x0e8a46c1224f5a63, 0x81e2d7997211c1e8, 0xfb3aa75142244891, + 0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec, 0x41da32eaea507767, 0x3b024222da65fe1e, + 0xa2722586f2d042ee, 0xd8aa554ec2e5cb97, 0x57c2c41692bb501c, 0x2d1ab4dea28ed965, + 0x624ac0f56a91f461, 0x1892b03d5aa47d18, 0x97fa21650afae693, 0xed2251ad3acf6fea, + 0x095ac9329ac4bc9b, 0x7382b9faaaf135e2, 0xfcea28a2faafae69, 0x8632586aca9a2710, + 0xc9622c4102850a14, 0xb3ba5c8932b0836d, 0x3cd2cdd162ee18e6, 0x460abd1952db919f, + 0x256b24ca6b12f26d, 0x5fb354025b277b14, 0xd0dbc55a0b79e09f, 0xaa03b5923b4c69e6, + 0xe553c1b9f35344e2, 0x9f8bb171c366cd9b, 0x10e3202993385610, 0x6a3b50e1a30ddf69, + 0x8e43c87e03060c18, 0xf49bb8b633338561, 0x7bf329ee636d1eea, 0x012b592653589793, + 0x4e7b2d0d9b47ba97, 0x34a35dc5ab7233ee, 0xbbcbcc9dfb2ca865, 0xc113bc55cb19211c, + 0x5863dbf1e3ac9dec, 0x22bbab39d3991495, 0xadd33a6183c78f1e, 0xd70b4aa9b3f20667, + 0x985b3e827bed2b63, 0xe2834e4a4bd8a21a, 0x6debdf121b863991, 0x1733afda2bb3b0e8, + 0xf34b37458bb86399, 0x8993478dbb8deae0, 0x06fbd6d5ebd3716b, 0x7c23a61ddbe6f812, + 0x3373d23613f9d516, 0x49aba2fe23cc5c6f, 0xc6c333a67392c7e4, 0xbc1b436e43a74e9d, + 0x95ac9329ac4bc9b5, 0xef74e3e19c7e40cc, 0x601c72b9cc20db47, 0x1ac40271fc15523e, + 0x5594765a340a7f3a, 0x2f4c0692043ff643, 0xa02497ca54616dc8, 0xdafce7026454e4b1, + 0x3e847f9dc45f37c0, 0x445c0f55f46abeb9, 0xcb349e0da4342532, 0xb1eceec59401ac4b, + 0xfebc9aee5c1e814f, 0x8464ea266c2b0836, 0x0b0c7b7e3c7593bd, 0x71d40bb60c401ac4, + 0xe8a46c1224f5a634, 0x927c1cda14c02f4d, 0x1d148d82449eb4c6, 0x67ccfd4a74ab3dbf, + 0x289c8961bcb410bb, 0x5244f9a98c8199c2, 0xdd2c68f1dcdf0249, 0xa7f41839ecea8b30, + 0x438c80a64ce15841, 0x3954f06e7cd4d138, 0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca, + 0x83b465d5d4a0eece, 0xf96c151de49567b7, 0x76048445b4cbfc3c, 0x0cdcf48d84fe7545, + 0x6fbd6d5ebd3716b7, 0x15651d968d029fce, 0x9a0d8ccedd5c0445, 0xe0d5fc06ed698d3c, + 0xaf85882d2576a038, 0xd55df8e515432941, 0x5a3569bd451db2ca, 0x20ed197575283bb3, + 0xc49581ead523e8c2, 0xbe4df122e51661bb, 0x3125607ab548fa30, 0x4bfd10b2857d7349, + 0x04ad64994d625e4d, 0x7e7514517d57d734, 0xf11d85092d094cbf, 0x8bc5f5c11d3cc5c6, + 0x12b5926535897936, 0x686de2ad05bcf04f, 0xe70573f555e26bc4, 0x9ddd033d65d7e2bd, + 0xd28d7716adc8cfb9, 0xa85507de9dfd46c0, 0x273d9686cda3dd4b, 0x5de5e64efd965432, + 0xb99d7ed15d9d8743, 0xc3450e196da80e3a, 0x4c2d9f413df695b1, 0x36f5ef890dc31cc8, + 0x79a59ba2c5dc31cc, 0x037deb6af5e9b8b5, 0x8c157a32a5b7233e, 0xf6cd0afa9582aa47, + 0x4ad64994d625e4da, 0x300e395ce6106da3, 0xbf66a804b64ef628, 0xc5bed8cc867b7f51, + 0x8aeeace74e645255, 0xf036dc2f7e51db2c, 0x7f5e4d772e0f40a7, 0x05863dbf1e3ac9de, + 0xe1fea520be311aaf, 0x9b26d5e88e0493d6, 0x144e44b0de5a085d, 0x6e963478ee6f8124, + 0x21c640532670ac20, 0x5b1e309b16452559, 0xd476a1c3461bbed2, 0xaeaed10b762e37ab, + 0x37deb6af5e9b8b5b, 0x4d06c6676eae0222, 0xc26e573f3ef099a9, 0xb8b627f70ec510d0, + 0xf7e653dcc6da3dd4, 0x8d3e2314f6efb4ad, 0x0256b24ca6b12f26, 0x788ec2849684a65f, + 0x9cf65a1b368f752e, 0xe62e2ad306bafc57, 0x6946bb8b56e467dc, 0x139ecb4366d1eea5, + 0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8, 0xa97e5ef8cea5d153, 0xd3a62e30fe90582a, + 0xb0c7b7e3c7593bd8, 0xca1fc72bf76cb2a1, 0x45775673a732292a, 0x3faf26bb9707a053, + 0x70ff52905f188d57, 0x0a2722586f2d042e, 0x854fb3003f739fa5, 0xff97c3c80f4616dc, + 0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4, 0xee5fbac7cf26d75f, 0x9487ca0fff135e26, + 0xdbd7be24370c7322, 0xa10fceec0739fa5b, 0x2e675fb4576761d0, 0x54bf2f7c6752e8a9, + 0xcdcf48d84fe75459, 0xb71738107fd2dd20, 0x387fa9482f8c46ab, 0x42a7d9801fb9cfd2, + 0x0df7adabd7a6e2d6, 0x772fdd63e7936baf, 0xf8474c3bb7cdf024, 0x829f3cf387f8795d, + 0x66e7a46c27f3aa2c, 0x1c3fd4a417c62355, 0x935745fc4798b8de, 0xe98f353477ad31a7, + 0xa6df411fbfb21ca3, 0xdc0731d78f8795da, 0x536fa08fdfd90e51, 0x29b7d047efec8728 + }, + { + 0x0000000000000000, 0x89e99ffd73bddf69, 0x388a19a9bfec2db9, 0xb1638654cc51f2d0, + 0x711433537fd85b72, 0xf8fdacae0c65841b, 0x499e2afac03476cb, 0xc077b507b389a9a2, + 0xe22866a6ffb0b6e4, 0x6bc1f95b8c0d698d, 0xdaa27f0f405c9b5d, 0x534be0f233e14434, + 0x933c55f58068ed96, 0x1ad5ca08f3d532ff, 0xabb64c5c3f84c02f, 0x225fd3a14c391f46, + 0xef09eb1ea7f6fea3, 0x66e074e3d44b21ca, 0xd783f2b7181ad31a, 0x5e6a6d4a6ba70c73, + 0x9e1dd84dd82ea5d1, 0x17f447b0ab937ab8, 0xa697c1e467c28868, 0x2f7e5e19147f5701, + 0x0d218db858464847, 0x84c812452bfb972e, 0x35ab9411e7aa65fe, 0xbc420bec9417ba97, + 0x7c35beeb279e1335, 0xf5dc21165423cc5c, 0x44bfa74298723e8c, 0xcd5638bfebcfe1e5, + 0xf54af06e177a6e2d, 0x7ca36f9364c7b144, 0xcdc0e9c7a8964394, 0x4429763adb2b9cfd, + 0x845ec33d68a2355f, 0x0db75cc01b1fea36, 0xbcd4da94d74e18e6, 0x353d4569a4f3c78f, + 0x176296c8e8cad8c9, 0x9e8b09359b7707a0, 0x2fe88f615726f570, 0xa601109c249b2a19, + 0x6676a59b971283bb, 0xef9f3a66e4af5cd2, 0x5efcbc3228feae02, 0xd71523cf5b43716b, + 0x1a431b70b08c908e, 0x93aa848dc3314fe7, 0x22c902d90f60bd37, 0xab209d247cdd625e, + 0x6b572823cf54cbfc, 0xe2beb7debce91495, 0x53dd318a70b8e645, 0xda34ae770305392c, + 0xf86b7dd64f3c266a, 0x7182e22b3c81f903, 0xc0e1647ff0d00bd3, 0x4908fb82836dd4ba, + 0x897f4e8530e47d18, 0x0096d1784359a271, 0xb1f5572c8f0850a1, 0x381cc8d1fcb58fc8, + 0xc1ccc68f76634f31, 0x4825597205de9058, 0xf946df26c98f6288, 0x70af40dbba32bde1, + 0xb0d8f5dc09bb1443, 0x39316a217a06cb2a, 0x8852ec75b65739fa, 0x01bb7388c5eae693, + 0x23e4a02989d3f9d5, 0xaa0d3fd4fa6e26bc, 0x1b6eb980363fd46c, 0x9287267d45820b05, + 0x52f0937af60ba2a7, 0xdb190c8785b67dce, 0x6a7a8ad349e78f1e, 0xe393152e3a5a5077, + 0x2ec52d91d195b192, 0xa72cb26ca2286efb, 0x164f34386e799c2b, 0x9fa6abc51dc44342, + 0x5fd11ec2ae4deae0, 0xd638813fddf03589, 0x675b076b11a1c759, 0xeeb29896621c1830, + 0xcced4b372e250776, 0x4504d4ca5d98d81f, 0xf467529e91c92acf, 0x7d8ecd63e274f5a6, + 0xbdf9786451fd5c04, 0x3410e7992240836d, 0x857361cdee1171bd, 0x0c9afe309dacaed4, + 0x348636e16119211c, 0xbd6fa91c12a4fe75, 0x0c0c2f48def50ca5, 0x85e5b0b5ad48d3cc, + 0x459205b21ec17a6e, 0xcc7b9a4f6d7ca507, 0x7d181c1ba12d57d7, 0xf4f183e6d29088be, + 0xd6ae50479ea997f8, 0x5f47cfbaed144891, 0xee2449ee2145ba41, 0x67cdd61352f86528, + 0xa7ba6314e171cc8a, 0x2e53fce992cc13e3, 0x9f307abd5e9de133, 0x16d9e5402d203e5a, + 0xdb8fddffc6efdfbf, 0x52664202b55200d6, 0xe305c4567903f206, 0x6aec5bab0abe2d6f, + 0xaa9beeacb93784cd, 0x23727151ca8a5ba4, 0x9211f70506dba974, 0x1bf868f87566761d, + 0x39a7bb59395f695b, 0xb04e24a44ae2b632, 0x012da2f086b344e2, 0x88c43d0df50e9b8b, + 0x48b3880a46873229, 0xc15a17f7353aed40, 0x703991a3f96b1f90, 0xf9d00e5e8ad6c0f9, + 0xa8c0ab4db4510d09, 0x212934b0c7ecd260, 0x904ab2e40bbd20b0, 0x19a32d197800ffd9, + 0xd9d4981ecb89567b, 0x503d07e3b8348912, 0xe15e81b774657bc2, 0x68b71e4a07d8a4ab, + 0x4ae8cdeb4be1bbed, 0xc3015216385c6484, 0x7262d442f40d9654, 0xfb8b4bbf87b0493d, + 0x3bfcfeb83439e09f, 0xb215614547843ff6, 0x0376e7118bd5cd26, 0x8a9f78ecf868124f, + 0x47c9405313a7f3aa, 0xce20dfae601a2cc3, 0x7f4359faac4bde13, 0xf6aac607dff6017a, + 0x36dd73006c7fa8d8, 0xbf34ecfd1fc277b1, 0x0e576aa9d3938561, 0x87bef554a02e5a08, + 0xa5e126f5ec17454e, 0x2c08b9089faa9a27, 0x9d6b3f5c53fb68f7, 0x1482a0a12046b79e, + 0xd4f515a693cf1e3c, 0x5d1c8a5be072c155, 0xec7f0c0f2c233385, 0x659693f25f9eecec, + 0x5d8a5b23a32b6324, 0xd463c4ded096bc4d, 0x6500428a1cc74e9d, 0xece9dd776f7a91f4, + 0x2c9e6870dcf33856, 0xa577f78daf4ee73f, 0x141471d9631f15ef, 0x9dfdee2410a2ca86, + 0xbfa23d855c9bd5c0, 0x364ba2782f260aa9, 0x8728242ce377f879, 0x0ec1bbd190ca2710, + 0xceb60ed623438eb2, 0x475f912b50fe51db, 0xf63c177f9cafa30b, 0x7fd58882ef127c62, + 0xb283b03d04dd9d87, 0x3b6a2fc0776042ee, 0x8a09a994bb31b03e, 0x03e03669c88c6f57, + 0xc397836e7b05c6f5, 0x4a7e1c9308b8199c, 0xfb1d9ac7c4e9eb4c, 0x72f4053ab7543425, + 0x50abd69bfb6d2b63, 0xd942496688d0f40a, 0x6821cf32448106da, 0xe1c850cf373cd9b3, + 0x21bfe5c884b57011, 0xa8567a35f708af78, 0x1935fc613b595da8, 0x90dc639c48e482c1, + 0x690c6dc2c2324238, 0xe0e5f23fb18f9d51, 0x5186746b7dde6f81, 0xd86feb960e63b0e8, + 0x18185e91bdea194a, 0x91f1c16cce57c623, 0x20924738020634f3, 0xa97bd8c571bbeb9a, + 0x8b240b643d82f4dc, 0x02cd94994e3f2bb5, 0xb3ae12cd826ed965, 0x3a478d30f1d3060c, + 0xfa303837425aafae, 0x73d9a7ca31e770c7, 0xc2ba219efdb68217, 0x4b53be638e0b5d7e, + 0x860586dc65c4bc9b, 0x0fec1921167963f2, 0xbe8f9f75da289122, 0x37660088a9954e4b, + 0xf711b58f1a1ce7e9, 0x7ef82a7269a13880, 0xcf9bac26a5f0ca50, 0x467233dbd64d1539, + 0x642de07a9a740a7f, 0xedc47f87e9c9d516, 0x5ca7f9d3259827c6, 0xd54e662e5625f8af, + 0x1539d329e5ac510d, 0x9cd04cd496118e64, 0x2db3ca805a407cb4, 0xa45a557d29fda3dd, + 0x9c469dacd5482c15, 0x15af0251a6f5f37c, 0xa4cc84056aa401ac, 0x2d251bf81919dec5, + 0xed52aeffaa907767, 0x64bb3102d92da80e, 0xd5d8b756157c5ade, 0x5c3128ab66c185b7, + 0x7e6efb0a2af89af1, 0xf78764f759454598, 0x46e4e2a39514b748, 0xcf0d7d5ee6a96821, + 0x0f7ac8595520c183, 0x869357a4269d1eea, 0x37f0d1f0eaccec3a, 0xbe194e0d99713353, + 0x734f76b272bed2b6, 0xfaa6e94f01030ddf, 0x4bc56f1bcd52ff0f, 0xc22cf0e6beef2066, + 0x025b45e10d6689c4, 0x8bb2da1c7edb56ad, 0x3ad15c48b28aa47d, 0xb338c3b5c1377b14, + 0x916710148d0e6452, 0x188e8fe9feb3bb3b, 0xa9ed09bd32e249eb, 0x20049640415f9682, + 0xe0732347f2d63f20, 0x699abcba816be049, 0xd8f93aee4d3a1299, 0x5110a5133e87cdf0 + }, + { + 0x0000000000000000, 0xf4125129ce4038be, 0xc37d8400c417e217, 0x376fd5290a57daa9, + 0xada22e52d0b85745, 0x59b07f7b1ef86ffb, 0x6edfaa5214afb552, 0x9acdfb7bdaef8dec, + 0x701d7af6f9e73de1, 0x840f2bdf37a7055f, 0xb360fef63df0dff6, 0x4772afdff3b0e748, + 0xddbf54a4295f6aa4, 0x29ad058de71f521a, 0x1ec2d0a4ed4888b3, 0xead0818d2308b00d, + 0xe03af5edf3ce7bc2, 0x1428a4c43d8e437c, 0x234771ed37d999d5, 0xd75520c4f999a16b, + 0x4d98dbbf23762c87, 0xb98a8a96ed361439, 0x8ee55fbfe761ce90, 0x7af70e962921f62e, + 0x90278f1b0a294623, 0x6435de32c4697e9d, 0x535a0b1bce3ea434, 0xa7485a32007e9c8a, + 0x3d85a149da911166, 0xc997f06014d129d8, 0xfef825491e86f371, 0x0aea7460d0c6cbcf, + 0xeb2ccd88bf0b64ef, 0x1f3e9ca1714b5c51, 0x285149887b1c86f8, 0xdc4318a1b55cbe46, + 0x468ee3da6fb333aa, 0xb29cb2f3a1f30b14, 0x85f367daaba4d1bd, 0x71e136f365e4e903, + 0x9b31b77e46ec590e, 0x6f23e65788ac61b0, 0x584c337e82fbbb19, 0xac5e62574cbb83a7, + 0x3693992c96540e4b, 0xc281c805581436f5, 0xf5ee1d2c5243ec5c, 0x01fc4c059c03d4e2, + 0x0b1638654cc51f2d, 0xff04694c82852793, 0xc86bbc6588d2fd3a, 0x3c79ed4c4692c584, + 0xa6b416379c7d4868, 0x52a6471e523d70d6, 0x65c99237586aaa7f, 0x91dbc31e962a92c1, + 0x7b0b4293b52222cc, 0x8f1913ba7b621a72, 0xb876c6937135c0db, 0x4c6497babf75f865, + 0xd6a96cc1659a7589, 0x22bb3de8abda4d37, 0x15d4e8c1a18d979e, 0xe1c6b9e86fcdaf20, + 0xfd00bd4226815ab5, 0x0912ec6be8c1620b, 0x3e7d3942e296b8a2, 0xca6f686b2cd6801c, + 0x50a29310f6390df0, 0xa4b0c2393879354e, 0x93df1710322eefe7, 0x67cd4639fc6ed759, + 0x8d1dc7b4df666754, 0x790f969d11265fea, 0x4e6043b41b718543, 0xba72129dd531bdfd, + 0x20bfe9e60fde3011, 0xd4adb8cfc19e08af, 0xe3c26de6cbc9d206, 0x17d03ccf0589eab8, + 0x1d3a48afd54f2177, 0xe92819861b0f19c9, 0xde47ccaf1158c360, 0x2a559d86df18fbde, + 0xb09866fd05f77632, 0x448a37d4cbb74e8c, 0x73e5e2fdc1e09425, 0x87f7b3d40fa0ac9b, + 0x6d2732592ca81c96, 0x99356370e2e82428, 0xae5ab659e8bffe81, 0x5a48e77026ffc63f, + 0xc0851c0bfc104bd3, 0x34974d223250736d, 0x03f8980b3807a9c4, 0xf7eac922f647917a, + 0x162c70ca998a3e5a, 0xe23e21e357ca06e4, 0xd551f4ca5d9ddc4d, 0x2143a5e393dde4f3, + 0xbb8e5e984932691f, 0x4f9c0fb1877251a1, 0x78f3da988d258b08, 0x8ce18bb14365b3b6, + 0x66310a3c606d03bb, 0x92235b15ae2d3b05, 0xa54c8e3ca47ae1ac, 0x515edf156a3ad912, + 0xcb93246eb0d554fe, 0x3f8175477e956c40, 0x08eea06e74c2b6e9, 0xfcfcf147ba828e57, + 0xf61685276a444598, 0x0204d40ea4047d26, 0x356b0127ae53a78f, 0xc179500e60139f31, + 0x5bb4ab75bafc12dd, 0xafa6fa5c74bc2a63, 0x98c92f757eebf0ca, 0x6cdb7e5cb0abc874, + 0x860bffd193a37879, 0x7219aef85de340c7, 0x45767bd157b49a6e, 0xb1642af899f4a2d0, + 0x2ba9d183431b2f3c, 0xdfbb80aa8d5b1782, 0xe8d45583870ccd2b, 0x1cc604aa494cf595, + 0xd1585cd715952601, 0x254a0dfedbd51ebf, 0x1225d8d7d182c416, 0xe63789fe1fc2fca8, + 0x7cfa7285c52d7144, 0x88e823ac0b6d49fa, 0xbf87f685013a9353, 0x4b95a7accf7aabed, + 0xa1452621ec721be0, 0x555777082232235e, 0x6238a2212865f9f7, 0x962af308e625c149, + 0x0ce708733cca4ca5, 0xf8f5595af28a741b, 0xcf9a8c73f8ddaeb2, 0x3b88dd5a369d960c, + 0x3162a93ae65b5dc3, 0xc570f813281b657d, 0xf21f2d3a224cbfd4, 0x060d7c13ec0c876a, + 0x9cc0876836e30a86, 0x68d2d641f8a33238, 0x5fbd0368f2f4e891, 0xabaf52413cb4d02f, + 0x417fd3cc1fbc6022, 0xb56d82e5d1fc589c, 0x820257ccdbab8235, 0x761006e515ebba8b, + 0xecddfd9ecf043767, 0x18cfacb701440fd9, 0x2fa0799e0b13d570, 0xdbb228b7c553edce, + 0x3a74915faa9e42ee, 0xce66c07664de7a50, 0xf909155f6e89a0f9, 0x0d1b4476a0c99847, + 0x97d6bf0d7a2615ab, 0x63c4ee24b4662d15, 0x54ab3b0dbe31f7bc, 0xa0b96a247071cf02, + 0x4a69eba953797f0f, 0xbe7bba809d3947b1, 0x89146fa9976e9d18, 0x7d063e80592ea5a6, + 0xe7cbc5fb83c1284a, 0x13d994d24d8110f4, 0x24b641fb47d6ca5d, 0xd0a410d28996f2e3, + 0xda4e64b25950392c, 0x2e5c359b97100192, 0x1933e0b29d47db3b, 0xed21b19b5307e385, + 0x77ec4ae089e86e69, 0x83fe1bc947a856d7, 0xb491cee04dff8c7e, 0x40839fc983bfb4c0, + 0xaa531e44a0b704cd, 0x5e414f6d6ef73c73, 0x692e9a4464a0e6da, 0x9d3ccb6daae0de64, + 0x07f13016700f5388, 0xf3e3613fbe4f6b36, 0xc48cb416b418b19f, 0x309ee53f7a588921, + 0x2c58e19533147cb4, 0xd84ab0bcfd54440a, 0xef256595f7039ea3, 0x1b3734bc3943a61d, + 0x81facfc7e3ac2bf1, 0x75e89eee2dec134f, 0x42874bc727bbc9e6, 0xb6951aeee9fbf158, + 0x5c459b63caf34155, 0xa857ca4a04b379eb, 0x9f381f630ee4a342, 0x6b2a4e4ac0a49bfc, + 0xf1e7b5311a4b1610, 0x05f5e418d40b2eae, 0x329a3131de5cf407, 0xc6886018101cccb9, + 0xcc621478c0da0776, 0x387045510e9a3fc8, 0x0f1f907804cde561, 0xfb0dc151ca8ddddf, + 0x61c03a2a10625033, 0x95d26b03de22688d, 0xa2bdbe2ad475b224, 0x56afef031a358a9a, + 0xbc7f6e8e393d3a97, 0x486d3fa7f77d0229, 0x7f02ea8efd2ad880, 0x8b10bba7336ae03e, + 0x11dd40dce9856dd2, 0xe5cf11f527c5556c, 0xd2a0c4dc2d928fc5, 0x26b295f5e3d2b77b, + 0xc7742c1d8c1f185b, 0x33667d34425f20e5, 0x0409a81d4808fa4c, 0xf01bf9348648c2f2, + 0x6ad6024f5ca74f1e, 0x9ec4536692e777a0, 0xa9ab864f98b0ad09, 0x5db9d76656f095b7, + 0xb76956eb75f825ba, 0x437b07c2bbb81d04, 0x7414d2ebb1efc7ad, 0x800683c27fafff13, + 0x1acb78b9a54072ff, 0xeed929906b004a41, 0xd9b6fcb9615790e8, 0x2da4ad90af17a856, + 0x274ed9f07fd16399, 0xd35c88d9b1915b27, 0xe4335df0bbc6818e, 0x10210cd97586b930, + 0x8aecf7a2af6934dc, 0x7efea68b61290c62, 0x499173a26b7ed6cb, 0xbd83228ba53eee75, + 0x5753a30686365e78, 0xa341f22f487666c6, 0x942e27064221bc6f, 0x603c762f8c6184d1, + 0xfaf18d54568e093d, 0x0ee3dc7d98ce3183, 0x398c09549299eb2a, 0xcd9e587d5cd9d394 + }, + { + 0x0000000000000000, 0x8ce168638c796306, 0x329bf69440655567, 0xbe7a9ef7cc1c3661, + 0x6537ed2880caaace, 0xe9d6854b0cb3c9c8, 0x57ac1bbcc0afffa9, 0xdb4d73df4cd69caf, + 0xca6fda510195559c, 0x468eb2328dec369a, 0xf8f42cc541f000fb, 0x741544a6cd8963fd, + 0xaf583779815fff52, 0x23b95f1a0d269c54, 0x9dc3c1edc13aaa35, 0x1122a98e4d43c933, + 0xbf8692f15bbd3853, 0x3367fa92d7c45b55, 0x8d1d64651bd86d34, 0x01fc0c0697a10e32, + 0xdab17fd9db77929d, 0x565017ba570ef19b, 0xe82a894d9b12c7fa, 0x64cbe12e176ba4fc, + 0x75e948a05a286dcf, 0xf90820c3d6510ec9, 0x4772be341a4d38a8, 0xcb93d65796345bae, + 0x10dea588dae2c701, 0x9c3fcdeb569ba407, 0x2245531c9a879266, 0xaea43b7f16fef160, + 0x545403b1efede3cd, 0xd8b56bd2639480cb, 0x66cff525af88b6aa, 0xea2e9d4623f1d5ac, + 0x3163ee996f274903, 0xbd8286fae35e2a05, 0x03f8180d2f421c64, 0x8f19706ea33b7f62, + 0x9e3bd9e0ee78b651, 0x12dab1836201d557, 0xaca02f74ae1de336, 0x2041471722648030, + 0xfb0c34c86eb21c9f, 0x77ed5cabe2cb7f99, 0xc997c25c2ed749f8, 0x4576aa3fa2ae2afe, + 0xebd29140b450db9e, 0x6733f9233829b898, 0xd94967d4f4358ef9, 0x55a80fb7784cedff, + 0x8ee57c68349a7150, 0x0204140bb8e31256, 0xbc7e8afc74ff2437, 0x309fe29ff8864731, + 0x21bd4b11b5c58e02, 0xad5c237239bced04, 0x1326bd85f5a0db65, 0x9fc7d5e679d9b863, + 0x448aa639350f24cc, 0xc86bce5ab97647ca, 0x761150ad756a71ab, 0xfaf038cef91312ad, + 0xa8a80763dfdbc79a, 0x24496f0053a2a49c, 0x9a33f1f79fbe92fd, 0x16d2999413c7f1fb, + 0xcd9fea4b5f116d54, 0x417e8228d3680e52, 0xff041cdf1f743833, 0x73e574bc930d5b35, + 0x62c7dd32de4e9206, 0xee26b5515237f100, 0x505c2ba69e2bc761, 0xdcbd43c51252a467, + 0x07f0301a5e8438c8, 0x8b115879d2fd5bce, 0x356bc68e1ee16daf, 0xb98aaeed92980ea9, + 0x172e95928466ffc9, 0x9bcffdf1081f9ccf, 0x25b56306c403aaae, 0xa9540b65487ac9a8, + 0x721978ba04ac5507, 0xfef810d988d53601, 0x40828e2e44c90060, 0xcc63e64dc8b06366, + 0xdd414fc385f3aa55, 0x51a027a0098ac953, 0xefdab957c596ff32, 0x633bd13449ef9c34, + 0xb876a2eb0539009b, 0x3497ca888940639d, 0x8aed547f455c55fc, 0x060c3c1cc92536fa, + 0xfcfc04d230362457, 0x701d6cb1bc4f4751, 0xce67f24670537130, 0x42869a25fc2a1236, + 0x99cbe9fab0fc8e99, 0x152a81993c85ed9f, 0xab501f6ef099dbfe, 0x27b1770d7ce0b8f8, + 0x3693de8331a371cb, 0xba72b6e0bdda12cd, 0x0408281771c624ac, 0x88e94074fdbf47aa, + 0x53a433abb169db05, 0xdf455bc83d10b803, 0x613fc53ff10c8e62, 0xeddead5c7d75ed64, + 0x437a96236b8b1c04, 0xcf9bfe40e7f27f02, 0x71e160b72bee4963, 0xfd0008d4a7972a65, + 0x264d7b0beb41b6ca, 0xaaac13686738d5cc, 0x14d68d9fab24e3ad, 0x9837e5fc275d80ab, + 0x89154c726a1e4998, 0x05f42411e6672a9e, 0xbb8ebae62a7b1cff, 0x376fd285a6027ff9, + 0xec22a15aead4e356, 0x60c3c93966ad8050, 0xdeb957ceaab1b631, 0x52583fad26c8d537, + 0x7a092894e7201c5f, 0xf6e840f76b597f59, 0x4892de00a7454938, 0xc473b6632b3c2a3e, + 0x1f3ec5bc67eab691, 0x93dfaddfeb93d597, 0x2da53328278fe3f6, 0xa1445b4babf680f0, + 0xb066f2c5e6b549c3, 0x3c879aa66acc2ac5, 0x82fd0451a6d01ca4, 0x0e1c6c322aa97fa2, + 0xd5511fed667fe30d, 0x59b0778eea06800b, 0xe7cae979261ab66a, 0x6b2b811aaa63d56c, + 0xc58fba65bc9d240c, 0x496ed20630e4470a, 0xf7144cf1fcf8716b, 0x7bf524927081126d, + 0xa0b8574d3c578ec2, 0x2c593f2eb02eedc4, 0x9223a1d97c32dba5, 0x1ec2c9baf04bb8a3, + 0x0fe06034bd087190, 0x8301085731711296, 0x3d7b96a0fd6d24f7, 0xb19afec3711447f1, + 0x6ad78d1c3dc2db5e, 0xe636e57fb1bbb858, 0x584c7b887da78e39, 0xd4ad13ebf1deed3f, + 0x2e5d2b2508cdff92, 0xa2bc434684b49c94, 0x1cc6ddb148a8aaf5, 0x9027b5d2c4d1c9f3, + 0x4b6ac60d8807555c, 0xc78bae6e047e365a, 0x79f13099c862003b, 0xf51058fa441b633d, + 0xe432f1740958aa0e, 0x68d399178521c908, 0xd6a907e0493dff69, 0x5a486f83c5449c6f, + 0x81051c5c899200c0, 0x0de4743f05eb63c6, 0xb39eeac8c9f755a7, 0x3f7f82ab458e36a1, + 0x91dbb9d45370c7c1, 0x1d3ad1b7df09a4c7, 0xa3404f40131592a6, 0x2fa127239f6cf1a0, + 0xf4ec54fcd3ba6d0f, 0x780d3c9f5fc30e09, 0xc677a26893df3868, 0x4a96ca0b1fa65b6e, + 0x5bb4638552e5925d, 0xd7550be6de9cf15b, 0x692f95111280c73a, 0xe5cefd729ef9a43c, + 0x3e838eadd22f3893, 0xb262e6ce5e565b95, 0x0c187839924a6df4, 0x80f9105a1e330ef2, + 0xd2a12ff738fbdbc5, 0x5e404794b482b8c3, 0xe03ad963789e8ea2, 0x6cdbb100f4e7eda4, + 0xb796c2dfb831710b, 0x3b77aabc3448120d, 0x850d344bf854246c, 0x09ec5c28742d476a, + 0x18cef5a6396e8e59, 0x942f9dc5b517ed5f, 0x2a550332790bdb3e, 0xa6b46b51f572b838, + 0x7df9188eb9a42497, 0xf11870ed35dd4791, 0x4f62ee1af9c171f0, 0xc383867975b812f6, + 0x6d27bd066346e396, 0xe1c6d565ef3f8090, 0x5fbc4b922323b6f1, 0xd35d23f1af5ad5f7, + 0x0810502ee38c4958, 0x84f1384d6ff52a5e, 0x3a8ba6baa3e91c3f, 0xb66aced92f907f39, + 0xa748675762d3b60a, 0x2ba90f34eeaad50c, 0x95d391c322b6e36d, 0x1932f9a0aecf806b, + 0xc27f8a7fe2191cc4, 0x4e9ee21c6e607fc2, 0xf0e47ceba27c49a3, 0x7c0514882e052aa5, + 0x86f52c46d7163808, 0x0a1444255b6f5b0e, 0xb46edad297736d6f, 0x388fb2b11b0a0e69, + 0xe3c2c16e57dc92c6, 0x6f23a90ddba5f1c0, 0xd15937fa17b9c7a1, 0x5db85f999bc0a4a7, + 0x4c9af617d6836d94, 0xc07b9e745afa0e92, 0x7e01008396e638f3, 0xf2e068e01a9f5bf5, + 0x29ad1b3f5649c75a, 0xa54c735cda30a45c, 0x1b36edab162c923d, 0x97d785c89a55f13b, + 0x3973beb78cab005b, 0xb592d6d400d2635d, 0x0be84823ccce553c, 0x8709204040b7363a, + 0x5c44539f0c61aa95, 0xd0a53bfc8018c993, 0x6edfa50b4c04fff2, 0xe23ecd68c07d9cf4, + 0xf31c64e68d3e55c7, 0x7ffd0c85014736c1, 0xc1879272cd5b00a0, 0x4d66fa11412263a6, + 0x962b89ce0df4ff09, 0x1acae1ad818d9c0f, 0xa4b07f5a4d91aa6e, 0x28511739c1e8c968 + }, + { + 0x0000000000000000, 0x3504e58b9ba6dd1e, 0x6a09cb17374dba3c, 0x5f0d2e9caceb6722, + 0xd413962e6e9b7478, 0xe11773a5f53da966, 0xbe1a5d3959d6ce44, 0x8b1eb8b2c270135a, + 0x837e0a0f85a17b9b, 0xb67aef841e07a685, 0xe977c118b2ecc1a7, 0xdc732493294a1cb9, + 0x576d9c21eb3a0fe3, 0x626979aa709cd2fd, 0x3d645736dc77b5df, 0x0860b2bd47d168c1, + 0x2da5324c53d5645d, 0x18a1d7c7c873b943, 0x47acf95b6498de61, 0x72a81cd0ff3e037f, + 0xf9b6a4623d4e1025, 0xccb241e9a6e8cd3b, 0x93bf6f750a03aa19, 0xa6bb8afe91a57707, + 0xaedb3843d6741fc6, 0x9bdfddc84dd2c2d8, 0xc4d2f354e139a5fa, 0xf1d616df7a9f78e4, + 0x7ac8ae6db8ef6bbe, 0x4fcc4be62349b6a0, 0x10c1657a8fa2d182, 0x25c580f114040c9c, + 0x5b4a6498a7aac8ba, 0x6e4e81133c0c15a4, 0x3143af8f90e77286, 0x04474a040b41af98, + 0x8f59f2b6c931bcc2, 0xba5d173d529761dc, 0xe55039a1fe7c06fe, 0xd054dc2a65dadbe0, + 0xd8346e97220bb321, 0xed308b1cb9ad6e3f, 0xb23da5801546091d, 0x8739400b8ee0d403, + 0x0c27f8b94c90c759, 0x39231d32d7361a47, 0x662e33ae7bdd7d65, 0x532ad625e07ba07b, + 0x76ef56d4f47face7, 0x43ebb35f6fd971f9, 0x1ce69dc3c33216db, 0x29e278485894cbc5, + 0xa2fcc0fa9ae4d89f, 0x97f8257101420581, 0xc8f50bedada962a3, 0xfdf1ee66360fbfbd, + 0xf5915cdb71ded77c, 0xc095b950ea780a62, 0x9f9897cc46936d40, 0xaa9c7247dd35b05e, + 0x2182caf51f45a304, 0x14862f7e84e37e1a, 0x4b8b01e228081938, 0x7e8fe469b3aec426, + 0xb694c9314f559174, 0x83902cbad4f34c6a, 0xdc9d022678182b48, 0xe999e7ade3bef656, + 0x62875f1f21cee50c, 0x5783ba94ba683812, 0x088e940816835f30, 0x3d8a71838d25822e, + 0x35eac33ecaf4eaef, 0x00ee26b5515237f1, 0x5fe30829fdb950d3, 0x6ae7eda2661f8dcd, + 0xe1f95510a46f9e97, 0xd4fdb09b3fc94389, 0x8bf09e07932224ab, 0xbef47b8c0884f9b5, + 0x9b31fb7d1c80f529, 0xae351ef687262837, 0xf138306a2bcd4f15, 0xc43cd5e1b06b920b, + 0x4f226d53721b8151, 0x7a2688d8e9bd5c4f, 0x252ba64445563b6d, 0x102f43cfdef0e673, + 0x184ff17299218eb2, 0x2d4b14f9028753ac, 0x72463a65ae6c348e, 0x4742dfee35cae990, + 0xcc5c675cf7bafaca, 0xf95882d76c1c27d4, 0xa655ac4bc0f740f6, 0x935149c05b519de8, + 0xeddeada9e8ff59ce, 0xd8da4822735984d0, 0x87d766bedfb2e3f2, 0xb2d3833544143eec, + 0x39cd3b8786642db6, 0x0cc9de0c1dc2f0a8, 0x53c4f090b129978a, 0x66c0151b2a8f4a94, + 0x6ea0a7a66d5e2255, 0x5ba4422df6f8ff4b, 0x04a96cb15a139869, 0x31ad893ac1b54577, + 0xbab3318803c5562d, 0x8fb7d40398638b33, 0xd0bafa9f3488ec11, 0xe5be1f14af2e310f, + 0xc07b9fe5bb2a3d93, 0xf57f7a6e208ce08d, 0xaa7254f28c6787af, 0x9f76b17917c15ab1, + 0x146809cbd5b149eb, 0x216cec404e1794f5, 0x7e61c2dce2fcf3d7, 0x4b652757795a2ec9, + 0x430595ea3e8b4608, 0x76017061a52d9b16, 0x290c5efd09c6fc34, 0x1c08bb769260212a, + 0x971603c450103270, 0xa212e64fcbb6ef6e, 0xfd1fc8d3675d884c, 0xc81b2d58fcfb5552, + 0x4670b431c63cb183, 0x737451ba5d9a6c9d, 0x2c797f26f1710bbf, 0x197d9aad6ad7d6a1, + 0x9263221fa8a7c5fb, 0xa767c794330118e5, 0xf86ae9089fea7fc7, 0xcd6e0c83044ca2d9, + 0xc50ebe3e439dca18, 0xf00a5bb5d83b1706, 0xaf07752974d07024, 0x9a0390a2ef76ad3a, + 0x111d28102d06be60, 0x2419cd9bb6a0637e, 0x7b14e3071a4b045c, 0x4e10068c81edd942, + 0x6bd5867d95e9d5de, 0x5ed163f60e4f08c0, 0x01dc4d6aa2a46fe2, 0x34d8a8e13902b2fc, + 0xbfc61053fb72a1a6, 0x8ac2f5d860d47cb8, 0xd5cfdb44cc3f1b9a, 0xe0cb3ecf5799c684, + 0xe8ab8c721048ae45, 0xddaf69f98bee735b, 0x82a2476527051479, 0xb7a6a2eebca3c967, + 0x3cb81a5c7ed3da3d, 0x09bcffd7e5750723, 0x56b1d14b499e6001, 0x63b534c0d238bd1f, + 0x1d3ad0a961967939, 0x283e3522fa30a427, 0x77331bbe56dbc305, 0x4237fe35cd7d1e1b, + 0xc92946870f0d0d41, 0xfc2da30c94abd05f, 0xa3208d903840b77d, 0x9624681ba3e66a63, + 0x9e44daa6e43702a2, 0xab403f2d7f91dfbc, 0xf44d11b1d37ab89e, 0xc149f43a48dc6580, + 0x4a574c888aac76da, 0x7f53a903110aabc4, 0x205e879fbde1cce6, 0x155a6214264711f8, + 0x309fe2e532431d64, 0x059b076ea9e5c07a, 0x5a9629f2050ea758, 0x6f92cc799ea87a46, + 0xe48c74cb5cd8691c, 0xd1889140c77eb402, 0x8e85bfdc6b95d320, 0xbb815a57f0330e3e, + 0xb3e1e8eab7e266ff, 0x86e50d612c44bbe1, 0xd9e823fd80afdcc3, 0xececc6761b0901dd, + 0x67f27ec4d9791287, 0x52f69b4f42dfcf99, 0x0dfbb5d3ee34a8bb, 0x38ff5058759275a5, + 0xf0e47d00896920f7, 0xc5e0988b12cffde9, 0x9aedb617be249acb, 0xafe9539c258247d5, + 0x24f7eb2ee7f2548f, 0x11f30ea57c548991, 0x4efe2039d0bfeeb3, 0x7bfac5b24b1933ad, + 0x739a770f0cc85b6c, 0x469e9284976e8672, 0x1993bc183b85e150, 0x2c975993a0233c4e, + 0xa789e12162532f14, 0x928d04aaf9f5f20a, 0xcd802a36551e9528, 0xf884cfbdceb84836, + 0xdd414f4cdabc44aa, 0xe845aac7411a99b4, 0xb748845bedf1fe96, 0x824c61d076572388, + 0x0952d962b42730d2, 0x3c563ce92f81edcc, 0x635b1275836a8aee, 0x565ff7fe18cc57f0, + 0x5e3f45435f1d3f31, 0x6b3ba0c8c4bbe22f, 0x34368e546850850d, 0x01326bdff3f65813, + 0x8a2cd36d31864b49, 0xbf2836e6aa209657, 0xe025187a06cbf175, 0xd521fdf19d6d2c6b, + 0xabae19982ec3e84d, 0x9eaafc13b5653553, 0xc1a7d28f198e5271, 0xf4a3370482288f6f, + 0x7fbd8fb640589c35, 0x4ab96a3ddbfe412b, 0x15b444a177152609, 0x20b0a12aecb3fb17, + 0x28d01397ab6293d6, 0x1dd4f61c30c44ec8, 0x42d9d8809c2f29ea, 0x77dd3d0b0789f4f4, + 0xfcc385b9c5f9e7ae, 0xc9c760325e5f3ab0, 0x96ca4eaef2b45d92, 0xa3ceab256912808c, + 0x860b2bd47d168c10, 0xb30fce5fe6b0510e, 0xec02e0c34a5b362c, 0xd9060548d1fdeb32, + 0x5218bdfa138df868, 0x671c5871882b2576, 0x381176ed24c04254, 0x0d159366bf669f4a, + 0x057521dbf8b7f78b, 0x3071c45063112a95, 0x6f7ceacccffa4db7, 0x5a780f47545c90a9, + 0xd166b7f5962c83f3, 0xe462527e0d8a5eed, 0xbb6f7ce2a16139cf, 0x8e6b99693ac7e4d1 + }, + { + 0x0000000000000000, 0xe39d1389931b9354, 0xec6301407ea0b5c3, 0x0ffe12c9edbb2697, + 0xf39f24d3a5d6f8ed, 0x1002375a36cd6bb9, 0x1ffc2593db764d2e, 0xfc61361a486dde7a, + 0xcc676ff4133a62b1, 0x2ffa7c7d8021f1e5, 0x20046eb46d9ad772, 0xc3997d3dfe814426, + 0x3ff84b27b6ec9a5c, 0xdc6558ae25f70908, 0xd39b4a67c84c2f9f, 0x300659ee5b57bccb, + 0xb397f9bb7ee35609, 0x500aea32edf8c55d, 0x5ff4f8fb0043e3ca, 0xbc69eb729358709e, + 0x4008dd68db35aee4, 0xa395cee1482e3db0, 0xac6bdc28a5951b27, 0x4ff6cfa1368e8873, + 0x7ff0964f6dd934b8, 0x9c6d85c6fec2a7ec, 0x9393970f1379817b, 0x700e84868062122f, + 0x8c6fb29cc80fcc55, 0x6ff2a1155b145f01, 0x600cb3dcb6af7996, 0x8391a05525b4eac2, + 0x4c76d525a5513f79, 0xafebc6ac364aac2d, 0xa015d465dbf18aba, 0x4388c7ec48ea19ee, + 0xbfe9f1f60087c794, 0x5c74e27f939c54c0, 0x538af0b67e277257, 0xb017e33fed3ce103, + 0x8011bad1b66b5dc8, 0x638ca9582570ce9c, 0x6c72bb91c8cbe80b, 0x8fefa8185bd07b5f, + 0x738e9e0213bda525, 0x90138d8b80a63671, 0x9fed9f426d1d10e6, 0x7c708ccbfe0683b2, + 0xffe12c9edbb26970, 0x1c7c3f1748a9fa24, 0x13822ddea512dcb3, 0xf01f3e5736094fe7, + 0x0c7e084d7e64919d, 0xefe31bc4ed7f02c9, 0xe01d090d00c4245e, 0x03801a8493dfb70a, + 0x3386436ac8880bc1, 0xd01b50e35b939895, 0xdfe5422ab628be02, 0x3c7851a325332d56, + 0xc01967b96d5ef32c, 0x23847430fe456078, 0x2c7a66f913fe46ef, 0xcfe7757080e5d5bb, + 0x98edaa4b4aa27ef2, 0x7b70b9c2d9b9eda6, 0x748eab0b3402cb31, 0x9713b882a7195865, + 0x6b728e98ef74861f, 0x88ef9d117c6f154b, 0x87118fd891d433dc, 0x648c9c5102cfa088, + 0x548ac5bf59981c43, 0xb717d636ca838f17, 0xb8e9c4ff2738a980, 0x5b74d776b4233ad4, + 0xa715e16cfc4ee4ae, 0x4488f2e56f5577fa, 0x4b76e02c82ee516d, 0xa8ebf3a511f5c239, + 0x2b7a53f0344128fb, 0xc8e74079a75abbaf, 0xc71952b04ae19d38, 0x24844139d9fa0e6c, + 0xd8e577239197d016, 0x3b7864aa028c4342, 0x34867663ef3765d5, 0xd71b65ea7c2cf681, + 0xe71d3c04277b4a4a, 0x04802f8db460d91e, 0x0b7e3d4459dbff89, 0xe8e32ecdcac06cdd, + 0x148218d782adb2a7, 0xf71f0b5e11b621f3, 0xf8e11997fc0d0764, 0x1b7c0a1e6f169430, + 0xd49b7f6eeff3418b, 0x37066ce77ce8d2df, 0x38f87e2e9153f448, 0xdb656da70248671c, + 0x27045bbd4a25b966, 0xc4994834d93e2a32, 0xcb675afd34850ca5, 0x28fa4974a79e9ff1, + 0x18fc109afcc9233a, 0xfb6103136fd2b06e, 0xf49f11da826996f9, 0x17020253117205ad, + 0xeb633449591fdbd7, 0x08fe27c0ca044883, 0x0700350927bf6e14, 0xe49d2680b4a4fd40, + 0x670c86d591101782, 0x8491955c020b84d6, 0x8b6f8795efb0a241, 0x68f2941c7cab3115, + 0x9493a20634c6ef6f, 0x770eb18fa7dd7c3b, 0x78f0a3464a665aac, 0x9b6db0cfd97dc9f8, + 0xab6be921822a7533, 0x48f6faa81131e667, 0x4708e861fc8ac0f0, 0xa495fbe86f9153a4, + 0x58f4cdf227fc8dde, 0xbb69de7bb4e71e8a, 0xb497ccb2595c381d, 0x570adf3bca47ab49, + 0x1a8272c5cdd36e8f, 0xf91f614c5ec8fddb, 0xf6e17385b373db4c, 0x157c600c20684818, + 0xe91d561668059662, 0x0a80459ffb1e0536, 0x057e575616a523a1, 0xe6e344df85beb0f5, + 0xd6e51d31dee90c3e, 0x35780eb84df29f6a, 0x3a861c71a049b9fd, 0xd91b0ff833522aa9, + 0x257a39e27b3ff4d3, 0xc6e72a6be8246787, 0xc91938a2059f4110, 0x2a842b2b9684d244, + 0xa9158b7eb3303886, 0x4a8898f7202babd2, 0x45768a3ecd908d45, 0xa6eb99b75e8b1e11, + 0x5a8aafad16e6c06b, 0xb917bc2485fd533f, 0xb6e9aeed684675a8, 0x5574bd64fb5de6fc, + 0x6572e48aa00a5a37, 0x86eff7033311c963, 0x8911e5cadeaaeff4, 0x6a8cf6434db17ca0, + 0x96edc05905dca2da, 0x7570d3d096c7318e, 0x7a8ec1197b7c1719, 0x9913d290e867844d, + 0x56f4a7e0688251f6, 0xb569b469fb99c2a2, 0xba97a6a01622e435, 0x590ab52985397761, + 0xa56b8333cd54a91b, 0x46f690ba5e4f3a4f, 0x49088273b3f41cd8, 0xaa9591fa20ef8f8c, + 0x9a93c8147bb83347, 0x790edb9de8a3a013, 0x76f0c95405188684, 0x956ddadd960315d0, + 0x690cecc7de6ecbaa, 0x8a91ff4e4d7558fe, 0x856fed87a0ce7e69, 0x66f2fe0e33d5ed3d, + 0xe5635e5b166107ff, 0x06fe4dd2857a94ab, 0x09005f1b68c1b23c, 0xea9d4c92fbda2168, + 0x16fc7a88b3b7ff12, 0xf561690120ac6c46, 0xfa9f7bc8cd174ad1, 0x190268415e0cd985, + 0x290431af055b654e, 0xca9922269640f61a, 0xc56730ef7bfbd08d, 0x26fa2366e8e043d9, + 0xda9b157ca08d9da3, 0x390606f533960ef7, 0x36f8143cde2d2860, 0xd56507b54d36bb34, + 0x826fd88e8771107d, 0x61f2cb07146a8329, 0x6e0cd9cef9d1a5be, 0x8d91ca476aca36ea, + 0x71f0fc5d22a7e890, 0x926defd4b1bc7bc4, 0x9d93fd1d5c075d53, 0x7e0eee94cf1cce07, + 0x4e08b77a944b72cc, 0xad95a4f30750e198, 0xa26bb63aeaebc70f, 0x41f6a5b379f0545b, + 0xbd9793a9319d8a21, 0x5e0a8020a2861975, 0x51f492e94f3d3fe2, 0xb2698160dc26acb6, + 0x31f82135f9924674, 0xd26532bc6a89d520, 0xdd9b20758732f3b7, 0x3e0633fc142960e3, + 0xc26705e65c44be99, 0x21fa166fcf5f2dcd, 0x2e0404a622e40b5a, 0xcd99172fb1ff980e, + 0xfd9f4ec1eaa824c5, 0x1e025d4879b3b791, 0x11fc4f8194089106, 0xf2615c0807130252, + 0x0e006a124f7edc28, 0xed9d799bdc654f7c, 0xe2636b5231de69eb, 0x01fe78dba2c5fabf, + 0xce190dab22202f04, 0x2d841e22b13bbc50, 0x227a0ceb5c809ac7, 0xc1e71f62cf9b0993, + 0x3d86297887f6d7e9, 0xde1b3af114ed44bd, 0xd1e52838f956622a, 0x32783bb16a4df17e, + 0x027e625f311a4db5, 0xe1e371d6a201dee1, 0xee1d631f4fbaf876, 0x0d807096dca16b22, + 0xf1e1468c94ccb558, 0x127c550507d7260c, 0x1d8247ccea6c009b, 0xfe1f5445797793cf, + 0x7d8ef4105cc3790d, 0x9e13e799cfd8ea59, 0x91edf5502263ccce, 0x7270e6d9b1785f9a, + 0x8e11d0c3f91581e0, 0x6d8cc34a6a0e12b4, 0x6272d18387b53423, 0x81efc20a14aea777, + 0xb1e99be44ff91bbc, 0x5274886ddce288e8, 0x5d8a9aa43159ae7f, 0xbe17892da2423d2b, + 0x4276bf37ea2fe351, 0xa1ebacbe79347005, 0xae15be77948f5692, 0x4d88adfe0794c5c6 + }, + { + 0x0000000000000000, 0x62a95de6e302eff2, 0xc552bbcdc605dfe4, 0xa7fbe62b25073016, + 0xa1fc51c8d49c2ca3, 0xc3550c2e379ec351, 0x64aeea051299f347, 0x0607b7e3f19b1cb5, + 0x68a185c2f1afca2d, 0x0a08d82412ad25df, 0xadf33e0f37aa15c9, 0xcf5a63e9d4a8fa3b, + 0xc95dd40a2533e68e, 0xabf489ecc631097c, 0x0c0f6fc7e336396a, 0x6ea632210034d698, + 0xd1430b85e35f945a, 0xb3ea5663005d7ba8, 0x1411b048255a4bbe, 0x76b8edaec658a44c, + 0x70bf5a4d37c3b8f9, 0x121607abd4c1570b, 0xb5ede180f1c6671d, 0xd744bc6612c488ef, + 0xb9e28e4712f05e77, 0xdb4bd3a1f1f2b185, 0x7cb0358ad4f58193, 0x1e19686c37f76e61, + 0x181edf8fc66c72d4, 0x7ab78269256e9d26, 0xdd4c64420069ad30, 0xbfe539a4e36b42c2, + 0x89df31589e28bbdf, 0xeb766cbe7d2a542d, 0x4c8d8a95582d643b, 0x2e24d773bb2f8bc9, + 0x282360904ab4977c, 0x4a8a3d76a9b6788e, 0xed71db5d8cb14898, 0x8fd886bb6fb3a76a, + 0xe17eb49a6f8771f2, 0x83d7e97c8c859e00, 0x242c0f57a982ae16, 0x468552b14a8041e4, + 0x4082e552bb1b5d51, 0x222bb8b45819b2a3, 0x85d05e9f7d1e82b5, 0xe77903799e1c6d47, + 0x589c3add7d772f85, 0x3a35673b9e75c077, 0x9dce8110bb72f061, 0xff67dcf658701f93, + 0xf9606b15a9eb0326, 0x9bc936f34ae9ecd4, 0x3c32d0d86feedcc2, 0x5e9b8d3e8cec3330, + 0x303dbf1f8cd8e5a8, 0x5294e2f96fda0a5a, 0xf56f04d24add3a4c, 0x97c65934a9dfd5be, + 0x91c1eed75844c90b, 0xf368b331bb4626f9, 0x5493551a9e4116ef, 0x363a08fc7d43f91d, + 0x38e744e264c6e4d5, 0x5a4e190487c40b27, 0xfdb5ff2fa2c33b31, 0x9f1ca2c941c1d4c3, + 0x991b152ab05ac876, 0xfbb248cc53582784, 0x5c49aee7765f1792, 0x3ee0f301955df860, + 0x5046c12095692ef8, 0x32ef9cc6766bc10a, 0x95147aed536cf11c, 0xf7bd270bb06e1eee, + 0xf1ba90e841f5025b, 0x9313cd0ea2f7eda9, 0x34e82b2587f0ddbf, 0x564176c364f2324d, + 0xe9a44f678799708f, 0x8b0d1281649b9f7d, 0x2cf6f4aa419caf6b, 0x4e5fa94ca29e4099, + 0x48581eaf53055c2c, 0x2af14349b007b3de, 0x8d0aa562950083c8, 0xefa3f88476026c3a, + 0x8105caa57636baa2, 0xe3ac974395345550, 0x44577168b0336546, 0x26fe2c8e53318ab4, + 0x20f99b6da2aa9601, 0x4250c68b41a879f3, 0xe5ab20a064af49e5, 0x87027d4687ada617, + 0xb13875bafaee5f0a, 0xd391285c19ecb0f8, 0x746ace773ceb80ee, 0x16c39391dfe96f1c, + 0x10c424722e7273a9, 0x726d7994cd709c5b, 0xd5969fbfe877ac4d, 0xb73fc2590b7543bf, + 0xd999f0780b419527, 0xbb30ad9ee8437ad5, 0x1ccb4bb5cd444ac3, 0x7e6216532e46a531, + 0x7865a1b0dfddb984, 0x1accfc563cdf5676, 0xbd371a7d19d86660, 0xdf9e479bfada8992, + 0x607b7e3f19b1cb50, 0x02d223d9fab324a2, 0xa529c5f2dfb414b4, 0xc78098143cb6fb46, + 0xc1872ff7cd2de7f3, 0xa32e72112e2f0801, 0x04d5943a0b283817, 0x667cc9dce82ad7e5, + 0x08dafbfde81e017d, 0x6a73a61b0b1cee8f, 0xcd8840302e1bde99, 0xaf211dd6cd19316b, + 0xa926aa353c822dde, 0xcb8ff7d3df80c22c, 0x6c7411f8fa87f23a, 0x0edd4c1e19851dc8, + 0x71ce89c4c98dc9aa, 0x1367d4222a8f2658, 0xb49c32090f88164e, 0xd6356fefec8af9bc, + 0xd032d80c1d11e509, 0xb29b85eafe130afb, 0x156063c1db143aed, 0x77c93e273816d51f, + 0x196f0c0638220387, 0x7bc651e0db20ec75, 0xdc3db7cbfe27dc63, 0xbe94ea2d1d253391, + 0xb8935dceecbe2f24, 0xda3a00280fbcc0d6, 0x7dc1e6032abbf0c0, 0x1f68bbe5c9b91f32, + 0xa08d82412ad25df0, 0xc224dfa7c9d0b202, 0x65df398cecd78214, 0x0776646a0fd56de6, + 0x0171d389fe4e7153, 0x63d88e6f1d4c9ea1, 0xc4236844384baeb7, 0xa68a35a2db494145, + 0xc82c0783db7d97dd, 0xaa855a65387f782f, 0x0d7ebc4e1d784839, 0x6fd7e1a8fe7aa7cb, + 0x69d0564b0fe1bb7e, 0x0b790badece3548c, 0xac82ed86c9e4649a, 0xce2bb0602ae68b68, + 0xf811b89c57a57275, 0x9ab8e57ab4a79d87, 0x3d43035191a0ad91, 0x5fea5eb772a24263, + 0x59ede95483395ed6, 0x3b44b4b2603bb124, 0x9cbf5299453c8132, 0xfe160f7fa63e6ec0, + 0x90b03d5ea60ab858, 0xf21960b8450857aa, 0x55e28693600f67bc, 0x374bdb75830d884e, + 0x314c6c96729694fb, 0x53e5317091947b09, 0xf41ed75bb4934b1f, 0x96b78abd5791a4ed, + 0x2952b319b4fae62f, 0x4bfbeeff57f809dd, 0xec0008d472ff39cb, 0x8ea9553291fdd639, + 0x88aee2d16066ca8c, 0xea07bf378364257e, 0x4dfc591ca6631568, 0x2f5504fa4561fa9a, + 0x41f336db45552c02, 0x235a6b3da657c3f0, 0x84a18d168350f3e6, 0xe608d0f060521c14, + 0xe00f671391c900a1, 0x82a63af572cbef53, 0x255ddcde57ccdf45, 0x47f48138b4ce30b7, + 0x4929cd26ad4b2d7f, 0x2b8090c04e49c28d, 0x8c7b76eb6b4ef29b, 0xeed22b0d884c1d69, + 0xe8d59cee79d701dc, 0x8a7cc1089ad5ee2e, 0x2d872723bfd2de38, 0x4f2e7ac55cd031ca, + 0x218848e45ce4e752, 0x43211502bfe608a0, 0xe4daf3299ae138b6, 0x8673aecf79e3d744, + 0x8074192c8878cbf1, 0xe2dd44ca6b7a2403, 0x4526a2e14e7d1415, 0x278fff07ad7ffbe7, + 0x986ac6a34e14b925, 0xfac39b45ad1656d7, 0x5d387d6e881166c1, 0x3f9120886b138933, + 0x3996976b9a889586, 0x5b3fca8d798a7a74, 0xfcc42ca65c8d4a62, 0x9e6d7140bf8fa590, + 0xf0cb4361bfbb7308, 0x92621e875cb99cfa, 0x3599f8ac79beacec, 0x5730a54a9abc431e, + 0x513712a96b275fab, 0x339e4f4f8825b059, 0x9465a964ad22804f, 0xf6ccf4824e206fbd, + 0xc0f6fc7e336396a0, 0xa25fa198d0617952, 0x05a447b3f5664944, 0x670d1a551664a6b6, + 0x610aadb6e7ffba03, 0x03a3f05004fd55f1, 0xa458167b21fa65e7, 0xc6f14b9dc2f88a15, + 0xa85779bcc2cc5c8d, 0xcafe245a21ceb37f, 0x6d05c27104c98369, 0x0fac9f97e7cb6c9b, + 0x09ab28741650702e, 0x6b027592f5529fdc, 0xccf993b9d055afca, 0xae50ce5f33574038, + 0x11b5f7fbd03c02fa, 0x731caa1d333eed08, 0xd4e74c361639dd1e, 0xb64e11d0f53b32ec, + 0xb049a63304a02e59, 0xd2e0fbd5e7a2c1ab, 0x751b1dfec2a5f1bd, 0x17b2401821a71e4f, + 0x791472392193c8d7, 0x1bbd2fdfc2912725, 0xbc46c9f4e7961733, 0xdeef94120494f8c1, + 0xd8e823f1f50fe474, 0xba417e17160d0b86, 0x1dba983c330a3b90, 0x7f13c5dad008d462 + }, + { + 0x0000000000000000, 0x381d0015c96f4444, 0x703a002b92de8888, 0x4827003e5bb1cccc, + 0xe074005725bd1110, 0xd8690042ecd25554, 0x904e007cb7639998, 0xa85300697e0cdddc, + 0xebb126fd13edb14b, 0xd3ac26e8da82f50f, 0x9b8b26d6813339c3, 0xa39626c3485c7d87, + 0x0bc526aa3650a05b, 0x33d826bfff3fe41f, 0x7bff2681a48e28d3, 0x43e226946de16c97, + 0xfc3b6ba97f4cf1fd, 0xc4266bbcb623b5b9, 0x8c016b82ed927975, 0xb41c6b9724fd3d31, + 0x1c4f6bfe5af1e0ed, 0x24526beb939ea4a9, 0x6c756bd5c82f6865, 0x54686bc001402c21, + 0x178a4d546ca140b6, 0x2f974d41a5ce04f2, 0x67b04d7ffe7fc83e, 0x5fad4d6a37108c7a, + 0xf7fe4d03491c51a6, 0xcfe34d16807315e2, 0x87c44d28dbc2d92e, 0xbfd94d3d12ad9d6a, + 0xd32ff101a60e7091, 0xeb32f1146f6134d5, 0xa315f12a34d0f819, 0x9b08f13ffdbfbc5d, + 0x335bf15683b36181, 0x0b46f1434adc25c5, 0x4361f17d116de909, 0x7b7cf168d802ad4d, + 0x389ed7fcb5e3c1da, 0x0083d7e97c8c859e, 0x48a4d7d7273d4952, 0x70b9d7c2ee520d16, + 0xd8ead7ab905ed0ca, 0xe0f7d7be5931948e, 0xa8d0d78002805842, 0x90cdd795cbef1c06, + 0x2f149aa8d942816c, 0x17099abd102dc528, 0x5f2e9a834b9c09e4, 0x67339a9682f34da0, + 0xcf609afffcff907c, 0xf77d9aea3590d438, 0xbf5a9ad46e2118f4, 0x87479ac1a74e5cb0, + 0xc4a5bc55caaf3027, 0xfcb8bc4003c07463, 0xb49fbc7e5871b8af, 0x8c82bc6b911efceb, + 0x24d1bc02ef122137, 0x1cccbc17267d6573, 0x54ebbc297dcca9bf, 0x6cf6bc3cb4a3edfb, + 0x8d06c450148b7249, 0xb51bc445dde4360d, 0xfd3cc47b8655fac1, 0xc521c46e4f3abe85, + 0x6d72c40731366359, 0x556fc412f859271d, 0x1d48c42ca3e8ebd1, 0x2555c4396a87af95, + 0x66b7e2ad0766c302, 0x5eaae2b8ce098746, 0x168de28695b84b8a, 0x2e90e2935cd70fce, + 0x86c3e2fa22dbd212, 0xbedee2efebb49656, 0xf6f9e2d1b0055a9a, 0xcee4e2c4796a1ede, + 0x713daff96bc783b4, 0x4920afeca2a8c7f0, 0x0107afd2f9190b3c, 0x391aafc730764f78, + 0x9149afae4e7a92a4, 0xa954afbb8715d6e0, 0xe173af85dca41a2c, 0xd96eaf9015cb5e68, + 0x9a8c8904782a32ff, 0xa2918911b14576bb, 0xeab6892feaf4ba77, 0xd2ab893a239bfe33, + 0x7af889535d9723ef, 0x42e5894694f867ab, 0x0ac28978cf49ab67, 0x32df896d0626ef23, + 0x5e293551b28502d8, 0x663435447bea469c, 0x2e13357a205b8a50, 0x160e356fe934ce14, + 0xbe5d3506973813c8, 0x864035135e57578c, 0xce67352d05e69b40, 0xf67a3538cc89df04, + 0xb59813aca168b393, 0x8d8513b96807f7d7, 0xc5a2138733b63b1b, 0xfdbf1392fad97f5f, + 0x55ec13fb84d5a283, 0x6df113ee4dbae6c7, 0x25d613d0160b2a0b, 0x1dcb13c5df646e4f, + 0xa2125ef8cdc9f325, 0x9a0f5eed04a6b761, 0xd2285ed35f177bad, 0xea355ec696783fe9, + 0x42665eafe874e235, 0x7a7b5eba211ba671, 0x325c5e847aaa6abd, 0x0a415e91b3c52ef9, + 0x49a37805de24426e, 0x71be7810174b062a, 0x3999782e4cfacae6, 0x0184783b85958ea2, + 0xa9d77852fb99537e, 0x91ca784732f6173a, 0xd9ed78796947dbf6, 0xe1f0786ca0289fb2, + 0x3154aef3718177f9, 0x0949aee6b8ee33bd, 0x416eaed8e35fff71, 0x7973aecd2a30bb35, + 0xd120aea4543c66e9, 0xe93daeb19d5322ad, 0xa11aae8fc6e2ee61, 0x9907ae9a0f8daa25, + 0xdae5880e626cc6b2, 0xe2f8881bab0382f6, 0xaadf8825f0b24e3a, 0x92c2883039dd0a7e, + 0x3a91885947d1d7a2, 0x028c884c8ebe93e6, 0x4aab8872d50f5f2a, 0x72b688671c601b6e, + 0xcd6fc55a0ecd8604, 0xf572c54fc7a2c240, 0xbd55c5719c130e8c, 0x8548c564557c4ac8, + 0x2d1bc50d2b709714, 0x1506c518e21fd350, 0x5d21c526b9ae1f9c, 0x653cc53370c15bd8, + 0x26dee3a71d20374f, 0x1ec3e3b2d44f730b, 0x56e4e38c8ffebfc7, 0x6ef9e3994691fb83, + 0xc6aae3f0389d265f, 0xfeb7e3e5f1f2621b, 0xb690e3dbaa43aed7, 0x8e8de3ce632cea93, + 0xe27b5ff2d78f0768, 0xda665fe71ee0432c, 0x92415fd945518fe0, 0xaa5c5fcc8c3ecba4, + 0x020f5fa5f2321678, 0x3a125fb03b5d523c, 0x72355f8e60ec9ef0, 0x4a285f9ba983dab4, + 0x09ca790fc462b623, 0x31d7791a0d0df267, 0x79f0792456bc3eab, 0x41ed79319fd37aef, + 0xe9be7958e1dfa733, 0xd1a3794d28b0e377, 0x9984797373012fbb, 0xa1997966ba6e6bff, + 0x1e40345ba8c3f695, 0x265d344e61acb2d1, 0x6e7a34703a1d7e1d, 0x56673465f3723a59, + 0xfe34340c8d7ee785, 0xc62934194411a3c1, 0x8e0e34271fa06f0d, 0xb6133432d6cf2b49, + 0xf5f112a6bb2e47de, 0xcdec12b37241039a, 0x85cb128d29f0cf56, 0xbdd61298e09f8b12, + 0x158512f19e9356ce, 0x2d9812e457fc128a, 0x65bf12da0c4dde46, 0x5da212cfc5229a02, + 0xbc526aa3650a05b0, 0x844f6ab6ac6541f4, 0xcc686a88f7d48d38, 0xf4756a9d3ebbc97c, + 0x5c266af440b714a0, 0x643b6ae189d850e4, 0x2c1c6adfd2699c28, 0x14016aca1b06d86c, + 0x57e34c5e76e7b4fb, 0x6ffe4c4bbf88f0bf, 0x27d94c75e4393c73, 0x1fc44c602d567837, + 0xb7974c09535aa5eb, 0x8f8a4c1c9a35e1af, 0xc7ad4c22c1842d63, 0xffb04c3708eb6927, + 0x4069010a1a46f44d, 0x7874011fd329b009, 0x3053012188987cc5, 0x084e013441f73881, + 0xa01d015d3ffbe55d, 0x98000148f694a119, 0xd0270176ad256dd5, 0xe83a0163644a2991, + 0xabd827f709ab4506, 0x93c527e2c0c40142, 0xdbe227dc9b75cd8e, 0xe3ff27c9521a89ca, + 0x4bac27a02c165416, 0x73b127b5e5791052, 0x3b96278bbec8dc9e, 0x038b279e77a798da, + 0x6f7d9ba2c3047521, 0x57609bb70a6b3165, 0x1f479b8951dafda9, 0x275a9b9c98b5b9ed, + 0x8f099bf5e6b96431, 0xb7149be02fd62075, 0xff339bde7467ecb9, 0xc72e9bcbbd08a8fd, + 0x84ccbd5fd0e9c46a, 0xbcd1bd4a1986802e, 0xf4f6bd7442374ce2, 0xccebbd618b5808a6, + 0x64b8bd08f554d57a, 0x5ca5bd1d3c3b913e, 0x1482bd23678a5df2, 0x2c9fbd36aee519b6, + 0x9346f00bbc4884dc, 0xab5bf01e7527c098, 0xe37cf0202e960c54, 0xdb61f035e7f94810, + 0x7332f05c99f595cc, 0x4b2ff049509ad188, 0x0308f0770b2b1d44, 0x3b15f062c2445900, + 0x78f7d6f6afa53597, 0x40ead6e366ca71d3, 0x08cdd6dd3d7bbd1f, 0x30d0d6c8f414f95b, + 0x9883d6a18a182487, 0xa09ed6b4437760c3, 0xe8b9d68a18c6ac0f, 0xd0a4d69fd1a9e84b + }, + }; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64.cs new file mode 100644 index 00000000000..f3dabdc2f71 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64.cs @@ -0,0 +1,63 @@ +/* + * Originally ported from: https://github.com/gityf/crc/blob/8045f50ba6e4193d4ee5d2539025fef26e613c9f/crc/crc64.c + * + * Copyright (c) 2012, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ + +using System; +using System.Security.Cryptography; + +namespace Java.Interop.Tools.JavaCallableWrappers +{ + /// + /// CRC64 variant: crc-64-jones 64-bit + /// * Poly: 0xad93d23594c935a9 + /// + /// Changes beyond initial implementation: + /// * Starting Value: ulong.MaxValue + /// * XOR length in HashFinal() + /// * Using spliced table for faster processing + /// + public partial class Crc64 : HashAlgorithm + { + ulong crc = ulong.MaxValue; + ulong length = 0; + + public override void Initialize () + { + crc = ulong.MaxValue; + length = 0; + } + + protected override unsafe void HashCore (byte [] array, int ibStart, int cbSize) + { + Crc64Helper.HashCore (array, ibStart, cbSize, ref crc, ref length); + } + + protected override byte [] HashFinal () => BitConverter.GetBytes (crc ^ length); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64Helper.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64Helper.cs new file mode 100644 index 00000000000..82ab2a90bc8 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/Crc64Helper.cs @@ -0,0 +1,91 @@ +/* + * Originally ported from: https://github.com/gityf/crc/blob/8045f50ba6e4193d4ee5d2539025fef26e613c9f/crc/crc64.c + * + * Copyright (c) 2012, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ + +using System; +using System.Security.Cryptography; + +namespace Java.Interop.Tools.JavaCallableWrappers +{ + /// + /// CRC64 variant: crc-64-jones 64-bit + /// * Poly: 0xad93d23594c935a9 + /// + /// Changes beyond initial implementation: + /// * Starting Value: ulong.MaxValue + /// * XOR length in HashFinal() + /// * Using spliced table for faster processing + /// + internal static partial class Crc64Helper + { + + internal static byte [] Compute (byte [] array) + { + ulong crc = ulong.MaxValue; + ulong length = 0; + + HashCore (array, 0, array.Length, ref crc, ref length); + + return BitConverter.GetBytes (crc ^ length); + } + + internal static unsafe void HashCore (byte [] array, int ibStart, int cbSize, ref ulong crc, ref ulong length) + { + int len = cbSize; + int idx = ibStart; + + fixed (ulong* tptr = table) { + fixed (byte* aptr = array) { + while (len >= 8) { + crc ^= *((ulong*) (aptr + idx)); + crc = + tptr [7 * 256 + (crc & 0xff)] ^ + tptr [6 * 256 + ((crc >> 8) & 0xff)] ^ + tptr [5 * 256 + ((crc >> 16) & 0xff)] ^ + tptr [4 * 256 + ((crc >> 24) & 0xff)] ^ + tptr [3 * 256 + ((crc >> 32) & 0xff)] ^ + tptr [2 * 256 + ((crc >> 40) & 0xff)] ^ + tptr [1 * 256 + ((crc >> 48) & 0xff)] ^ + tptr [0 * 256 + (crc >> 56)]; + idx += 8; + len -= 8; + } + + while (len > 0) { + crc = tptr [0 * 256 + ((crc ^ aptr [idx]) & 0xff)] ^ (crc >> 8); + idx++; + len--; + } + } + } + + length += (ulong) cbSize; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidator.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidator.cs new file mode 100644 index 00000000000..daf4e6dd044 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidator.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaCallableWrappers +{ + public static class IdentifierValidator + { + // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure#identifiers + private const string FormattingCharacter = @"\p{Cf}"; + private const string ConnectingCharacter = @"\p{Pc}"; + private const string DecimalDigitCharacter = @"\p{Nd}"; + private const string CombiningCharacter = @"\p{Mn}\p{Mc}"; + private const string LetterCharacter = @"\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}"; + + private const string IdentifierPartCharacter = LetterCharacter + + DecimalDigitCharacter + + ConnectingCharacter + + CombiningCharacter + + FormattingCharacter; + + private const string IdentifierStartCharacter = "(" + LetterCharacter + "_)"; + + private const string Identifier = IdentifierStartCharacter + "(" + IdentifierPartCharacter + ")"; + + static Regex IsValidIdentifierRegex = new Regex ($"^[{IdentifierStartCharacter}][{IdentifierPartCharacter}]*$", RegexOptions.Compiled); + + // We use [^ ...] to detect any character that is NOT a match. + static Regex validIdentifier = new Regex ($"[^{Identifier}]", RegexOptions.Compiled); + + public static string CreateValidIdentifier (string? identifier, bool useEncodedReplacements = false) + { + if (identifier == null || string.IsNullOrWhiteSpace (identifier)) return string.Empty; + + var normalizedIdentifier = identifier.Normalize (); + + if (useEncodedReplacements) + return validIdentifier.Replace (normalizedIdentifier, new MatchEvaluator (EncodeReplacement)); + + return validIdentifier.Replace (normalizedIdentifier, "_"); + } + + public static bool IsValidIdentifier (string identifier) + { + return IsValidIdentifierRegex.IsMatch (identifier); + } + + // Makes uglier but unique identifiers by encoding each invalid character with its character value + static string EncodeReplacement (Match match) => $"_x{(ushort) match.Value [0]}_"; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableMethodClassifier.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableMethodClassifier.cs new file mode 100644 index 00000000000..75e8061d6d4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableMethodClassifier.cs @@ -0,0 +1,9 @@ +using Mono.Cecil; + +namespace Java.Interop.Tools.JavaCallableWrappers +{ + public abstract class JavaCallableMethodClassifier + { + public abstract bool ShouldBeDynamicallyRegistered (TypeDefinition topType, MethodDefinition registeredMethod, MethodDefinition implementedMethod, CustomAttribute? registerAttribute); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaPeerStyle.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaPeerStyle.cs new file mode 100644 index 00000000000..917196a1605 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaPeerStyle.cs @@ -0,0 +1,7 @@ +namespace Java.Interop.Tools.JavaCallableWrappers +{ + public enum JavaPeerStyle { + XAJavaInterop1, + JavaInterop1, + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs new file mode 100644 index 00000000000..638464335d8 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using Mono.Cecil; + +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Diagnostics; +using Java.Interop.Tools.TypeNameMappings; +using Java.Interop.Tools.JavaCallableWrappers.Utilities; + +namespace Java.Interop.Tools.JavaCallableWrappers +{ + public class JavaTypeScanner + { + public Action Logger { get; private set; } + public bool ErrorOnCustomJavaObject { get; set; } + + readonly IMetadataResolver cache; + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public JavaTypeScanner (Action logger) => throw new NotSupportedException (); + + public JavaTypeScanner (Action logger, TypeDefinitionCache cache) + : this (logger, (IMetadataResolver) cache) + { + } + + public JavaTypeScanner (Action logger, IMetadataResolver resolver) + { + if (logger == null) + throw new ArgumentNullException (nameof (logger)); + Logger = logger; + this.cache = cache ?? new TypeDefinitionCache (); + } + + public List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver) + { + var javaTypes = new List (); + + foreach (var assembly in assemblies) { + var assm = resolver.GetAssembly (assembly); + + foreach (ModuleDefinition md in assm.Modules) { + foreach (TypeDefinition td in md.Types) { + AddJavaTypes (javaTypes, td); + } + } + } + + return javaTypes; + } + + public List GetJavaTypes (AssemblyDefinition assembly) + { + var javaTypes = new List (); + + foreach (ModuleDefinition md in assembly.Modules) { + foreach (TypeDefinition td in md.Types) { + AddJavaTypes (javaTypes, td); + } + } + + return javaTypes; + } + + void AddJavaTypes (List javaTypes, TypeDefinition type) + { + if (type.HasJavaPeer (cache)) { + javaTypes.Add (type); + } else if (type.IsClass && !type.IsSubclassOf ("System.Exception", cache) && type.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) { + var level = ErrorOnCustomJavaObject ? TraceLevel.Error : TraceLevel.Warning; + var prefix = ErrorOnCustomJavaObject ? "error" : "warning"; + Logger ( + level, + $"{prefix} XA4212: Type `{type.FullName}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported."); + return; + } + + if (!type.HasNestedTypes) + return; + + foreach (TypeDefinition nested in type.NestedTypes) + AddJavaTypes (javaTypes, nested); + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type) => throw new NotSupportedException (); + + public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type, TypeDefinitionCache cache) => + ShouldSkipJavaCallableWrapperGeneration (type, (IMetadataResolver) cache); + + public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type, IMetadataResolver resolver) + { + if (JavaNativeTypeManager.IsNonStaticInnerClass (type, resolver)) + return true; + + foreach (var c in CecilExtensions.GetTypeRegistrationAttributes (type)) { + if (c.DoNotGenerateAcw) { + return true; + } + } + + return false; + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log) => throw new NotSupportedException (); + + // Returns all types for which we need to generate Java delegate types. + public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log, TypeDefinitionCache cache) => + GetJavaTypes (assemblies, resolver, log, (IMetadataResolver) cache); + + public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log, IMetadataResolver metadataResolver) + { + Action l = (level, value) => log ("{0}", new string [] { value }); + return new JavaTypeScanner (l, metadataResolver).GetJavaTypes (assemblies, resolver); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs new file mode 100644 index 00000000000..45164f6a29a --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs @@ -0,0 +1,290 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Mono.Cecil; + +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.TypeNameMappings; + +namespace Java.Interop.Tools.JavaCallableWrappers { + + /* + * TypeNameMapGenerator is responsible for generating a "mapping file" to + * support CPU-efficient mapping between Java types and Managed types + * (wherein "CPU-efficient" means "NO REFLECTION REQUIRED"). + * + * This is done by storing the data in a form that can be easily passed + * to bsearch(3), allowing a binary search of the contents. + * + * The format of the file is: + * + * // header + * "version=" INT \0 (must be '1') + * "entry-count=" INT \0 (bsearch(3) `nel` value) + * "entry-len=" INT \0 (bsearch(3) `width` value) + * "value-offset=" INT \0 (offset to value within entry) + * + * ENTRIES + * \0 + * + * The header consists of NUL-separated key=value string pairs, including + * the file format version ("1"). (Why strings? So I don't have to worry + * about byte-ordering concerns. Besides, the ENTRIES will be strings, + * and it makes viewing the file contents with strings(1) easy.) + * + * ENTRIES consists of rows that are `entry-len` bytes in length, containing + * a "key" and a "value". The "key" is NUL-padded so that the "value" starts + * at `value-offset` bytes into the row, and "value" is NUL-padded to ensure + * that the entire row length is `entry-len` bytes in length. + * + * After ENTRIES is a final terminating NUL. + * + * In string-form, a valid mapping would be: + * + * "version=1\u0000" + + * "entry-count=1\u0000" + + * "entry-len=10\u0000" + + * "value-offset=4\u0000" + + * "key\u0000value\u0000" + + * "\u0000" + * + * The rows MUST be sorted so that strcmp(3) can be used to compare keys + * values between rows + */ + public class TypeNameMapGenerator : IDisposable { + + Action Log; + List Types; + DirectoryAssemblyResolver? Resolver; + readonly IMetadataResolver Cache; + + [Obsolete ("Use TypeNameMapGenerator(IEnumerable, Action, TypeDefinitionCache)")] + public TypeNameMapGenerator (IEnumerable assemblies, Action logMessage) + : this (assemblies, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new[]{value}), resolver: null) + { + if (logMessage == null) + throw new ArgumentNullException (nameof (logMessage)); + } + + [Obsolete ("Use TypeNameMapGenerator(IEnumerable, Action, TypeDefinitionCache)")] + public TypeNameMapGenerator (IEnumerable assemblies, Action logger) + : this (assemblies, logger, resolver: null) + { } + + public TypeNameMapGenerator (IEnumerable assemblies, Action logger, TypeDefinitionCache? cache) + : this (assemblies, logger, (IMetadataResolver?) cache) + { + } + + public TypeNameMapGenerator (IEnumerable assemblies, Action logger, IMetadataResolver? resolver) + { + if (assemblies == null) + throw new ArgumentNullException ("assemblies"); + if (logger == null) + throw new ArgumentNullException (nameof (logger)); + + Cache = resolver ?? new TypeDefinitionCache (); + Log = logger; + var Assemblies = assemblies.ToList (); + var rp = new ReaderParameters (); + + Resolver = new DirectoryAssemblyResolver (Log, loadDebugSymbols: true, loadReaderParameters: rp); + foreach (var assembly in Assemblies) { + var directory = Path.GetDirectoryName (assembly); + if (string.IsNullOrEmpty (directory)) + continue; + if (!Resolver.SearchDirectories.Contains (directory)) + Resolver.SearchDirectories.Add (directory); + } + foreach (var assembly in Assemblies) { + Resolver.Load (Path.GetFullPath (assembly)); + } + + var scanner = new JavaTypeScanner (Log, Cache) { + ErrorOnCustomJavaObject = false, + }; + Types = scanner.GetJavaTypes (Assemblies, Resolver); + } + + [Obsolete ("Use TypeNameMapGenerator(IEnumerable, Action, TypeDefinitionCache)")] + public TypeNameMapGenerator (IEnumerable types, Action logMessage) + : this (types, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new [] { value }), resolver: null) + { + if (logMessage == null) + throw new ArgumentNullException (nameof (logMessage)); + } + + [Obsolete ("Use TypeNameMapGenerator(IEnumerable, Action, TypeDefinitionCache)")] + public TypeNameMapGenerator (IEnumerable types, Action logger) + : this (types, logger, resolver: null) + { } + + public TypeNameMapGenerator (IEnumerable types, Action logger, TypeDefinitionCache? cache) + : this (types, logger, (IMetadataResolver?) cache) + { + } + + public TypeNameMapGenerator (IEnumerable types, Action logger, IMetadataResolver? resolver) + { + if (types == null) + throw new ArgumentNullException ("types"); + if (logger == null) + throw new ArgumentNullException (nameof (logger)); + + Cache = resolver ?? new TypeDefinitionCache (); + + Log = logger; + Types = types.ToList (); + } + + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose (bool disposing) + { + if (!disposing || Resolver == null) + return; + + Resolver.Dispose (); + Resolver = null; + } + + public void WriteJavaToManaged (Stream output) + { + if (output == null) + throw new ArgumentNullException ("output"); + + var typeMap = GetTypeMapping ( + t => t.IsInterface || t.HasGenericParameters, + JavaNativeTypeManager.ToJniName, + (t, c) => t.GetPartialAssemblyQualifiedName (c)); + + WriteBinaryMapping (output, typeMap); + } + + Dictionary GetTypeMapping (Func skipType, Func key, Func value) + { + var typeMap = new Dictionary (); + var aliases = new Dictionary> (); + foreach (var type in Types) { + if (skipType (type)) + continue; + + var k = key (type, Cache); + + TypeDefinition? e; + if (!typeMap.TryGetValue (k, out e)) { + typeMap.Add (k, type); + } else if (type.IsAbstract || type.IsInterface || e.IsAbstract || e.IsInterface) { + // Two separate types w/ the same key; a JavaToManaged issue. + // Prefer the base (abstract?) class over the invoker. + var b = e; + if (type.IsAssignableFrom (e, Cache)) + b = type; + typeMap [k] = b; + } else { + List? a; + if (!aliases.TryGetValue (k, out a)) { + aliases.Add (k, a = new List ()); + a.Add (value (e, Cache)); + } + a.Add (value (type, Cache)); + } + } + foreach (var e in aliases.OrderBy (e => e.Key)) { + Log (TraceLevel.Warning, $"Mapping for type '{e.Key}' is ambiguous between {e.Value.Count} types."); + Log (TraceLevel.Warning, $" Using: {e.Value.First ()}"); + foreach (var o in e.Value.Skip (1)) { + Log (TraceLevel.Info, $" Ignoring: {o}"); + } + } + return typeMap.ToDictionary (e => e.Key, e => value (e.Value, Cache)); + } + + static void WriteBinaryMapping (Stream o, Dictionary mapping) + { + var encoding = Encoding.UTF8; + var binary = ToBinary (mapping, encoding); + + var keyLen = binary.Keys.Max (v => v?.Length) ?? 0; + var valueLen = binary.Values.Max (v => v?.Length) ?? 0; + + WriteHeader (o, binary.Count, keyLen, valueLen, encoding); + + foreach (var key in binary.Keys.OrderBy (k => k, new ArrayComparer ())) { + Write (o, key, keyLen); + Write (o, binary [key], valueLen); + } + o.WriteByte (0x0); + } + + static Dictionary ToBinary(Dictionary map, Encoding encoding) + { + return map.ToDictionary (e => encoding.GetBytes (e.Key), e => encoding.GetBytes (e.Value)); + } + + static void WriteHeader (Stream o, int entries, int keyLen, int valueLen, Encoding encoding) + { + var header = string.Format ("version=1\u0000entry-count={0}\u0000entry-len={1}\u0000value-offset={2}\u0000", entries, checked (keyLen + 1 + valueLen + 1), keyLen + 1); + WriteString (o, header, encoding); + } + + static void WriteString (Stream o, string value, Encoding encoding) + { + var data = encoding.GetBytes (value); + o.Write (data, 0, data.Length); + } + + static void Write (Stream o, byte[] value, int length) + { + o.Write (value, 0, value.Length); + for (int i = value.Length; i < length; ++i) + o.WriteByte (0x0); + o.WriteByte (0x0); + } + + public void WriteManagedToJava (Stream output) + { + if (output == null) + throw new ArgumentNullException ("output"); + + var typeMap = GetTypeMapping ( + t => false, + (t, c) => t.GetPartialAssemblyQualifiedName (c), + JavaNativeTypeManager.ToJniName); + + WriteBinaryMapping (output, typeMap); + } + } + + class ArrayComparer : IComparer { + + public int Compare (T []? x, T []? y) + { + if (x == null && y == null) + return 0; + if (x == null) + return -1; + if (y == null) + return 1; + int len = Math.Min (x.Length, y.Length); + for (int i = 0; i < len; ++i) { + var c = Comparer.Default.Compare (x [i], y [i]); + if (c != 0) + return c; + } + if (x.Length == y.Length) + return 0; + if (x.Length > y.Length) + return 1; + return -1; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource.csproj b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource.csproj new file mode 100644 index 00000000000..f745905fc16 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource.csproj @@ -0,0 +1,23 @@ + + + + $(DotNetTargetFramework) + enable + + + + + + $(ToolOutputFullPath) + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/IronyExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/IronyExtensions.cs new file mode 100644 index 00000000000..b4260935d33 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/IronyExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Irony.Ast; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource { + + static class IronyExtensions { + + public static void MakePlusRule (this NonTerminal star, Grammar grammar, BnfTerm delimiter) + { + star.Rule = grammar.MakePlusRule (star, delimiter); + } + + public static void MakeStarRule (this NonTerminal star, Grammar grammar, BnfTerm delimiter, BnfTerm of) + { + star.Rule = grammar.MakeStarRule (star, delimiter, of); + } + + public static void MakeStarRule (this NonTerminal star, Grammar grammar, BnfTerm of) + { + star.Rule = grammar.MakeStarRule (star, of); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/JavaStubParser.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/JavaStubParser.cs new file mode 100644 index 00000000000..00182bfb15d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/JavaStubParser.cs @@ -0,0 +1,679 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Irony.Parsing; +using Irony.Ast; + +using Xamarin.Android.Tools.ApiXmlAdjuster; + +namespace Java.Interop.Tools.JavaSource { + + [Language ("JavaStub", "1.0", "Java Stub grammar in Android SDK (android-stubs-src.jar)")] + public partial class JavaStubGrammar : Grammar + { + NonTerminal DefaultNonTerminal (string label) + { + var nt = new NonTerminal (label); + nt.AstConfig.NodeCreator = delegate { throw new NotImplementedException (label); }; + return nt; + } + + KeyTerm Keyword (string label) + { + var ret = ToTerm (label); + ret.AstConfig.NodeCreator = delegate (AstContext ctx, ParseTreeNode node) { + node.AstNode = node.Token.ValueString; + }; + return ret; + } + + KeyTerm T (string term) + { + return Keyword (term); + } + + AstNodeCreator CreateArrayCreator () + { + return delegate (AstContext ctx, ParseTreeNode node) { + ProcessChildren (ctx, node); + node.AstNode = (from n in node.ChildNodes select (T)n.AstNode).ToArray (); + }; + } + + AstNodeCreator CreateStringFlattener (string separator = "", string prefix = "") + { + return delegate (AstContext ctx, ParseTreeNode node) { + ProcessChildren (ctx, node); + node.AstNode = prefix + string.Join (separator, node.ChildNodes.Select (n => n.AstNode?.ToString ())); + }; + } + + void SelectSingleChild (AstContext ctx, ParseTreeNode node) + { + ProcessChildren (ctx, node); + if (node.ChildNodes.Count == 1) + node.AstNode = node.ChildNodes.First ().AstNode; + } + + void ProcessChildren (AstContext ctx, ParseTreeNode node) + { + foreach (var cn in node.ChildNodes) { + if (cn.Term.AstConfig.NodeCreator != null) + cn.Term.AstConfig.NodeCreator (ctx, cn); + } + } + + AstNodeCreator SelectChildValueAt (int index) + { + return delegate (AstContext ctx, ParseTreeNode node) { + ProcessChildren (ctx, node); + node.AstNode = node.ChildNodes [index].AstNode; + }; + } + + void DoNothing (AstContext ctx, ParseTreeNode node) + { + ProcessChildren (ctx, node); + // do nothing except for processing children. + } + + public JavaStubGrammar () + { + CommentTerminal single_line_comment = new CommentTerminal ("SingleLineComment", "//", "\r", "\n"); + CommentTerminal delimited_comment = new CommentTerminal ("DelimitedComment", "/*", "*/"); + + NonGrammarTerminals.Add (single_line_comment); + NonGrammarTerminals.Add (delimited_comment); + + IdentifierTerminal identifier = new IdentifierTerminal ("identifier"); + + KeyTerm keyword_package = Keyword ("package"); + KeyTerm keyword_import = Keyword ("import"); + KeyTerm keyword_public = Keyword ("public"); + KeyTerm keyword_protected = Keyword ("protected"); + KeyTerm keyword_static = Keyword ("static"); + KeyTerm keyword_final = Keyword ("final"); + KeyTerm keyword_abstract = Keyword ("abstract"); + KeyTerm keyword_synchronized = Keyword ("synchronized"); + KeyTerm keyword_default = Keyword ("default"); + KeyTerm keyword_native = Keyword ("native"); + KeyTerm keyword_volatile = Keyword ("volatile"); + KeyTerm keyword_transient = Keyword ("transient"); + KeyTerm keyword_enum = Keyword ("enum"); + KeyTerm keyword_class = Keyword ("class"); + KeyTerm keyword_interface = Keyword ("interface"); + KeyTerm keyword_at_interface = Keyword ("@interface"); + KeyTerm keyword_extends = Keyword ("extends"); + KeyTerm keyword_implements = Keyword ("implements"); + KeyTerm keyword_throw = Keyword ("throw"); + KeyTerm keyword_throws = Keyword ("throws"); + KeyTerm keyword_null = Keyword ("null"); + KeyTerm keyword_super = Keyword ("super"); + KeyTerm keyword_true = Keyword ("true"); + KeyTerm keyword_false = Keyword ("false"); + KeyTerm keyword_new = Keyword ("new"); + + var compile_unit = DefaultNonTerminal ("compile_unit"); + var opt_package_decl = DefaultNonTerminal ("opt_package_declaration"); + var package_decl = DefaultNonTerminal ("package_declaration"); + var imports = DefaultNonTerminal ("imports"); + var import = DefaultNonTerminal ("import"); + var type_decls = DefaultNonTerminal ("type_decls"); + var type_decl = DefaultNonTerminal ("type_decl"); + var enum_decl = DefaultNonTerminal ("enum_decl"); + var enum_body = DefaultNonTerminal ("enum_body"); + var class_decl = DefaultNonTerminal ("class_decl"); + var opt_generic_arg_decl = DefaultNonTerminal ("opt_generic_arg_decl"); + var opt_extends_decl = DefaultNonTerminal ("opt_extends_decl"); + var opt_implements_decl = DefaultNonTerminal ("opt_implements_decl"); + var implements_decl = DefaultNonTerminal ("implements_decl"); + var interface_decl = DefaultNonTerminal ("interface_decl"); + var iface_or_at_iface = DefaultNonTerminal ("iface_or_at_iface"); + var type_body = DefaultNonTerminal ("type_body"); + var type_members = DefaultNonTerminal ("type_members"); + var type_member = DefaultNonTerminal ("type_member"); + var nested_type_decl = DefaultNonTerminal ("nested_type_decl"); + var ctor_decl = DefaultNonTerminal ("ctor_decl"); + var method_decl = DefaultNonTerminal ("method_decl"); + var field_decl = DefaultNonTerminal ("field_decl"); + var opt_field_assignment = DefaultNonTerminal ("opt_field_assignment"); + var static_ctor_decl = DefaultNonTerminal ("static_ctor_decl"); + var enum_members_decl = DefaultNonTerminal ("enum_members_decl"); + var enum_member_initializers = DefaultNonTerminal ("enum_member_initializers"); + var enum_member_initializer = DefaultNonTerminal ("enum_member_initializer"); + var opt_enum_braces = DefaultNonTerminal ("opt_enum_braces"); + var opt_final_field_assign = DefaultNonTerminal ("opt_final_field_assign"); + var final_field_assign = DefaultNonTerminal ("final_field_assign"); + var terminate_decl_or_body = DefaultNonTerminal ("terminate_decl_or_body"); + var assignments = DefaultNonTerminal ("assignments"); + var assignment = DefaultNonTerminal ("assignment"); + var assign_expr = DefaultNonTerminal ("assign_expr"); + var rvalue_expressions = DefaultNonTerminal ("rvalue_expressions"); + var rvalue_expression = DefaultNonTerminal ("rvalue_expression"); + var array_literal = DefaultNonTerminal ("array_literal"); + var annotations = DefaultNonTerminal ("annotations"); + var annotation = DefaultNonTerminal ("annotation"); + var opt_annotation_args = DefaultNonTerminal ("opt_annotation_args"); + var annotation_value_assignments = DefaultNonTerminal ("annotation_value_assignments"); + var annot_assign_expr = DefaultNonTerminal ("annot_assign_expr"); + var modifiers_then_opt_generic_arg = DefaultNonTerminal ("modifiers_then_opt_generic_arg"); + var modifier_or_generic_arg = DefaultNonTerminal ("modifier_or_generic_arg"); + var modifiers = DefaultNonTerminal ("modifiers"); + var modifier = DefaultNonTerminal ("modifier"); + var argument_decls = DefaultNonTerminal ("argument_decls"); + var argument_decl = DefaultNonTerminal ("argument_decl"); + var comma_separated_types = DefaultNonTerminal ("comma_separated_types"); + var throws_decl = DefaultNonTerminal ("throws_decl"); + var opt_throws_decl = DefaultNonTerminal ("opt_throws_decl"); + var type_name = DefaultNonTerminal ("type_name"); + var dotted_identifier = DefaultNonTerminal ("dotted_identifier"); + var array_type = DefaultNonTerminal ("array_type"); + var vararg_type = DefaultNonTerminal ("vararg_type"); + var generic_type = DefaultNonTerminal ("generic_type"); + var generic_definition_arguments = DefaultNonTerminal ("generic_definition_arguments"); + var generic_definition_argument = DefaultNonTerminal ("generic_definition_argument"); + var generic_definition_constraints = DefaultNonTerminal ("generic_definition_constraints"); + var generic_definition_arguments_spec = DefaultNonTerminal ("generic_definition_arguments_spec"); + var generic_instance_arguments_spec = DefaultNonTerminal ("generic_instance_arguments_spec"); + var generic_instance_arguments = DefaultNonTerminal ("generic_instance_arguments"); + var generic_instance_argument = DefaultNonTerminal ("generic_instance_argument"); + var generic_instance_identifier_or_q = DefaultNonTerminal ("generic_instance_identifier_or_q"); + var generic_instance_constraints = DefaultNonTerminal ("generic_instance_constraints"); + var generic_instance_constraints_extends = DefaultNonTerminal ("generic_instance_constraints_extends"); + var generic_instance_constraints_super = DefaultNonTerminal ("generic_instance_constraints_super"); + var generic_instance_constraint_types = DefaultNonTerminal ("generic_instance_constraint_types"); + var impl_expressions = DefaultNonTerminal ("impl_expressions"); + var impl_expression = DefaultNonTerminal ("impl_expression"); + var call_super = DefaultNonTerminal ("call_super"); + var super_args = DefaultNonTerminal ("super_args"); + var default_value_expr = DefaultNonTerminal ("default_value_expr"); + var default_value_casted = DefaultNonTerminal ("default_value_casted"); + var default_value_literal = DefaultNonTerminal ("default_value_literal"); + var new_array = DefaultNonTerminal ("new_array"); + var runtime_exception = DefaultNonTerminal ("runtime_exception"); + var numeric_terminal = TerminalFactory.CreateCSharpNumber ("numeric_value_literal"); + numeric_terminal.AddPrefix ("-", NumberOptions.AllowSign); + numeric_terminal.AddPrefix ("+", NumberOptions.AllowSign); + //numeric_terminal.AddSuffix ("f"); + numeric_terminal.AddSuffix ("L"); + var numeric_literal = DefaultNonTerminal ("numeric_literal"); + var string_literal = TerminalFactory.CreateCSharpString ("string_literal"); + var value_literal = DefaultNonTerminal ("value_literal"); + var identifier_wild = DefaultNonTerminal ("identifier_wild"); + + // + + compile_unit.Rule = opt_package_decl + imports + type_decls; + opt_package_decl.Rule = package_decl | Empty; + package_decl.Rule = keyword_package + dotted_identifier + ";"; + imports.Rule = MakeStarRule (imports, import); + import.Rule = keyword_import + dotted_identifier + ";"; + type_decls.Rule = MakeStarRule (type_decls, type_decl); + + type_decl.Rule = class_decl | interface_decl | enum_decl; + // FIXME: those modifiers_then_opt_generic_arg should be actually just modifiers... see modifiers_then_opt_generic_arg.Rule below. + enum_decl.Rule = annotations + modifiers_then_opt_generic_arg + keyword_enum + identifier + opt_implements_decl + "{" + enum_body + "}"; + enum_body.Rule = Empty | enum_members_decl + type_members; + class_decl.Rule = annotations + modifiers_then_opt_generic_arg + keyword_class + identifier + opt_generic_arg_decl + opt_extends_decl + opt_implements_decl + type_body; + interface_decl.Rule = annotations + modifiers_then_opt_generic_arg + iface_or_at_iface + identifier + opt_generic_arg_decl + opt_extends_decl + opt_implements_decl + type_body; + iface_or_at_iface.Rule = keyword_interface | keyword_at_interface; + + opt_generic_arg_decl.Rule = Empty | "<" + generic_definition_arguments + ">"; + opt_extends_decl.Rule = Empty | keyword_extends + implements_decl; // when it is used with an interface, it can be more than one... + opt_implements_decl.Rule = Empty | keyword_implements + implements_decl; + implements_decl.Rule = MakePlusRule (implements_decl, ToTerm (","), type_name); + type_body.Rule = T ("{") + type_members + T ("}"); + annotations.Rule = MakeStarRule (annotations, annotation); + annotation.Rule = T ("@") + dotted_identifier + opt_annotation_args; + opt_annotation_args.Rule = Empty | T ("(") + annotation_value_assignments + T (")"); + annotation_value_assignments.Rule = rvalue_expression | MakeStarRule (annotation_value_assignments, ToTerm (","), annot_assign_expr); + annot_assign_expr.Rule = assign_expr | T ("{") + rvalue_expressions + T ("}"); + + // HACK: I believe this is an Irony bug that adding opt_generic_arg_decl here results in shift-reduce conflict, but it's too complicated to investigate the actual issue. + // As a workaround I add generic arguments as part of this "modifier" so that it can be safely added to a generic method declaration. + modifiers_then_opt_generic_arg.Rule = MakeStarRule (modifiers_then_opt_generic_arg, modifier_or_generic_arg); + modifiers.Rule = MakeStarRule (modifiers, modifier); + modifier_or_generic_arg.Rule = modifier | generic_definition_arguments_spec; + modifier.Rule = keyword_public | keyword_protected | keyword_final | keyword_abstract | keyword_synchronized | keyword_default | keyword_native | keyword_volatile | keyword_transient | keyword_static; + + type_members.Rule = MakeStarRule (type_members, type_member); + type_member.Rule = nested_type_decl | ctor_decl | method_decl | field_decl | static_ctor_decl; + nested_type_decl.Rule = type_decl; + enum_members_decl.Rule = enum_member_initializers + ";"; + enum_member_initializers.Rule = MakeStarRule (enum_member_initializers, ToTerm (","), enum_member_initializer); + enum_member_initializer.Rule = annotations + identifier + opt_enum_braces; + opt_enum_braces.Rule = Empty | "(" + ")"; + static_ctor_decl.Rule = annotations + keyword_static + "{" + assignments + "}"; + assignments.Rule = MakeStarRule (assignments, assignment); + assignment.Rule = assign_expr + ";"; + assign_expr.Rule = identifier + "=" + rvalue_expression; + rvalue_expressions.Rule = MakeStarRule (rvalue_expressions, ToTerm (","), rvalue_expression); + rvalue_expression.Rule = value_literal | new_array | type_name | identifier | array_literal | annotation; + array_literal.Rule = "{" + rvalue_expressions + "}"; + + field_decl.Rule = annotations + modifiers_then_opt_generic_arg + type_name + identifier + opt_field_assignment + ";" + opt_final_field_assign; + opt_field_assignment.Rule = Empty | "=" + rvalue_expression; + opt_final_field_assign.Rule = Empty | "{" + assign_expr + ";" + "}"; + terminate_decl_or_body.Rule = ";" | ("{" + impl_expressions + "}") | (keyword_default + default_value_literal + ";"); + + ctor_decl.Rule = annotations + modifiers_then_opt_generic_arg + identifier + "(" + argument_decls + ")" + opt_throws_decl + terminate_decl_or_body; // these Empties can make the structure common to method_decl. + + method_decl.Rule = annotations + modifiers_then_opt_generic_arg + /*opt_generic_arg_decl*/ type_name + identifier + "(" + argument_decls + ")" + opt_throws_decl + terminate_decl_or_body; + + impl_expressions.Rule = MakeStarRule (impl_expressions, impl_expression); + impl_expression.Rule = call_super | runtime_exception | assign_expr; + call_super.Rule = keyword_super + "(" + super_args + ")" + ";"; + super_args.Rule = MakeStarRule (super_args, ToTerm (","), default_value_expr); + default_value_expr.Rule = keyword_null | default_value_casted | default_value_literal; + default_value_casted.Rule = "(" + type_name + ")" + default_value_expr; + default_value_literal.Rule = numeric_terminal | "\"\"" | "{" + "}" | keyword_true | keyword_false; + runtime_exception.Rule = keyword_throw + keyword_new + identifier + "(\"Stub!\"" + ")" + ";"; + new_array.Rule = keyword_new + dotted_identifier + "[" + numeric_literal + "]"; + + argument_decls.Rule = annotations | MakeStarRule (argument_decls, ToTerm (","), argument_decl); + + argument_decl.Rule = annotations + type_name + identifier; + + throws_decl.Rule = keyword_throws + comma_separated_types; + comma_separated_types.Rule = MakeStarRule (comma_separated_types, ToTerm (","), type_name); + opt_throws_decl.Rule = Empty | throws_decl; + + type_name.Rule = dotted_identifier | array_type | vararg_type | generic_type; + + vararg_type.Rule = type_name + T ("..."); + array_type.Rule = type_name + ("[") + T ("]"); + + generic_definition_arguments_spec.Rule = "<" + generic_definition_arguments + ">"; + generic_type.Rule = dotted_identifier + generic_instance_arguments_spec; + generic_instance_arguments_spec.Rule = "<" + generic_instance_arguments + ">"; + generic_definition_arguments.Rule = MakePlusRule (generic_definition_arguments, ToTerm (","), generic_definition_argument); + generic_definition_argument.Rule = identifier + generic_definition_constraints; + generic_definition_constraints.Rule = Empty | generic_instance_constraints_extends | generic_instance_constraints_super; + generic_instance_arguments.Rule = MakePlusRule (generic_instance_arguments, ToTerm (","), generic_instance_argument); + generic_instance_argument.Rule = generic_instance_identifier_or_q + generic_instance_constraints; + generic_instance_identifier_or_q.Rule = type_name | T ("?"); + generic_instance_constraints.Rule = Empty | generic_instance_constraints_extends | generic_instance_constraints_super; + generic_instance_constraints_extends.Rule = keyword_extends + generic_instance_constraint_types; + generic_instance_constraints_super.Rule = keyword_super + generic_instance_constraint_types; + generic_instance_constraint_types.Rule = MakePlusRule (generic_instance_constraint_types, ToTerm ("&"), type_name); + + dotted_identifier.Rule = MakePlusRule (dotted_identifier, ToTerm ("."), identifier_wild); + + numeric_literal.Rule = numeric_terminal; + numeric_literal.Rule |= "(" + numeric_literal + "/" + numeric_literal + ")"; + value_literal.Rule = string_literal | numeric_literal | keyword_null; + identifier_wild.Rule = identifier | "*"; + + // Define AST node creators + + Func stripGenerics = s => s.IndexOf ('<') > 0 ? s.Substring (0, s.IndexOf ('<')) : s; + + single_line_comment.AstConfig.NodeCreator = DoNothing; + delimited_comment.AstConfig.NodeCreator = DoNothing; + identifier.AstConfig.NodeCreator = (ctx, node) => node.AstNode = node.Token.ValueString; + compile_unit.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var pkg = new JavaPackage (null) { Name = (string) node.ChildNodes [0].AstNode }; + + foreach (var t in (IEnumerable) node.ChildNodes [2].AstNode) + pkg.AddType (t); + + node.AstNode = pkg; + }; + opt_package_decl.AstConfig.NodeCreator = SelectSingleChild; + package_decl.AstConfig.NodeCreator = SelectChildValueAt (1); + imports.AstConfig.NodeCreator = CreateArrayCreator (); + import.AstConfig.NodeCreator = SelectChildValueAt (1); + type_decls.AstConfig.NodeCreator = CreateArrayCreator (); + type_decl.AstConfig.NodeCreator = SelectSingleChild; + opt_generic_arg_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = node.ChildNodes.Count == 0 ? null : node.ChildNodes [1].AstNode; + }; + opt_extends_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = node.ChildNodes.Count == 0 ? null : node.ChildNodes [1].AstNode; + }; + opt_implements_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = node.ChildNodes.Count == 0 ? null : node.ChildNodes [1].AstNode; + }; + implements_decl.AstConfig.NodeCreator = CreateArrayCreator (); + Action fillType = (node, type) => { + var modsOrTps = (IEnumerable)node.ChildNodes [1].AstNode; + var mods = modsOrTps.OfType (); + bool isEnum = node.ChildNodes [2].AstNode as string == "enum"; + type.Abstract |= mods.Contains ("abstract"); + type.Static |= mods.Contains ("static"); + type.Final |= mods.Contains ("final"); + type.Visibility = mods.FirstOrDefault (s => s == "public" || s == "protected") ?? ""; + type.Name = (string)node.ChildNodes [3].AstNode; + type.Deprecated = ((IEnumerable)node.ChildNodes [0].AstNode).Any (v => v == "java.lang.Deprecated" || v == "Deprecated") ? "deprecated" : "not deprecated"; + type.TypeParameters = isEnum ? null : (JavaTypeParameters) node.ChildNodes [4].AstNode; + type.Members = (IList)node.ChildNodes [isEnum ? 6 : 7].AstNode; + }; + enum_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var type = new JavaClass (null) { Extends = "java.lang.Enum", Final = true }; + var methods = new JavaMember [] { + new JavaMethod (null) { + Deprecated = "not deprecated", + Name = "valueOf", + // Return needs to be filled later, with full package name. + Static = true, + Visibility = "public", + Parameters = new JavaParameter [] { new JavaParameter (null) { Name = "name", Type = "java.lang.String" }}, + }, + new JavaMethod (null) { + Deprecated = "not deprecated", + Name = "values", + // Return needs to be filled later, with full package name. + Static = true, + Visibility = "public", + Parameters = new JavaParameter [0], + } + }; + fillType (node, type); + node.AstNode = type; + }; + class_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var exts = ((IEnumerable) node.ChildNodes [5].AstNode) ?? Enumerable.Empty (); + var impls = ((IEnumerable) node.ChildNodes [6].AstNode) ?? Enumerable.Empty (); + var ext = exts.FirstOrDefault () ?? "java.lang.Object"; + var type = new JavaClass (null) { + Extends = stripGenerics (ext), + ExtendsGeneric = ext, + Implements = impls.Select (s => new JavaImplements { Name = stripGenerics (s), NameGeneric = s }).ToArray (), + }; + fillType (node, type); + node.AstNode = type; + }; + interface_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + bool annot = node.ChildNodes [2].AstNode as string == "@interface"; + var exts = ((IEnumerable)node.ChildNodes [5].AstNode) ?? Enumerable.Empty (); + var impls = ((IEnumerable)node.ChildNodes [6].AstNode) ?? Enumerable.Empty (); + var type = new JavaInterface (null) { + Implements = exts.Concat (impls).Select (s => new JavaImplements { Name = stripGenerics (s), NameGeneric = s }).ToList (), + }; + if (annot) + type.Implements.Add (new JavaImplements { Name = "java.lang.annotation.Annotation", NameGeneric = "java.lang.annotation.Annotation" }); + fillType (node, type); + node.AstNode = type; + }; + iface_or_at_iface.AstConfig.NodeCreator = SelectSingleChild; + type_body.AstConfig.NodeCreator = SelectChildValueAt (1); + type_members.AstConfig.NodeCreator = CreateArrayCreator (); + type_member.AstConfig.NodeCreator = SelectSingleChild; + nested_type_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = new JavaNestedType (null) { Type = (JavaType) node.ChildNodes [0].AstNode }; + }; + Action fillMethodBase = (node, method) => { + bool ctor = node.ChildNodes.Count == 8; + var modsOrTps = (IEnumerable)node.ChildNodes [1].AstNode; + var mods = modsOrTps.OfType (); + method.Static = mods.Contains ("static"); + method.Visibility = mods.FirstOrDefault (s => s == "public" || s == "protected") ?? ""; + method.Name = (string)node.ChildNodes [ctor ? 2 : 3].AstNode; + method.Parameters = ((IEnumerable)node.ChildNodes [ctor ? 4 : 5].AstNode).ToArray (); + method.ExtendedSynthetic = mods.Contains ("synthetic"); + // HACK: Exception "name" can be inconsistent for nested types, and this nested type detection is hacky. + Func stripPackage = s => { + var packageTokens = s.Split ('.').TakeWhile (t => !t.Any (c => Char.IsUpper (c))); + return s.Substring (Enumerable.Sum (packageTokens.Select (t => t.Length)) + packageTokens.Count ()); + }; + method.Exceptions = ((IEnumerable)node.ChildNodes [ctor ? 6 : 7].AstNode) + ?.Select (s => new JavaException { Type = s, Name = stripPackage (s) }) + ?.ToArray (); + method.Deprecated = ((IEnumerable)node.ChildNodes [0].AstNode).Any (v => v == "java.lang.Deprecated" || v == "Deprecated") ? "deprecated" : "not deprecated"; + method.Final = mods.Contains ("final"); + method.TypeParameters = modsOrTps.OfType ().FirstOrDefault (); + }; + ctor_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var annots = node.ChildNodes [0].AstNode; + var modsOrTps = (IEnumerable)node.ChildNodes [1].AstNode; + var mods = modsOrTps.OfType (); + var ctor = new JavaConstructor (null); + fillMethodBase (node, ctor); + node.AstNode = ctor; + }; + method_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var annots = node.ChildNodes [0].AstNode; + var modsOrTps = (IEnumerable)node.ChildNodes [1].AstNode; + var mods = modsOrTps.OfType (); + var method = new JavaMethod (null) { + Return = (string)node.ChildNodes [2].AstNode, + Abstract = mods.Contains ("abstract"), + Native = mods.Contains ("native"), + Synchronized = mods.Contains ("synchronized"), + ExtendedSynthetic = mods.Contains ("synthetic"), + }; + fillMethodBase (node, method); + node.AstNode = method; + }; + field_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var annots = node.ChildNodes [0].AstNode; + var modsOrTps = (IEnumerable)node.ChildNodes [1].AstNode; + var mods = modsOrTps.OfType (); + var value = node.ChildNodes [4].AstNode?.ToString (); + var type = (string)node.ChildNodes [2].AstNode; + node.AstNode = new JavaField (null) { + Static = mods.Contains ("static"), + Visibility = mods.FirstOrDefault (s => s == "public" || s == "protected") ?? "", + Type = stripGenerics (type), + TypeGeneric = type, + Name = (string) node.ChildNodes [3].AstNode, + Deprecated = ((IEnumerable) node.ChildNodes [0].AstNode).Any (v => v == "java.lang.Deprecated" || v == "Deprecated") ? "deprecated" : "not deprecated", + Value = value == "null" ? null : value, // null will not be explicitly written. + Volatile = mods.Contains ("volatile"), + Final = mods.Contains ("final"), + Transient = mods.Contains ("transient"), + }; + }; + opt_field_assignment.AstConfig.NodeCreator = (ctx, node) => node.AstNode = node.ChildNodes.Count > 0 ? node.ChildNodes [1].AstNode : null; + opt_final_field_assign.AstConfig.NodeCreator = (ctx, node) => node.AstNode = node.ChildNodes.Count > 0 ? node.ChildNodes [1].AstNode : null; + static_ctor_decl.AstConfig.NodeCreator = DoNothing; // static constructors are ignorable. + enum_body.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var ml = new List (); + foreach (var c in node.ChildNodes) + ml.AddRange ((IEnumerable) c.AstNode); + node.AstNode = ml; + }; + enum_members_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + if (node.ChildNodes.Count > 0) + node.AstNode = ((IEnumerable) node.ChildNodes [0].AstNode) + .Select (s => new JavaField (null) { + Name = s, + Final = true, + Deprecated = "not deprecated", + Static = true, + // Type needs to be filled later, with full package name. + Visibility = "public" + }); + }; + enum_member_initializers.AstConfig.NodeCreator = CreateArrayCreator (); + enum_member_initializer.AstConfig.NodeCreator = SelectChildValueAt (1); + opt_enum_braces.AstConfig.NodeCreator = DoNothing; + terminate_decl_or_body.AstConfig.NodeCreator = DoNothing; // method/ctor body doesn't matter. + assignments.AstConfig.NodeCreator = CreateArrayCreator (); + assignment.AstConfig.NodeCreator = SelectChildValueAt (0); + assign_expr.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = new KeyValuePair ((string)node.ChildNodes [0].AstNode, node.ChildNodes [2].AstNode?.ToString ()); + }; + rvalue_expressions.AstConfig.NodeCreator = CreateArrayCreator (); + rvalue_expression.AstConfig.NodeCreator = SelectSingleChild; + array_literal.AstConfig.NodeCreator = CreateStringFlattener (); + annotations.AstConfig.NodeCreator = CreateArrayCreator (); + annotation.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node.ChildNodes [1]); // we only care about name. + node.AstNode = node.ChildNodes [1].AstNode; + }; + opt_annotation_args.AstConfig.NodeCreator = DoNothing; + annotation_value_assignments.AstConfig.NodeCreator = DoNothing; + annot_assign_expr.AstConfig.NodeCreator = DoNothing; + modifiers_then_opt_generic_arg.AstConfig.NodeCreator = CreateArrayCreator (); + modifier_or_generic_arg.AstConfig.NodeCreator = SelectSingleChild; + modifiers.AstConfig.NodeCreator = CreateArrayCreator (); + modifier.AstConfig.NodeCreator = CreateStringFlattener (); + argument_decls.AstConfig.NodeCreator = CreateArrayCreator (); + argument_decl.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = new JavaParameter (null) { Type = (string) node.ChildNodes [1].AstNode, Name = (string) node.ChildNodes [2].AstNode }; + }; + opt_throws_decl.AstConfig.NodeCreator = SelectSingleChild; + throws_decl.AstConfig.NodeCreator = SelectChildValueAt (1); + comma_separated_types.AstConfig.NodeCreator = CreateArrayCreator (); + type_name.AstConfig.NodeCreator = SelectSingleChild; + dotted_identifier.AstConfig.NodeCreator = CreateStringFlattener ("."); + array_type.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = node.ChildNodes [0].AstNode + "[]"; + }; + vararg_type.AstConfig.NodeCreator = CreateStringFlattener (); + generic_type.AstConfig.NodeCreator = CreateStringFlattener (); + generic_definition_arguments_spec.AstConfig.NodeCreator = SelectChildValueAt (1); + generic_instance_arguments_spec.AstConfig.NodeCreator = (ctx, node) => { + // It is distinct from generic type parameters definition. + ProcessChildren (ctx, node); + node.AstNode = "<" + string.Join (", ", (IEnumerable) node.ChildNodes [1].AstNode) + ">"; + }; + generic_definition_arguments.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = new JavaTypeParameters ((JavaMethod?) null) { TypeParameters = node.ChildNodes.Select (c => c.AstNode).Cast ().ToList () }; + }; + generic_definition_argument.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + node.AstNode = new JavaTypeParameter (null) { + Name = (string) node.ChildNodes [0].AstNode, + GenericConstraints = (JavaGenericConstraints) node.ChildNodes [1].AstNode + }; + }; + generic_definition_constraints.AstConfig.NodeCreator = SelectSingleChild; + generic_instance_arguments.AstConfig.NodeCreator = CreateArrayCreator (); + generic_instance_argument.AstConfig.NodeCreator = CreateStringFlattener (); + generic_instance_identifier_or_q.AstConfig.NodeCreator = SelectSingleChild; + generic_instance_constraints.AstConfig.NodeCreator = (ctx, node) => { + ProcessChildren (ctx, node); + var c = (JavaGenericConstraints?) node.ChildNodes.FirstOrDefault ()?.AstNode; + if (c != null) + node.AstNode = " " + c.BoundsType + " " + string.Join (" & ", c.GenericConstraints.Select (cc => cc.Type)); + }; + AstNodeCreator createGenericConstaints = (ctx, node) => { + ProcessChildren (ctx, node); + var cl = ((IEnumerable) node.ChildNodes [1].AstNode).Select (s => new JavaGenericConstraint { Type = s }); + node.AstNode = new JavaGenericConstraints () { + BoundsType = (string) node.ChildNodes [0].AstNode, + GenericConstraints = cl.Any () ? cl.ToArray () : null, + }; + }; + generic_instance_constraints_extends.AstConfig.NodeCreator = createGenericConstaints; + generic_instance_constraints_super.AstConfig.NodeCreator = createGenericConstaints; + generic_instance_constraint_types.AstConfig.NodeCreator = CreateArrayCreator (); + impl_expressions.AstConfig.NodeCreator = CreateArrayCreator (); + impl_expression.AstConfig.NodeCreator = SelectSingleChild; + // each expression item is not seriously processed. + // They are insignificant except for consts, and for consts they are just string values. + call_super.AstConfig.NodeCreator = CreateStringFlattener (); + super_args.AstConfig.NodeCreator = CreateStringFlattener (); + default_value_expr.AstConfig.NodeCreator = CreateStringFlattener (); + default_value_casted.AstConfig.NodeCreator = CreateStringFlattener (); + default_value_literal.AstConfig.NodeCreator = CreateStringFlattener (); + new_array.AstConfig.NodeCreator = DoNothing; + runtime_exception.AstConfig.NodeCreator = CreateStringFlattener (); + Func stripTail = (s, t) => s.EndsWith (t, StringComparison.Ordinal) ? s.Substring (0, s.Length - t.Length) : s; + numeric_terminal.AstConfig.NodeCreator = (ctx, node) => node.AstNode = stripTail (stripTail (node.Token.Text, "L"), "f"); + numeric_literal.AstConfig.NodeCreator = CreateStringFlattener (); + string_literal.AstConfig.NodeCreator = (ctx, node) => node.AstNode = '"' + node.Token.ValueString + '"'; + value_literal.AstConfig.NodeCreator = SelectSingleChild; + identifier_wild.AstConfig.NodeCreator = SelectSingleChild; + + this.Root = compile_unit; + } + } + + public class JavaStubParser : Irony.Parsing.Parser { + + public JavaStubParser () + : base (new JavaStubGrammar () {LanguageFlags = LanguageFlags.Default | LanguageFlags.CreateAst}) + { + + } + + public JavaPackage? TryLoad (string uri) + { + return TryLoad (uri, out var _); + } + + public JavaPackage? TryLoad (string uri, out ParseTree parseTree) + { + return TryParse (File.ReadAllText (uri), uri, out parseTree); + } + + public JavaPackage? TryParse (string text) + { + return TryParse (text, null, out var _); + } + + public JavaPackage? TryParse (string text, out ParseTree parseTree) + { + return TryParse (text, null, out parseTree); + } + + public JavaPackage? TryParse (string text, string? fileName, out ParseTree parseTree) + { + parseTree = base.Parse (text, fileName); + if (parseTree.HasErrors ()) + return null; + var parsedPackage = (JavaPackage) parseTree.Root.AstNode; + FlattenNestedTypes (parsedPackage); + return parsedPackage; + } + + void FlattenNestedTypes (JavaPackage package) + { + var results = new List (); + foreach (var t in package.AllTypes) + Flatten (results, t); + + package.ClearTypes (); + + foreach (var t in results) + package.AddType (t); + + void Flatten (List list, JavaType t) + { + list.Add (t); + foreach (var nt in t.Members.OfType ()) { + if (nt.Type == null) + continue; + nt.Type.Name = t.Name + '.' + nt.Type.Name; + foreach (var nc in nt.Type.Members.OfType ()) + nc.Name = nt.Type.Name; + Flatten (list, nt.Type); + } + t.Members = t.Members.Where (_ => !(_ is JavaNestedType)).ToArray (); + } + } + } + + class JavaNestedType : JavaMember + { + public JavaNestedType (JavaType? type) + : base (type) + { + } + + public JavaType? Type { get; set; } + } +} + diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/JavadocInfo.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/JavadocInfo.cs new file mode 100644 index 00000000000..675193a0981 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/JavadocInfo.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +using Irony.Ast; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource { + + sealed class JavadocInfo { + public readonly ICollection Exceptions = new Collection (); + public readonly ICollection Extra = new Collection (); + public readonly ICollection Remarks = new Collection (); + public readonly ICollection Parameters = new Collection (); + public readonly ICollection Returns = new Collection (); + + public override string ToString () + { + return new XElement ("Javadoc", + new XElement (nameof (Parameters), Parameters), + new XElement (nameof (Remarks), Remarks), + new XElement (nameof (Returns), Returns), + new XElement (nameof (Exceptions), Exceptions), + new XElement (nameof (Extra), Extra)) + .ToString (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.BlockTagsBnfTerms.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.BlockTagsBnfTerms.cs new file mode 100644 index 00000000000..7465b5c4122 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.BlockTagsBnfTerms.cs @@ -0,0 +1,296 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +using Irony.Ast; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource { + + public partial class SourceJavadocToXmldocGrammar { + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags + public class BlockTagsBnfTerms { + + internal BlockTagsBnfTerms () + { + } + + internal void CreateRules (SourceJavadocToXmldocGrammar grammar) + { + AllBlockTerms.Rule = AuthorDeclaration + | ApiSinceDeclaration + | DeprecatedDeclaration + | DeprecatedSinceDeclaration + | ExceptionDeclaration + | InheritDocDeclaration + | HideDeclaration + | ParamDeclaration + | ReturnDeclaration + | SeeDeclaration + | SerialDataDeclaration + | SerialFieldDeclaration + | SinceDeclaration + | ThrowsDeclaration + | UnknownTagDeclaration + | VersionDeclaration + ; + BlockValue.Rule = grammar.HtmlTerms.ParsedCharacterData + | grammar.HtmlTerms.InlineDeclaration + ; + BlockValues.MakePlusRule (grammar, BlockValue); + + AuthorDeclaration.Rule = "@author" + BlockValues; + AuthorDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.AuthorTag)) + return; + // Ignore; not sure how best to convert to Xmldoc + FinishParse (context, parseNode); + }; + + ApiSinceDeclaration.Rule = "@apiSince" + BlockValues; + ApiSinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.SinceTag)) { + return; + } + var p = new XElement ("para", "Added in API level ", AstNodeToXmlContent (parseNode.ChildNodes [1]), "."); + FinishParse (context, parseNode).Remarks.Add (p); + parseNode.AstNode = p; + }; + + DeprecatedDeclaration.Rule = "@deprecated" + BlockValues; + DeprecatedDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.DeprecatedTag)) { + return; + } + var p = new XElement ("para", "This member is deprecated. ", AstNodeToXmlContent (parseNode.ChildNodes [1])); + FinishParse (context, parseNode).Remarks.Add (p); + parseNode.AstNode = p; + }; + + DeprecatedSinceDeclaration.Rule = "@deprecatedSince" + BlockValues; + DeprecatedSinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.DeprecatedTag)) { + return; + } + var p = new XElement ("para", "This member was deprecated in API level ", AstNodeToXmlContent (parseNode.ChildNodes [1]), "."); + FinishParse (context, parseNode).Remarks.Add (p); + parseNode.AstNode = p; + }; + + var nonSpaceTerm = new RegexBasedTerminal ("[^ \n\r\t]", "[^ \n\r\t]+") { + AstConfig = new AstNodeConfig { + NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value, + }, + }; + + ExceptionDeclaration.Rule = "@exception" + nonSpaceTerm + BlockValues; + ExceptionDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.ExceptionTag)) { + return; + } + /* TODO: convert `nonSpaceTerm` into a proper CREF + var e = new XElement ("exception", + new XAttribute ("cref", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]))), + AstNodeToXmlContent (parseNode.ChildNodes [2])); + FinishParse (context, parseNode).Exceptions.Add (e); + parseNode.AstNode = e; + */ + FinishParse (context, parseNode); + }; + + // Ignore @hide tags + HideDeclaration.Rule = "@hide" + | "@hide" + BlockValues + ; + HideDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + FinishParse (context, parseNode); + }; + + InheritDocDeclaration.Rule = "@inheritDoc" + | "@inheritDoc" + BlockValues + ; + InheritDocDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.InheritDocTag)) { + return; + } + // TODO: Iterate through parents for corresponding javadoc element. + FinishParse (context, parseNode); + }; + + ParamDeclaration.Rule = "@param" + nonSpaceTerm + | "@param" + nonSpaceTerm + BlockValues + ; + ParamDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.ParamTag)) { + return; + } + var paramName = string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1])); + var p = new XElement ("param", new XAttribute ("name", paramName)); + if (parseNode.ChildNodes.Count >= 3) { + p.Add (AstNodeToXmlContent (parseNode.ChildNodes [2])); + } else { + p.Add (paramName); + } + FinishParse (context, parseNode).Parameters.Add (p); + parseNode.AstNode = p; + }; + + ReturnDeclaration.Rule = "@return" + | "@return" + BlockValues + ; + ReturnDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.ReturnTag)) { + return; + } + var jdi = FinishParse (context, parseNode); + // If we have no return value, continue + if (parseNode.ChildNodes.Count < 2) { + return; + } + // When encountering multiple @return keys in a line, append subsequent @return key content to the original element. + if (jdi.Returns.Count == 0) { + var r = new XElement ("returns", + AstNodeToXmlContent (parseNode.ChildNodes [1])); + FinishParse (context, parseNode).Returns.Add (r); + parseNode.AstNode = r; + } else { + var r = jdi.Returns.First () as XElement; + if (r != null) { + r.Add (" ", AstNodeToXmlContent (parseNode.ChildNodes [1])); + parseNode.AstNode = r; + } + } + }; + + SeeDeclaration.Rule = "@see" + BlockValues; + SeeDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.SeeTag)) { + return; + } + /* TODO: @see supports multiple forms; see: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#see + // Also need to convert to appropriate CREF value, ignore for now + var e = new XElement ("seealso", + new XAttribute ("cref", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1])))); + FinishParse (context, parseNode).Extra.Add (e); + parseNode.AstNode = e; + */ + FinishParse (context, parseNode); + + }; + + SinceDeclaration.Rule = "@since" + BlockValues; + SinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.SinceTag)) { + return; + } + var p = new XElement ("para", "Added in ", AstNodeToXmlContent (parseNode.ChildNodes [1]), "."); + FinishParse (context, parseNode).Remarks.Add (p); + parseNode.AstNode = p; + }; + + ThrowsDeclaration.Rule = "@throws" + nonSpaceTerm + | "@throws" + nonSpaceTerm + BlockValues + ; + ThrowsDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.ExceptionTag)) { + return; + } + /* TODO: convert `nonSpaceTerm` into a proper CREF + var e = new XElement ("exception", + new XAttribute ("cref", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]))), + AstNodeToXmlContent (parseNode.ChildNodes [2])); + FinishParse (context, parseNode).Exceptions.Add (e); + parseNode.AstNode = e; + */ + FinishParse (context, parseNode); + }; + + // Ignore serialization informatino + SerialDeclaration.Rule = "@serial" + BlockValues; + SerialDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.SerialTag)) { + return; + } + FinishParse (context, parseNode); + }; + + SerialDataDeclaration.Rule = "@serialData" + BlockValues; + SerialDataDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.SerialTag)) { + return; + } + FinishParse (context, parseNode); + }; + + SerialFieldDeclaration.Rule = "@serialField" + BlockValues; + SerialFieldDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.SerialTag)) { + return; + } + FinishParse (context, parseNode); + }; + + var unknownTagTerminal = new RegexBasedTerminal ("@[unknown]", @"@\S+") { + Priority = TerminalPriority.Low, + }; + unknownTagTerminal.AstConfig.NodeCreator = (context, parseNode) => + parseNode.AstNode = parseNode.Token.Value.ToString (); + + + UnknownTagDeclaration.Rule = unknownTagTerminal + | unknownTagTerminal + BlockValues + ; + UnknownTagDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.Remarks)) { + return; + } + Console.WriteLine ($"# Unsupported @block-tag value: {parseNode.ChildNodes [0].AstNode}"); + FinishParse (context, parseNode); + }; + + // Ignore Version + VersionDeclaration.Rule = "@version" + BlockValues; + VersionDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.VersionTag)) { + return; + } + FinishParse (context, parseNode); + }; + } + + public readonly NonTerminal AllBlockTerms = new NonTerminal (nameof (AllBlockTerms), ConcatChildNodes); + + public readonly Terminal Cdata = new CharacterDataTerminal ("#CDATA", preserveLeadingWhitespace: true); +/* + public readonly Terminal Cdata = new RegexBasedTerminal (nameof (BlockValue), "[^<]*") { + AstConfig = new AstNodeConfig { + NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value.ToString (), + }, + }; + */ + + public readonly NonTerminal BlockValue = new NonTerminal (nameof (BlockValue), ConcatChildNodes); + public readonly NonTerminal BlockValues = new NonTerminal (nameof (BlockValues), ConcatChildNodes); + public readonly NonTerminal AuthorDeclaration = new NonTerminal (nameof (AuthorDeclaration)); + public readonly NonTerminal ApiSinceDeclaration = new NonTerminal (nameof (ApiSinceDeclaration)); + public readonly NonTerminal DeprecatedDeclaration = new NonTerminal (nameof (DeprecatedDeclaration)); + public readonly NonTerminal DeprecatedSinceDeclaration = new NonTerminal (nameof (DeprecatedSinceDeclaration)); + public readonly NonTerminal ExceptionDeclaration = new NonTerminal (nameof (ExceptionDeclaration)); + public readonly NonTerminal HideDeclaration = new NonTerminal (nameof (HideDeclaration)); + public readonly NonTerminal InheritDocDeclaration = new NonTerminal (nameof (InheritDocDeclaration)); + public readonly NonTerminal ParamDeclaration = new NonTerminal (nameof (ParamDeclaration)); + public readonly NonTerminal ReturnDeclaration = new NonTerminal (nameof (ReturnDeclaration)); + public readonly NonTerminal SeeDeclaration = new NonTerminal (nameof (SeeDeclaration)); + public readonly NonTerminal SerialDeclaration = new NonTerminal (nameof (SerialDeclaration)); + public readonly NonTerminal SerialDataDeclaration = new NonTerminal (nameof (SerialDataDeclaration)); + public readonly NonTerminal SerialFieldDeclaration = new NonTerminal (nameof (SerialFieldDeclaration)); + public readonly NonTerminal SinceDeclaration = new NonTerminal (nameof (SinceDeclaration)); + public readonly NonTerminal ThrowsDeclaration = new NonTerminal (nameof (ThrowsDeclaration)); + public readonly NonTerminal UnknownTagDeclaration = new NonTerminal (nameof (UnknownTagDeclaration)); + public readonly NonTerminal VersionDeclaration = new NonTerminal (nameof (VersionDeclaration)); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.HtmlBnfTerms.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.HtmlBnfTerms.cs new file mode 100644 index 00000000000..82abd11c753 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.HtmlBnfTerms.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Xml; +using System.Xml.Linq; + +using Irony.Ast; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource { + + using static IronyExtensions; + + public partial class SourceJavadocToXmldocGrammar { + + public class HtmlBnfTerms { + internal HtmlBnfTerms () + { + } + + internal void CreateRules (SourceJavadocToXmldocGrammar grammar) + { + AllHtmlTerms.Rule = TopLevelInlineDeclaration + | PBlockDeclaration + | PreBlockDeclaration + ; + + var inlineDeclaration = new NonTerminal ("", ConcatChildNodes) { + Rule = ParsedCharacterData + | FontStyleDeclaration + /* + | PhraseDeclaration + | SpecialDeclaration + | FormCtrlDeclaration + */ + | InlineHyperLinkDeclaration + | CodeElementDeclaration + | grammar.InlineTagsTerms.AllInlineTerms + | UnknownHtmlElementStart + , + }; + var inlineDeclarations = new NonTerminal ("*", ConcatChildNodes); + inlineDeclarations.MakePlusRule (grammar, inlineDeclaration); + + InlineDeclaration.Rule = inlineDeclaration; + InlineDeclarations.MakeStarRule (grammar, InlineDeclaration); + + TopLevelInlineDeclaration.Rule = inlineDeclarations; + TopLevelInlineDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + var remarks = FinishParse (context, parseNode).Remarks; + var addRemarks = grammar.ShouldImport (ImportJavadoc.Remarks) || + (grammar.ShouldImport (ImportJavadoc.Summary) && remarks.Count == 0); + if (!addRemarks) { + parseNode.AstNode = ""; + return; + } + foreach (var p in GetParagraphs (parseNode.ChildNodes)) { + remarks.Add (p); + } + parseNode.AstNode = ""; + }; + + var fontstyle_tt = CreateHtmlToCrefElement (grammar, "tt", "c", InlineDeclarations, optionalEnd: true); + var fontstyle_i = CreateHtmlToCrefElement (grammar, "i", "i", InlineDeclarations, optionalEnd: true); + + var preText = new PreBlockDeclarationBodyTerminal (); + PreBlockDeclaration.Rule = CreateStartElement ("pre") + preText + CreateEndElement ("pre", grammar, optional: true); + PreBlockDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (!grammar.ShouldImport (ImportJavadoc.Remarks)) { + parseNode.AstNode = ""; + return; + } + var c = new XElement ("code", + new XAttribute ("lang", "text/java"), + parseNode.ChildNodes [1].Token.Value); + FinishParse (context, parseNode).Remarks.Add (c); + parseNode.AstNode = c; + }; + + FontStyleDeclaration.Rule = fontstyle_tt | fontstyle_i; + + PBlockDeclaration.Rule = + CreateStartElement ("p") + InlineDeclarations + CreateEndElement ("p", grammar, optional:true) + ; + PBlockDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + var remarks = FinishParse (context, parseNode).Remarks; + var addRemarks = grammar.ShouldImport (ImportJavadoc.Remarks) || + (grammar.ShouldImport (ImportJavadoc.Summary) && remarks.Count == 0); + if (!addRemarks) { + parseNode.AstNode = ""; + return; + } + var p = new XElement ("para", + parseNode.ChildNodes + .Select (c => AstNodeToXmlContent (c))); + FinishParse (context, parseNode).Remarks.Add (p); + parseNode.AstNode = p; + }; + + InlineHyperLinkDeclaration.Rule = InlineHyperLinkOpenTerm + InlineDeclarations + CreateEndElement ("a", grammar, optional: true); + InlineHyperLinkDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + var nodesAsString = GetChildNodesAsString (parseNode); + var tokenValue = parseNode.ChildNodes [0].Token.Text; + int stopIndex = nodesAsString.IndexOf ('>'); + + if (stopIndex == -1 || !tokenValue.Contains ("href", StringComparison.OrdinalIgnoreCase)) { + parseNode.AstNode = new XText (nodesAsString); + return; + } + + var attributeName = parseNode.ChildNodes [0].Term.Name; + var attributeValue = nodesAsString.Substring (0, stopIndex).Trim ().Trim ('\'', '"'); + var elementValue = nodesAsString.Substring (stopIndex + 1); + if (!string.IsNullOrEmpty (attributeValue) && attributeValue.StartsWith ("http", StringComparison.OrdinalIgnoreCase)) { + var unparsed = $"{elementValue}"; + XNode? seeElement = TryParseElement (unparsed); + if (seeElement == null) { + // Try to parse with HTML entities decoded + seeElement = TryParseElement (WebUtility.HtmlDecode (unparsed)); + if (seeElement == null) { + // Finally, try to parse with only the element value encoded + seeElement = TryParseElement ($"{WebUtility.HtmlEncode (elementValue)}", logError: true); + } + } + parseNode.AstNode = seeElement ?? new XText (nodesAsString); + } else { + // TODO: Need to convert relative paths or code references to appropriate CREF value. + parseNode.AstNode = new XText (elementValue); + } + }; + + CodeElementDeclaration.Rule = CodeElementContentTerm; + CodeElementDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + // Parse the entire element captured in the token + var codeElementText = parseNode.ChildNodes [0].Token.Text; + int startIndex = codeElementText.IndexOf ('>'); + int stopIndex = codeElementText.LastIndexOf ('<'); + if (startIndex == -1 || stopIndex == -1) { + parseNode.AstNode = new XText (codeElementText); + return; + } + var target = codeElementText.Substring (startIndex + 1, stopIndex - startIndex - 1); + parseNode.AstNode = new XElement ("c", target); + }; + } + + static IEnumerable GetParagraphs (ParseTreeNodeList children) + { + var items = new List (); + foreach (var child in children) { + var s = child.AstNode as string; + if (s == null || (!s.Contains ("\n\n") && !s.Contains ("\r\n\r\n"))) { + items.Add (child.AstNode); + continue; + } + + const string UnixParagraph = "\n\n"; + const string DosParagraph = "\r\n\r\n"; + for (int i = 0; i < s.Length; ) { + int len = 0; + int n = -1; + + if ((n = s.IndexOf (UnixParagraph, i, StringComparison.Ordinal)) >= 0) { + len = UnixParagraph.Length; + } + else if ((n = s.IndexOf (DosParagraph, i, StringComparison.Ordinal)) >= 0) { + len = DosParagraph.Length; + } + + if (n <= 0) { + items.Add (s.Substring (i)); + break; + } + + var c = s.Substring (i, n-i); + items.Add (c); + i = n + len; + yield return new XElement ("para", items.Select (v => ToXmlContent (v))); + items.Clear (); + } + } + if (items.Count > 0) { + yield return new XElement ("para", items.Select (v => ToXmlContent (v))); + } + } + + static string GetChildNodesAsString (ParseTreeNode parseNode) + { + var unparsed = string.Empty; + foreach (var cn in parseNode.ChildNodes) { + if (cn.ChildNodes?.Count > 1) { + foreach (var gcn in cn.ChildNodes) { + unparsed += gcn.AstNode?.ToString (); + } + } else { + unparsed += cn.AstNode?.ToString (); + } + } + return unparsed; + } + + static XElement? TryParseElement (string unparsed, bool logError = false) + { + try { + return XElement.Parse (unparsed); + } catch (Exception x) { + if (logError) + Console.Error.WriteLine ($"## Unable to parse HTML element: `{unparsed}`\n{x.GetType ()}: {x.Message}"); + return null; + } + } + + public readonly NonTerminal AllHtmlTerms = new NonTerminal (nameof (AllHtmlTerms), ConcatChildNodes); + + public readonly NonTerminal TopLevelInlineDeclaration = new NonTerminal (nameof (TopLevelInlineDeclaration), ConcatChildNodes); + + + // https://www.w3.org/TR/html401/struct/global.html#h-7.5.3 +// public readonly Terminal ParsedCharacterData = new RegexBasedTerminal (nameof (ParsedCharacterData), "[^<{@}]*") { +// public readonly Terminal ParsedCharacterData = new WikiTextTerminal (nameof (ParsedCharacterData)) {* + public readonly Terminal ParsedCharacterData = new CharacterDataTerminal ("#PCDATA", preserveLeadingWhitespace:true); + + // https://www.w3.org/TR/html4/sgml/dtd.html#inline + public readonly NonTerminal InlineDeclaration = new NonTerminal (nameof (InlineDeclaration), ConcatChildNodes); + public readonly NonTerminal InlineDeclarations = new NonTerminal (nameof (InlineDeclarations), ConcatChildNodes); + // https://www.w3.org/TR/html4/sgml/dtd.html#fontstyle + public readonly NonTerminal FontStyleDeclaration = new NonTerminal (nameof (FontStyleDeclaration), ConcatChildNodes); + // https://www.w3.org/TR/html4/sgml/dtd.html#phrase + public readonly NonTerminal PhraseDeclaration = new NonTerminal (nameof (PhraseDeclaration), ConcatChildNodes); + // https://www.w3.org/TR/html4/sgml/dtd.html#special + public readonly NonTerminal SpecialDeclaration = new NonTerminal (nameof (SpecialDeclaration), ConcatChildNodes); + // https://www.w3.org/TR/html4/sgml/dtd.html#formctrl + public readonly NonTerminal FormCtrlDeclaration = new NonTerminal (nameof (FormCtrlDeclaration), ConcatChildNodes); + // https://www.w3.org/TR/html4/sgml/dtd.html#block + public readonly NonTerminal BlockDeclaration = new NonTerminal (nameof (BlockDeclaration), ConcatChildNodes); + public readonly NonTerminal PBlockDeclaration = new NonTerminal (nameof (PBlockDeclaration), ConcatChildNodes); + public readonly NonTerminal PreBlockDeclaration = new NonTerminal (nameof (PreBlockDeclaration), ConcatChildNodes); + public readonly NonTerminal InlineHyperLinkDeclaration = new NonTerminal (nameof (InlineHyperLinkDeclaration), ConcatChildNodes); + public readonly NonTerminal CodeElementDeclaration = new NonTerminal (nameof (CodeElementDeclaration), ConcatChildNodes); + + public readonly Terminal CodeElementContentTerm = new RegexBasedTerminal ("", $@"(?i)]*>(.|\s)*?(<\/code>|<\/null>|)") { + AstConfig = new AstNodeConfig { + NodeCreator = (context, parseNode) => parseNode.AstNode = "", + }, + }; + + public readonly Terminal InlineHyperLinkOpenTerm = new RegexBasedTerminal (" parseNode.AstNode = parseNode.Token.Value.ToString (), + }, + }; + + static NonTerminal CreateHtmlToCrefElement (Grammar grammar, string htmlElement, string crefElement, BnfTerm body, bool optionalEnd = false) + { + var start = CreateStartElement (htmlElement); + var end = CreateEndElement (htmlElement, grammar, optionalEnd); + var nonTerminal = new NonTerminal ("<" + htmlElement + ">", ConcatChildNodes) { + Rule = start + body + end, + AstConfig = { + NodeCreator = (context, parseNode) => { + var n = new XElement (crefElement, + parseNode.ChildNodes.Select (c => c.AstNode ?? "")); + parseNode.AstNode = n; + }, + } + }; + return nonTerminal; + } + + static RegexBasedTerminal CreateStartElement (string startElement, string attribute = "") + { + return new RegexBasedTerminal ($"<{startElement} {attribute}>", $@"(?i)<\b{startElement}\b\s*{attribute}[^>]*>") { + AstConfig = new AstNodeConfig { + NodeCreator = (context, parseNode) => parseNode.AstNode = "", + }, + }; + } + + static NonTerminal CreateEndElement (string endElement, Grammar grammar, bool optional = false) + { + var end = new NonTerminal (endElement, nodeCreator: (context, parseNode) => parseNode.AstNode = "") { + Rule = grammar.ToTerm ("") | "", + }; + if (optional) { + end.Rule |= grammar.Empty; + } + return end; + } + } + } + + // Based in part on WikiTextTerminal + class CharacterDataTerminal : Terminal { + + char[]? _stopChars; + + bool preserveLeadingWhitespace; + + public CharacterDataTerminal (string name, bool preserveLeadingWhitespace) + : base (name) + { + base.Priority = TerminalPriority.Low; + + this.preserveLeadingWhitespace = preserveLeadingWhitespace; + + this.AstConfig.NodeCreator = (context, parseNode) => + parseNode.AstNode = parseNode.Token.Value.ToString (); + } + + public override void Init (GrammarData grammarData) + { + base.Init (grammarData); + var stopCharSet = new Irony.CharHashSet (); + foreach(var term in grammarData.Terminals) { + var firsts = term.GetFirsts (); + if (firsts == null) + continue; + foreach (var first in firsts) { + if (string.IsNullOrEmpty (first)) + continue; + stopCharSet.Add (first [0]); + } + } + _stopChars = stopCharSet.ToArray(); + } + + public override Token? TryMatch (ParsingContext context, ISourceStream source) + { + if (_stopChars is null) + throw new InvalidOperationException ("Init must be called before TryMatch"); + + var stopIndex = source.Text.IndexOfAny (_stopChars, source.Location.Position); + if (stopIndex == source.Location.Position) + return null; + if (stopIndex < 0) + stopIndex = source.Text.Length; + source.PreviewPosition = stopIndex; + + // preserve leading whitespace, if present. + int start = source.Location.Position; + if (preserveLeadingWhitespace) { + while (start > 0 && char.IsWhiteSpace (source.Text, start-1)) { + start--; + } + } + var content = source.Text.Substring (start, stopIndex - start); + + return source.CreateToken (this.OutputTerminal, content); + } + } + + class PreBlockDeclarationBodyTerminal : Terminal { + + public PreBlockDeclarationBodyTerminal () + : base ("
 body")
+		{
+			this.AstConfig.NodeCreator = (context, parseNode) =>
+				parseNode.AstNode = parseNode.Token.Value.ToString ();
+		}
+
+		public override void Init (GrammarData grammarData)
+		{
+			base.Init (grammarData);
+		}
+
+		public override Token? TryMatch (ParsingContext context, ISourceStream source)
+		{
+			int startIndex  = source.Location.Position;
+			var stopIndex   = source.Text.IndexOf ("
", source.Location.Position, StringComparison.OrdinalIgnoreCase); + if (stopIndex < 0) + stopIndex = source.Text.Length; + source.PreviewPosition = stopIndex; + + var content = source.Text.Substring (startIndex, stopIndex - startIndex); + + return source.CreateToken (this.OutputTerminal, content); + } + } + + class UnknownHtmlElementStartTerminal : Terminal { + + bool addingRemarks; + + public UnknownHtmlElementStartTerminal (string name) + : base (name) + { + base.Priority = TerminalPriority.Low-1; + } + + public override void Init (GrammarData grammarData) + { + base.Init (grammarData); + var g = grammarData.Grammar as SourceJavadocToXmldocGrammar; + addingRemarks = g?.ShouldImport (ImportJavadoc.Remarks) ?? false; + } + + public override Token? TryMatch (ParsingContext context, ISourceStream source) + { + if (source.Text [source.Location.Position] != '<') + return null; + source.PreviewPosition += 1; + int start = source.Location.Position; + int stop = start; + while (stop < source.Text.Length && source.Text [stop] != '>' ) + stop++; + if (addingRemarks) { + Console.Error.WriteLine ($"# Unsupported HTML element: {source.Text.Substring (start, stop - start)}"); + } + return source.CreateToken (this.OutputTerminal, "<"); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.InlineTagsBnfTerms.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.InlineTagsBnfTerms.cs new file mode 100644 index 00000000000..2592762f0b5 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.InlineTagsBnfTerms.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +using Irony.Ast; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource { + + public partial class SourceJavadocToXmldocGrammar { + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags + public class InlineTagsBnfTerms { + + public InlineTagsBnfTerms () + { + } + + internal void CreateRules (SourceJavadocToXmldocGrammar grammar) + { + AllInlineTerms.Rule = CodeDeclaration + | DocRootDeclaration + | InheritDocDeclaration + | LinkDeclaration + | LinkplainDeclaration + | LiteralDeclaration + | SeeDeclaration + | ValueDeclaration + | IgnorableDeclaration + | InlineParamDeclaration + ; + + CodeDeclaration.Rule = grammar.ToTerm ("{@code") + InlineValue + "}"; + CodeDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + parseNode.AstNode = new XElement ("c", parseNode.ChildNodes [1].AstNode?.ToString ()?.Trim ()); + }; + + DocRootDeclaration.Rule = grammar.ToTerm ("{@docRoot}"); + DocRootDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + var docRoot = grammar.XmldocSettings.DocRootValue; + if (!string.IsNullOrEmpty (docRoot)) { + if (!docRoot.EndsWith ("/", StringComparison.OrdinalIgnoreCase)) { + docRoot += "/"; + } + } else { + docRoot = "{@docRoot}"; + } + parseNode.AstNode = new XText (docRoot); + }; + + InheritDocDeclaration.Rule = grammar.ToTerm ("{@inheritDoc}"); + InheritDocDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + // TODO: Iterate through parents for corresponding javadoc element. + parseNode.AstNode = new XText ("To be added"); + }; + + LinkDeclaration.Rule = grammar.ToTerm ("{@link") + InlineValue + new NonTerminal ("Optional }", nodeCreator: (context, parseNode) => parseNode.AstNode = "") { + Rule = grammar.ToTerm ("}") | grammar.Empty, + }; + LinkDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + // TODO: *everything*; {@link target label}, but target can contain spaces! + // Also need to convert to appropriate CREF value, use code text for now. + // Also some {@link tags are missing a closing bracket, use plain text rather than throwing for now. + var target = parseNode.ChildNodes [1].AstNode; + var optionalBracketMatch = parseNode.ChildNodes [2]; + if (optionalBracketMatch.ChildNodes.Count > 0 && optionalBracketMatch.ChildNodes [0].Term.Name == "}") { + parseNode.AstNode = new XElement ("c", target); + } else { + parseNode.AstNode = new XText (target.ToString () ?? string.Empty); + } + }; + + LinkplainDeclaration.Rule = grammar.ToTerm ("{@linkplain") + InlineValue + "}"; + LinkplainDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + // TODO: *everything*; {@link target label}, but target can contain spaces! + // Also need to convert to appropriate CREF value, use text for now. + var target = parseNode.ChildNodes [1].AstNode.ToString (); + parseNode.AstNode = new XText (target ?? string.Empty); + }; + + LiteralDeclaration.Rule = grammar.ToTerm ("{@literal") + InlineValue + "}"; + LiteralDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + var content = parseNode.ChildNodes [1].AstNode.ToString (); + parseNode.AstNode = new XText (content ?? string.Empty); + }; + + SeeDeclaration.Rule = grammar.ToTerm ("{@see") + InlineValue + "}"; + SeeDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + // TODO: @see supports multiple forms; see: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#see + // Also need to convert to appropriate CREF value, ignore for now + var target = parseNode.ChildNodes [1].AstNode; + parseNode.AstNode = new XElement ("c", target); + }; + + ValueDeclaration.Rule = grammar.ToTerm ("{@value}") + | grammar.ToTerm ("{@value") + InlineValue + "}"; + ValueDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + if (parseNode.ChildNodes.Count > 1) { + // TODO: Need to convert to appropriate CREF value, use code text for now. + var field = parseNode.ChildNodes [1].AstNode.ToString (); + parseNode.AstNode = new XElement ("c", field); + } + else { + // TODO: Display the value of the corresponding static field. + parseNode.AstNode = new XText ("To be added"); + } + }; + + InlineParamDeclaration.Rule = grammar.ToTerm ("{@param") + InlineValue + "}"; + InlineParamDeclaration.AstConfig.NodeCreator = (context, parseNode) => { + var target = parseNode.ChildNodes [1].AstNode; + parseNode.AstNode = new XElement ("paramref", target); + }; + } + + public readonly NonTerminal AllInlineTerms = new NonTerminal (nameof (AllInlineTerms), ConcatChildNodes); + + public readonly Terminal InlineValue = new RegexBasedTerminal (nameof (InlineValue), "[^}]*") { + AstConfig = new AstNodeConfig { + NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value, + }, + }; + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#code + public readonly NonTerminal CodeDeclaration = new NonTerminal (nameof (CodeDeclaration)); + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#docRoot + public readonly NonTerminal DocRootDeclaration = new NonTerminal (nameof (DocRootDeclaration)); + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#inheritDoc + public readonly NonTerminal InheritDocDeclaration = new NonTerminal (nameof (InheritDocDeclaration)); + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#link + public readonly NonTerminal LinkDeclaration = new NonTerminal (nameof (LinkDeclaration)); + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#linkplain + public readonly NonTerminal LinkplainDeclaration = new NonTerminal (nameof (LinkplainDeclaration)); + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#literal + public readonly NonTerminal LiteralDeclaration = new NonTerminal (nameof (LiteralDeclaration)); + + public readonly NonTerminal SeeDeclaration = new NonTerminal (nameof (SeeDeclaration)); + + // https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#value + public readonly NonTerminal ValueDeclaration = new NonTerminal (nameof (ValueDeclaration)); + + public readonly NonTerminal InlineParamDeclaration = new NonTerminal (nameof (InlineParamDeclaration)); + + public readonly Terminal IgnorableDeclaration = new IgnorableCharTerminal (nameof (IgnorableDeclaration)) { + AstConfig = new AstNodeConfig { + NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value.ToString (), + }, + }; + + } + } + + class IgnorableCharTerminal : Terminal + { + public IgnorableCharTerminal (string name) + : base (name) + { + Priority = TerminalPriority.Low - 1; + } + + public override Token? TryMatch (ParsingContext context, ISourceStream source) + { + var startChar = source.Text [source.Location.Position]; + if (startChar != '@' + && startChar != '{' + && startChar != '}' + ) { + return null; + } + source.PreviewPosition += 1; + return source.CreateToken (OutputTerminal, startChar); + } + + } + +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.cs new file mode 100644 index 00000000000..5f53795508d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +using Irony.Ast; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource { + + [Language ("SourceJavadocToXmldoc", "0.1", "Convert Javadoc within Java source code, sans comment delimiter, to CSC /doc XML.")] + public partial class SourceJavadocToXmldocGrammar : Grammar { + + public readonly BlockTagsBnfTerms BlockTagsTerms; + public readonly InlineTagsBnfTerms InlineTagsTerms; + public readonly HtmlBnfTerms HtmlTerms; + + public readonly XmldocSettings XmldocSettings; + + public SourceJavadocToXmldocGrammar (XmldocSettings settings) + { + BlockTagsTerms = new BlockTagsBnfTerms (); + InlineTagsTerms = new InlineTagsBnfTerms (); + HtmlTerms = new HtmlBnfTerms (); + + XmldocSettings = settings; + + BlockTagsTerms.CreateRules (this); + InlineTagsTerms.CreateRules (this); + HtmlTerms.CreateRules (this); + + var remark = new NonTerminal ("", ConcatChildNodes) { + Rule = HtmlTerms.AllHtmlTerms, + }; + var remarks = new NonTerminal ("*", ConcatChildNodes); + remarks.MakeStarRule (this, remark); + + var block = new NonTerminal ("@block", ConcatChildNodes) { + Rule = BlockTagsTerms.AllBlockTerms, + }; + var blocks = new NonTerminal ("@blocks", ConcatChildNodes); + blocks.MakeStarRule (this, block); + + var root = new NonTerminal ("", ConcatChildNodes) { + Rule = remarks + blocks, + }; + + root.AstConfig.NodeCreator = (context, parseNode) => { + FinishParse (context, parseNode); + }; + + this.Root = root; + } + + internal bool ShouldImport (ImportJavadoc value) + { + var v = (ImportJavadoc) XmldocSettings.Style; + return v.HasFlag (value); + } + + internal static void ConcatChildNodes (AstContext context, ParseTreeNode parseNode) + { + switch (parseNode.ChildNodes.Count) { + case 0: + parseNode.AstNode = ""; + break; + case 1: + parseNode.AstNode = parseNode.ChildNodes [0].AstNode ?? ""; + break; + default: { + parseNode.AstNode = parseNode.ChildNodes + .Select (c => c.AstNode ?? "") + .ToArray (); + break; + } + } + } + + internal static IEnumerable AstNodeToXmlContent (ParseTreeNode node) + { + return ToXmlContent (node.AstNode); + } + + // Trim leading & trailing whitespace from `value`, which could be: + // * a string + // * an object[] + // * Anything else (XElement, etc.) + internal static IEnumerable ToXmlContent (object? value) + { + if (value == null) + yield break; + if (value is string s) { + yield return s.Trim (); + } + else if (value is IEnumerable nested) { + object? first = null; + object? last = null; + foreach (var n in nested) { + if (first != null) { + if (last != null) + yield return last; + last = n; + continue; + } + first = n; + if (first is string s1) { + yield return s1.TrimStart (); + } + else + yield return ToXmlContent (first); + } + if (last != null) { + if (last is string l) + yield return l.TrimEnd (); + else + yield return ToXmlContent (last); + } + } + else + yield return value; + } + + internal static JavadocInfo FinishParse (AstContext context, ParseTreeNode parseNode) + { + const string key = ".__JavadocInfo"; + if (!context.Values.TryGetValue (key, out var r)) { + context.Values.Add (key, r = new JavadocInfo ()); + } + parseNode.Tag = r; + return (JavadocInfo) r; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocParser.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocParser.cs new file mode 100644 index 00000000000..ee7ae0149eb --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocParser.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Text; + +using Irony; +using Irony.Ast; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource { + + [Flags] + internal enum ImportJavadoc { + None, + Summary = 1 << 0, + Remarks = 1 << 1, + AuthorTag = 1 << 2, + DeprecatedTag = 1 << 3, + ExceptionTag = 1 << 4, + ParamTag = 1 << 5, + ReturnTag = 1 << 6, + SeeTag = 1 << 7, + SerialTag = 1 << 8, + SinceTag = 1 << 9, + VersionTag = 1 << 10, + ExtraRemarks = 1 << 11, + InheritDocTag = 1 << 12, + } + + [Flags] + public enum XmldocStyle { + None, + Full = ImportJavadoc.Summary + | ImportJavadoc.Remarks + | ImportJavadoc.AuthorTag + | ImportJavadoc.DeprecatedTag + | ImportJavadoc.ExceptionTag + | ImportJavadoc.ParamTag + | ImportJavadoc.ReturnTag + | ImportJavadoc.SeeTag + | ImportJavadoc.SerialTag + | ImportJavadoc.SinceTag + | ImportJavadoc.VersionTag + | ImportJavadoc.ExtraRemarks + | ImportJavadoc.InheritDocTag + , + IntelliSense = ImportJavadoc.Summary + | ImportJavadoc.ExceptionTag + | ImportJavadoc.ParamTag + | ImportJavadoc.ReturnTag + , + IntelliSenseAndExtraRemarks = IntelliSense + | ImportJavadoc.ExtraRemarks + , + } + + public class SourceJavadocToXmldocParser : Irony.Parsing.Parser { + + public SourceJavadocToXmldocParser (XmldocSettings settings) + : base (CreateGrammar (settings)) + { + XmldocSettings = settings; + } + + public XmldocSettings XmldocSettings { get; } + + + + static Grammar CreateGrammar (XmldocSettings settings) + { + return new SourceJavadocToXmldocGrammar (settings) { + LanguageFlags = LanguageFlags.Default | LanguageFlags.CreateAst, + }; + } + + public IEnumerable TryParse (string javadoc, string? fileName = null, Action? onError = null) + { + onError = onError ?? DumpMessages; + + ParseTree parseTree; + var r = TryParse (javadoc, fileName, out parseTree); + if (parseTree.HasErrors ()) { + onError (parseTree); + } + return r; + } + + public IEnumerable TryParse (string javadoc, string? fileName, out ParseTree parseTree) + { + parseTree = base.Parse (javadoc, fileName); + if (parseTree.HasErrors ()) { + return Array.Empty(); + } + return CreateParseIterator (parseTree); + } + + IEnumerable CreateParseIterator (ParseTree parseTree) + { + if (parseTree.Root.Tag is JavadocInfo info) { + foreach (var n in info.Parameters) + yield return n; + var summary = CreateSummaryNode (info); + if (summary != null) + yield return summary; + var style = (ImportJavadoc) XmldocSettings.Style; + if (style.HasFlag (ImportJavadoc.Remarks) && + (info.Remarks.Count > 0 || XmldocSettings.ExtraRemarks?.Length > 0)) { + yield return new XElement ("remarks", info.Remarks, XmldocSettings.ExtraRemarks); + } + else if (style.HasFlag (ImportJavadoc.ExtraRemarks) && XmldocSettings.ExtraRemarks?.Length > 0) { + yield return new XElement ("remarks", XmldocSettings.ExtraRemarks); + } + foreach (var n in info.Returns) { + yield return n; + } + foreach (var n in info.Exceptions) { + yield return n; + } + foreach (var n in info.Extra) { + yield return n; + } + yield break; + } + var ast = parseTree.Root.AstNode; + if (ast is XNode node) { + yield return node; + } + else { + yield return new XCData (ast?.ToString () ?? string.Empty); + } + } + + static XElement? CreateSummaryNode (JavadocInfo info) + { + var summaryNode = info.Remarks.FirstOrDefault (); + if (summaryNode == null) + return null; + + if (summaryNode is XElement p) { + var summaryItems = new List (); + for (var n = p.FirstNode; n != null; n = n.NextNode) { + if (n is XText text) { + var tdot = text.Value.IndexOf ('.'); + if (tdot < 0) { + summaryItems.Add (n); + continue; + } + summaryItems.Add (text.Value.Substring (0, tdot+1)); + break; + } + summaryItems.Add (n); + } + return new XElement ("summary", summaryItems); + } + var content = summaryNode.ToString (); + if (string.IsNullOrWhiteSpace (content)) + return null; + + var dot = content.IndexOf ('.'); + if (dot <= 0) + return new XElement ("summary", content); + return new XElement ("summary", content.Substring (0, dot+1)); + } + + static void DumpMessages (ParseTree parseTree) + { + foreach (var m in parseTree.ParserMessages) { + Console.Error.WriteLine ($"{m.Level} {m.Location}: {m.Message}"); + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/XmldocSettings.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/XmldocSettings.cs new file mode 100644 index 00000000000..4906ceed621 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/XmldocSettings.cs @@ -0,0 +1,12 @@ +using System; +using System.Xml.Linq; + +namespace Java.Interop.Tools.JavaSource +{ + public class XmldocSettings + { + public string DocRootValue { get; set; } = string.Empty; + public XElement []? ExtraRemarks { get; set; } + public XmldocStyle Style { get; set; } = XmldocStyle.Full; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaSource/README.md b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/README.md new file mode 100644 index 00000000000..5465daf8a2d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaSource/README.md @@ -0,0 +1,22 @@ +# Java.Interop.Tools.JavaSource + +Utilities for processing Java source code. + +## SourceJavadocToXmldocGrammar & SourceJavadocToXmldocParser + +`SourceJavadocToXmldocParser` parses Javadoc comments, as found in +`java-source-utils.jar` output (commit 69e1b80a), and converts it into +C# /doc XML via the Irony `SourceJavadocToXmldocGrammar` grammar. + +Multiple Javadoc+HTML language constructs are not yet supported: + + * Member lookup: + `@see #hashCode` is currently translated into + ``; no translation is performed. + This should be turned into + ``, but requires + additional plumbing so that `SourceJavadocToXmldocGrammar` can "know" + about all the possible types & members, and how to map them to C# names. + + * The following HTML elements need to be (better) supported: + `ul`, `li`. diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ApiImporterOptions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ApiImporterOptions.cs new file mode 100644 index 00000000000..4c5160788d4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ApiImporterOptions.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.ObjectModel; + +namespace Java.Interop.Tools.JavaTypeSystem; + +public class ApiImporterOptions +{ + public Collection SupportedTypeMapAttributes { get; } = ["Android.Runtime.RegisterAttribute"]; +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs new file mode 100644 index 00000000000..990c7abcb64 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiExporter.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public static class JavaXmlApiExporter + { + public static void Save (JavaTypeCollection types, string xmlFile) + { + using (var writer = XmlWriter.Create (xmlFile, new XmlWriterSettings { + Encoding = new UTF8Encoding (false, true), + Indent = true, + OmitXmlDeclaration = true, + })) + Save (types, writer); + } + + public static void Save (JavaTypeCollection types, XmlWriter writer) + { + writer.WriteStartElement ("api"); + + if (types.Platform.HasValue ()) + writer.WriteAttributeString ("platform", types.Platform); + + writer.WriteAttributeString ("api-source", "JavaTypeSystem"); + + foreach (var pkg in types.Packages.Values) { + + if (!pkg.Types.Any (t => !t.IsReferencedOnly)) + continue; + + writer.WriteStartElement ("package"); + writer.WriteAttributeString ("name", pkg.Name); + + if (pkg.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + + if (!string.IsNullOrEmpty (pkg.JniName)) + writer.WriteAttributeString ("jni-name", pkg.JniName); + + foreach (var type in pkg.Types) { + if (type.IsReferencedOnly) + continue; // skip reference only types + + SaveType (type, writer); + } + + WriteFullEndElement (writer); + } + + WriteFullEndElement (writer); + } + + static void SaveType (JavaTypeModel type, XmlWriter writer) + { + if (type is JavaClassModel cls) + SaveType (type, writer, "class", XmlConvert.ToString (cls.IsAbstract), cls.BaseType, cls.BaseTypeGeneric, cls.BaseTypeJni, cls.AnnotatedVisibility); + else + SaveType (type, writer, "interface", "true", null, null, null, type.AnnotatedVisibility); + + foreach (var nested in type.NestedTypes) + SaveType (nested, writer); + } + + static void SaveType (JavaTypeModel cls, XmlWriter writer, string elementName, string abs, string? ext, string? extgen, string? jniExt, string annotatedVisibility) + { + writer.WriteStartElement (elementName); + + writer.WriteAttributeStringIfValue ("abstract", abs); + writer.WriteAttributeString ("deprecated", cls.Deprecated); + writer.WriteAttributeStringIfValue ("extends", ext); + writer.WriteAttributeStringIfValue ("extends-generic-aware", extgen); + writer.WriteAttributeStringIfValue ("jni-extends", jniExt); + writer.WriteAttributeString ("final", XmlConvert.ToString (cls.IsFinal)); + writer.WriteAttributeString ("name", cls.NestedName); + writer.WriteAttributeString ("static", XmlConvert.ToString (cls.IsStatic)); + writer.WriteAttributeString ("visibility", cls.Visibility); + writer.WriteAttributeStringIfValue ("jni-signature", cls.ExtendedJniSignature); + writer.WriteAttributeStringIfValue ("annotated-visibility", annotatedVisibility); + + if (cls.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + if (cls.PropertyBag.TryGetValue ("deprecated-since", out var dep)) + writer.WriteAttributeString ("deprecated-since", dep); + + SaveTypeParameters (cls.TypeParameters, writer); + + foreach (var imp in cls.Implements.OrderBy (i => i.Name, StringComparer.Ordinal)) { + writer.WriteStartElement ("implements"); + writer.WriteAttributeString ("name", imp.Name); + writer.WriteAttributeString ("name-generic-aware", imp.NameGeneric); + writer.WriteAttributeStringIfValue ("jni-type", imp.JniType); + + if (imp.PropertyBag.TryGetValue ("merge.SourceFile", out var imp_source)) + writer.WriteAttributeString ("merge.SourceFile", imp_source); + + WriteFullEndElement (writer); + } + + if (cls is JavaClassModel klass) + foreach (var m in klass.Constructors.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.IsSynthetic)) + SaveConstructor (m, writer); + + foreach (var m in cls.Methods.OrderBy (m => m.Name, StringComparer.Ordinal).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.IsSynthetic)) + SaveMethod (m, writer); + + foreach (var m in cls.Fields.OrderBy (m => m.Name, StringComparer.OrdinalIgnoreCase)) + SaveField (m, writer); + + WriteFullEndElement (writer); + } + + static void SaveTypeParameters (JavaTypeParameters parameters, XmlWriter writer) + { + if (parameters.Count == 0) + return; + + writer.WriteStartElement ("typeParameters"); + + if (parameters.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + + foreach (var tp in parameters) { + writer.WriteStartElement ("typeParameter"); + writer.WriteAttributeString ("name", tp.Name); + writer.WriteAttributeStringIfValue ("classBound", tp.ExtendedClassBound); + writer.WriteAttributeStringIfValue ("jni-classBound", tp.ExtendedJniClassBound); + writer.WriteAttributeStringIfValue ("interfaceBounds", tp.ExtendedInterfaceBounds); + writer.WriteAttributeStringIfValue ("jni-interfaceBounds", tp.ExtendedJniInterfaceBounds); + + if (tp.GenericConstraints.Count > 0) { + // If there is only one generic constraint that specifies java.lang.Object, + // that is not really a constraint, so skip that. + // jar2xml does not emit that either. + if (tp.GenericConstraints.Count == 1 && tp.GenericConstraints[0].Type == "java.lang.Object") { + WriteFullEndElement (writer); + continue; + } + + writer.WriteStartElement ("genericConstraints"); + + foreach (var g in tp.GenericConstraints) { + writer.WriteStartElement ("genericConstraint"); + writer.WriteAttributeString ("type", g.Type); + WriteFullEndElement (writer); + } + + WriteFullEndElement (writer); + } + + WriteFullEndElement (writer); + } + + WriteFullEndElement (writer); + } + + static void SaveConstructor (JavaConstructorModel ctor, XmlWriter writer) + => SaveMember (ctor, writer, "constructor", null, null, null, null, null, ctor.DeclaringType.FullName, null, null, null, ctor.Parameters, ctor.IsBridge, null, ctor.IsSynthetic, null, ctor.AnnotatedVisibility); + + static void SaveField (JavaFieldModel field, XmlWriter writer) + { + var value = field.Value; + + if (value != null && (field.Type == "double" || field.Type == "float")) + value = value.Replace ("E+", "E"); + + SaveMember (field, writer, "field", null, null, null, null, + XmlConvert.ToString (field.IsTransient), + field.Type, + field.TypeGeneric, + value, + XmlConvert.ToString (field.IsVolatile), + null, + null, + null, + null, + field.IsNotNull, + field.AnnotatedVisibility); + } + + static void SaveMethod (JavaMethodModel method, XmlWriter writer) + { + bool check (JavaMethodModel _) => _.BaseMethod?.DeclaringType?.Visibility == "public" && + !method.IsStatic && + method.Parameters.All (p => p.InstantiatedGenericArgumentName == null); + + // skip synthetic methods, that's what jar2xml does. + // However, jar2xml is based on Java reflection and it generates synthetic methods + // that actually needs to be generated in the output XML (they are not marked as + // "synthetic" either by asm or java reflection), when: + // - the synthetic method is actually from non-public ancestor class + // (e.g. FileBackupHelperBase.writeNewStateDescription()) + // For such case, it does not skip generation. + if (method.IsSynthetic && (method.BaseMethod == null || check (method))) + return; + + // Here we skip most of the overriding methods of a virtual method, unless + // - the method visibility or final-ity has changed: protected Object#clone() is often + // overriden as public. In that case, we need a "new" method. + // - the method is covariant. In that case we need another overload. + // - they differ in "abstract" or "final" method attribute. + // - the derived method is static. + // - the base method is in the NON-public class. + // - none of the arguments are type parameters. + // - finally, it is the synthetic method already checked above. + if (method.BaseMethod != null && + !method.BaseMethod.IsAbstract && + method.BaseMethod.Visibility == method.Visibility && + method.BaseMethod.IsAbstract == method.IsAbstract && + method.BaseMethod.IsFinal == method.IsFinal && + !method.IsSynthetic && + check (method)) + return; + + SaveMember (m: method, writer: writer, elementName: "method", + abs: XmlConvert.ToString (method.IsAbstract), + native: XmlConvert.ToString (method.IsNative), + ret: GetVisibleReturnTypeString (method), + sync: XmlConvert.ToString (method.IsSynchronized), + transient: null, + type: null, + typeGeneric: null, + value: null, + volat: null, + parameters: method.Parameters, + extBridge: method.IsBridge, + jniReturn: method.ReturnJni, + extSynthetic: method.IsSynthetic, + notNull: method.ReturnNotNull, + annotatedVisibility: method.AnnotatedVisibility); + } + + static string GetVisibleReturnTypeString (JavaMethodModel method) + { + if (GetVisibleNonSpecialType (method, method.ReturnTypeModel) is JavaTypeReference jtr) + return jtr.ToString (); + + return method.Return; + } + + public static string? GetVisibleParamterTypeName (this JavaParameterModel parameter) + { + if (GetVisibleNonSpecialType (parameter.DeclaringMethod, parameter.TypeModel) is JavaTypeReference jtr) + return jtr.ToString (); + + return parameter.GenericType; + } + + static JavaTypeReference? GetVisibleNonSpecialType (JavaMethodModel method, JavaTypeReference? r) + { + if (r == null || r.SpecialName != null || r.ReferencedTypeParameter != null || r.ArrayPart != null) + return null; + + var requiredVisibility = method?.Visibility == "public" && method.DeclaringType?.Visibility == "public" ? "public" : method?.Visibility; + + for (var t = r; t != null; t = (t.ReferencedType as JavaClassModel)?.BaseTypeReference) { + if (t.ReferencedType == null) + break; + if (IsAcceptableVisibility (required: requiredVisibility, actual: t.ReferencedType.Visibility)) + return t; + } + + return null; + } + + static bool IsAcceptableVisibility (string? required, string? actual) + { + if (required == "public") + return actual == "public"; + else + return true; + } + + static void SaveMember (JavaMemberModel m, XmlWriter writer, string elementName, + string? abs, string? native, string? ret, string? sync, + string? transient, string? type, string? typeGeneric, + string? value, string? volat, + IEnumerable? parameters, + bool? extBridge, string? jniReturn, bool? extSynthetic, bool? notNull, string? annotatedVisibility) + { + // If any of the parameters contain reference to non-public type, it cannot be generated. + // TODO + //if (parameters != null && parameters.Any (p => p.ResolvedType?.ReferencedType != null && string.IsNullOrEmpty (p.ResolvedType.ReferencedType.Visibility))) + // return; + + if (parameters != null && parameters.Any (p => p.TypeModel != null && p.TypeModel.ReferencedType?.Visibility.HasValue () == false)) + return; + + writer.WriteStartElement (elementName); + + writer.WriteAttributeStringIfValue ("abstract", abs); + writer.WriteAttributeString ("deprecated", m.Deprecated); + writer.WriteAttributeString ("final", XmlConvert.ToString (m.IsFinal)); + writer.WriteAttributeString ("name", m.Name); + writer.WriteAttributeString ("jni-signature", m.JniSignature); + + if (notNull.GetValueOrDefault () && m is JavaFieldModel) + writer.WriteAttributeString (m is JavaFieldModel ? "not-null" : "return-not-null", "true"); + + if (extBridge.HasValue) + writer.WriteAttributeString ("bridge", extBridge.Value ? "true" : "false"); + + writer.WriteAttributeStringIfValue ("native", native); + writer.WriteAttributeStringIfValue ("return", ret); + writer.WriteAttributeStringIfValue ("jni-return", jniReturn); + writer.WriteAttributeString ("static", XmlConvert.ToString (m.IsStatic)); + writer.WriteAttributeStringIfValue ("synchronized", sync); + writer.WriteAttributeStringIfValue ("transient", transient); + writer.WriteAttributeStringIfValue ("type", type); + writer.WriteAttributeStringIfValue ("type-generic-aware", typeGeneric); + writer.WriteAttributeStringIfValue ("value", value); + writer.WriteAttributeStringIfValue ("annotated-visibility", annotatedVisibility); + + if (extSynthetic.HasValue) + writer.WriteAttributeString ("synthetic", extSynthetic.Value ? "true" : "false"); + + writer.WriteAttributeString ("visibility", m.Visibility); + writer.WriteAttributeStringIfValue ("volatile", volat); + + if (m.PropertyBag.TryGetValue ("merge.SourceFile", out var source)) + writer.WriteAttributeString ("merge.SourceFile", source); + if (m.PropertyBag.TryGetValue ("deprecated-since", out var dep)) + writer.WriteAttributeString ("deprecated-since", dep); + + if (notNull.GetValueOrDefault () && !(m is JavaFieldModel)) + writer.WriteAttributeString (m is JavaFieldModel ? "not-null" : "return-not-null", "true"); + + if (m is JavaMethodModel m2) + SaveTypeParameters (m2.TypeParameters, writer); + + if (parameters != null) { + foreach (var p in parameters) { + writer.WriteStartElement ("parameter"); + writer.WriteAttributeString ("name", p.Name); + writer.WriteAttributeString ("type", GetVisibleParamterTypeName (p)); + writer.WriteAttributeStringIfValue ("jni-type", p.JniType); + + if (p.IsNotNull == true) + writer.WriteAttributeString ("not-null", "true"); + + WriteFullEndElement (writer); + } + } + + if (m is JavaMethodModel method) { + foreach (var e in method.Exceptions.OrderBy (e => e.Name.LastSubset ('/'), StringComparer.Ordinal)) { + writer.WriteStartElement ("exception"); + writer.WriteAttributeString ("name", e.Name.LastSubset ('/')); + writer.WriteAttributeString ("type", e.Type); + WriteFullEndElement (writer); + } + } + + WriteFullEndElement (writer); + } + + static void WriteFullEndElement (XmlWriter writer) => writer.WriteEndElement (); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs new file mode 100644 index 00000000000..514d011d34b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/JavaXmlApiImporter.cs @@ -0,0 +1,375 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public class JavaXmlApiImporter + { + public static JavaTypeCollection ParseString (string xml, JavaTypeCollection? collection = null) + { + var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + return Parse (doc, collection); + } + + public static JavaTypeCollection Parse (TextReader reader, JavaTypeCollection? collection = null) + { + var doc = XDocument.Load (reader, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + return Parse (doc, collection); + } + + public static JavaTypeCollection Parse (string filename, JavaTypeCollection? collection = null) + { + var doc = XDocument.Load (filename, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + + return Parse (doc, collection); + } + + static JavaTypeCollection Parse (XDocument doc, JavaTypeCollection? collection = null) + { + collection ??= new JavaTypeCollection (); + + var root = doc.Root; + + if (root is null) + throw new ArgumentException ("Invalid XML file doesn't contain a root node"); + + collection.ApiSource = root.XGetAttributeOrNull ("api-source"); + collection.Platform = root.XGetAttributeOrNull ("platform"); + + var packages = new List (); + + foreach (var elem in root.Elements ()) { + switch (elem.Name.LocalName) { + case "package": + packages.Add (ParsePackage (elem, collection)); + break; + } + } + + // First add all non-nested types + foreach (var type in packages.SelectMany (p => p.Types).Where (t => !t.NestedName.Contains ('.'))) + collection.AddType (type); + + // Add all nested types + // This needs to be done ordered from least nested to most nested, in order for nesting to work. + // That is, 'android.foo.Blah' needs to be added before 'android.foo.Blah.Bar'. + foreach (var type in packages.SelectMany (p => p.Types).Where (t => t.NestedName.Contains ('.')).OrderBy (t => t.FullName.Count (c => c == '.')).ToArray ()) { + collection.AddType (type); + + // Remove nested types from Package. In this model, Package only contains top-level types, which then contain nested types. + type.Package.Types.Remove (type); + } + + return collection; + } + + public static JavaPackage ParsePackage (XElement package, JavaTypeCollection collection) + { + var pkg = collection.AddPackage ( + name: package.XGetAttribute ("name"), + jniName: package.XGetAttribute ("jni-name"), + managedName: package.XGetAttributeOrNull ("managedName") + ); + + if (package.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + pkg.PropertyBag.Add ("merge.SourceFile", source); + + foreach (var elem in package.Elements ()) { + switch (elem.Name.LocalName) { + case "class": + if (elem.XGetAttributeAsBool ("obfuscated")) + continue; + + pkg.Types.Add (ParseClass (pkg, elem)); + break; + case "interface": + if (elem.XGetAttributeAsBool ("obfuscated")) + continue; + + pkg.Types.Add (ParseInterface (pkg, elem)); + break; + } + } + + return pkg; + } + + public static JavaClassModel ParseClass (JavaPackage package, XElement element) + { + var model = new JavaClassModel ( + javaPackage: package, + javaNestedName: element.XGetAttribute ("name"), + javaVisibility: element.XGetAttribute ("visibility"), + javaAbstract: element.XGetAttributeAsBool ("abstract"), + javaFinal: element.XGetAttributeAsBool ("final"), + javaBaseType: element.XGetAttribute ("extends"), + javaBaseTypeGeneric: element.XGetAttribute ("extends-generic-aware"), + javaDeprecated: element.XGetAttribute ("deprecated"), + javaStatic: element.XGetAttributeAsBool ("static"), + jniSignature: element.XGetAttribute ("jni-signature"), + baseTypeJni: element.XGetAttribute ("jni-extends"), + annotatedVisibility: element.XGetAttribute ("annotated-visibility") + ); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + model.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + model.PropertyBag.Add ("deprecated-since", dep); + + if (element.Element ("typeParameters") is XElement tp) + ParseTypeParameters (model.TypeParameters, tp); + + foreach (var child in element.Elements ()) { + switch (child.Name.LocalName) { + case "constructor": + model.Constructors.Add (ParseConstructor (model, child)); + break; + case "field": + model.Fields.Add (ParseField (model, child)); + break; + case "implements": + model.Implements.Add (ParseImplements (child)); + break; + case "method": + model.Methods.Add (ParseMethod (model, child)); + break; + } + } + + return model; + } + + public static JavaInterfaceModel ParseInterface (JavaPackage package, XElement element) + { + var nested_name = element.XGetAttribute ("name"); + var visibility = element.XGetAttribute ("visibility"); + var deprecated = element.XGetAttribute ("deprecated"); + var is_static = element.XGetAttribute ("static") == "true"; + var jni_signature = element.XGetAttribute ("jni-signature"); + var annotated_visibility = element.XGetAttribute ("annotated-visibility"); + + var model = new JavaInterfaceModel (package, nested_name, visibility, deprecated, is_static, jni_signature, annotated_visibility); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + model.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + model.PropertyBag.Add ("deprecated-since", dep); + + if (element.Element ("typeParameters") is XElement tp) + ParseTypeParameters (model.TypeParameters, tp); + + foreach (var child in element.Elements ()) { + switch (child.Name.LocalName) { + case "field": + model.Fields.Add (ParseField (model, child)); + break; + case "implements": + model.Implements.Add (ParseImplements (child)); + break; + case "method": + if (child.XGetAttribute ("synthetic") != "true") + model.Methods.Add (ParseMethod (model, child)); + break; + } + } + + return model; + } + + public static JavaMethodModel ParseMethod (JavaTypeModel type, XElement element) + { + var method = new JavaMethodModel ( + javaName: element.XGetAttribute ("name"), + javaVisibility: element.XGetAttribute ("visibility"), + javaAbstract: element.XGetAttributeAsBool ("abstract"), + javaFinal: element.XGetAttributeAsBool ("final"), + javaStatic: element.XGetAttributeAsBool ("static"), + javaReturn: element.XGetAttribute ("return"), + javaDeclaringType: type, + deprecated: element.XGetAttribute ("deprecated"), + jniSignature: element.XGetAttribute ("jni-signature"), + isSynthetic: element.XGetAttributeAsBool ("synthetic"), + isBridge: element.XGetAttributeAsBool ("bridge"), + returnJni: element.XGetAttribute ("jni-return"), + isNative: element.XGetAttributeAsBool ("native"), + isSynchronized: element.XGetAttributeAsBool ("synchronized"), + returnNotNull: element.XGetAttributeAsBool ("return-not-null"), + annotatedVisibility: element.XGetAttributeOrNull ("annotated-visibility") + ); + + if (element.Element ("typeParameters") is XElement tp) + ParseTypeParameters (method.TypeParameters, tp); + + foreach (var child in element.Elements ("parameter")) + method.Parameters.Add (ParseParameter (method, child)); + foreach (var child in element.Elements ("exception")) + method.Exceptions.Add (ParseException (child)); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + method.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + method.PropertyBag.Add ("deprecated-since", dep); + + return method; + } + + public static JavaConstructorModel ParseConstructor (JavaTypeModel type, XElement element) + { + var method = new JavaConstructorModel ( + javaName: element.XGetAttribute ("name"), + javaVisibility: element.XGetAttribute ("visibility"), + javaStatic: element.XGetAttributeAsBool ("static"), + javaDeclaringType: type, + deprecated: element.XGetAttribute ("deprecated"), + jniSignature: element.XGetAttribute ("jni-signature"), + isSynthetic: element.XGetAttributeAsBool ("synthetic"), + isBridge: element.XGetAttributeAsBool ("bridge"), + annotatedVisibility: element.XGetAttributeOrNull ("annotated-visibility") + ); + + // Yes, constructors in Java can have generic type parameters ¯\_(ツ)_/¯ + if (element.Element ("typeParameters") is XElement tp) + ParseTypeParameters (method.TypeParameters, tp); + + foreach (var child in element.Elements ("exception")) + method.Exceptions.Add (ParseException (child)); + + foreach (var child in element.Elements ("parameter")) + method.Parameters.Add (ParseParameter (method, child)); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + method.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + method.PropertyBag.Add ("deprecated-since", dep); + + return method; + } + + public static JavaFieldModel ParseField (JavaTypeModel type, XElement element) + { + var field = new JavaFieldModel ( + name: element.XGetAttribute ("name"), + visibility: element.XGetAttribute ("visibility"), + type: element.XGetAttribute ("type"), + typeGeneric: element.XGetAttribute ("type-generic-aware"), + isStatic: element.XGetAttributeAsBool ("static"), + value: element.Attribute ("value")?.Value, + declaringType: type, + isFinal: element.XGetAttributeAsBool ("final"), + deprecated: element.XGetAttribute ("deprecated"), + jniSignature: element.XGetAttribute ("jni-signature"), + isTransient: element.XGetAttributeAsBool ("transient"), + isVolatile: element.XGetAttributeAsBool ("volatile"), + isNotNull: element.XGetAttributeAsBool ("not-null"), + annotatedVisibility: element.XGetAttributeOrNull ("annotated-visibility") + ); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + field.PropertyBag.Add ("merge.SourceFile", source); + if (element.XGetAttribute ("deprecated-since") is string dep && dep.HasValue ()) + field.PropertyBag.Add ("deprecated-since", dep); + + return field; + } + + public static JavaImplementsModel ParseImplements (XElement element) + { + var model = new JavaImplementsModel ( + name: element.XGetAttribute ("name"), + nameGeneric: element.XGetAttribute ("name-generic-aware"), + jniType: element.XGetAttribute ("jni-type") + ); + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + model.PropertyBag.Add ("merge.SourceFile", source); + + return model; + } + + public static JavaExceptionModel ParseException (XElement element) + { + return new JavaExceptionModel ( + name: element.XGetAttribute ("name"), + type: element.XGetAttribute ("type-generic-aware") + ); + } + + public static JavaParameterModel ParseParameter (JavaMethodModel method, XElement element) + { + var parameter = new JavaParameterModel ( + declaringMethod: method, + javaName: element.XGetAttribute ("name"), + javaType: element.XGetAttribute ("type"), + jniType: element.XGetAttribute ("jni-type"), + isNotNull: element.XGetAttributeAsBool ("not-null") + ); + + return parameter; + } + + public static void ParseTypeParameters (JavaTypeParameters parameters, XElement element) + { + foreach (var elem in element.Elements ()) { + if (elem.Name.LocalName == "typeParameter") + ParseTypeParameter (parameters, elem); + } + + if (element.XGetAttribute ("merge.SourceFile") is string source && source.HasValue ()) + parameters.PropertyBag.Add ("merge.SourceFile", source); + } + + public static void ParseTypeParameter (JavaTypeParameters parameters, XElement element) + { + var parameter = new JavaTypeParameter (element.XGetAttribute ("name"), parameters) { + ExtendedJniClassBound = element.XGetAttribute ("jni-classBound"), + ExtendedClassBound = element.XGetAttribute ("classBound"), + ExtendedInterfaceBounds = element.XGetAttribute ("interfaceBounds"), + ExtendedJniInterfaceBounds = element.XGetAttribute ("jni-interfaceBounds") + }; + + parameters.Add (parameter); + + if (element.Element ("genericConstraints") is XElement gc) { + parameter.GenericConstraints.AddRange (ParseGenericConstraints (gc)); + return; + } + + // Now we have to deal with the format difference... + // Some versions of class-parse stopped generating but started + // generating "classBound" and "interfaceBounds" attributes instead. + // They don't make sense and blocking this effort, but we have to deal with that... + if (!string.IsNullOrEmpty (parameter.ExtendedClassBound) || !string.IsNullOrEmpty (parameter.ExtendedInterfaceBounds)) { + if (!string.IsNullOrEmpty (parameter.ExtendedClassBound)) + parameter.GenericConstraints.Add (new JavaGenericConstraint (parameter.ExtendedClassBound)); + if (!string.IsNullOrEmpty (parameter.ExtendedInterfaceBounds)) + foreach (var ic in parameter.ExtendedInterfaceBounds.Split (':')) + parameter.GenericConstraints.Add (new JavaGenericConstraint (ic)); + } + } + + public static List ParseGenericConstraints (XElement element) + { + var list = new List (); + + foreach (var elem in element.Elements ()) { + if (elem.Name.LocalName == "genericConstraint") + list.Add (ParseGenericConstraint (elem)); + } + + return list; + } + + public static JavaGenericConstraint ParseGenericConstraint (XElement element) + { + return new JavaGenericConstraint ( + element.XGetAttribute ("type") + ); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs new file mode 100644 index 00000000000..908485d5889 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Adapters/ManagedApiImporter.cs @@ -0,0 +1,390 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.JavaTypeSystem.Models; +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public static class ManagedApiImporter + { + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static JavaTypeCollection Parse (AssemblyDefinition assembly, JavaTypeCollection collection) => throw new NotSupportedException (); + + public static JavaTypeCollection Parse (AssemblyDefinition assembly, JavaTypeCollection collection, TypeDefinitionCache resolver, ApiImporterOptions options) + { + var types_to_add = new List (); + + foreach (var md in assembly.Modules) + foreach (var td in md.Types) { + if (!ShouldSkipType (td, resolver, options) && ParseType (td, collection, options) is JavaTypeModel type) + types_to_add.Add (type); + } + + // This needs to be done ordered from least nested to most nested, in order for nesting to work. + // That is, 'android.foo.Blah' needs to be added before 'android.foo.Blah.Bar'. + // Plus, we may have unnested managed types that are actually nested in Java-land: + // ex: IContextMenu and IContextMenuContextMenuItem + foreach (var type in types_to_add.OrderBy (t => t.FullName.Count (c => c == '.')).ToArray ()) + AddReferenceTypeRecursive (type, collection); + + return collection; + } + + public static JavaTypeModel? ParseType (TypeDefinition type, JavaTypeCollection collection, ApiImporterOptions options) + { + if (!type.IsPublic && !type.IsNested) + return null; + + if (!ShouldImport (type)) + return null; + + var model = type.IsInterface ? (JavaTypeModel?) ParseInterface (type, collection, options) : ParseClass (type, collection, options); + + if (model is null) + return null; + + foreach (var nested in type.NestedTypes) + if (ParseType (nested, collection, options) is JavaTypeModel nested_model) + model.NestedTypes.Add (nested_model); + + return model; + } + + static bool ShouldImport (TypeDefinition td) + { + // We want to exclude "IBlahInvoker" and "IBlahImplementor" and "BlahConsts" types + if (td.Name.EndsWith ("Invoker", StringComparison.Ordinal)) { + var n = td.FullName; + n = n.Substring (0, n.Length - "Invoker".Length); + + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + + if (types.Any (t => t.FullName == n)) + return false; + } + + if (td.Name.EndsWith ("Implementor", StringComparison.Ordinal)) { + var n = td.FullName; + n = n.Substring (0, n.Length - "Implementor".Length); + + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + + if (types.Any (t => t.FullName == n)) + return false; + } + + if (td.Name.EndsWith ("Consts", StringComparison.Ordinal)) { + var n = td.FullName; + n = n.Substring (0, n.Length - "Consts".Length); + + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + + if (types.Any (t => t.FullName == n)) + return false; + } + + return true; + } + + public static JavaClassModel? ParseClass (TypeDefinition type, JavaTypeCollection collection, ApiImporterOptions options) + { + // TODO: type parameters? + var obs_attr = GetObsoleteAttribute (type.CustomAttributes); + var reg_attr = GetRegisterAttribute (type.CustomAttributes, options); + + if (reg_attr is null) + return null; + + var encoded_fullname = ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.'); + var (package, nested_name) = DecodeRegisterJavaFullName (encoded_fullname); + + var base_jni = GetBaseTypeJni (type, options); + + var model = new JavaClassModel ( + javaPackage: GetOrCreatePackage (collection, package, type.Namespace), + javaNestedName: nested_name, + javaVisibility: type.IsPublic || type.IsNestedPublic ? "public" : "protected internal", + javaAbstract: type.IsAbstract, + javaFinal: type.IsSealed, + javaBaseType: base_jni.Replace ('/', '.').Replace ('$', '.'), + javaBaseTypeGeneric: base_jni.Replace ('/', '.').Replace ('$', '.'), + javaDeprecated: obs_attr != null ? "deprecated" : "not-deprecated", + javaStatic: false, + jniSignature: FormatJniSignature (package, nested_name), + baseTypeJni: base_jni.HasValue () ? $"L{base_jni};" : string.Empty, + annotatedVisibility: string.Empty + ); ; + + ParseImplementedInterfaces (type, model, options); + + foreach (var method in type.Methods.Where (m => !m.IsConstructor)) + if (ParseMethod (method, model, options) is JavaMethodModel m) + model.Methods.Add (m); + + return model; + } + + public static JavaInterfaceModel? ParseInterface (TypeDefinition type, JavaTypeCollection collection, ApiImporterOptions options) + { + // TODO: type paramters? + var obs_attr = GetObsoleteAttribute (type.CustomAttributes); + var reg_attr = GetRegisterAttribute (type.CustomAttributes, options); + + if (reg_attr is null) + return null; + + var encoded_fullname = ((string) reg_attr.ConstructorArguments [0].Value); + var (package, nested_name) = DecodeRegisterJavaFullName (encoded_fullname); + + var model = new JavaInterfaceModel ( + javaPackage: GetOrCreatePackage (collection, package, type.Namespace), + javaNestedName: nested_name, + javaVisibility: type.IsPublic || type.IsNestedPublic ? "public" : "protected internal", + javaDeprecated: obs_attr != null ? "deprecated" : "not-deprecated", + javaStatic: false, + jniSignature: FormatJniSignature (package, nested_name), + annotatedVisibility: "" + ); + + ParseImplementedInterfaces (type, model, options); + + foreach (var method in type.Methods) + if (ParseMethod (method, model, options) is JavaMethodModel m) + model.Methods.Add (m); + + return model; + } + + public static JavaMethodModel? ParseMethod (MethodDefinition method, JavaTypeModel declaringType, ApiImporterOptions options) + { + if (method.IsPrivate || method.IsAssembly) + return null; + + var obs_attr = GetObsoleteAttribute (method.CustomAttributes); + var reg_attr = GetRegisterAttribute (method.CustomAttributes, options); + + if (reg_attr is null) + return null; + + var deprecated = (obs_attr != null) ? (string) obs_attr.ConstructorArguments [0].Value ?? "deprecated" : "not deprecated"; + var jni_signature = JniSignature.Parse ((string) reg_attr.ConstructorArguments [1].Value!); + + var model = new JavaMethodModel ( + javaName: (string) reg_attr.ConstructorArguments [0].Value, + javaVisibility: method.Visibility (), + javaAbstract: method.IsAbstract, + javaFinal: method.IsFinal, + javaStatic: method.IsStatic, + javaReturn: jni_signature.Return.Type, + javaDeclaringType: declaringType, + deprecated: deprecated, + jniSignature: jni_signature.ToString (), + isSynthetic: false, + isBridge: false, + returnJni: jni_signature.Return.Jni, + isNative: false, + isSynchronized: false, + returnNotNull: false, + annotatedVisibility: null + ); + + for (var i = 0; i < jni_signature.Parameters.Count; i++) + model.Parameters.Add (ParseParameterModel (model, jni_signature.Parameters [i], method.Parameters [i])); + + return model; + } + + static JavaParameterModel ParseParameterModel (JavaMethodModel declaringMethod, JniTypeName jniParameter, ParameterDefinition managedParameter) + { + var raw_type = jniParameter.Type; + + // This covers a special case where we have generated an interface method like: + // void DoThing (System.Collections.Generics.IList p0); + // However the [Register] JNI signature for this method is missing generic information: + // "(Ljava/util/List;)V" + // We need to try to rebuild the generic signature from the [Register] attributes + // on the type components that make up the signature: + // java.util.List + + // TODO: This is more correct, but differs from ApiXmlAdjuster. + //if (managedParameter.ParameterType is GenericInstanceType) + // if (TypeReferenceToJavaType (managedParameter.ParameterType) is string s) + // raw_type = s; + + return new JavaParameterModel (declaringMethod, managedParameter.Name, raw_type, jniParameter.Jni, false); + } + + static void AddReferenceTypeRecursive (JavaTypeModel type, JavaTypeCollection collection) + { + collection.AddReferencedType (type); + + foreach (var nested in type.NestedTypes) + AddReferenceTypeRecursive (nested, collection); + } + + static bool ShouldSkipType (TypeDefinition type, TypeDefinitionCache cache, ApiImporterOptions options) + { + // We want to use Java's collection types instead of our managed adapter. + // eg: 'Java.Util.ArrayList' over 'Android.Runtime.JavaList' + // So don't import our adapters. + switch (type.FullName) { + case "Android.Runtime.JavaCollection": + case "Android.Runtime.JavaDictionary": + case "Android.Runtime.JavaList": + case "Android.Runtime.JavaSet": + return true; + } + + // Currently we do not support generic types because they conflict. + // ex: AdapterView`1 and AdapterView both have: + // [Register ("android/widget/AdapterView")] + // So we do not import the generic type if we also find a non-generic type. + var non_generic_type = type.HasGenericParameters + ? type.Module.GetType (type.FullName.Substring (0, type.FullName.IndexOf ('`'))) + : null; + + if (ShouldSkipGeneric (type, non_generic_type, cache, options)) + return true; + + return false; + } + + static bool ShouldSkipGeneric (TypeDefinition? a, TypeDefinition? b, TypeDefinitionCache cache, ApiImporterOptions options) + { + if (a == null || b == null) + return false; + if (!a.ImplementsInterface ("Android.Runtime.IJavaObject", cache) || !b.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) + return false; + + return GetRegisteredJavaTypeName (a, options) == GetRegisteredJavaTypeName (b, options); + } + + static string? TypeReferenceToJavaType (TypeReference type, ApiImporterOptions options) + { + var retval = GetRegisteredJavaName (type, options); + + if (retval != null && type is GenericInstanceType generic) { + var parameters = generic.GenericArguments.Select (ga => GetRegisteredJavaName (ga.Resolve (), options)).ToArray (); + + if (parameters.WhereNotNull ().Any ()) + retval += $"<{string.Join (", ", parameters.WhereNotNull ())}>"; + } + + return retval; + } + + static string? GetRegisteredJavaName (TypeReference type, ApiImporterOptions options) + { + var td = type.Resolve (); + + return GetRegisteredJavaTypeName (td, options); + } + + static void ParseImplementedInterfaces (TypeDefinition type, JavaTypeModel model, ApiImporterOptions options) + { + foreach (var iface_impl in type.Interfaces) { + var iface = iface_impl.InterfaceType; + var iface_def = iface.Resolve (); + + if (iface_def is null || iface_def.IsNotPublic) + continue; + + if (GetRegisterAttribute (iface_def.CustomAttributes, options) is CustomAttribute reg_attr) { + var jni = (string) reg_attr.ConstructorArguments [0].Value; + var name = jni.Replace ('/', '.').Replace ('$', '.'); + + model.Implements.Add (new JavaImplementsModel (name, name, $"L{jni};")); + } + } + } + + static string GetBaseTypeJni (TypeDefinition type, ApiImporterOptions options) + { + // Find a Java base type, ignoring generic types, if nothing else it will be Java.Lang.Object + TypeDefinition? base_type = type; + + while (true) { + base_type = base_type.BaseType?.Resolve (); + + if (base_type is null) + break; + + // These are the base types for Java.Lang.Object and Java.Lang.Throwable + if (base_type.FullName == "System.Object" || base_type.FullName == "System.Exception") + return string.Empty; + + if (base_type.HasGenericParameters || base_type.IsGenericInstance) + continue; + + if (GetRegisterAttribute (base_type.CustomAttributes, options) is CustomAttribute reg_attr) + return (string) reg_attr.ConstructorArguments [0].Value; + } + + return "java/lang/Object"; + } + + static CustomAttribute? GetObsoleteAttribute (Collection attributes) => + attributes.FirstOrDefault (a => a.AttributeType.FullNameCorrected () == "System.ObsoleteAttribute"); + + static CustomAttribute? GetRegisterAttribute (Collection attributes, ApiImporterOptions options) => + attributes.FirstOrDefault (a => { + var attrType = a.AttributeType.FullNameCorrected (); + + return options.SupportedTypeMapAttributes.Contains (attrType); + }); + + static string? GetRegisteredJavaTypeName (TypeDefinition type, ApiImporterOptions options) + { + if (GetSpecialCase (type) is string s) + return s; + + if (GetRegisterAttribute (type.CustomAttributes, options) is CustomAttribute reg_attr) + return ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.'); + + return null; + } + + static string? GetSpecialCase (TypeDefinition type) + { + return type.FullName switch { + "System.Collections.Generic.IList`1" => "java.util.List", + "System.Collections.Generic.IDictionary`2" => "java.util.Map", + "System.Collections.Generic.ICollection`1" => "java.util.Collection", + "System.String" => "java.lang.String", + _ => null, + }; + } + + static string FullNameCorrected (this TypeReference t) => t.FullName.Replace ('/', '.'); + + public static string Visibility (this MethodDefinition m) => + m.IsPublic ? "public" : m.IsFamilyOrAssembly ? "protected internal" : m.IsFamily ? "protected" : m.IsAssembly ? "internal" : "private"; + + static (string package, string nestedName) DecodeRegisterJavaFullName (string value) + { + value = value.Replace ('/', '.'); + var idx = value.LastIndexOf ('.'); + + var package = idx >= 0 ? value.Substring (0, idx) : string.Empty; + var nested_name = idx >= 0 ? value.Substring (idx + 1) : value; + + return (package, nested_name); + } + + static string FormatJniSignature (string package, string nestedName) + { + if (package.HasValue ()) + return $"L{package.Replace ('.', '/')}/{nestedName};"; + + return "L" + nestedName + ";"; + } + + static JavaPackage GetOrCreatePackage (JavaTypeCollection collection, string package, string managedName) + { + return collection.AddPackage (package, package.Replace ('.', '/'), managedName); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs new file mode 100644 index 00000000000..7d4f9785025 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/CollectionExtensions.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + static class CollectionExtensions + { + public static bool ContainsAny (this ICollection collection, params T[] values) + { + foreach (var v in values) + if (collection.Contains (v)) + return true; + + return false; + } + + public static IEnumerable WhereNotNull (this IEnumerable values) where T : class + { + return values.Where (p => p != null).Cast (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs new file mode 100644 index 00000000000..47a8ab6d7fa --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/StringExtensions.cs @@ -0,0 +1,47 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + static class StringExtensions + { + /// + /// Shortcut for !string.IsNullOrWhiteSpace (s) + /// + public static bool HasValue ([NotNullWhen (true)]this string? s) => !string.IsNullOrWhiteSpace (s); + + /// + /// Removes the final subset of a delimited string. ("127.0.0.1" -> "127.0.0") + /// + [return: NotNullIfNotNull ("s")] + public static string? ChompLast (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return string.Empty; + + return s.Substring (0, index); + } + + /// + /// Returns the final subset of a delimited string. ("127.0.0.1" -> "1") + /// + [return: NotNullIfNotNull ("s")] + public static string? LastSubset (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return s; + + return s.Substring (index + 1); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs new file mode 100644 index 00000000000..0d3367e3087 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Extensions/XmlExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.Xml; +using System.Xml.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + static class XmlExtensions + { + public static string XGetAttribute (this XElement element, string name) + { + return XGetAttributeOrNull (element, name) ?? string.Empty; + } + + public static string? XGetAttributeOrNull (this XElement element, string name) + { + return element.Attribute (name)?.Value.Trim (); + } + + public static bool XGetAttributeAsBool (this XElement element, string name) + { + return XGetAttributeOrNull (element, name) == "true"; + } + + public static void WriteAttributeStringIfValue (this XmlWriter writer, string attributeName, string? value) + { + if (value.HasValue ()) + writer.WriteAttributeString (attributeName, value); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj new file mode 100644 index 00000000000..968d1a81360 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Java.Interop.Tools.JavaTypeSystem.csproj @@ -0,0 +1,24 @@ + + + + $(DotNetTargetFramework) + enable + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs new file mode 100644 index 00000000000..fd679a31744 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/IJavaResolvable.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public interface IJavaResolvable + { + void Resolve (JavaTypeCollection types, ICollection unresolvables); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs new file mode 100644 index 00000000000..30656a64e9d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaBuiltInType.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + // Represents a Java built-in type like 'int' or 'float' + public class JavaBuiltInType : JavaTypeModel + { + public JavaBuiltInType (string name) : base (new JavaPackage ("", "", null), name, "public", false, true, "not deprecated", false, "", "") { } + + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) + { + throw new NotImplementedException (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs new file mode 100644 index 00000000000..35ef3996f2d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaClassModel : JavaTypeModel + { + IDictionary? generic_inheritance_mapping; + + public string BaseType { get; } + public string BaseTypeGeneric { get; } + public string BaseTypeJni { get; } + + public JavaTypeReference? BaseTypeReference { get; private set; } + public List Constructors { get; } = new List (); + + public JavaClassModel (JavaPackage javaPackage, string javaNestedName, string javaVisibility, bool javaAbstract, bool javaFinal, string javaBaseType, string javaBaseTypeGeneric, string javaDeprecated, bool javaStatic, string jniSignature, string baseTypeJni, string annotatedVisibility) : + base (javaPackage, javaNestedName, javaVisibility, javaAbstract, javaFinal, javaDeprecated, javaStatic, jniSignature, annotatedVisibility) + { + BaseType = javaBaseType; + BaseTypeGeneric = javaBaseTypeGeneric; + BaseTypeJni = baseTypeJni; + } + + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) + { + var type_parameters = GetApplicableTypeParameters ().ToArray (); + + // Resolve base class + if (FullName != "java.lang.Object" && FullName != "java.lang.Throwable") { + try { + BaseTypeReference = types.ResolveTypeReference (TypeResolutionOptions.ResolveGenerics ? BaseTypeGeneric : BaseType, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, BaseTypeGeneric, UnresolvableType.BaseType)); + + throw; + } + + // Apparently some Java obfuscator sets a class's base type to itself, which + // results in a stack overflow. Check for this case and remove the offending type. + if (BaseTypeReference.ReferencedType is JavaClassModel jcm && jcm == this) { + unresolvables.Add (new JavaUnresolvableModel (this, BaseTypeGeneric, UnresolvableType.InvalidBaseType)); + throw new JavaTypeResolutionException (BaseTypeGeneric); + } + + // We don't resolve reference-only types by default, so if our base class + // is a reference only type, we need to force it to resolve here. This will be + // needed later when we attempt to resolve base methods. + try { + if (BaseTypeReference.ReferencedType is JavaClassModel klass && klass.FullName != "java.lang.Object" && klass.BaseTypeReference is null && klass.IsReferencedOnly) + klass.Resolve (types, unresolvables); + } catch (JavaTypeResolutionException) { + // Ignore + } + } + + // Resolve constructors + foreach (var ctor in Constructors) + ctor.Resolve (types, unresolvables); + + base.Resolve (types, unresolvables); + } + + public virtual void ResolveBaseMembers () + { + var klass = BaseTypeReference?.ReferencedType as JavaClassModel; + + foreach (var method in Methods) + method.FindBaseMethod (klass); + + foreach (var nested in NestedTypes.OfType ()) + nested.ResolveBaseMembers (); + } + + public IDictionary? GenericInheritanceMapping { + get { + PrepareGenericInheritanceMapping (); + return generic_inheritance_mapping; + } + } + + void PrepareGenericInheritanceMapping () + { + if (generic_inheritance_mapping != null) + return; // already done. + + var bt = BaseTypeReference?.ReferencedType as JavaClassModel; + + if (BaseTypeReference is null || bt is null) { + generic_inheritance_mapping = new Dictionary (); + return; + } + + // begin processing from the base class. + bt.PrepareGenericInheritanceMapping (); + + if (BaseTypeReference.TypeParameters is null) { + generic_inheritance_mapping = new Dictionary (); + return; + } + + if (BaseTypeReference.ReferencedType is null || BaseTypeReference.ReferencedType?.TypeParameters.Count == 0) { + // FIXME: I guess this should not happen. But this still happens. + //Log.LogWarning ("Warning: '{0}' is referenced as base type of '{1}' and expected to have generic type parameters, but it does not.", cls.ExtendsGeneric, cls.FullName); + generic_inheritance_mapping = new Dictionary (); + return; + } + + // NRT - This is checked above but compiler can't figure it out + if (BaseTypeReference.ReferencedType!.TypeParameters.Count != BaseTypeReference.TypeParameters.Count) + throw new Exception (string.Format ("On {0}.{1}, referenced generic arguments count do not match the base type parameters definition", + DeclaringType?.Name, Name)); + + generic_inheritance_mapping = new Dictionary (); + foreach (var kvp in BaseTypeReference.ReferencedType.TypeParameters.Zip ( + BaseTypeReference.TypeParameters, + (def, use) => new KeyValuePair (def, use)) + .Where (p => p.Value.ReferencedTypeParameter == null || p.Key.Name != p.Value.ReferencedTypeParameter.Name)) + generic_inheritance_mapping.Add (new JavaTypeReference (kvp.Key, null), kvp.Value); + } + + public override string ToString () => $"[Class] {FullName}"; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs new file mode 100644 index 00000000000..a9141ec2dbe --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaConstructorModel.cs @@ -0,0 +1,14 @@ +using System; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaConstructorModel : JavaMethodModel + { + public JavaConstructorModel (string javaName, string javaVisibility, bool javaStatic, JavaTypeModel javaDeclaringType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge, string? annotatedVisibility) + : base (javaName, javaVisibility, false, false, javaStatic, "void", javaDeclaringType, deprecated, jniSignature, isSynthetic, isBridge, string.Empty, false, false, false, annotatedVisibility) + { + } + + public override string ToString () => $"Constructor: {DeclaringType.FullName}.{Name}"; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs new file mode 100644 index 00000000000..3d1e3882af2 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaExceptionModel.cs @@ -0,0 +1,16 @@ +using System; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaExceptionModel + { + public string Name { get; } + public string Type { get; } + + public JavaExceptionModel (string name, string type) + { + Name = name; + Type = type; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs new file mode 100644 index 00000000000..efbc65a6aba --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaFieldModel.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaFieldModel : JavaMemberModel + { + public string Type { get; } + public string TypeGeneric { get; } + public string? Value { get; } + public bool IsTransient { get; } + public bool IsVolatile { get; } + public bool IsNotNull { get; } + + public JavaTypeReference? TypeModel { get; private set; } + + public JavaFieldModel (string name, string visibility, string type, string typeGeneric, string? value, bool isStatic, JavaTypeModel declaringType, bool isFinal, string deprecated, string jniSignature, bool isTransient, bool isVolatile, bool isNotNull, string? annotatedVisibility) + : base (name, isStatic, isFinal, visibility, declaringType, deprecated, jniSignature, annotatedVisibility) + { + Type = type; + TypeGeneric = typeGeneric; + Value = value; + IsTransient = isTransient; + IsVolatile = isVolatile; + IsNotNull = isNotNull; + } + + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) + { + if (Name.Contains ('$')) { + unresolvables.Add (new JavaUnresolvableModel (this, "$", UnresolvableType.DollarSign)); + return; + } + + var type_parameters = DeclaringType.GetApplicableTypeParameters ().ToArray (); + + try { + TypeModel = types.ResolveTypeReference (TypeGeneric, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, TypeGeneric, UnresolvableType.FieldType)); + + return; + } + } + + public override string ToString () + { + if (DeclaringType != null) + return $"[Field] {DeclaringType.FullName}.{Name}"; + + return $"[Field] {Name}"; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs new file mode 100644 index 00000000000..600e2e7af31 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaGenericConstraint.cs @@ -0,0 +1,11 @@ +using System; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaGenericConstraint + { + public string Type { get; } + + public JavaGenericConstraint (string type) => Type = type; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs new file mode 100644 index 00000000000..b4812395b67 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaImplementsModel.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaImplementsModel + { + public string Name { get; } + public string NameGeneric { get; } + public string JniType { get; } + + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaImplementsModel (string name, string nameGeneric, string jniType) + { + Name = name; + NameGeneric = nameGeneric; + JniType = jniType; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs new file mode 100644 index 00000000000..2ce22c435a4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaInterfaceModel.cs @@ -0,0 +1,14 @@ +using System; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaInterfaceModel : JavaTypeModel + { + public JavaInterfaceModel (JavaPackage javaPackage, string javaNestedName, string javaVisibility, string javaDeprecated, bool javaStatic, string jniSignature, string annotatedVisibility) : + base (javaPackage, javaNestedName, javaVisibility, false, false, javaDeprecated, javaStatic, jniSignature, annotatedVisibility) + { + } + + public override string ToString () => $"Interface: {FullName}"; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs new file mode 100644 index 00000000000..d4a6fed1a30 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMemberModel.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public abstract class JavaMemberModel : IJavaResolvable + { + public string Name { get; } + public bool IsStatic { get; } + public JavaTypeModel DeclaringType { get; } + public bool IsFinal { get; } + public string Visibility { get; } + public string Deprecated { get; } + public string JniSignature { get; } + public string? AnnotatedVisibility { get; } + + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaMemberModel (string name, bool isStatic, bool isFinal, string visibility, JavaTypeModel declaringType, string deprecated, string jniSignature, string? annotatedVisibility) + { + Name = name; + IsStatic = isStatic; + IsFinal = isFinal; + Visibility = visibility; + DeclaringType = declaringType; + Deprecated = deprecated; + JniSignature = jniSignature; + AnnotatedVisibility = annotatedVisibility; + } + + public abstract void Resolve (JavaTypeCollection types, ICollection unresolvables); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs new file mode 100644 index 00000000000..2588dfd6e8d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaMethodModel.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaMethodModel : JavaMemberModel + { + public string Return { get; } + public string ReturnGeneric { get; } + public bool IsAbstract { get; } + public bool IsBridge { get; } + public string ReturnJni { get; } + public bool IsSynthetic { get; } + public bool IsSynchronized { get; } + public bool IsNative { get; } + public bool ReturnNotNull { get; } + + public JavaTypeParameters TypeParameters { get; } + public JavaTypeReference? ReturnTypeModel { get; private set; } + public JavaMethodModel? BaseMethod { get; set; } + public List Parameters { get; } = new List (); + public List Exceptions { get; } = new List (); + + public JavaMethodModel (string javaName, string javaVisibility, bool javaAbstract, bool javaFinal, bool javaStatic, string javaReturn, JavaTypeModel javaDeclaringType, string deprecated, string jniSignature, bool isSynthetic, bool isBridge, string returnJni, bool isNative, bool isSynchronized, bool returnNotNull, string? annotatedVisibility) + : base (javaName, javaStatic, javaFinal, javaVisibility, javaDeclaringType, deprecated, jniSignature, annotatedVisibility) + { + IsAbstract = javaAbstract; + Return = javaReturn; + ReturnGeneric = javaReturn; + IsBridge = isBridge; + IsSynthetic = isSynthetic; + ReturnJni = returnJni; + IsNative = isNative; + IsSynchronized = isSynchronized; + ReturnNotNull = returnNotNull; + + TypeParameters = new JavaTypeParameters (this); + } + + public override void Resolve (JavaTypeCollection types, ICollection unresolvables) + { + if (Name.Contains ('$')) { + unresolvables.Add (new JavaUnresolvableModel (this, "$", UnresolvableType.DollarSign)); + return; + } + + var type_parameters = GetApplicableTypeParameters ().ToArray (); + + try { + ReturnTypeModel = types.ResolveTypeReference (Return, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, Return, UnresolvableType.ReturnType)); + + return; + } + + foreach (var p in Parameters.OfType ()) + p.Resolve (types, unresolvables); + } + + // Return method's type parameters, plus type parameters for any declaring type(s). + public IEnumerable GetApplicableTypeParameters () + { + foreach (var jtp in TypeParameters) + yield return jtp; + + if (DeclaringType != null) + foreach (var jtp in DeclaringType.GetApplicableTypeParameters ()) + yield return jtp; + } + + public void FindBaseMethod (JavaClassModel? type) + { + if (type is null) + return; + + var pt = (JavaClassModel)DeclaringType; + + var candidates = type.Methods.Where (p => p.Name == Name && IsImplementing (this, p, pt.GenericInheritanceMapping ?? throw new InvalidOperationException ($"missing {nameof (pt.GenericInheritanceMapping)}!"))); + + JavaMethodModel? candidate; + + // Prefer non-synthetic, non-bridge methods + if (candidates.FirstOrDefault (c => !c.IsSynthetic && !c.IsBridge) is JavaMethodModel jm) + candidate = jm; + else + candidate = candidates.FirstOrDefault (); + + if (candidate != null) { + BaseMethod = candidate; + + for (var i = 0; i < candidate.Parameters.Count; i++) + if (candidate.Parameters [i].TypeModel?.ReferencedTypeParameter != null && Parameters [i].TypeModel?.ReferencedTypeParameter == null) + Parameters [i].InstantiatedGenericArgumentName = candidate.Parameters [i].TypeModel?.ReferencedTypeParameter?.Name; + + return; + } + + if (type.BaseTypeReference?.ReferencedType is JavaClassModel klass) + FindBaseMethod (klass); + } + + // It should detect implementation method for: + // - equivalent implementation + // - generic instantiation + // - TODO: variance + // - TODO?: array indicator fixup ("T..." should match "T[]") + public static bool IsImplementing (JavaMethodModel derived, JavaMethodModel basis, IDictionary genericInstantiation) + { + if (genericInstantiation == null) + throw new ArgumentNullException ("genericInstantiation"); + + if (basis.Name != derived.Name) + return false; + + if (basis.Parameters.Count != derived.Parameters.Count) + return false; + + if (basis.Parameters.Zip (derived.Parameters, (bp, dp) => IsParameterAssignableTo (dp, bp, derived, basis, genericInstantiation)).All (v => v)) + return true; + return false; + } + + static bool IsParameterAssignableTo (JavaParameterModel dp, JavaParameterModel bp, JavaMethodModel derived, JavaMethodModel basis, IDictionary genericInstantiation) + { + // If type names are equivalent, they simply match... except that the generic type parameter names match. + // Generic type arguments need more check, so do not examine them just by name. + // + // FIXME: It is likely that this check should NOT result in "this method is not an override", + // but rather like "this method is an override, but it should be still generated in the resulting XML". + // For example, this results in that java.util.EnumMap#put() is NOT an override of + // java.util.AbstractMap#put(), it is an override, not just that it is still generated in the XML. + if (bp.TypeModel?.ReferencedTypeParameter != null && dp.TypeModel?.ReferencedTypeParameter != null && + bp.TypeModel.ReferencedTypeParameter.ToString () != dp.TypeModel.ReferencedTypeParameter.ToString ()) + return false; + if (bp.GenericType == dp.GenericType) + return true; + + if (bp.TypeModel?.ArrayPart != bp.TypeModel?.ArrayPart) + return false; + + // if base is type with generic type parameters and derived is without any generic args, that's OK. + // java.lang.Class should match java.lang.Class. + if (bp.TypeModel?.ReferencedType != null && dp.TypeModel?.ReferencedType != null && + bp.TypeModel?.ReferencedType.FullName == dp.TypeModel?.ReferencedType.FullName && + dp.TypeModel?.TypeParameters == null) + return true; + + // generic instantiation check. + var baseGTP = bp.TypeModel?.ReferencedTypeParameter; + if (baseGTP != null) { + if (baseGTP.Parent?.DeclaringMethod != null && IsConformantType (baseGTP, dp.TypeModel)) + return true; + var k = genericInstantiation.Keys.FirstOrDefault (tr => bp.TypeModel?.Equals (tr) ?? false); + if (k == null) + // the specified generic type parameter is not part of + // the mappings e.g. non-instantiated ones. + return false; + if (genericInstantiation [k].Equals (dp.TypeModel)) + // the specified generic type parameter exactly matches + // whatever specified at the derived method. + return true; + } + + // FIXME: implement variance check. + + return false; + } + + static bool IsConformantType (JavaTypeParameter typeParameter, JavaTypeReference? examinedType) + { + if (!typeParameter.GenericConstraints.Any ()) + return true; + // FIXME: implement correct generic constraint conformance check. + //Log.LogDebug ("NOTICE: generic constraint conformance check is not implemented, so the type might be actually compatible. Type parameter: {0}{1}, examined type: {2}", + // typeParameter.Name, typeParameter.Parent?.ParentMethod?.Name ?? typeParameter.Parent?.ParentType?.Name, examinedType); + return false; + } + + public override string ToString () => "[Method] " + ToStringHelper (Return, Name, TypeParameters); + + // Content of this value is not stable. + public string ToStringHelper (string? returnType, string? name, JavaTypeParameters? typeParameters) + { + return string.Format ("{0}{1}{2}{3}{4}{5}({6})", + returnType, + returnType == null ? null : " ", + name, + typeParameters?.Any () == true ? "<" : null, + typeParameters?.Any () == true ? string.Join (", ", typeParameters) : null, + typeParameters?.Any () == true ? ">" : null, + string.Join (", ", Parameters)); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs new file mode 100644 index 00000000000..d16929fbe40 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaPackage.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaPackage + { + public string Name { get; } + public string JniName { get; } + + // Note 'null' is significant: it means 'not-set'. + // Empty string means "set to a blank namespace". + public string? ManagedName { get; set; } + + public List Types { get; } = new List (); + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaPackage (string name, string jniName, string? managedName) + { + Name = name; + JniName = jniName; + ManagedName = managedName; + } + + public override string ToString () => string.Format ($"[Package] {Name}"); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs new file mode 100644 index 00000000000..12f23dd9f49 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaParameterModel.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaParameterModel : IJavaResolvable + { + public string Name { get; } + public string Type { get; } + public string JniType { get; } + public bool IsNotNull { get; } + public string GenericType { get; } + + public JavaMethodModel DeclaringMethod { get; } + public JavaTypeReference? TypeModel { get; private set; } + public bool IsParameterArray { get; private set; } + public string? InstantiatedGenericArgumentName { get; internal set; } + + public JavaParameterModel (JavaMethodModel declaringMethod, string javaName, string javaType, string jniType, bool isNotNull) + { + DeclaringMethod = declaringMethod; + Name = javaName; + Type = javaType; + JniType = jniType; + IsNotNull = isNotNull; + GenericType = javaType; + + if (Type.Contains ('<')) + Type = Type.Substring (0, Type.IndexOf ('<')); + } + + public void Resolve (JavaTypeCollection types, ICollection unresolvables) + { + var jtn = JavaTypeName.Parse (GenericType); + + if (jtn.ArrayPart == "...") + IsParameterArray = true; + + var type_parameters = DeclaringMethod.GetApplicableTypeParameters ().ToArray (); + + try { + TypeModel = types.ResolveTypeReference (GenericType, type_parameters); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, Type, UnresolvableType.ParameterType)); + + return; + } + } + + public override string ToString () + { + return $"{GenericType} {Name}"; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs new file mode 100644 index 00000000000..f1c65249f54 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeModel.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public abstract class JavaTypeModel : IJavaResolvable + { + /// + /// Only the type's name, does not include declaring type name for nested type. + /// + public string Name { get; } + + /// + /// Includes declaring type name(s) if type is nested (period separator). ex: Manifest.permission + /// + public string NestedName { get; set; } + + public string Visibility { get; } + public string AnnotatedVisibility { get; } + public bool IsAbstract { get; } + public bool IsFinal { get; } + public string Deprecated { get; } + public bool IsStatic { get; } + public string ExtendedJniSignature { get; } + public bool IsReferencedOnly { get; internal set; } + + public JavaPackage Package { get; } + public JavaTypeModel? DeclaringType { get; internal set; } + public List NestedTypes { get; } = new List (); + + public JavaTypeParameters TypeParameters { get; } + public List Implements { get; } = new List (); + public List ImplementsModels { get; } = new List (); + public List Methods { get; } = new List (); + public List Fields { get; } = new List (); + + public Dictionary PropertyBag { get; } = new Dictionary (); + + protected JavaTypeModel (JavaPackage javaPackage, string javaNestedName, string javaVisibility, bool javaAbstract, bool javaFinal, string deprecated, bool javaStatic, string jniSignature, string annotatedVisibility) + { + Package = javaPackage; + NestedName = javaNestedName.Replace ('$', '.'); + Name = NestedName.LastSubset ('.'); + Visibility = javaVisibility; + AnnotatedVisibility = annotatedVisibility; + IsAbstract = javaAbstract; + IsFinal = javaFinal; + Deprecated = deprecated; + IsStatic = javaStatic; + ExtendedJniSignature = jniSignature; + + TypeParameters = new JavaTypeParameters (this); + } + + /// + /// Returns string containing package name, declaring type name, and type's name. (ex: 'java.util.ArrayList.Keys') + /// + public string FullName { + get { + if (DeclaringType != null) + return $"{DeclaringType.FullName}.{Name}"; + + if (Package.Name.Length > 0) + return $"{Package.Name}.{NestedName}"; + + return Name; + } + } + + public bool IsNested => NestedName.Contains ('.'); + + public virtual void Resolve (JavaTypeCollection types, ICollection unresolvables) + { + var type_parameters = GetApplicableTypeParameters ().ToArray (); + + // Resolve any implemented interfaces + foreach (var i in Implements) { + try { + var implements = types.ResolveTypeReference (TypeResolutionOptions.ResolveGenerics ? i.NameGeneric : i.Name, type_parameters); + + if (implements is null) + throw new Exception (); + + ImplementsModels.Add (implements); + } catch (JavaTypeResolutionException) { + unresolvables.Add (new JavaUnresolvableModel (this, i.NameGeneric, UnresolvableType.ImplementsType)); + + throw; + } + } + + // Resolve members + foreach (var method in Methods) + method.Resolve (types, unresolvables); + + foreach (var field in Fields) + field.Resolve (types, unresolvables); + + // Resolve nested types + foreach (var child in NestedTypes) + child.Resolve (types, unresolvables); + } + + // Return type's type parameters, plus type parameters for any types this is nested in. + public IEnumerable GetApplicableTypeParameters () + { + foreach (var jtp in TypeParameters) + yield return jtp; + + if (DeclaringType != null) + foreach (var jtp in DeclaringType.GetApplicableTypeParameters ()) + yield return jtp; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs new file mode 100644 index 00000000000..6b0995c7a56 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeName.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + // An internal Type that represents a parsed Java type name structure. + // A type name string is passed to Parse() method to create this instance + // (the only place you can create an instance of this type), then it is + // used to create JavaTypeReference instance. + // + // The structure does not depend on any context type information. + // + // It is constructed from a "dotted" name. + // Unlike JNI-based names, there is no way to determine that a dot is within + // package name, between package and class, or for nested class. + // Hence it is impossible to get a package and a local names without + // context type information. Such analyses should be done at JavaTypeReference. + // + // A generic type parameter, or a primitive type, is also represented by this too. + // + public class JavaTypeName + { + const string extendsLabel = " extends "; + const string superLabel = " super "; + + static readonly string [] genericConstraintsLabels = { extendsLabel, superLabel }; + + public JavaTypeName? GenericParent { get; set; } + // NRT - This is always set via Parse + public string DottedName { get; set; } = null!; + public string? BoundsType { get; set; } // " extends " / " super " + public IList? GenericConstraints { get; private set; } + public IList? GenericArguments { get; private set; } + public string? ArrayPart { get; set; } + + JavaTypeName () + { + } + + public static JavaTypeName Parse (string dottedFullName) + { + var ret = new JavaTypeName (); + + foreach (var label in genericConstraintsLabels) { + int gcidx = dottedFullName.IndexOf (label, StringComparison.Ordinal); + int gcgidx = gcidx < 0 ? -1 : dottedFullName.IndexOf ('<', 0, gcidx); + int gccidx = gcidx < 0 ? -1 : dottedFullName.IndexOf (',', 0, gcidx); + if (gcidx > 0 && gcgidx < 0 && gccidx < 0) { + string args = dottedFullName.Substring (gcidx + label.Length).Trim (); + ret.BoundsType = label; + ret.GenericConstraints = ParseCommaSeparatedTypeNames (args).Select (s => Parse (s)).ToArray (); + dottedFullName = dottedFullName.Substring (0, gcidx).Trim (); + } + } + + if (dottedFullName.EndsWith ("...", StringComparison.Ordinal)) { + ret.ArrayPart = "..."; + dottedFullName = dottedFullName.Substring (0, dottedFullName.Length - 3); + } + while (dottedFullName.LastOrDefault () == ']') { + int aidx = dottedFullName.LastIndexOf ('['); + ret.ArrayPart += dottedFullName.Substring (aidx); + dottedFullName = dottedFullName.Substring (0, aidx); + } + + int idx = dottedFullName.IndexOf ('<'); + int nextIndex = dottedFullName.Length; + if (idx > 0) { + int last = GetMatchingGenericCloser (dottedFullName, idx + 1); + ret.GenericArguments = ParseCommaSeparatedTypeNames (dottedFullName.Substring (idx + 1, last - idx - 1)) + .Select (s => JavaTypeName.Parse (s.Trim ())) + .ToArray (); + nextIndex = last + 1; + } + // at this state, there is no way to distinguish package name from this name specification. + ret.DottedName = idx < 0 ? dottedFullName : dottedFullName.Substring (0, idx); + + if (nextIndex < dottedFullName.Length) { + if (dottedFullName [nextIndex] != '.') + throw new ArgumentException (nameof (dottedFullName)); + // the generic parent is parsed, but the rest is still there. + var parent = ret; + ret = Parse (dottedFullName.Substring (nextIndex + 1)); + ret.GenericParent = parent; + } + + return ret; + } + + static int GetMatchingGenericCloser (string str, int start) + { + int count = 0; + for (int i = start; i < str.Length; i++) { + switch (str [i]) { + case '<': + count++; + break; + case '>': + if (count-- == 0) + return i; + break; + } + } + return -1; + } + + static IEnumerable ParseCommaSeparatedTypeNames (string args) + { + int comma = args.IndexOf (','); + if (comma < 0) + yield return args; + else { + int open = args.IndexOf ('<', 0, comma); + if (open > 0) { + int openCount = 1; + int i = open + 1; + while (i < args.Length) { + if (args [i] == '<') + openCount++; + else if (args [i] == '>') + openCount--; + i++; + if (openCount == 0) + break; + } + yield return args.Substring (0, i); + if (i < args.Length) { + comma = args.IndexOf (',', i); + if (comma > 0) + foreach (var s in ParseCommaSeparatedTypeNames (args.Substring (comma + 1))) + yield return s; + } + } else { + yield return args.Substring (0, comma); + foreach (var s in ParseCommaSeparatedTypeNames (args.Substring (comma + 1).Trim ())) + yield return s; + } + } + } + + public string FullNameNonGeneric { + get { + if (GenericParent != null) + return GenericParent.FullNameNonGeneric + "." + DottedName; + else + return DottedName; + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs new file mode 100644 index 00000000000..a817c539dc4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeParameter : IJavaResolvable + { + public string Name { get; set; } + + public JavaTypeParameters Parent { get; } + + public string? ExtendedJniClassBound { get; set; } + public string? ExtendedClassBound { get; set; } + public string? ExtendedInterfaceBounds { get; set; } + public string? ExtendedJniInterfaceBounds { get; set; } + + public List GenericConstraints { get; } = new List (); + + public JavaTypeParameter (string name, JavaTypeParameters parent) + { + Name = name; + Parent = parent; + } + + public void Resolve (JavaTypeCollection types, ICollection unresolvables) + { + // TODO: Resolve generic constraints + //var type_parameters = GetApplicableTypeParameters ().ToArray (); + } + + public override string ToString () => Name ?? ""; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs new file mode 100644 index 00000000000..003b155ac19 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeParameters.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeParameters : Collection + { + public JavaTypeModel? DeclaringType { get; } + public JavaMethodModel? DeclaringMethod { get; } + + public Dictionary PropertyBag { get; } = new Dictionary (); + + public JavaTypeParameters (JavaTypeModel declaringType) => DeclaringType = declaringType; + public JavaTypeParameters (JavaMethodModel declaringMethod) => DeclaringMethod = declaringMethod; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs new file mode 100644 index 00000000000..18753009132 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaTypeReference.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeReference + { + public static readonly JavaTypeReference Void = new JavaTypeReference ("void"); + public static readonly JavaTypeReference Boolean = new JavaTypeReference ("boolean"); + public static readonly JavaTypeReference Char = new JavaTypeReference ("char"); + public static readonly JavaTypeReference Byte = new JavaTypeReference ("byte"); + public static readonly JavaTypeReference Short = new JavaTypeReference ("short"); + public static readonly JavaTypeReference Int = new JavaTypeReference ("int"); + public static readonly JavaTypeReference Long = new JavaTypeReference ("long"); + public static readonly JavaTypeReference Float = new JavaTypeReference ("float"); + public static readonly JavaTypeReference Double = new JavaTypeReference ("double"); + public static readonly JavaTypeReference GenericWildcard = new JavaTypeReference ("?"); + public static readonly JavaTypeReference UInt = new JavaTypeReference ("uint"); + public static readonly JavaTypeReference UShort = new JavaTypeReference ("ushort"); + public static readonly JavaTypeReference ULong = new JavaTypeReference ("ulong"); + public static readonly JavaTypeReference UByte = new JavaTypeReference ("ubyte"); + + public string? SpecialName { get; private set; } + public string? WildcardBoundsType { get; private set; } + public IList? WildcardConstraints { get; private set; } + public JavaTypeModel? ReferencedType { get; private set; } + public JavaTypeParameter? ReferencedTypeParameter { get; private set; } + public IList? TypeParameters { get; private set; } + public string? ArrayPart { get; private set; } + + JavaTypeReference (string? specialName) + { + SpecialName = specialName; + } + + public JavaTypeReference (string? constraintLabel, IEnumerable? wildcardConstraints, string? arrayPart) + { + SpecialName = GenericWildcard.SpecialName; + ArrayPart = arrayPart; + WildcardBoundsType = constraintLabel; + WildcardConstraints = wildcardConstraints != null && wildcardConstraints.Any () ? wildcardConstraints.ToList () : null; + } + + public JavaTypeReference (JavaTypeReference referencedType, string? arrayPart, string? wildcardBoundsType, IEnumerable? wildcardConstraints) + { + if (referencedType == null) + throw new ArgumentNullException (nameof (referencedType)); + + SpecialName = referencedType.SpecialName; + WildcardBoundsType = wildcardBoundsType; + WildcardConstraints = wildcardConstraints?.ToList (); + ReferencedType = referencedType.ReferencedType; + ReferencedTypeParameter = referencedType.ReferencedTypeParameter; + TypeParameters = referencedType.TypeParameters; + ArrayPart = arrayPart; + } + + public JavaTypeReference (JavaTypeParameter referencedTypeParameter, string? arrayPart) + { + ReferencedTypeParameter = referencedTypeParameter ?? throw new ArgumentNullException (nameof (referencedTypeParameter)); + ArrayPart = arrayPart; + } + + public JavaTypeReference (JavaTypeModel referencedType, IList? typeParameters, string? arrayPart) + { + ReferencedType = referencedType ?? throw new ArgumentNullException (nameof (referencedType)); + TypeParameters = typeParameters; + ArrayPart = arrayPart; + } + + internal static JavaTypeReference? GetSpecialType (string? name) + { + return name switch { + "void" => Void, + "boolean" => Boolean, + "char" => Char, + "byte" => Byte, + "short" => Short, + "int" => Int, + "long" => Long, + "float" => Float, + "double" => Double, + "uint" => UInt, + "ushort" => UShort, + "ulong" => ULong, + "ubyte" => UByte, + "?" => GenericWildcard, + _ => null, + }; + } + + public override string ToString () + { + if (SpecialName == GenericWildcard.SpecialName && WildcardConstraints != null) + return SpecialName + WildcardBoundsType + string.Join (" & ", WildcardConstraints); + else if (SpecialName != null) + return SpecialName + ArrayPart; + else if (ReferencedTypeParameter != null) + return ReferencedTypeParameter.Name + ArrayPart; + else + return string.Format ("{0}{1}{2}", + ReferencedType?.FullName.Replace ('$', '.'), + TypeParameters?.Any () == true ? '<' + string.Join (", ", TypeParameters.Select (_ => _.ToString ())) + '>' : null, + ArrayPart); + } + + public override int GetHashCode () + { + // it's skipping TypeParameters because it's too annoying... + if (SpecialName != null) + return SpecialName.GetHashCode (); + return (ReferencedType != null ? ReferencedType.Name?.GetHashCode () ?? 0 : 0) << 15 + + (ReferencedTypeParameter != null ? ReferencedTypeParameter.Name?.GetHashCode () ?? 0 : 0) << 7 + + (ArrayPart != null ? ArrayPart.GetHashCode () : 0); + } + + public override bool Equals (object? obj) + { + return AreEqual (this, obj as JavaTypeReference); + } + + // It compares two JavaTypeReferences. + // Note that it is to compare them as a type reference, not as its object entity. + // So, for example, if one has a TypeParameter with T with some contraint and + // the other has a TypeParameter with T somehow without it, they are still "same". + public static bool AreEqual (JavaTypeReference tr1, JavaTypeReference? tr2) + { + if (tr1 == null) + return tr2 == null; + else if (tr2 == null) + return false; + + if (tr1.ArrayPart != tr2.ArrayPart) + return false; + + if (tr1.SpecialName != null) + return tr1.SpecialName == tr2.SpecialName; + + if (tr1.ReferencedTypeParameter != null) { + if (tr2.ReferencedTypeParameter == null || tr1.ReferencedTypeParameter.Name != tr2.ReferencedTypeParameter.Name) + return false; + + return true; + } else if (tr2.ReferencedTypeParameter != null) + return false; + + if (tr1.ReferencedType == null || tr2.ReferencedType == null) + return false; + if (tr1.ReferencedType.Package != tr2.ReferencedType.Package) + return false; + if (tr1.ReferencedType.NestedName != tr2.ReferencedType.NestedName) + return false; + return true; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs new file mode 100644 index 00000000000..abd86cdbd86 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JniTypeName.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JniSignature + { + public JniTypeName Return { get; } + public List Parameters { get; } = new List (); + + public JniSignature (JniTypeName returnType, params JniTypeName[] parameterTypes) + { + Return = returnType; + Parameters.AddRange (parameterTypes); + } + + public static JniSignature Parse (string signature) + { + var idx = signature.LastIndexOf (')') + 1; + var jni = new JniSignature (JniTypeName.Parse (signature.Substring (idx))); + + // Strip out return type + if (signature.StartsWith ("(", StringComparison.Ordinal)) { + var e = signature.IndexOf (')'); + signature = signature.Substring (1, e >= 0 ? e - 1 : signature.Length - 1); + } + + // Parse parameters + var i = 0; + + while (i < signature.Length) { + var t = JniTypeName.Parse (signature.Substring (i)); + + jni.Parameters.Add (t); + i += t.Jni.Length; + } + + return jni; + } + + public override string ToString () + { + return $"({string.Join ("", Parameters)}){Return}"; + } + } + + public class JniTypeName + { + public string Type { get; } + public string Jni { get; } + public bool IsKeyword { get; } + + public JniTypeName (string jni, string type, bool isKeyword) + { + Jni = jni; + Type = type; + IsKeyword = isKeyword; + } + + // This returns the first type found in the signature and ignores any extra signature data + public static JniTypeName Parse (string signature) + { + var index = 0; + + switch (signature [index]) { + case '[': { + ++index; + + if (index >= signature.Length) + throw new InvalidOperationException ("Missing array type after '[' at index " + index + " in: " + signature); + + var r = Parse (signature.Substring (index)); + + return new JniTypeName (signature.Substring (0, index) + r.Jni, r.Type + "[]", r.IsKeyword); + } + case 'B': + return new JniTypeName ("B", "byte", true); + case 'C': + return new JniTypeName ("C", "char", true); + case 'D': + return new JniTypeName ("D", "double", true); + case 'F': + return new JniTypeName ("F", "float", true); + case 'I': + return new JniTypeName ("I", "int", true); + case 'J': + return new JniTypeName ("J", "long", true); + case 'L': { + var e = signature.IndexOf (';', index); + + if (e <= 0) + throw new InvalidOperationException ("Missing reference type after 'L' at index " + index + "in: " + signature); + + //var s = index; + //index = e + 1; + + return new JniTypeName ( + signature.Substring (0, e + 1), + signature.Substring (index + 1, e - 1).Replace ("/", ".").Replace ("$", "."), + false + ); + } + case 'S': + return new JniTypeName ("S", "short", true); + case 'V': + return new JniTypeName ("V", "void", true); + case 'Z': + return new JniTypeName ("Z", "boolean", true); + default: + throw new InvalidOperationException ("Unknown JNI Type '" + signature [index] + "' within: " + signature); + } + } + + // This throws an exception if there is extra data in the signature + public static JniTypeName ParseExact (string signature) + { + var jni = Parse (signature); + + if (jni.Jni.Length != signature.Length) + throw new InvalidOperationException ("Extra JNI signature"); + + return jni; + } + + public override string ToString () => Jni; + } +} + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs new file mode 100644 index 00000000000..2c4f428b22c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/JavaTypeCollection.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaTypeCollection + { + readonly Dictionary packages = new Dictionary (); + readonly Dictionary types = new Dictionary (); + readonly Dictionary types_flattened = new Dictionary (); + readonly Dictionary referenced_types_flattened = new Dictionary (); + readonly Dictionary built_in_types = new Dictionary (); + + // Expose ReadOnly versions so internal type management cannot be bypassed + public IReadOnlyDictionary Packages => packages; + public IReadOnlyDictionary Types => types; + + public IReadOnlyDictionary TypesFlattened => types_flattened; + + // We only keep a flattened version of reference types. The main issue is that the Managed nesting + // may not match the Java nesting (ie: types nested in Java interfaces that C# originally didn't support). + // Since we don't actually *need* this model to be nested it's simpler to keep them flattened. + public IReadOnlyDictionary ReferencedTypesFlattened => referenced_types_flattened; + + public string? ApiSource { get; set; } + public string? Platform { get; set; } + + public JavaTypeCollection () + { + built_in_types.Add ("void", new JavaBuiltInType ("void")); + built_in_types.Add ("boolean", new JavaBuiltInType ("boolean")); + built_in_types.Add ("int", new JavaBuiltInType ("int")); + built_in_types.Add ("byte", new JavaBuiltInType ("byte")); + built_in_types.Add ("double", new JavaBuiltInType ("double")); + built_in_types.Add ("float", new JavaBuiltInType ("float")); + built_in_types.Add ("long", new JavaBuiltInType ("long")); + built_in_types.Add ("short", new JavaBuiltInType ("short")); + built_in_types.Add ("char", new JavaBuiltInType ("char")); + } + + /// + /// Adds a new package with the specified name. Note if package already exists, existing package will be returned. + /// + public JavaPackage AddPackage (string name, string jniName, string? managedName = null) + { + if (packages.TryGetValue (name, out var pkg)) + return pkg; + + var new_pkg = new JavaPackage (name, jniName, managedName); + + packages.Add (new_pkg.Name, new_pkg); + + return new_pkg; + } + + /// + /// Adds a type to the collection. Note declaring classes must be added before nested classes. + /// + /// True if type was added to collection. False if type could not be added because its declaring type was missing. + public bool AddType (JavaTypeModel type) + { + var nested_name = type.NestedName; + + // Not a nested type + if (!nested_name.Contains ('.')) { + types [type.FullName] = type; + + types_flattened [type.FullName] = type; + + return true; + } + + var full_name = type.FullName.ChompLast ('.'); + + // Nested type, find declaring model to put it in + if (types_flattened.TryGetValue (full_name, out var declaring)) { + if (!declaring.NestedTypes.Contains (type)) + declaring.NestedTypes.Add (type); + + type.DeclaringType = declaring; + types_flattened [type.FullName] = type; + + return true; + } + + // Could not find declaring type to nest child type in + return false; + } + + /// + /// Adds a reference type to the collection. + /// + public void AddReferencedType (JavaTypeModel type) + { + type.IsReferencedOnly = true; + + referenced_types_flattened [type.FullName] = type; + } + + // This is a little trickier than we may initially think, because nested classes + // will also need to be removed from TypesFlattened (recursively). Note this only + // removes the type from this collection, it does not remove a nested type from + // its declaring type model. Returns true if type(s) were removed. + public bool RemoveType (JavaTypeModel type) + { + var removed = false; + + // Remove all nested types + foreach (var nested in type.NestedTypes) + removed |= RemoveType (nested); + + // Remove ourselves + removed |= types_flattened.Remove (type.FullName); + removed |= types.Remove (type.FullName); + + return removed; + } + + /// + /// Ensures all types needed by the binding types can be found. Removes members or types + /// that need types that cannot be found. + /// + public CollectionResolutionResults ResolveCollection (TypeResolutionOptions? options = null) + { + options ??= TypeResolutionOptions.Default; + + var results = new CollectionResolutionResults (); + + while (true) { + var unresolvables = new Collection (); + + foreach (var t in Types) + try { + t.Value.Resolve (this, unresolvables); + } catch (JavaTypeResolutionException) { + } + + foreach (var u in unresolvables) { + if (u.Unresolvable is JavaTypeModel type) { + u.RemovedEntireType = RemoveResolvedType (type); + } else if (u.Unresolvable is JavaConstructorModel ctor) { + // Remove from declaring type (must pattern check for ctor before method) + ((JavaClassModel) ctor.DeclaringType).Constructors.Remove (ctor); + } else if (u.Unresolvable is JavaMethodModel method) { + // Remove from declaring type + u.RemovedEntireType = RemoveMethod (method, options); + } else if (u.Unresolvable is JavaFieldModel field) { + // Remove from declaring type + field.DeclaringType.Fields.Remove (field); + } else if (u.Unresolvable is JavaParameterModel parameter) { + // Remove method from declaring type + u.RemovedEntireType = RemoveMethod (parameter.DeclaringMethod, options); + } else { + // *Shouldn't* be possible + throw new Exception ($"Encountered unknown IJavaResolvable: '{u.Unresolvable.GetType ().Name}'"); + } + } + + if (unresolvables.Any ()) + results.Add (new CollectionResolutionResult (unresolvables)); + + // We may have removed a type that other types/members reference, so we have + // to keep doing this until we do not remove any types. + if (!unresolvables.Any (u => u.RemovedEntireType)) + break; + } + + // Once we have resolved all base classes we can resolve class members + foreach (var klass in TypesFlattened.Values.OfType ()) + klass.ResolveBaseMembers (); + + return results; + } + + public JavaTypeReference ResolveTypeReference (string name, params JavaTypeParameter [] contextTypeParameters) + => ResolveTypeReference (JavaTypeName.Parse (name), contextTypeParameters); + + public JavaTypeReference ResolveTypeReference (JavaTypeName tn, params JavaTypeParameter [] contextTypeParameters) + { + var tp = contextTypeParameters.FirstOrDefault (xp => xp.Name == tn.DottedName); + + if (tp != null) + return new JavaTypeReference (tp, tn.ArrayPart); + + if (tn.DottedName == JavaTypeReference.GenericWildcard.SpecialName) + return new JavaTypeReference (tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters)), tn.ArrayPart); + + var primitive = JavaTypeReference.GetSpecialType (tn.DottedName); + + if (primitive != null) + return tn.ArrayPart == null && tn.GenericConstraints == null ? primitive : new JavaTypeReference (primitive, tn.ArrayPart, tn.BoundsType, tn.GenericConstraints?.Select (gc => ResolveTypeReference (gc, contextTypeParameters))); + + var type = FindType (tn.FullNameNonGeneric); + + if (type is null) + throw new JavaTypeResolutionException (tn.FullNameNonGeneric); + + return new JavaTypeReference (type, + tn.GenericArguments != null ? tn.GenericArguments.Select (_ => ResolveTypeReference (_, contextTypeParameters)).ToArray () : null, + tn.ArrayPart); + } + + // Returns true if a type was removed. + bool RemoveMethod (JavaMethodModel method, TypeResolutionOptions options) + { + // We cannot remove a non-static, non-default method on an interface without breaking the contract. + // If we need to do that we have to remove the entire interface instead. + if (method.DeclaringType is JavaInterfaceModel && !method.IsStatic && method.IsAbstract && options.RemoveInterfacesWithUnresolvableMembers) + return RemoveResolvedType (method.DeclaringType); + + if (method is JavaConstructorModel ctor && method.DeclaringType is JavaClassModel klass) + klass.Constructors.Remove (ctor); + else + method.DeclaringType.Methods.Remove (method); + + return false; + } + + bool RemoveResolvedType (JavaTypeModel type) + { + var removed = false; + + // Remove from declaring type + if (type.DeclaringType != null) + removed |= type.DeclaringType.NestedTypes.Remove (type); + + // Remove from collection + removed |= RemoveType (type); + + // Remove from declaring package + type.Package.Types.Remove (type); + + return removed; + } + + public JavaTypeModel? FindType (string type) + { + // Prefer built-in types + if (built_in_types.TryGetValue (type, out var builtin)) + return builtin; + + // Then binding types + if (TypesFlattened.TryGetValue (type, out var value)) + return value; + + // Finally reference types + if (ReferencedTypesFlattened.TryGetValue (type, out var ref_type)) + return ref_type; + + // We moved this type to "mono.android.app.IntentService" which makes this + // type resolution fail if a user tries to reference it in Java. + if (type == "android.app.IntentService") + return FindType ("mono.android.app.IntentService"); + + return null; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs new file mode 100644 index 00000000000..de3ce34d547 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/CollectionResolutionResult.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + // This class represents the "cycles" it took to resolve the collection. + // Example: + // - Cycle 1 removed 'com.example.MyType' because 'android.util.List' was missing + // - Cycle 2 removed 'com.example.MyDerivedType' because 'com.example.MyType' is now missing + // This distinction can be interesting, because Cycle 1 removals are often due to missing + // dependencies, whereas the remaining cycles are just the internal fallout from Cycle 1. + public class CollectionResolutionResults : Collection + { + } + + public class CollectionResolutionResult + { + public Collection Unresolvables { get; } + + public CollectionResolutionResult (Collection unresolvables) => + Unresolvables = unresolvables; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaTypeResolutionException.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaTypeResolutionException.cs new file mode 100644 index 00000000000..b13dcfc1356 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaTypeResolutionException.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public class JavaTypeResolutionException : Exception + { + public JavaTypeResolutionException (string message) : base (message) + { + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs new file mode 100644 index 00000000000..d805480057b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs @@ -0,0 +1,86 @@ +using System; + +namespace Java.Interop.Tools.JavaTypeSystem.Models +{ + public class JavaUnresolvableModel + { + public IJavaResolvable Unresolvable { get; } + public string MissingType { get; } + public UnresolvableType Type { get; } + public bool RemovedEntireType { get; set; } + + public JavaUnresolvableModel (IJavaResolvable unresolvable, string missingType, UnresolvableType type) + { + Unresolvable = unresolvable; + MissingType = missingType; + Type = type; + } + + public string GetDisplayMessage () + { + var member = Unresolvable as JavaMemberModel; + + if (Type == UnresolvableType.DollarSign) + return RemovedEntireType ? + $"The type '{member?.DeclaringType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign." : + $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign."; + + if (Type == UnresolvableType.InvalidBaseType) + return $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the base type '{MissingType}' is invalid."; + + if (Unresolvable is JavaTypeModel) + return $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found."; + + return RemovedEntireType ? + $"The type '{member?.DeclaringType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found." : + $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found."; + } + + string GetUnresolvableType () + { + if (Unresolvable is JavaFieldModel) + return "field"; + if (Unresolvable is JavaConstructorModel || (Unresolvable is JavaParameterModel p && p.DeclaringMethod is JavaConstructorModel)) + return "constructor"; + if (Unresolvable is JavaMethodModel || (Unresolvable is JavaParameterModel p2 && p2.DeclaringMethod is JavaMethodModel)) + return "method"; + if (Unresolvable is JavaClassModel) + return "class"; + if (Unresolvable is JavaInterfaceModel) + return "interface"; + + return string.Empty; + } + + string GetUnresolvable () + { + if (Unresolvable is JavaParameterModel p) + return p.DeclaringMethod.ToString (); + + return Unresolvable.ToString () ?? string.Empty; + } + + string GetReason () + { + return Type switch { + UnresolvableType.FieldType => "field type", + UnresolvableType.ReturnType => "return type", + UnresolvableType.ParameterType => "parameter type", + UnresolvableType.BaseType => "base type", + UnresolvableType.ImplementsType => "implemented interface type", + _ => throw new NotImplementedException (), + }; + } + } + + public enum UnresolvableType + { + DollarSign, + FieldType, + ReturnType, + ParameterType, + BaseType, + ImplementsType, + InvalidBaseType, + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/TypeResolutionOptions.cs b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/TypeResolutionOptions.cs new file mode 100644 index 00000000000..8305222643b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.JavaTypeSystem/Utilities/TypeResolutionOptions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Java.Interop.Tools.JavaTypeSystem +{ + public class TypeResolutionOptions + { + // We *should* do this, but ApiXmlAdjuster does not, so we have this flag for compatibility. + // If a member on an interface cannot be resolved and needs to be removed, remove the whole interface. + public bool RemoveInterfacesWithUnresolvableMembers { get; set; } = false; + + public static TypeResolutionOptions Default => new TypeResolutionOptions (); + + public static bool ResolveGenerics = true; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/DefaultProjectResolver.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/DefaultProjectResolver.cs new file mode 100644 index 00000000000..61581ac380c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/DefaultProjectResolver.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven; + +public class DefaultProjectResolver : IProjectResolver +{ + readonly Dictionary poms = new (); + + public void Register (Project project) + { + poms.Add (project.VersionedArtifactString, project); + } + + public virtual Project Resolve (Artifact artifact) + { + if (poms.TryGetValue (artifact.VersionedArtifactString, out var project)) + return project; + + throw new InvalidOperationException ($"No POM registered for {artifact}"); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Extensions/PropertyStack.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Extensions/PropertyStack.cs new file mode 100644 index 00000000000..b5f9b141363 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Extensions/PropertyStack.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Xml.Linq; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven.Extensions; + +class PropertyStack +{ + // Why go to this trouble? + // A property can be specified in both a child POM and its parent POM. + // Even if the property is being consumed in the parent POM, the property in + // the child POM takes precedence. + readonly List>> stack = new (); + + public void Push (ModelProperties? properties) + { + // We add a new list to the stack, even if it's empty, so that the Pop works later + var list = new List> (); + + if (properties?.Any is Collection props) + foreach (var prop in props) + list.Add (new KeyValuePair (prop.Name.LocalName, prop.Value)); + + stack.Add (list); + } + + public void Pop () + { + stack.RemoveAt (stack.Count - 1); + } + + public string Apply (string value) + { + if (stack.Count == 0 || !value.Contains ("${")) + return value; + + foreach (var property_set in stack) { + foreach (var prop in property_set) + value = value.Replace ($"${{{prop.Key}}}", prop.Value); + } + + return value; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Extensions/StringExtensions.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Extensions/StringExtensions.cs new file mode 100644 index 00000000000..7c75975a77f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Extensions/StringExtensions.cs @@ -0,0 +1,84 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop.Tools.Maven.Extensions; + +static class StringExtensions +{ + /// + /// Shortcut for !string.IsNullOrWhiteSpace (s) + /// + public static bool HasValue ([NotNullWhen (true)] this string? s) => !string.IsNullOrWhiteSpace (s); + + /// + /// Shortcut for s ?? string.Empty + /// + public static string OrEmpty (this string? str) => str ?? string.Empty; + + /// + /// Removes the first subset of a delimited string. ("127.0.0.1" -> "0.0.1") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? ChompFirst (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.IndexOf (separator); + + if (index < 0) + return string.Empty; + + return s.Substring (index + 1); + } + + /// + /// Removes the final subset of a delimited string. ("127.0.0.1" -> "127.0.0") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? ChompLast (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return string.Empty; + + return s.Substring (0, index); + } + + /// + /// Returns the first subset of a delimited string. ("127.0.0.1" -> "127") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? FirstSubset (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.IndexOf (separator); + + if (index < 0) + return s; + + return s.Substring (0, index); + } + + /// + /// Returns the final subset of a delimited string. ("127.0.0.1" -> "1") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? LastSubset (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return s; + + return s.Substring (index + 1); + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/IProjectResolver.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/IProjectResolver.cs new file mode 100644 index 00000000000..6e1533ded48 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/IProjectResolver.cs @@ -0,0 +1,8 @@ +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven; + +public interface IProjectResolver +{ + Project Resolve (Artifact artifact); +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Java.Interop.Tools.Maven.csproj b/external/Java.Interop/src/Java.Interop.Tools.Maven/Java.Interop.Tools.Maven.csproj new file mode 100644 index 00000000000..8202293636c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Java.Interop.Tools.Maven.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + enable + true + ..\..\product.snk + + + + + + $(UtilityOutputFullPath) + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Java.Interop.Tools.Maven.targets b/external/Java.Interop/src/Java.Interop.Tools.Maven/Java.Interop.Tools.Maven.targets new file mode 100644 index 00000000000..bda3aae042e --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Java.Interop.Tools.Maven.targets @@ -0,0 +1,42 @@ + + + + + + + + maven-4.0.0.xsd + + + + <_XscgenOpt Include="$(MavenXsd)" /> + <_XscgenOpt Include="--namespace http://maven.apache.org/POM/4.0.0=Java.Interop.Tools.Maven.Models" /> + <_XscgenOpt Include="--typeNameSubstitute T:Model=Project" /> + <_XscgenOpt Include="--nullable" /> + <_XscgenOpt Include="--pcl" /> + <_XscgenOpt Include="--netCore" /> + <_XscgenOpt Include="--nullableReferenceAttributes" /> + <_XscgenOpt Include="-o "Models"" /> + + + + + + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Artifact.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Artifact.cs new file mode 100644 index 00000000000..9c10518a148 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Artifact.cs @@ -0,0 +1,102 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop.Tools.Maven.Models; + +public class Artifact +{ + public string GroupId { get; } + + public string Id { get; } + + public string Version { get; } + + public string ArtifactString => $"{GroupId}:{Id}"; + + // Format should match Project.ArtifactString for comparisons. + public string VersionedArtifactString => $"{GroupId}:{Id}:{Version}"; + + public Artifact (string groupId, string artifactId, string version) + { + if (groupId is null) + throw new ArgumentNullException (nameof (groupId)); + if (artifactId is null) + throw new ArgumentNullException (nameof (artifactId)); + if (version is null) + throw new ArgumentNullException (nameof (version)); + if (!IsValidCoordinate (groupId)) + throw new ArgumentException ($"Invalid Maven groupId: '{groupId}'", nameof (groupId)); + if (!IsValidCoordinate (artifactId)) + throw new ArgumentException ($"Invalid Maven artifactId: '{artifactId}'", nameof (artifactId)); + // Allow empty version (callers may construct a partial coordinate when + // the version is to be inherited from a parent POM), but reject + // whitespace-only or otherwise malformed non-empty values. + if (version.Length > 0 && !IsValidVersion (version)) + throw new ArgumentException ($"Invalid Maven version: '{version}'", nameof (version)); + + Id = artifactId; + GroupId = groupId; + Version = version; + } + + public static Artifact Parse (string value) + { + if (TryParse (value, out var artifact)) + return artifact; + + throw new ArgumentException ($"Invalid artifact format: {value}"); + } + + public static bool TryParse (string? value, [NotNullWhen (true)]out Artifact? artifact) + { + artifact = null; + + if (value is null) + return false; + + var parts = value.Split ([':'], 4); + + if (parts.Length != 3) + return false; + + // Parsed coordinates must have all three parts fully populated. + if (!IsValidCoordinate (parts [0]) || !IsValidCoordinate (parts [1]) || !IsValidVersion (parts [2])) + return false; + + artifact = new Artifact (parts [0], parts [1], parts [2]); + + return true; + } + + // Per https://maven.apache.org/pom.html#Maven_Coordinates groupId/artifactId + // must match [A-Za-z0-9_\-.]+ + static bool IsValidCoordinate (string value) + { + if (string.IsNullOrWhiteSpace (value)) + return false; + foreach (var c in value) { + if (!((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '_' || c == '-' || c == '.')) + return false; + } + return true; + } + + // Maven versions are permissive; reject only obviously broken values + // (empty/whitespace, embedded whitespace, path separators, or ':' which + // would break parsing). + static bool IsValidVersion (string value) + { + if (string.IsNullOrWhiteSpace (value)) + return false; + foreach (var c in value) { + if (c == ':' || c == '/' || c == '\\' || char.IsWhiteSpace (c)) + return false; + } + return true; + } + + public override string ToString () => VersionedArtifactString; +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Dependency.Partial.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Dependency.Partial.cs new file mode 100644 index 00000000000..9ee5c918d55 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Dependency.Partial.cs @@ -0,0 +1,9 @@ +using Java.Interop.Tools.Maven.Extensions; + +namespace Java.Interop.Tools.Maven.Models; + +public partial class Dependency +{ + public Artifact ToArtifact () + => new Artifact (GroupId.OrEmpty (), ArtifactId.OrEmpty (), Version.OrEmpty ()); +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/MavenVersion.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/MavenVersion.cs new file mode 100644 index 00000000000..ffeb1291172 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/MavenVersion.cs @@ -0,0 +1,140 @@ +using System; +using Java.Interop.Tools.Maven.Extensions; + +namespace Java.Interop.Tools.Maven.Models; + +// https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855 +public class MavenVersion : IComparable, IComparable, IEquatable +{ + public string? Major { get; private set; } + public string? Minor { get; private set; } + public string? Patch { get; private set; } + public string RawVersion { get; private set; } + public bool IsValid { get; private set; } = true; + + MavenVersion (string rawVersion) => RawVersion = rawVersion; + + public static MavenVersion Parse (string version) + { + var mv = new MavenVersion (version); + + if (!version.HasValue ()) { + mv.IsValid = false; + return mv; + } + + // We're going to parse through this assuming it's a valid Maven version + mv.Major = version.FirstSubset ('.'); + version = version.ChompFirst ('.'); + + if (!TryParsePart (mv.Major, out var _, out var _)) + mv.IsValid = false; + + if (!version.HasValue ()) + return mv; + + mv.Minor = version.FirstSubset ('.'); + version = version.ChompFirst ('.'); + + if (!TryParsePart (mv.Minor, out var _, out var _)) + mv.IsValid = false; + + if (!version.HasValue ()) + return mv; + + mv.Patch = version.FirstSubset ('.'); + version = version.ChompFirst ('.'); + + if (!TryParsePart (mv.Patch, out var _, out var _)) + mv.IsValid = false; + + if (!version.HasValue ()) + return mv; + + // If there's something left, this is a nonstandard Maven version and all bets are off + mv.IsValid = false; + + return mv; + } + + public int CompareTo (object obj) + { + return CompareTo (obj as MavenVersion); + } + + public int CompareTo (MavenVersion? other) + { + if (other is null) + return 1; + + // If either instance is nonstandard, Maven does a simple string compare + if (!IsValid || !other.IsValid) + return string.Compare (RawVersion, other.RawVersion); + + var major_compare = ComparePart (Major ?? "0", other.Major ?? "0"); + + if (major_compare != 0) + return major_compare; + + var minor_compare = ComparePart (Minor ?? "0", other.Minor ?? "0"); + + if (minor_compare != 0) + return minor_compare; + + return ComparePart (Patch ?? "0", other.Patch ?? "0"); + } + + public bool Equals (MavenVersion other) + { + return CompareTo (other) == 0; + } + + int ComparePart (string a, string b) + { + // Check if they're the same string + if (a == b) + return 0; + + // Don't need to check the return because this shouldn't be called if IsValid = false + TryParsePart (a, out var a_version, out var a_qualifier); + TryParsePart (b, out var b_version, out var b_qualifier); + + // If neither have a qualifier, treat them like numbers + if (a_qualifier is null && b_qualifier is null) + return a_version.CompareTo (b_version); + + // If the numeric versions are different, just use those + if (a_version != b_version) + return a_version.CompareTo (b_version); + + // Identical versions with different qualifier fields are compared by using basic string comparison. + if (a_qualifier is not null && b_qualifier is not null) + return a_qualifier.CompareTo (b_qualifier); + + // All versions with a qualifier are older than the same version without a qualifier (release version). + if (a_qualifier is not null) + return -1; + + return 1; + } + + static bool TryParsePart (string part, out int version, out string? qualifier) + { + // These can look like: + // 1 + // 1-anything + var version_string = part.FirstSubset ('-'); + qualifier = null; + + // The first piece must be a number + if (!int.TryParse (version_string, out version)) + return false; + + part = part.ChompFirst ('-'); + + if (part.HasValue ()) + qualifier = part; + + return true; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/MavenVersionRange.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/MavenVersionRange.cs new file mode 100644 index 00000000000..083ee835797 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/MavenVersionRange.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using Java.Interop.Tools.Maven.Extensions; + +namespace Java.Interop.Tools.Maven.Models; + +public class MavenVersionRange +{ + public string? MinVersion { get; private set; } + public string? MaxVersion { get; private set; } + public bool IsMinInclusive { get; private set; } = true; + public bool IsMaxInclusive { get; private set; } + public bool HasLowerBound { get; private set; } + public bool HasUpperBound { get; private set; } + + // Adapted from https://github.com/Redth/MavenNet/blob/master/MavenNet/MavenVersionRange.cs + // Original version uses NuGetVersion, which doesn't cover all "valid" Maven version cases + public static IEnumerable Parse (string range) + { + if (!range.HasValue ()) + yield break; + + // Do a pass over the range string to parse out version groups + // eg: (1.0],(1.1,] + var in_group = false; + var current_group = string.Empty; + + foreach (var c in range) { + if (c == '(' || c == '[') { + current_group += c; + in_group = true; + } else if (c == ')' || c == ']' || (!in_group && c == ',')) { + // Don't add the , separating groups + if (in_group) + current_group += c; + + in_group = false; + + if (current_group.HasValue ()) + yield return ParseSingle (current_group); + + current_group = string.Empty; + } else { + current_group += c; + } + } + + if (!string.IsNullOrEmpty (current_group)) + yield return ParseSingle (current_group); + } + + static MavenVersionRange ParseSingle (string range) + { + var mv = new MavenVersionRange (); + + // Check for opening ( or [ + if (range [0] == '(') { + mv.IsMinInclusive = false; + range = range.Substring (1); + } else if (range [0] == '[') { + range = range.Substring (1); + } + + var last = range.Length - 1; + + // Check for closing ) or ] + if (range [last] == ')') { + mv.IsMaxInclusive = false; + range = range.Substring (0, last); + } else if (range [last] == ']') { + mv.IsMaxInclusive = true; + range = range.Substring (0, last); + } + + // Look for a single value + if (!range.Contains (",")) { + mv.MinVersion = range; + mv.HasLowerBound = true; + + // Special case [1.0] + if (mv.IsMinInclusive && mv.IsMaxInclusive) { + mv.MaxVersion = range; + mv.HasUpperBound = true; + } + + return mv; + } + + // Split the 2 values (note either can be empty) + var lower = range.FirstSubset (',').Trim (); + var upper = range.LastSubset (',').Trim (); + + if (lower.HasValue ()) { + mv.MinVersion = lower; + mv.HasLowerBound = true; + } + + if (upper.HasValue ()) { + mv.MaxVersion = upper; + mv.HasUpperBound = true; + } + + return mv; + } + + public bool ContainsVersion (MavenVersion version) + { + if (HasLowerBound) { + var min_version = MavenVersion.Parse (MinVersion!); + + if (IsMinInclusive && version.CompareTo (min_version) < 0) + return false; + else if (!IsMinInclusive && version.CompareTo (min_version) <= 0) + return false; + } + + if (HasUpperBound) { + var max_version = MavenVersion.Parse (MaxVersion!); + + if (IsMaxInclusive && version.CompareTo (max_version) > 0) + return false; + else if (!IsMaxInclusive && version.CompareTo (max_version) >= 0) + return false; + } + + return true; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Project.Partial.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Project.Partial.cs new file mode 100644 index 00000000000..44e7f7aefc4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Project.Partial.cs @@ -0,0 +1,55 @@ +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using Java.Interop.Tools.Maven.Extensions; + +namespace Java.Interop.Tools.Maven.Models; + +public partial class Project +{ + static readonly XmlSerializer xml_serializer = new (typeof (Project)); + + public static Project Load (Stream stream) + { + using (var xr = new XmlTextReader (stream) { Namespaces = false }) + return Load (xr); + } + + public static Project Load (XmlReader reader) + => (Project) xml_serializer.Deserialize (reader); + + public static Project Parse (string xml) + { + using (var sr = new StringReader (xml)) + using (var xr = new XmlTextReader (sr) { Namespaces = false }) + return Load (xr); + } + + public bool TryGetParentPomArtifact ([NotNullWhen (true)] out Artifact? parent) + { + parent = null; + + if (Parent is not null) { + parent = new Artifact (Parent.GroupId.OrEmpty (), Parent.ArtifactId.OrEmpty (), Parent.Version.OrEmpty ()); + return true; + } + + return false; + } + + public override string ToString () => VersionedArtifactString; + + public string ToXml () + { + var serializer = new XmlSerializer (typeof (Project)); + + using (var sw = new StringWriter ()) { + serializer.Serialize (sw, this); + return sw.ToString (); + } + } + + // Format should match Artifact.VersionedArtifactString for comparisons. + public string VersionedArtifactString => $"{GroupId}:{ArtifactId}:{Version}"; +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Project.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Project.cs new file mode 100644 index 00000000000..5f2359a90ae --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/Project.cs @@ -0,0 +1,5960 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// This code was generated by XmlSchemaClassGenerator version 2.1.1057.0 using the following command: +// xscgen maven-4.0.0.xsd --namespace http://maven.apache.org/POM/4.0.0=Java.Interop.Tools.Maven.Models --typeNameSubstitute T:Model=Project --nullable --pcl --netCore --nullableReferenceAttributes -o Models +namespace Java.Interop.Tools.Maven.Models +{ + + + /// + /// 3.0.0+ + /// The <code>&lt;project&gt;</code> element is the root of the descriptor. + /// The following table lists all of the possible child elements. + /// 3.0.0+ + /// The <code>&lt;project&gt;</code> element is the root of the descriptor. + /// The following table lists all of the possible child elements. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Model")] + [System.Xml.Serialization.XmlRootAttribute("project")] + public partial class Project + { + + /// + /// 4.0.0+ + /// Declares to which version of project descriptor this POM conforms. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("modelVersion")] + public string ModelVersion { get; set; } + + /// + /// 4.0.0+ + /// The location of the parent project, if one exists. Values from the parent + /// project will be the default for this project if they are left unspecified. The location + /// is given as a group ID, artifact ID and version. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("parent")] + public Parent Parent { get; set; } + + /// + /// 3.0.0+ + /// A universally unique identifier for a project. It is normal to + /// use a fully-qualified package name to distinguish it from other + /// projects with a similar name (eg. <code>org.apache.maven</code>). + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId { get; set; } + + /// + /// 3.0.0+ + /// The identifier for this artifact that is unique within the group given by the + /// group ID. An artifact is something that is either produced or used by a project. + /// Examples of artifacts produced by Maven for a project include: JARs, source and binary + /// distributions, and WARs. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 4.0.0+ + /// The current version of the artifact produced by this project. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _packaging = "jar"; + + /// + /// 4.0.0+ + /// The type of artifact this project produces, for example <code>jar</code> + /// <code>war</code> + /// <code>ear</code> + /// <code>pom</code>. + /// Plugins can create their own packaging, and + /// therefore their own packaging types, + /// so this list does not contain all possible types. + /// + [System.ComponentModel.DefaultValueAttribute("jar")] + [System.Xml.Serialization.XmlElementAttribute("packaging")] + public string Packaging + { + get + { + return _packaging; + } + set + { + _packaging = value; + } + } + + /// + /// 3.0.0+ + /// The full name of the project. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 3.0.0+ + /// A detailed description of the project, used by Maven whenever it needs to + /// describe the project, such as on the web site. While this element can be specified as + /// CDATA to enable the use of HTML tags within the description, it is discouraged to allow + /// plain text representation. If you need to modify the index page of the generated web + /// site, you are able to specify your own instead of adjusting this text. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("description")] + public string Description { get; set; } + + /// + /// 3.0.0+ + /// The URL to the project's homepage. + /// <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if + /// project's <code>child.project.url.inherit.append.path="false"</code> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + /// + /// 3.0.0+ + /// The year of the project's inception, specified with 4 digits. This value is + /// used when generating copyright notices as well as being informational. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("inceptionYear")] + public string InceptionYear { get; set; } + + /// + /// 3.0.0+ + /// This element describes various attributes of the organization to which the + /// project belongs. These attributes are utilized when documentation is created (for + /// copyright notices and links). + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("organization")] + public Organization Organization { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _licenses; + + /// + /// 3.0.0+ + /// This element describes all of the licenses for this project. + /// Each license is described by a <code>license</code> element, which + /// is then described by additional elements. + /// Projects should only list the license(s) that applies to the project + /// and not the licenses that apply to dependencies. + /// If multiple licenses are listed, it is assumed that the user can select + /// any of them, not that they must accept all. + /// + [System.Xml.Serialization.XmlArrayAttribute("licenses")] + [System.Xml.Serialization.XmlArrayItemAttribute("license")] + public System.Collections.ObjectModel.Collection Licenses + { + get + { + return _licenses; + } + private set + { + _licenses = value; + } + } + + /// + /// Gets a value indicating whether the Licenses collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool LicensesSpecified + { + get + { + return (this.Licenses.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Project() + { + this._licenses = new System.Collections.ObjectModel.Collection(); + this._developers = new System.Collections.ObjectModel.Collection(); + this._contributors = new System.Collections.ObjectModel.Collection(); + this._mailingLists = new System.Collections.ObjectModel.Collection(); + this._modules = new System.Collections.ObjectModel.Collection(); + this._dependencies = new System.Collections.ObjectModel.Collection(); + this._repositories = new System.Collections.ObjectModel.Collection(); + this._pluginRepositories = new System.Collections.ObjectModel.Collection(); + this._profiles = new System.Collections.ObjectModel.Collection(); + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _developers; + + /// + /// 3.0.0+ + /// Describes the committers of a project. + /// + [System.Xml.Serialization.XmlArrayAttribute("developers")] + [System.Xml.Serialization.XmlArrayItemAttribute("developer")] + public System.Collections.ObjectModel.Collection Developers + { + get + { + return _developers; + } + private set + { + _developers = value; + } + } + + /// + /// Gets a value indicating whether the Developers collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DevelopersSpecified + { + get + { + return (this.Developers.Count != 0); + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _contributors; + + /// + /// 3.0.0+ + /// Describes the contributors to a project that are not yet committers. + /// + [System.Xml.Serialization.XmlArrayAttribute("contributors")] + [System.Xml.Serialization.XmlArrayItemAttribute("contributor")] + public System.Collections.ObjectModel.Collection Contributors + { + get + { + return _contributors; + } + private set + { + _contributors = value; + } + } + + /// + /// Gets a value indicating whether the Contributors collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ContributorsSpecified + { + get + { + return (this.Contributors.Count != 0); + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _mailingLists; + + /// + /// 3.0.0+ + /// Contains information about a project's mailing lists. + /// + [System.Xml.Serialization.XmlArrayAttribute("mailingLists")] + [System.Xml.Serialization.XmlArrayItemAttribute("mailingList")] + public System.Collections.ObjectModel.Collection MailingLists + { + get + { + return _mailingLists; + } + private set + { + _mailingLists = value; + } + } + + /// + /// Gets a value indicating whether the MailingLists collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MailingListsSpecified + { + get + { + return (this.MailingLists.Count != 0); + } + } + + /// + /// 4.0.0+ + /// Describes the prerequisites in the build environment for this project. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("prerequisites")] + public Prerequisites Prerequisites { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _modules; + + /// + /// 4.0.0+ + /// The modules (sometimes called subprojects) to build as a part of this + /// project. Each module listed is a relative path to the directory containing the module. + /// To be consistent with the way default urls are calculated from parent, it is recommended + /// to have module names match artifact ids. + /// + [System.Xml.Serialization.XmlArrayAttribute("modules")] + [System.Xml.Serialization.XmlArrayItemAttribute("module")] + public System.Collections.ObjectModel.Collection Modules + { + get + { + return _modules; + } + private set + { + _modules = value; + } + } + + /// + /// Gets a value indicating whether the Modules collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ModulesSpecified + { + get + { + return (this.Modules.Count != 0); + } + } + + /// + /// 4.0.0+ + /// Specification for the SCM used by the project, such as CVS, Subversion, etc. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("scm")] + public Scm Scm { get; set; } + + /// + /// 4.0.0+ + /// The project's issue management system information. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("issueManagement")] + public IssueManagement IssueManagement { get; set; } + + /// + /// 4.0.0+ + /// The project's continuous integration information. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("ciManagement")] + public CiManagement CiManagement { get; set; } + + /// + /// 4.0.0+ + /// Distribution information for a project that enables deployment of the site + /// and artifacts to remote web servers and repositories respectively. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("distributionManagement")] + public DistributionManagement DistributionManagement { get; set; } + + /// + /// 4.0.0+ + /// Properties that can be used throughout the POM as a substitution, and + /// are used as filters in resources if enabled. + /// The format is <code>&lt;name&gt;value&lt;/name&gt;</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("properties")] + public ModelProperties Properties { get; set; } + + /// + /// 4.0.0+ + /// Default dependency information for projects that inherit from this one. The + /// dependencies in this section are not immediately resolved. Instead, when a POM derived + /// from this one declares a dependency described by a matching groupId and artifactId, the + /// version and other values from this section are used for that dependency if they were not + /// already specified. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("dependencyManagement")] + public DependencyManagement DependencyManagement { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependencies; + + /// + /// 3.0.0+ + /// This element describes all of the dependencies associated with a + /// project. + /// These dependencies are used to construct a classpath for your + /// project during the build process. They are automatically downloaded from the + /// repositories defined in this project. + /// See <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">the + /// dependency mechanism</a> for more information. + /// + [System.Xml.Serialization.XmlArrayAttribute("dependencies")] + [System.Xml.Serialization.XmlArrayItemAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependencies + { + get + { + return _dependencies; + } + private set + { + _dependencies = value; + } + } + + /// + /// Gets a value indicating whether the Dependencies collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependenciesSpecified + { + get + { + return (this.Dependencies.Count != 0); + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _repositories; + + /// + /// 4.0.0+ + /// The lists of the remote repositories for discovering dependencies and + /// extensions. + /// + [System.Xml.Serialization.XmlArrayAttribute("repositories")] + [System.Xml.Serialization.XmlArrayItemAttribute("repository")] + public System.Collections.ObjectModel.Collection Repositories + { + get + { + return _repositories; + } + private set + { + _repositories = value; + } + } + + /// + /// Gets a value indicating whether the Repositories collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RepositoriesSpecified + { + get + { + return (this.Repositories.Count != 0); + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _pluginRepositories; + + /// + /// 4.0.0+ + /// The lists of the remote repositories for discovering plugins for builds and + /// reports. + /// + [System.Xml.Serialization.XmlArrayAttribute("pluginRepositories")] + [System.Xml.Serialization.XmlArrayItemAttribute("pluginRepository")] + public System.Collections.ObjectModel.Collection PluginRepositories + { + get + { + return _pluginRepositories; + } + private set + { + _pluginRepositories = value; + } + } + + /// + /// Gets a value indicating whether the PluginRepositories collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginRepositoriesSpecified + { + get + { + return (this.PluginRepositories.Count != 0); + } + } + + /// + /// 3.0.0+ + /// Information required to build the project. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("build")] + public Build Build { get; set; } + + /// + /// 4.0.0+ + /// <b>Deprecated</b>. Now ignored by Maven. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("reports")] + public ModelReports Reports { get; set; } + + /// + /// 4.0.0+ + /// This element includes the specification of report plugins to use + /// to generate the reports on the Maven-generated site. + /// These reports will be run when a user executes <code>mvn site</code>. + /// All of the reports will be included in the navigation bar for browsing. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("reporting")] + public Reporting Reporting { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _profiles; + + /// + /// 4.0.0+ + /// A listing of project-local build profiles which will modify the build process + /// when activated. + /// + [System.Xml.Serialization.XmlArrayAttribute("profiles")] + [System.Xml.Serialization.XmlArrayItemAttribute("profile")] + public System.Collections.ObjectModel.Collection Profiles + { + get + { + return _profiles; + } + private set + { + _profiles = value; + } + } + + /// + /// Gets a value indicating whether the Profiles collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProfilesSpecified + { + get + { + return (this.Profiles.Count != 0); + } + } + + /// + /// 4.0.0+ + /// When children inherit from project's url, append path or not? Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code> + /// <br><b>Default value is</b>: <code>true</code> + /// <br><b>Since</b>: Maven 3.6.1 + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlAttributeAttribute("child.project.url.inherit.append.path")] + public string ChildProjectUrlInheritAppendPath { get; set; } + } + + /// + /// 4.0.0+ + /// The <code>&lt;parent&gt;</code> element contains information required to locate the parent project from which + /// this project will inherit from. + /// <strong>Note:</strong> The children of this element are not interpolated and must be given as literal values. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Parent")] + public partial class Parent + { + + /// + /// 4.0.0+ + /// The group id of the parent project to inherit from. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId { get; set; } + + /// + /// 4.0.0+ + /// The artifact id of the parent project to inherit from. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 4.0.0+ + /// The version of the parent project to inherit. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _relativePath = "../pom.xml"; + + /// + /// 4.0.0+ + /// The relative path of the parent <code>pom.xml</code> file within the check out. + /// If not specified, it defaults to <code>../pom.xml</code>. + /// Maven looks for the parent POM first in this location on + /// the filesystem, then the local repository, and lastly in the remote repo. + /// <code>relativePath</code> allows you to select a different location, + /// for example when your structure is flat, or deeper without an intermediate parent POM. + /// However, the group ID, artifact ID and version are still required, + /// and must match the file in the location given or it will revert to the repository for the POM. + /// This feature is only for enhancing the development in a local checkout of that project. + /// Set the value to an empty string in case you want to disable the feature and always resolve + /// the parent POM from the repositories. + /// + [System.ComponentModel.DefaultValueAttribute("../pom.xml")] + [System.Xml.Serialization.XmlElementAttribute("relativePath")] + public string RelativePath + { + get + { + return _relativePath; + } + set + { + _relativePath = value; + } + } + } + + /// + /// 3.0.0+ + /// Specifies the organization that produces this project. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Organization")] + public partial class Organization + { + + /// + /// 3.0.0+ + /// The full name of the organization. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 3.0.0+ + /// The URL to the organization's home page. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelLicenses", AnonymousType=true)] + public partial class ModelLicenses + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _license; + + [System.Xml.Serialization.XmlElementAttribute("license")] + public System.Collections.ObjectModel.Collection License + { + get + { + return _license; + } + private set + { + _license = value; + } + } + + /// + /// Gets a value indicating whether the License collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool LicenseSpecified + { + get + { + return (this.License.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelLicenses() + { + this._license = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 3.0.0+ + /// Describes the licenses for this project. This is used to generate the license + /// page of the project's web site, as well as being taken into consideration in other reporting + /// and validation. The licenses listed for the project are that of the project itself, and not + /// of dependencies. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("License")] + public partial class License + { + + /// + /// 3.0.0+ + /// The full legal name of the license. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 3.0.0+ + /// The official url for the license text. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + /// + /// 3.0.0+ + /// The primary method by which this project may be distributed. + /// <dl> + /// <dt>repo</dt> + /// <dd>may be downloaded from the Maven repository</dd> + /// <dt>manual</dt> + /// <dd>user must manually download and install the dependency.</dd> + /// </dl> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("distribution")] + public string Distribution { get; set; } + + /// + /// 3.0.0+ + /// Addendum information pertaining to this license. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("comments")] + public string Comments { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelDevelopers", AnonymousType=true)] + public partial class ModelDevelopers + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _developer; + + [System.Xml.Serialization.XmlElementAttribute("developer")] + public System.Collections.ObjectModel.Collection Developer + { + get + { + return _developer; + } + private set + { + _developer = value; + } + } + + /// + /// Gets a value indicating whether the Developer collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DeveloperSpecified + { + get + { + return (this.Developer.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelDevelopers() + { + this._developer = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 3.0.0+ + /// Information about one of the committers on this project. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Developer")] + public partial class Developer + { + + /// + /// 3.0.0+ + /// The unique ID of the developer in the SCM. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("id")] + public string Id { get; set; } + + /// + /// 3.0.0+ + /// The full name of the contributor. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 3.0.0+ + /// The email address of the contributor. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("email")] + public string Email { get; set; } + + /// + /// 3.0.0+ + /// The URL for the homepage of the contributor. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + /// + /// 3.0.0+ + /// The organization to which the contributor belongs. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("organization")] + public string Organization { get; set; } + + /// + /// 3.0.0+ + /// The URL of the organization. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("organizationUrl")] + public string OrganizationUrl { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _roles; + + /// + /// 3.0.0+ + /// The roles the contributor plays in the project. Each role is described by a + /// <code>role</code> element, the body of which is a role name. This can also be used to + /// describe the contribution. + /// + [System.Xml.Serialization.XmlArrayAttribute("roles")] + [System.Xml.Serialization.XmlArrayItemAttribute("role")] + public System.Collections.ObjectModel.Collection Roles + { + get + { + return _roles; + } + private set + { + _roles = value; + } + } + + /// + /// Gets a value indicating whether the Roles collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RolesSpecified + { + get + { + return (this.Roles.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Developer() + { + this._roles = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 3.0.0+ + /// The timezone the contributor is in. Typically, this is a number in the range + /// <a href="http://en.wikipedia.org/wiki/UTC%E2%88%9212:00">-12</a> to <a href="http://en.wikipedia.org/wiki/UTC%2B14:00">+14</a> + /// or a valid time zone id like "America/Montreal" (UTC-05:00) or "Europe/Paris" (UTC+01:00). + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("timezone")] + public string Timezone { get; set; } + + /// + /// 3.0.0+ + /// Properties about the contributor, such as an instant messenger handle. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("properties")] + public DeveloperProperties Properties { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("DeveloperRoles", AnonymousType=true)] + public partial class DeveloperRoles + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _role; + + [System.Xml.Serialization.XmlElementAttribute("role")] + public System.Collections.ObjectModel.Collection Role + { + get + { + return _role; + } + private set + { + _role = value; + } + } + + /// + /// Gets a value indicating whether the Role collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RoleSpecified + { + get + { + return (this.Role.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public DeveloperRoles() + { + this._role = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("DeveloperProperties", AnonymousType=true)] + public partial class DeveloperProperties + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public DeveloperProperties() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelContributors", AnonymousType=true)] + public partial class ModelContributors + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _contributor; + + [System.Xml.Serialization.XmlElementAttribute("contributor")] + public System.Collections.ObjectModel.Collection Contributor + { + get + { + return _contributor; + } + private set + { + _contributor = value; + } + } + + /// + /// Gets a value indicating whether the Contributor collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ContributorSpecified + { + get + { + return (this.Contributor.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelContributors() + { + this._contributor = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 3.0.0+ + /// Description of a person who has contributed to the project, but who does not have + /// commit privileges. Usually, these contributions come in the form of patches submitted. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Contributor")] + public partial class Contributor + { + + /// + /// 3.0.0+ + /// The full name of the contributor. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 3.0.0+ + /// The email address of the contributor. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("email")] + public string Email { get; set; } + + /// + /// 3.0.0+ + /// The URL for the homepage of the contributor. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + /// + /// 3.0.0+ + /// The organization to which the contributor belongs. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("organization")] + public string Organization { get; set; } + + /// + /// 3.0.0+ + /// The URL of the organization. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("organizationUrl")] + public string OrganizationUrl { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _roles; + + /// + /// 3.0.0+ + /// The roles the contributor plays in the project. Each role is described by a + /// <code>role</code> element, the body of which is a role name. This can also be used to + /// describe the contribution. + /// + [System.Xml.Serialization.XmlArrayAttribute("roles")] + [System.Xml.Serialization.XmlArrayItemAttribute("role")] + public System.Collections.ObjectModel.Collection Roles + { + get + { + return _roles; + } + private set + { + _roles = value; + } + } + + /// + /// Gets a value indicating whether the Roles collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RolesSpecified + { + get + { + return (this.Roles.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Contributor() + { + this._roles = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 3.0.0+ + /// The timezone the contributor is in. Typically, this is a number in the range + /// <a href="http://en.wikipedia.org/wiki/UTC%E2%88%9212:00">-12</a> to <a href="http://en.wikipedia.org/wiki/UTC%2B14:00">+14</a> + /// or a valid time zone id like "America/Montreal" (UTC-05:00) or "Europe/Paris" (UTC+01:00). + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("timezone")] + public string Timezone { get; set; } + + /// + /// 3.0.0+ + /// Properties about the contributor, such as an instant messenger handle. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("properties")] + public ContributorProperties Properties { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ContributorRoles", AnonymousType=true)] + public partial class ContributorRoles + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _role; + + [System.Xml.Serialization.XmlElementAttribute("role")] + public System.Collections.ObjectModel.Collection Role + { + get + { + return _role; + } + private set + { + _role = value; + } + } + + /// + /// Gets a value indicating whether the Role collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RoleSpecified + { + get + { + return (this.Role.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ContributorRoles() + { + this._role = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ContributorProperties", AnonymousType=true)] + public partial class ContributorProperties + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ContributorProperties() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelMailingLists", AnonymousType=true)] + public partial class ModelMailingLists + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _mailingList; + + [System.Xml.Serialization.XmlElementAttribute("mailingList")] + public System.Collections.ObjectModel.Collection MailingList + { + get + { + return _mailingList; + } + private set + { + _mailingList = value; + } + } + + /// + /// Gets a value indicating whether the MailingList collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MailingListSpecified + { + get + { + return (this.MailingList.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelMailingLists() + { + this._mailingList = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 3.0.0+ + /// This element describes all of the mailing lists associated with a project. The + /// auto-generated site references this information. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("MailingList")] + public partial class MailingList + { + + /// + /// 3.0.0+ + /// The name of the mailing list. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 3.0.0+ + /// The email address or link that can be used to subscribe to + /// the mailing list. If this is an email address, a + /// <code>mailto:</code> link will automatically be created + /// when the documentation is created. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("subscribe")] + public string Subscribe { get; set; } + + /// + /// 3.0.0+ + /// The email address or link that can be used to unsubscribe to + /// the mailing list. If this is an email address, a + /// <code>mailto:</code> link will automatically be created + /// when the documentation is created. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("unsubscribe")] + public string Unsubscribe { get; set; } + + /// + /// 3.0.0+ + /// The email address or link that can be used to post to + /// the mailing list. If this is an email address, a + /// <code>mailto:</code> link will automatically be created + /// when the documentation is created. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("post")] + public string Post { get; set; } + + /// + /// 3.0.0+ + /// The link to a URL where you can browse the mailing list archive. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("archive")] + public string Archive { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _otherArchives; + + /// + /// 3.0.0+ + /// The link to alternate URLs where you can browse the list archive. + /// + [System.Xml.Serialization.XmlArrayAttribute("otherArchives")] + [System.Xml.Serialization.XmlArrayItemAttribute("otherArchive")] + public System.Collections.ObjectModel.Collection OtherArchives + { + get + { + return _otherArchives; + } + private set + { + _otherArchives = value; + } + } + + /// + /// Gets a value indicating whether the OtherArchives collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool OtherArchivesSpecified + { + get + { + return (this.OtherArchives.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public MailingList() + { + this._otherArchives = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("MailingListOtherArchives", AnonymousType=true)] + public partial class MailingListOtherArchives + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _otherArchive; + + [System.Xml.Serialization.XmlElementAttribute("otherArchive")] + public System.Collections.ObjectModel.Collection OtherArchive + { + get + { + return _otherArchive; + } + private set + { + _otherArchive = value; + } + } + + /// + /// Gets a value indicating whether the OtherArchive collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool OtherArchiveSpecified + { + get + { + return (this.OtherArchive.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public MailingListOtherArchives() + { + this._otherArchive = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Describes the prerequisites a project can have. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Prerequisites")] + public partial class Prerequisites + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _maven = "2.0"; + + /// + /// 4.0.0+ + /// For a plugin project (packaging is <code>maven-plugin</code>), the minimum version of + /// Maven required to use the resulting plugin.<br> + /// + [System.ComponentModel.DefaultValueAttribute("2.0")] + [System.Xml.Serialization.XmlElementAttribute("maven")] + public string Maven + { + get + { + return _maven; + } + set + { + _maven = value; + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelModules", AnonymousType=true)] + public partial class ModelModules + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _module; + + [System.Xml.Serialization.XmlElementAttribute("module")] + public System.Collections.ObjectModel.Collection Module + { + get + { + return _module; + } + private set + { + _module = value; + } + } + + /// + /// Gets a value indicating whether the Module collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ModuleSpecified + { + get + { + return (this.Module.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelModules() + { + this._module = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// The <code>&lt;scm&gt;</code> element contains informations required to the SCM + /// (Source Control Management) of the project. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Scm")] + public partial class Scm + { + + /// + /// 4.0.0+ + /// The source control management system URL + /// that describes the repository and how to connect to the + /// repository. For more information, see the + /// <a href="https://maven.apache.org/scm/scm-url-format.html">URL format</a> + /// and <a href="https://maven.apache.org/scm/scms-overview.html">list of supported SCMs</a>. + /// This connection is read-only. + /// <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if + /// scm's <code>child.scm.connection.inherit.append.path="false"</code> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("connection")] + public string Connection { get; set; } + + /// + /// 4.0.0+ + /// Just like <code>connection</code>, but for developers, i.e. this scm connection + /// will not be read only. + /// <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if + /// scm's <code>child.scm.developerConnection.inherit.append.path="false"</code> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("developerConnection")] + public string DeveloperConnection { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _tag = "HEAD"; + + /// + /// 4.0.0+ + /// The tag of current code. By default, it's set to HEAD during development. + /// + [System.ComponentModel.DefaultValueAttribute("HEAD")] + [System.Xml.Serialization.XmlElementAttribute("tag")] + public string Tag + { + get + { + return _tag; + } + set + { + _tag = value; + } + } + + /// + /// 4.0.0+ + /// The URL to the project's browsable SCM repository, such as ViewVC or Fisheye. + /// <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if + /// scm's <code>child.scm.url.inherit.append.path="false"</code> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + /// + /// 4.0.0+ + /// When children inherit from scm connection, append path or not? Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code> + /// <br><b>Default value is</b>: <code>true</code> + /// <br><b>Since</b>: Maven 3.6.1 + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlAttributeAttribute("child.scm.connection.inherit.append.path")] + public string ChildScmConnectionInheritAppendPath { get; set; } + + /// + /// 4.0.0+ + /// When children inherit from scm developer connection, append path or not? Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code> + /// <br><b>Default value is</b>: <code>true</code> + /// <br><b>Since</b>: Maven 3.6.1 + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlAttributeAttribute("child.scm.developerConnection.inherit.append.path")] + public string ChildScmDeveloperConnectionInheritAppendPath { get; set; } + + /// + /// 4.0.0+ + /// When children inherit from scm url, append path or not? Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code> + /// <br><b>Default value is</b>: <code>true</code> + /// <br><b>Since</b>: Maven 3.6.1 + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlAttributeAttribute("child.scm.url.inherit.append.path")] + public string ChildScmUrlInheritAppendPath { get; set; } + } + + /// + /// 4.0.0+ + /// Information about the issue tracking (or bug tracking) system used to manage this + /// project. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("IssueManagement")] + public partial class IssueManagement + { + + /// + /// 4.0.0+ + /// The name of the issue management system, e.g. Bugzilla + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("system")] + public string System { get; set; } + + /// + /// 4.0.0+ + /// URL for the issue management system used by the project. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + } + + /// + /// 4.0.0+ + /// The <code>&lt;CiManagement&gt;</code> element contains informations required to the + /// continuous integration system of the project. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("CiManagement")] + public partial class CiManagement + { + + /// + /// 4.0.0+ + /// The name of the continuous integration system, e.g. <code>continuum</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("system")] + public string System { get; set; } + + /// + /// 4.0.0+ + /// URL for the continuous integration system used by the project if it has a web + /// interface. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _notifiers; + + /// + /// 4.0.0+ + /// Configuration for notifying developers/users when a build is unsuccessful, + /// including user information and notification mode. + /// + [System.Xml.Serialization.XmlArrayAttribute("notifiers")] + [System.Xml.Serialization.XmlArrayItemAttribute("notifier")] + public System.Collections.ObjectModel.Collection Notifiers + { + get + { + return _notifiers; + } + private set + { + _notifiers = value; + } + } + + /// + /// Gets a value indicating whether the Notifiers collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool NotifiersSpecified + { + get + { + return (this.Notifiers.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public CiManagement() + { + this._notifiers = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("CiManagementNotifiers", AnonymousType=true)] + public partial class CiManagementNotifiers + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _notifier; + + [System.Xml.Serialization.XmlElementAttribute("notifier")] + public System.Collections.ObjectModel.Collection Notifier + { + get + { + return _notifier; + } + private set + { + _notifier = value; + } + } + + /// + /// Gets a value indicating whether the Notifier collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool NotifierSpecified + { + get + { + return (this.Notifier.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public CiManagementNotifiers() + { + this._notifier = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Configures one method for notifying users/developers when a build breaks. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Notifier")] + public partial class Notifier + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _type = "mail"; + + /// + /// 4.0.0+ + /// The mechanism used to deliver notifications. + /// + [System.ComponentModel.DefaultValueAttribute("mail")] + [System.Xml.Serialization.XmlElementAttribute("type")] + public string Type + { + get + { + return _type; + } + set + { + _type = value; + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private bool _sendOnError = true; + + /// + /// 4.0.0+ + /// Whether to send notifications on error. + /// + [System.ComponentModel.DefaultValueAttribute(true)] + [System.Xml.Serialization.XmlElementAttribute("sendOnError")] + public bool SendOnError + { + get + { + return _sendOnError; + } + set + { + _sendOnError = value; + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private bool _sendOnFailure = true; + + /// + /// 4.0.0+ + /// Whether to send notifications on failure. + /// + [System.ComponentModel.DefaultValueAttribute(true)] + [System.Xml.Serialization.XmlElementAttribute("sendOnFailure")] + public bool SendOnFailure + { + get + { + return _sendOnFailure; + } + set + { + _sendOnFailure = value; + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private bool _sendOnSuccess = true; + + /// + /// 4.0.0+ + /// Whether to send notifications on success. + /// + [System.ComponentModel.DefaultValueAttribute(true)] + [System.Xml.Serialization.XmlElementAttribute("sendOnSuccess")] + public bool SendOnSuccess + { + get + { + return _sendOnSuccess; + } + set + { + _sendOnSuccess = value; + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private bool _sendOnWarning = true; + + /// + /// 4.0.0+ + /// Whether to send notifications on warning. + /// + [System.ComponentModel.DefaultValueAttribute(true)] + [System.Xml.Serialization.XmlElementAttribute("sendOnWarning")] + public bool SendOnWarning + { + get + { + return _sendOnWarning; + } + set + { + _sendOnWarning = value; + } + } + + /// + /// 4.0.0+ + /// <b>Deprecated</b>. Where to send the notification to - eg email address. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("address")] + public string Address { get; set; } + + /// + /// 0.0.0+ + /// Extended configuration specific to this notifier goes here. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("configuration")] + public NotifierConfiguration Configuration { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("NotifierConfiguration", AnonymousType=true)] + public partial class NotifierConfiguration + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public NotifierConfiguration() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// This elements describes all that pertains to distribution for a project. It is + /// primarily used for deployment of artifacts and the site produced by the build. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("DistributionManagement")] + public partial class DistributionManagement + { + + /// + /// 4.0.0+ + /// Information needed to deploy the artifacts generated by the project to a + /// remote repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("repository")] + public DeploymentRepository Repository { get; set; } + + /// + /// 4.0.0+ + /// Where to deploy snapshots of artifacts to. If not given, it defaults to the + /// <code>repository</code> element. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("snapshotRepository")] + public DeploymentRepository SnapshotRepository { get; set; } + + /// + /// 4.0.0+ + /// Information needed for deploying the web site of the project. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("site")] + public Site Site { get; set; } + + /// + /// 4.0.0+ + /// The URL of the project's download page. If not given users will be + /// referred to the homepage given by <code>url</code>. + /// This is given to assist in locating artifacts that are not in the repository due to + /// licensing restrictions. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("downloadUrl")] + public string DownloadUrl { get; set; } + + /// + /// 4.0.0+ + /// Relocation information of the artifact if it has been moved to a new group ID + /// and/or artifact ID. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("relocation")] + public Relocation Relocation { get; set; } + + /// + /// 4.0.0+ + /// Gives the status of this artifact in the remote repository. + /// This must not be set in your local project, as it is updated by + /// tools placing it in the reposiory. Valid values are: <code>none</code> (default), + /// <code>converted</code> (repository manager converted this from an Maven 1 POM), + /// <code>partner</code> + /// (directly synced from a partner Maven 2 repository), <code>deployed</code> (was deployed from a Maven 2 + /// instance), <code>verified</code> (has been hand verified as correct and final). + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("status")] + public string Status { get; set; } + } + + /// + /// 4.0.0+ + /// Repository contains the information needed for deploying to the remote + /// repository. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("DeploymentRepository")] + public partial class DeploymentRepository + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private bool _uniqueVersion = true; + + /// + /// 4.0.0+ + /// Whether to assign snapshots a unique version comprised of the timestamp and + /// build number, or to use the same version each time + /// + [System.ComponentModel.DefaultValueAttribute(true)] + [System.Xml.Serialization.XmlElementAttribute("uniqueVersion")] + public bool UniqueVersion + { + get + { + return _uniqueVersion; + } + set + { + _uniqueVersion = value; + } + } + + /// + /// 4.0.0+ + /// How to handle downloading of releases from this repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("releases")] + public RepositoryPolicy Releases { get; set; } + + /// + /// 4.0.0+ + /// How to handle downloading of snapshots from this repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("snapshots")] + public RepositoryPolicy Snapshots { get; set; } + + /// + /// 4.0.0+ + /// A unique identifier for a repository. This is used to match the repository + /// to configuration in the <code>settings.xml</code> file, for example. Furthermore, the identifier is + /// used during POM inheritance and profile injection to detect repositories that should be merged. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("id")] + public string Id { get; set; } + + /// + /// 4.0.0+ + /// Human readable name of the repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 4.0.0+ + /// The url of the repository, in the form <code>protocol://hostname/path</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _layout = "default"; + + /// + /// 4.0.0+ + /// The type of layout this repository uses for locating and storing artifacts - + /// can be <code>legacy</code> or <code>default</code>. + /// + [System.ComponentModel.DefaultValueAttribute("default")] + [System.Xml.Serialization.XmlElementAttribute("layout")] + public string Layout + { + get + { + return _layout; + } + set + { + _layout = value; + } + } + } + + /// + /// 4.0.0+ + /// Download policy. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("RepositoryPolicy")] + public partial class RepositoryPolicy + { + + /// + /// 4.0.0+ + /// Whether to use this repository for downloading this type of artifact. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>true</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("enabled")] + public string Enabled { get; set; } + + /// + /// 4.0.0+ + /// The frequency for downloading updates - can be + /// <code>always,</code> + /// <code>daily</code> + /// (default), + /// <code>interval:XXX</code> + /// (in minutes) or + /// <code>never</code> + /// (only if it doesn't exist locally). + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("updatePolicy")] + public string UpdatePolicy { get; set; } + + /// + /// 4.0.0+ + /// What to do when verification of an artifact checksum fails. Valid values are + /// <code>ignore</code> + /// , + /// <code>fail</code> + /// or + /// <code>warn</code> + /// (the default). + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("checksumPolicy")] + public string ChecksumPolicy { get; set; } + } + + /// + /// 4.0.0+ + /// Contains the information needed for deploying websites. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Site")] + public partial class Site + { + + /// + /// 4.0.0+ + /// A unique identifier for a deployment location. This is used to match the + /// site to configuration in the <code>settings.xml</code> file, for example. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("id")] + public string Id { get; set; } + + /// + /// 4.0.0+ + /// Human readable name of the deployment location. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 4.0.0+ + /// The url of the location where website is deployed, in the form <code>protocol://hostname/path</code>. + /// <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if + /// site's <code>child.site.url.inherit.append.path="false"</code> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + /// + /// 4.0.0+ + /// When children inherit from distribution management site url, append path or not? Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code> + /// <br><b>Default value is</b>: <code>true</code> + /// <br><b>Since</b>: Maven 3.6.1 + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlAttributeAttribute("child.site.url.inherit.append.path")] + public string ChildSiteUrlInheritAppendPath { get; set; } + } + + /// + /// 4.0.0+ + /// Describes where an artifact has moved to. If any of the values are omitted, it is + /// assumed to be the same as it was before. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Relocation")] + public partial class Relocation + { + + /// + /// 4.0.0+ + /// The group ID the artifact has moved to. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId { get; set; } + + /// + /// 4.0.0+ + /// The new artifact ID of the artifact. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 4.0.0+ + /// The new version of the artifact. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + + /// + /// 4.0.0+ + /// An additional message to show the user about the move, such as the reason. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("message")] + public string Message { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelProperties", AnonymousType=true)] + public partial class ModelProperties + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelProperties() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Section for management of default dependency information for use in a group of + /// POMs. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("DependencyManagement")] + public partial class DependencyManagement + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependencies; + + /// + /// 4.0.0+ + /// The dependencies specified here are not used until they are referenced in a + /// POM within the group. This allows the specification of a "standard" version for a + /// particular dependency. + /// + [System.Xml.Serialization.XmlArrayAttribute("dependencies")] + [System.Xml.Serialization.XmlArrayItemAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependencies + { + get + { + return _dependencies; + } + private set + { + _dependencies = value; + } + } + + /// + /// Gets a value indicating whether the Dependencies collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependenciesSpecified + { + get + { + return (this.Dependencies.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public DependencyManagement() + { + this._dependencies = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("DependencyManagementDependencies", AnonymousType=true)] + public partial class DependencyManagementDependencies + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependency; + + [System.Xml.Serialization.XmlElementAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependency + { + get + { + return _dependency; + } + private set + { + _dependency = value; + } + } + + /// + /// Gets a value indicating whether the Dependency collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependencySpecified + { + get + { + return (this.Dependency.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public DependencyManagementDependencies() + { + this._dependency = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 3.0.0+ + /// The <code>&lt;dependency&gt;</code> element contains information about a dependency + /// of the project. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Dependency")] + public partial class Dependency + { + + /// + /// 3.0.0+ + /// The project group that produced the dependency, e.g. + /// <code>org.apache.maven</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId { get; set; } + + /// + /// 3.0.0+ + /// The unique id for an artifact produced by the project group, e.g. + /// <code>maven-artifact</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 3.0.0+ + /// The version of the dependency, e.g. <code>3.2.1</code>. In Maven 2, this can also be + /// specified as a range of versions. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _type = "jar"; + + /// + /// 4.0.0+ + /// The type of dependency, that will be mapped to a file extension, an optional classifier, and a few other attributes. + /// Some examples are <code>jar</code>, <code>war</code>, <code>ejb-client</code> + /// and <code>test-jar</code>: see <a href="../maven-core/artifact-handlers.html">default + /// artifact handlers</a> for a list. New types can be defined by extensions, so this is not a complete list. + /// + [System.ComponentModel.DefaultValueAttribute("jar")] + [System.Xml.Serialization.XmlElementAttribute("type")] + public string Type + { + get + { + return _type; + } + set + { + _type = value; + } + } + + /// + /// 4.0.0+ + /// The classifier of the dependency. It is appended to + /// the filename after the version. This allows: + /// <ul> + /// <li>referring to attached artifact, for example <code>sources</code> and <code>javadoc</code>: + /// see <a href="../maven-core/artifact-handlers.html">default artifact handlers</a> for a list,</li> + /// <li>distinguishing two artifacts + /// that belong to the same POM but were built differently. + /// For example, <code>jdk14</code> and <code>jdk15</code>.</li> + /// </ul> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("classifier")] + public string Classifier { get; set; } + + /// + /// 4.0.0+ + /// The scope of the dependency - <code>compile</code>, <code>runtime</code>, + /// <code>test</code>, <code>system</code>, and <code>provided</code>. Used to + /// calculate the various classpaths used for compilation, testing, and so on. + /// It also assists in determining which artifacts to include in a distribution of + /// this project. For more information, see + /// <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">the + /// dependency mechanism</a>. The default scope is <code>compile</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("scope")] + public string Scope { get; set; } + + /// + /// 4.0.0+ + /// FOR SYSTEM SCOPE ONLY. Note that use of this property is <b>discouraged</b> + /// and may be replaced in later versions. This specifies the path on the filesystem + /// for this dependency. + /// Requires an absolute path for the value, not relative. + /// Use a property that gives the machine specific absolute path, + /// e.g. <code>${java.home}</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("systemPath")] + public string SystemPath { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _exclusions; + + /// + /// 4.0.0+ + /// Lists a set of artifacts that should be excluded from this dependency's + /// artifact list when it comes to calculating transitive dependencies. + /// + [System.Xml.Serialization.XmlArrayAttribute("exclusions")] + [System.Xml.Serialization.XmlArrayItemAttribute("exclusion")] + public System.Collections.ObjectModel.Collection Exclusions + { + get + { + return _exclusions; + } + private set + { + _exclusions = value; + } + } + + /// + /// Gets a value indicating whether the Exclusions collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExclusionsSpecified + { + get + { + return (this.Exclusions.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Dependency() + { + this._exclusions = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 4.0.0+ + /// Indicates the dependency is optional for use of this library. While the + /// version of the dependency will be taken into account for dependency calculation if the + /// library is used elsewhere, it will not be passed on transitively. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>false</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("optional")] + public string Optional { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("DependencyExclusions", AnonymousType=true)] + public partial class DependencyExclusions + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _exclusion; + + [System.Xml.Serialization.XmlElementAttribute("exclusion")] + public System.Collections.ObjectModel.Collection Exclusion + { + get + { + return _exclusion; + } + private set + { + _exclusion = value; + } + } + + /// + /// Gets a value indicating whether the Exclusion collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExclusionSpecified + { + get + { + return (this.Exclusion.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public DependencyExclusions() + { + this._exclusion = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// The <code>&lt;exclusion&gt;</code> element contains informations required to exclude + /// an artifact to the project. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Exclusion")] + public partial class Exclusion + { + + /// + /// 4.0.0+ + /// The artifact ID of the project to exclude. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 4.0.0+ + /// The group ID of the project to exclude. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelDependencies", AnonymousType=true)] + public partial class ModelDependencies + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependency; + + [System.Xml.Serialization.XmlElementAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependency + { + get + { + return _dependency; + } + private set + { + _dependency = value; + } + } + + /// + /// Gets a value indicating whether the Dependency collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependencySpecified + { + get + { + return (this.Dependency.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelDependencies() + { + this._dependency = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelRepositories", AnonymousType=true)] + public partial class ModelRepositories + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _repository; + + [System.Xml.Serialization.XmlElementAttribute("repository")] + public System.Collections.ObjectModel.Collection Repository + { + get + { + return _repository; + } + private set + { + _repository = value; + } + } + + /// + /// Gets a value indicating whether the Repository collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RepositorySpecified + { + get + { + return (this.Repository.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelRepositories() + { + this._repository = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// A repository contains the information needed for establishing connections with + /// remote repository. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Repository")] + public partial class Repository + { + + /// + /// 4.0.0+ + /// How to handle downloading of releases from this repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("releases")] + public RepositoryPolicy Releases { get; set; } + + /// + /// 4.0.0+ + /// How to handle downloading of snapshots from this repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("snapshots")] + public RepositoryPolicy Snapshots { get; set; } + + /// + /// 4.0.0+ + /// A unique identifier for a repository. This is used to match the repository + /// to configuration in the <code>settings.xml</code> file, for example. Furthermore, the identifier is + /// used during POM inheritance and profile injection to detect repositories that should be merged. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("id")] + public string Id { get; set; } + + /// + /// 4.0.0+ + /// Human readable name of the repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 4.0.0+ + /// The url of the repository, in the form <code>protocol://hostname/path</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("url")] + public string Url { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _layout = "default"; + + /// + /// 4.0.0+ + /// The type of layout this repository uses for locating and storing artifacts - + /// can be <code>legacy</code> or <code>default</code>. + /// + [System.ComponentModel.DefaultValueAttribute("default")] + [System.Xml.Serialization.XmlElementAttribute("layout")] + public string Layout + { + get + { + return _layout; + } + set + { + _layout = value; + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelPluginRepositories", AnonymousType=true)] + public partial class ModelPluginRepositories + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _pluginRepository; + + [System.Xml.Serialization.XmlElementAttribute("pluginRepository")] + public System.Collections.ObjectModel.Collection PluginRepository + { + get + { + return _pluginRepository; + } + private set + { + _pluginRepository = value; + } + } + + /// + /// Gets a value indicating whether the PluginRepository collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginRepositorySpecified + { + get + { + return (this.PluginRepository.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelPluginRepositories() + { + this._pluginRepository = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 3.0.0+ + /// The <code>&lt;build&gt;</code> element contains informations required to build the project. + /// Default values are defined in Super POM. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Build")] + public partial class Build + { + + /// + /// 3.0.0+ + /// This element specifies a directory containing the source of the project. The + /// generated build system will compile the sources from this directory when the project is + /// built. The path given is relative to the project descriptor. + /// The default value is <code>src/main/java</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("sourceDirectory")] + public string SourceDirectory { get; set; } + + /// + /// 4.0.0+ + /// This element specifies a directory containing the script sources of the + /// project. This directory is meant to be different from the sourceDirectory, in that its + /// contents will be copied to the output directory in most cases (since scripts are + /// interpreted rather than compiled). + /// The default value is <code>src/main/scripts</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("scriptSourceDirectory")] + public string ScriptSourceDirectory { get; set; } + + /// + /// 4.0.0+ + /// This element specifies a directory containing the unit test source of the + /// project. The generated build system will compile these directories when the project is + /// being tested. The path given is relative to the project descriptor. + /// The default value is <code>src/test/java</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("testSourceDirectory")] + public string TestSourceDirectory { get; set; } + + /// + /// 4.0.0+ + /// The directory where compiled application classes are placed. + /// The default value is <code>target/classes</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("outputDirectory")] + public string OutputDirectory { get; set; } + + /// + /// 4.0.0+ + /// The directory where compiled test classes are placed. + /// The default value is <code>target/test-classes</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("testOutputDirectory")] + public string TestOutputDirectory { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _extensions; + + /// + /// 4.0.0+ + /// A set of build extensions to use from this project. + /// + [System.Xml.Serialization.XmlArrayAttribute("extensions")] + [System.Xml.Serialization.XmlArrayItemAttribute("extension")] + public System.Collections.ObjectModel.Collection Extensions + { + get + { + return _extensions; + } + private set + { + _extensions = value; + } + } + + /// + /// Gets a value indicating whether the Extensions collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExtensionsSpecified + { + get + { + return (this.Extensions.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Build() + { + this._extensions = new System.Collections.ObjectModel.Collection(); + this._resources = new System.Collections.ObjectModel.Collection(); + this._testResources = new System.Collections.ObjectModel.Collection(); + this._filters = new System.Collections.ObjectModel.Collection(); + this._plugins = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 3.0.0+ + /// The default goal (or phase in Maven 2) to execute when none is specified for + /// the project. Note that in case of a multi-module build, only the default goal of the top-level + /// project is relevant, i.e. the default goals of child modules are ignored. Since Maven 3, + /// multiple goals/phases can be separated by whitespace. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("defaultGoal")] + public string DefaultGoal { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _resources; + + /// + /// 3.0.0+ + /// This element describes all of the classpath resources such as properties + /// files associated with a project. These resources are often included in the final + /// package. + /// The default value is <code>src/main/resources</code>. + /// + [System.Xml.Serialization.XmlArrayAttribute("resources")] + [System.Xml.Serialization.XmlArrayItemAttribute("resource")] + public System.Collections.ObjectModel.Collection Resources + { + get + { + return _resources; + } + private set + { + _resources = value; + } + } + + /// + /// Gets a value indicating whether the Resources collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ResourcesSpecified + { + get + { + return (this.Resources.Count != 0); + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _testResources; + + /// + /// 4.0.0+ + /// This element describes all of the classpath resources such as properties + /// files associated with a project's unit tests. + /// The default value is <code>src/test/resources</code>. + /// + [System.Xml.Serialization.XmlArrayAttribute("testResources")] + [System.Xml.Serialization.XmlArrayItemAttribute("testResource")] + public System.Collections.ObjectModel.Collection TestResources + { + get + { + return _testResources; + } + private set + { + _testResources = value; + } + } + + /// + /// Gets a value indicating whether the TestResources collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TestResourcesSpecified + { + get + { + return (this.TestResources.Count != 0); + } + } + + /// + /// 4.0.0+ + /// The directory where all files generated by the build are placed. + /// The default value is <code>target</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("directory")] + public string Directory { get; set; } + + /// + /// 4.0.0+ + /// The filename (excluding the extension, and with no path information) that + /// the produced artifact will be called. + /// The default value is <code>${artifactId}-${version}</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("finalName")] + public string FinalName { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _filters; + + /// + /// 4.0.0+ + /// The list of filter properties files that are used when filtering is enabled. + /// + [System.Xml.Serialization.XmlArrayAttribute("filters")] + [System.Xml.Serialization.XmlArrayItemAttribute("filter")] + public System.Collections.ObjectModel.Collection Filters + { + get + { + return _filters; + } + private set + { + _filters = value; + } + } + + /// + /// Gets a value indicating whether the Filters collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FiltersSpecified + { + get + { + return (this.Filters.Count != 0); + } + } + + /// + /// 4.0.0+ + /// Default plugin information to be made available for reference by projects + /// derived from this one. This plugin configuration will not be resolved or bound to the + /// lifecycle unless referenced. Any local configuration for a given plugin will override + /// the plugin's entire definition here. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("pluginManagement")] + public PluginManagement PluginManagement { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugins; + + /// + /// 4.0.0+ + /// The list of plugins to use. + /// + [System.Xml.Serialization.XmlArrayAttribute("plugins")] + [System.Xml.Serialization.XmlArrayItemAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugins + { + get + { + return _plugins; + } + private set + { + _plugins = value; + } + } + + /// + /// Gets a value indicating whether the Plugins collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginsSpecified + { + get + { + return (this.Plugins.Count != 0); + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildExtensions", AnonymousType=true)] + public partial class BuildExtensions + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _extension; + + [System.Xml.Serialization.XmlElementAttribute("extension")] + public System.Collections.ObjectModel.Collection Extension + { + get + { + return _extension; + } + private set + { + _extension = value; + } + } + + /// + /// Gets a value indicating whether the Extension collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExtensionSpecified + { + get + { + return (this.Extension.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildExtensions() + { + this._extension = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Describes a build extension to utilise. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Extension")] + public partial class Extension + { + + /// + /// 4.0.0+ + /// The group ID of the extension's artifact. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId { get; set; } + + /// + /// 4.0.0+ + /// The artifact ID of the extension. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 4.0.0+ + /// The version of the extension. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildResources", AnonymousType=true)] + public partial class BuildResources + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _resource; + + [System.Xml.Serialization.XmlElementAttribute("resource")] + public System.Collections.ObjectModel.Collection Resource + { + get + { + return _resource; + } + private set + { + _resource = value; + } + } + + /// + /// Gets a value indicating whether the Resource collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ResourceSpecified + { + get + { + return (this.Resource.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildResources() + { + this._resource = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 3.0.0+ + /// This element describes all of the classpath resources associated with a project + /// or unit tests. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Resource")] + public partial class Resource + { + + /// + /// 3.0.0+ + /// Describe the resource target path. The path is relative to the target/classes + /// directory (i.e. <code>${project.build.outputDirectory}</code>). + /// For example, if you want that resource to appear in a specific package + /// (<code>org.apache.maven.messages</code>), you must specify this + /// element with this value: <code>org/apache/maven/messages</code>. + /// This is not required if you simply put the resources in that directory + /// structure at the source, however. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("targetPath")] + public string TargetPath { get; set; } + + /// + /// 3.0.0+ + /// Whether resources are filtered to replace tokens with parameterised values or not. + /// The values are taken from the <code>properties</code> element and from the + /// properties in the files listed in the <code>filters</code> element. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>false</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("filtering")] + public string Filtering { get; set; } + + /// + /// 3.0.0+ + /// Describe the directory where the resources are stored. The path is relative + /// to the POM. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("directory")] + public string Directory { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _includes; + + /// + /// 3.0.0+ + /// A list of patterns to include, e.g. <code>**&#47;*.xml</code>. + /// + [System.Xml.Serialization.XmlArrayAttribute("includes")] + [System.Xml.Serialization.XmlArrayItemAttribute("include")] + public System.Collections.ObjectModel.Collection Includes + { + get + { + return _includes; + } + private set + { + _includes = value; + } + } + + /// + /// Gets a value indicating whether the Includes collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IncludesSpecified + { + get + { + return (this.Includes.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Resource() + { + this._includes = new System.Collections.ObjectModel.Collection(); + this._excludes = new System.Collections.ObjectModel.Collection(); + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _excludes; + + /// + /// 3.0.0+ + /// A list of patterns to exclude, e.g. <code>**&#47;*.xml</code> + /// + [System.Xml.Serialization.XmlArrayAttribute("excludes")] + [System.Xml.Serialization.XmlArrayItemAttribute("exclude")] + public System.Collections.ObjectModel.Collection Excludes + { + get + { + return _excludes; + } + private set + { + _excludes = value; + } + } + + /// + /// Gets a value indicating whether the Excludes collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExcludesSpecified + { + get + { + return (this.Excludes.Count != 0); + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ResourceIncludes", AnonymousType=true)] + public partial class ResourceIncludes + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _include; + + [System.Xml.Serialization.XmlElementAttribute("include")] + public System.Collections.ObjectModel.Collection Include + { + get + { + return _include; + } + private set + { + _include = value; + } + } + + /// + /// Gets a value indicating whether the Include collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IncludeSpecified + { + get + { + return (this.Include.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ResourceIncludes() + { + this._include = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ResourceExcludes", AnonymousType=true)] + public partial class ResourceExcludes + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _exclude; + + [System.Xml.Serialization.XmlElementAttribute("exclude")] + public System.Collections.ObjectModel.Collection Exclude + { + get + { + return _exclude; + } + private set + { + _exclude = value; + } + } + + /// + /// Gets a value indicating whether the Exclude collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExcludeSpecified + { + get + { + return (this.Exclude.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ResourceExcludes() + { + this._exclude = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildTestResources", AnonymousType=true)] + public partial class BuildTestResources + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _testResource; + + [System.Xml.Serialization.XmlElementAttribute("testResource")] + public System.Collections.ObjectModel.Collection TestResource + { + get + { + return _testResource; + } + private set + { + _testResource = value; + } + } + + /// + /// Gets a value indicating whether the TestResource collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TestResourceSpecified + { + get + { + return (this.TestResource.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildTestResources() + { + this._testResource = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildFilters", AnonymousType=true)] + public partial class BuildFilters + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _filter; + + [System.Xml.Serialization.XmlElementAttribute("filter")] + public System.Collections.ObjectModel.Collection Filter + { + get + { + return _filter; + } + private set + { + _filter = value; + } + } + + /// + /// Gets a value indicating whether the Filter collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FilterSpecified + { + get + { + return (this.Filter.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildFilters() + { + this._filter = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Section for management of default plugin information for use in a group of POMs. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginManagement")] + public partial class PluginManagement + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugins; + + /// + /// 4.0.0+ + /// The list of plugins to use. + /// + [System.Xml.Serialization.XmlArrayAttribute("plugins")] + [System.Xml.Serialization.XmlArrayItemAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugins + { + get + { + return _plugins; + } + private set + { + _plugins = value; + } + } + + /// + /// Gets a value indicating whether the Plugins collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginsSpecified + { + get + { + return (this.Plugins.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginManagement() + { + this._plugins = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginManagementPlugins", AnonymousType=true)] + public partial class PluginManagementPlugins + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugin; + + [System.Xml.Serialization.XmlElementAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugin + { + get + { + return _plugin; + } + private set + { + _plugin = value; + } + } + + /// + /// Gets a value indicating whether the Plugin collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginSpecified + { + get + { + return (this.Plugin.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginManagementPlugins() + { + this._plugin = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// The <code>&lt;plugin&gt;</code> element contains informations required for a plugin. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Plugin")] + public partial class Plugin + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _groupId = "org.apache.maven.plugins"; + + /// + /// 4.0.0+ + /// The group ID of the plugin in the repository. + /// + [System.ComponentModel.DefaultValueAttribute("org.apache.maven.plugins")] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId + { + get + { + return _groupId; + } + set + { + _groupId = value; + } + } + + /// + /// 4.0.0+ + /// The artifact ID of the plugin in the repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 4.0.0+ + /// The version (or valid range of versions) of the plugin to be used. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + + /// + /// 4.0.0+ + /// Whether to load Maven extensions (such as packaging and type handlers) from + /// this plugin. For performance reasons, this should only be enabled when necessary. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>false</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("extensions")] + public string Extensions { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _executions; + + /// + /// 4.0.0+ + /// Multiple specifications of a set of goals to execute during the build + /// lifecycle, each having (possibly) a different configuration. + /// + [System.Xml.Serialization.XmlArrayAttribute("executions")] + [System.Xml.Serialization.XmlArrayItemAttribute("execution")] + public System.Collections.ObjectModel.Collection Executions + { + get + { + return _executions; + } + private set + { + _executions = value; + } + } + + /// + /// Gets a value indicating whether the Executions collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExecutionsSpecified + { + get + { + return (this.Executions.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Plugin() + { + this._executions = new System.Collections.ObjectModel.Collection(); + this._dependencies = new System.Collections.ObjectModel.Collection(); + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependencies; + + /// + /// 4.0.0+ + /// Additional dependencies that this project needs to introduce to the plugin's + /// classloader. + /// + [System.Xml.Serialization.XmlArrayAttribute("dependencies")] + [System.Xml.Serialization.XmlArrayItemAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependencies + { + get + { + return _dependencies; + } + private set + { + _dependencies = value; + } + } + + /// + /// Gets a value indicating whether the Dependencies collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependenciesSpecified + { + get + { + return (this.Dependencies.Count != 0); + } + } + + /// + /// 4.0.0+ + /// <b>Deprecated</b>. Unused by Maven. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("goals")] + public PluginGoals Goals { get; set; } + + /// + /// 4.0.0+ + /// Whether any configuration should be propagated to child POMs. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>true</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("inherited")] + public string Inherited { get; set; } + + /// + /// 0.0.0+ + /// <p>The configuration as DOM object.</p> + /// <p>By default, every element content is trimmed, but starting with Maven 3.1.0, you can add + /// <code>xml:space="preserve"</code> to elements you want to preserve whitespace.</p> + /// <p>You can control how child POMs inherit configuration from parent POMs by adding <code>combine.children</code> + /// or <code>combine.self</code> attributes to the children of the configuration element:</p> + /// <ul> + /// <li><code>combine.children</code>: available values are <code>merge</code> (default) and <code>append</code>,</li> + /// <li><code>combine.self</code>: available values are <code>merge</code> (default) and <code>override</code>.</li> + /// </ul> + /// <p>See <a href="https://maven.apache.org/pom.html#Plugins">POM Reference documentation</a> and + /// <a href="https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/xml/Xpp3DomUtils.html">Xpp3DomUtils</a> + /// for more information.</p> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("configuration")] + public PluginConfiguration Configuration { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginExecutions", AnonymousType=true)] + public partial class PluginExecutions + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _execution; + + [System.Xml.Serialization.XmlElementAttribute("execution")] + public System.Collections.ObjectModel.Collection Execution + { + get + { + return _execution; + } + private set + { + _execution = value; + } + } + + /// + /// Gets a value indicating whether the Execution collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExecutionSpecified + { + get + { + return (this.Execution.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginExecutions() + { + this._execution = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// The <code>&lt;execution&gt;</code> element contains informations required for the + /// execution of a plugin. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginExecution")] + public partial class PluginExecution + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _id = "default"; + + /// + /// 4.0.0+ + /// The identifier of this execution for labelling the goals during the build, + /// and for matching executions to merge during inheritance and profile injection. + /// + [System.ComponentModel.DefaultValueAttribute("default")] + [System.Xml.Serialization.XmlElementAttribute("id")] + public string Id + { + get + { + return _id; + } + set + { + _id = value; + } + } + + /// + /// 4.0.0+ + /// The build lifecycle phase to bind the goals in this execution to. If omitted, + /// the goals will be bound to the default phase specified by the plugin. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("phase")] + public string Phase { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _goals; + + /// + /// 4.0.0+ + /// The goals to execute with the given configuration. + /// + [System.Xml.Serialization.XmlArrayAttribute("goals")] + [System.Xml.Serialization.XmlArrayItemAttribute("goal")] + public System.Collections.ObjectModel.Collection Goals + { + get + { + return _goals; + } + private set + { + _goals = value; + } + } + + /// + /// Gets a value indicating whether the Goals collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool GoalsSpecified + { + get + { + return (this.Goals.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginExecution() + { + this._goals = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 4.0.0+ + /// Whether any configuration should be propagated to child POMs. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>true</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("inherited")] + public string Inherited { get; set; } + + /// + /// 0.0.0+ + /// <p>The configuration as DOM object.</p> + /// <p>By default, every element content is trimmed, but starting with Maven 3.1.0, you can add + /// <code>xml:space="preserve"</code> to elements you want to preserve whitespace.</p> + /// <p>You can control how child POMs inherit configuration from parent POMs by adding <code>combine.children</code> + /// or <code>combine.self</code> attributes to the children of the configuration element:</p> + /// <ul> + /// <li><code>combine.children</code>: available values are <code>merge</code> (default) and <code>append</code>,</li> + /// <li><code>combine.self</code>: available values are <code>merge</code> (default) and <code>override</code>.</li> + /// </ul> + /// <p>See <a href="https://maven.apache.org/pom.html#Plugins">POM Reference documentation</a> and + /// <a href="https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/xml/Xpp3DomUtils.html">Xpp3DomUtils</a> + /// for more information.</p> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("configuration")] + public PluginExecutionConfiguration Configuration { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginExecutionGoals", AnonymousType=true)] + public partial class PluginExecutionGoals + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _goal; + + [System.Xml.Serialization.XmlElementAttribute("goal")] + public System.Collections.ObjectModel.Collection Goal + { + get + { + return _goal; + } + private set + { + _goal = value; + } + } + + /// + /// Gets a value indicating whether the Goal collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool GoalSpecified + { + get + { + return (this.Goal.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginExecutionGoals() + { + this._goal = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginExecutionConfiguration", AnonymousType=true)] + public partial class PluginExecutionConfiguration + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginExecutionConfiguration() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginDependencies", AnonymousType=true)] + public partial class PluginDependencies + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependency; + + [System.Xml.Serialization.XmlElementAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependency + { + get + { + return _dependency; + } + private set + { + _dependency = value; + } + } + + /// + /// Gets a value indicating whether the Dependency collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependencySpecified + { + get + { + return (this.Dependency.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginDependencies() + { + this._dependency = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginGoals", AnonymousType=true)] + public partial class PluginGoals + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginGoals() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("PluginConfiguration", AnonymousType=true)] + public partial class PluginConfiguration + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public PluginConfiguration() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildPlugins", AnonymousType=true)] + public partial class BuildPlugins + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugin; + + [System.Xml.Serialization.XmlElementAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugin + { + get + { + return _plugin; + } + private set + { + _plugin = value; + } + } + + /// + /// Gets a value indicating whether the Plugin collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginSpecified + { + get + { + return (this.Plugin.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildPlugins() + { + this._plugin = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelReports", AnonymousType=true)] + public partial class ModelReports + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelReports() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Section for management of reports and their configuration. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Reporting")] + public partial class Reporting + { + + /// + /// 4.0.0+ + /// If true, then the default reports are not included in the site generation. + /// This includes the reports in the "Project Info" menu. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>false</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("excludeDefaults")] + public string ExcludeDefaults { get; set; } + + /// + /// 4.0.0+ + /// Where to store all of the generated reports. The default is + /// <code>${project.build.directory}/site</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("outputDirectory")] + public string OutputDirectory { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugins; + + /// + /// 4.0.0+ + /// The reporting plugins to use and their configuration. + /// + [System.Xml.Serialization.XmlArrayAttribute("plugins")] + [System.Xml.Serialization.XmlArrayItemAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugins + { + get + { + return _plugins; + } + private set + { + _plugins = value; + } + } + + /// + /// Gets a value indicating whether the Plugins collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginsSpecified + { + get + { + return (this.Plugins.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Reporting() + { + this._plugins = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ReportingPlugins", AnonymousType=true)] + public partial class ReportingPlugins + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugin; + + [System.Xml.Serialization.XmlElementAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugin + { + get + { + return _plugin; + } + private set + { + _plugin = value; + } + } + + /// + /// Gets a value indicating whether the Plugin collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginSpecified + { + get + { + return (this.Plugin.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ReportingPlugins() + { + this._plugin = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// The <code>&lt;plugin&gt;</code> element contains informations required for a report plugin. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ReportPlugin")] + public partial class ReportPlugin + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _groupId = "org.apache.maven.plugins"; + + /// + /// 4.0.0+ + /// The group ID of the reporting plugin in the repository. + /// + [System.ComponentModel.DefaultValueAttribute("org.apache.maven.plugins")] + [System.Xml.Serialization.XmlElementAttribute("groupId")] + public string GroupId + { + get + { + return _groupId; + } + set + { + _groupId = value; + } + } + + /// + /// 4.0.0+ + /// The artifact ID of the reporting plugin in the repository. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("artifactId")] + public string ArtifactId { get; set; } + + /// + /// 4.0.0+ + /// The version of the reporting plugin to be used. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _reportSets; + + /// + /// 4.0.0+ + /// Multiple specifications of a set of reports, each having (possibly) different + /// configuration. This is the reporting parallel to an <code>execution</code> in the build. + /// + [System.Xml.Serialization.XmlArrayAttribute("reportSets")] + [System.Xml.Serialization.XmlArrayItemAttribute("reportSet")] + public System.Collections.ObjectModel.Collection ReportSets + { + get + { + return _reportSets; + } + private set + { + _reportSets = value; + } + } + + /// + /// Gets a value indicating whether the ReportSets collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReportSetsSpecified + { + get + { + return (this.ReportSets.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ReportPlugin() + { + this._reportSets = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 4.0.0+ + /// Whether any configuration should be propagated to child POMs. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>true</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("inherited")] + public string Inherited { get; set; } + + /// + /// 0.0.0+ + /// <p>The configuration as DOM object.</p> + /// <p>By default, every element content is trimmed, but starting with Maven 3.1.0, you can add + /// <code>xml:space="preserve"</code> to elements you want to preserve whitespace.</p> + /// <p>You can control how child POMs inherit configuration from parent POMs by adding <code>combine.children</code> + /// or <code>combine.self</code> attributes to the children of the configuration element:</p> + /// <ul> + /// <li><code>combine.children</code>: available values are <code>merge</code> (default) and <code>append</code>,</li> + /// <li><code>combine.self</code>: available values are <code>merge</code> (default) and <code>override</code>.</li> + /// </ul> + /// <p>See <a href="https://maven.apache.org/pom.html#Plugins">POM Reference documentation</a> and + /// <a href="https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/xml/Xpp3DomUtils.html">Xpp3DomUtils</a> + /// for more information.</p> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("configuration")] + public ReportPluginConfiguration Configuration { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ReportPluginReportSets", AnonymousType=true)] + public partial class ReportPluginReportSets + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _reportSet; + + [System.Xml.Serialization.XmlElementAttribute("reportSet")] + public System.Collections.ObjectModel.Collection ReportSet + { + get + { + return _reportSet; + } + private set + { + _reportSet = value; + } + } + + /// + /// Gets a value indicating whether the ReportSet collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReportSetSpecified + { + get + { + return (this.ReportSet.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ReportPluginReportSets() + { + this._reportSet = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Represents a set of reports and configuration to be used to generate them. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ReportSet")] + public partial class ReportSet + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _id = "default"; + + /// + /// 0.0.0+ + /// The unique id for this report set, to be used during POM inheritance and profile injection + /// for merging of report sets. + /// + [System.ComponentModel.DefaultValueAttribute("default")] + [System.Xml.Serialization.XmlElementAttribute("id")] + public string Id + { + get + { + return _id; + } + set + { + _id = value; + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _reports; + + /// + /// 4.0.0+ + /// The list of reports from this plugin which should be generated from this set. + /// + [System.Xml.Serialization.XmlArrayAttribute("reports")] + [System.Xml.Serialization.XmlArrayItemAttribute("report")] + public System.Collections.ObjectModel.Collection Reports + { + get + { + return _reports; + } + private set + { + _reports = value; + } + } + + /// + /// Gets a value indicating whether the Reports collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReportsSpecified + { + get + { + return (this.Reports.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ReportSet() + { + this._reports = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 4.0.0+ + /// Whether any configuration should be propagated to child POMs. Note: While the type + /// of this field is <code>String</code> for technical reasons, the semantic type is actually + /// <code>Boolean</code>. Default value is <code>true</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("inherited")] + public string Inherited { get; set; } + + /// + /// 0.0.0+ + /// <p>The configuration as DOM object.</p> + /// <p>By default, every element content is trimmed, but starting with Maven 3.1.0, you can add + /// <code>xml:space="preserve"</code> to elements you want to preserve whitespace.</p> + /// <p>You can control how child POMs inherit configuration from parent POMs by adding <code>combine.children</code> + /// or <code>combine.self</code> attributes to the children of the configuration element:</p> + /// <ul> + /// <li><code>combine.children</code>: available values are <code>merge</code> (default) and <code>append</code>,</li> + /// <li><code>combine.self</code>: available values are <code>merge</code> (default) and <code>override</code>.</li> + /// </ul> + /// <p>See <a href="https://maven.apache.org/pom.html#Plugins">POM Reference documentation</a> and + /// <a href="https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/xml/Xpp3DomUtils.html">Xpp3DomUtils</a> + /// for more information.</p> + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("configuration")] + public ReportSetConfiguration Configuration { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ReportSetReports", AnonymousType=true)] + public partial class ReportSetReports + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _report; + + [System.Xml.Serialization.XmlElementAttribute("report")] + public System.Collections.ObjectModel.Collection Report + { + get + { + return _report; + } + private set + { + _report = value; + } + } + + /// + /// Gets a value indicating whether the Report collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReportSpecified + { + get + { + return (this.Report.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ReportSetReports() + { + this._report = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ReportSetConfiguration", AnonymousType=true)] + public partial class ReportSetConfiguration + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ReportSetConfiguration() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ReportPluginConfiguration", AnonymousType=true)] + public partial class ReportPluginConfiguration + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ReportPluginConfiguration() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ModelProfiles", AnonymousType=true)] + public partial class ModelProfiles + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _profile; + + [System.Xml.Serialization.XmlElementAttribute("profile")] + public System.Collections.ObjectModel.Collection Profile + { + get + { + return _profile; + } + private set + { + _profile = value; + } + } + + /// + /// Gets a value indicating whether the Profile collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProfileSpecified + { + get + { + return (this.Profile.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ModelProfiles() + { + this._profile = new System.Collections.ObjectModel.Collection(); + } + } + + /// + /// 4.0.0+ + /// Modifications to the build process which is activated based on environmental + /// parameters or command line arguments. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Profile")] + public partial class Profile + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private string _id = "default"; + + /// + /// 4.0.0+ + /// The identifier of this build profile. This is used for command line + /// activation, and identifies profiles to be merged. + /// + [System.ComponentModel.DefaultValueAttribute("default")] + [System.Xml.Serialization.XmlElementAttribute("id")] + public string Id + { + get + { + return _id; + } + set + { + _id = value; + } + } + + /// + /// 4.0.0+ + /// The conditional logic which will automatically trigger the inclusion of this + /// profile. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("activation")] + public Activation Activation { get; set; } + + /// + /// 4.0.0+ + /// Information required to build the project. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("build")] + public BuildBase Build { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _modules; + + /// + /// 4.0.0+ + /// The modules (sometimes called subprojects) to build as a part of this + /// project. Each module listed is a relative path to the directory containing the module. + /// To be consistent with the way default urls are calculated from parent, it is recommended + /// to have module names match artifact ids. + /// + [System.Xml.Serialization.XmlArrayAttribute("modules")] + [System.Xml.Serialization.XmlArrayItemAttribute("module")] + public System.Collections.ObjectModel.Collection Modules + { + get + { + return _modules; + } + private set + { + _modules = value; + } + } + + /// + /// Gets a value indicating whether the Modules collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ModulesSpecified + { + get + { + return (this.Modules.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public Profile() + { + this._modules = new System.Collections.ObjectModel.Collection(); + this._dependencies = new System.Collections.ObjectModel.Collection(); + this._repositories = new System.Collections.ObjectModel.Collection(); + this._pluginRepositories = new System.Collections.ObjectModel.Collection(); + } + + /// + /// 4.0.0+ + /// Distribution information for a project that enables deployment of the site + /// and artifacts to remote web servers and repositories respectively. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("distributionManagement")] + public DistributionManagement DistributionManagement { get; set; } + + /// + /// 4.0.0+ + /// Properties that can be used throughout the POM as a substitution, and + /// are used as filters in resources if enabled. + /// The format is <code>&lt;name&gt;value&lt;/name&gt;</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("properties")] + public ProfileProperties Properties { get; set; } + + /// + /// 4.0.0+ + /// Default dependency information for projects that inherit from this one. The + /// dependencies in this section are not immediately resolved. Instead, when a POM derived + /// from this one declares a dependency described by a matching groupId and artifactId, the + /// version and other values from this section are used for that dependency if they were not + /// already specified. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("dependencyManagement")] + public DependencyManagement DependencyManagement { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependencies; + + /// + /// 3.0.0+ + /// This element describes all of the dependencies associated with a + /// project. + /// These dependencies are used to construct a classpath for your + /// project during the build process. They are automatically downloaded from the + /// repositories defined in this project. + /// See <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">the + /// dependency mechanism</a> for more information. + /// + [System.Xml.Serialization.XmlArrayAttribute("dependencies")] + [System.Xml.Serialization.XmlArrayItemAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependencies + { + get + { + return _dependencies; + } + private set + { + _dependencies = value; + } + } + + /// + /// Gets a value indicating whether the Dependencies collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependenciesSpecified + { + get + { + return (this.Dependencies.Count != 0); + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _repositories; + + /// + /// 4.0.0+ + /// The lists of the remote repositories for discovering dependencies and + /// extensions. + /// + [System.Xml.Serialization.XmlArrayAttribute("repositories")] + [System.Xml.Serialization.XmlArrayItemAttribute("repository")] + public System.Collections.ObjectModel.Collection Repositories + { + get + { + return _repositories; + } + private set + { + _repositories = value; + } + } + + /// + /// Gets a value indicating whether the Repositories collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RepositoriesSpecified + { + get + { + return (this.Repositories.Count != 0); + } + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _pluginRepositories; + + /// + /// 4.0.0+ + /// The lists of the remote repositories for discovering plugins for builds and + /// reports. + /// + [System.Xml.Serialization.XmlArrayAttribute("pluginRepositories")] + [System.Xml.Serialization.XmlArrayItemAttribute("pluginRepository")] + public System.Collections.ObjectModel.Collection PluginRepositories + { + get + { + return _pluginRepositories; + } + private set + { + _pluginRepositories = value; + } + } + + /// + /// Gets a value indicating whether the PluginRepositories collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginRepositoriesSpecified + { + get + { + return (this.PluginRepositories.Count != 0); + } + } + + /// + /// 4.0.0+ + /// <b>Deprecated</b>. Now ignored by Maven. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("reports")] + public ProfileReports Reports { get; set; } + + /// + /// 4.0.0+ + /// This element includes the specification of report plugins to use + /// to generate the reports on the Maven-generated site. + /// These reports will be run when a user executes <code>mvn site</code>. + /// All of the reports will be included in the navigation bar for browsing. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("reporting")] + public Reporting Reporting { get; set; } + } + + /// + /// 4.0.0+ + /// The conditions within the build runtime environment which will trigger the + /// automatic inclusion of the build profile. Multiple conditions can be defined, which must + /// be all satisfied to activate the profile. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("Activation")] + public partial class Activation + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private bool _activeByDefault = false; + + /// + /// 4.0.0+ + /// If set to true, this profile will be active unless another profile in this + /// pom is activated using the command line -P option or by one of that profile's + /// activators. + /// + [System.ComponentModel.DefaultValueAttribute(false)] + [System.Xml.Serialization.XmlElementAttribute("activeByDefault")] + public bool ActiveByDefault + { + get + { + return _activeByDefault; + } + set + { + _activeByDefault = value; + } + } + + /// + /// 4.0.0+ + /// Specifies that this profile will be activated when a matching JDK is detected. + /// For example, <code>1.4</code> only activates on JDKs versioned 1.4, + /// while <code>!1.4</code> matches any JDK that is not version 1.4. Ranges are supported too: + /// <code>[1.5,)</code> activates when the JDK is 1.5 minimum. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("jdk")] + public string Jdk { get; set; } + + /// + /// 4.0.0+ + /// Specifies that this profile will be activated when matching operating system + /// attributes are detected. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("os")] + public ActivationOs Os { get; set; } + + /// + /// 4.0.0+ + /// Specifies that this profile will be activated when this system property is + /// specified. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("property")] + public ActivationProperty Property { get; set; } + + /// + /// 4.0.0+ + /// Specifies that this profile will be activated based on existence of a file. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("file")] + public ActivationFile File { get; set; } + } + + /// + /// 4.0.0+ + /// This is an activator which will detect an operating system's attributes in order + /// to activate its profile. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ActivationOS")] + public partial class ActivationOs + { + + /// + /// 4.0.0+ + /// The name of the operating system to be used to activate the profile. This must be an exact match + /// of the <code>${os.name}</code> Java property, such as <code>Windows XP</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 4.0.0+ + /// The general family of the OS to be used to activate the profile, such as + /// <code>windows</code> or <code>unix</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("family")] + public string Family { get; set; } + + /// + /// 4.0.0+ + /// The architecture of the operating system to be used to activate the + /// profile. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("arch")] + public string Arch { get; set; } + + /// + /// 4.0.0+ + /// The version of the operating system to be used to activate the + /// profile. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("version")] + public string Version { get; set; } + } + + /// + /// 4.0.0+ + /// This is the property specification used to activate a profile. If the value field + /// is empty, then the existence of the named property will activate the profile, otherwise it + /// does a case-sensitive match against the property value as well. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ActivationProperty")] + public partial class ActivationProperty + { + + /// + /// 4.0.0+ + /// The name of the property to be used to activate a profile. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("name")] + public string Name { get; set; } + + /// + /// 4.0.0+ + /// The value of the property required to activate a profile. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("value")] + public string Value { get; set; } + } + + /// + /// 4.0.0+ + /// This is the file specification used to activate the profile. The <code>missing</code> value + /// is the location of a file that needs to exist, and if it doesn't, the profile will be + /// activated. On the other hand, <code>exists</code> will test for the existence of the file and if it is + /// there, the profile will be activated.<br> + /// Variable interpolation for these file specifications is limited to <code>${basedir}</code>, + /// System properties and request properties. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ActivationFile")] + public partial class ActivationFile + { + + /// + /// 4.0.0+ + /// The name of the file that must be missing to activate the + /// profile. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("missing")] + public string Missing { get; set; } + + /// + /// 4.0.0+ + /// The name of the file that must exist to activate the profile. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("exists")] + public string Exists { get; set; } + } + + /// + /// 3.0.0+ + /// Generic informations for a build. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildBase")] + public partial class BuildBase + { + + /// + /// 3.0.0+ + /// The default goal (or phase in Maven 2) to execute when none is specified for + /// the project. Note that in case of a multi-module build, only the default goal of the top-level + /// project is relevant, i.e. the default goals of child modules are ignored. Since Maven 3, + /// multiple goals/phases can be separated by whitespace. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("defaultGoal")] + public string DefaultGoal { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _resources; + + /// + /// 3.0.0+ + /// This element describes all of the classpath resources such as properties + /// files associated with a project. These resources are often included in the final + /// package. + /// The default value is <code>src/main/resources</code>. + /// + [System.Xml.Serialization.XmlArrayAttribute("resources")] + [System.Xml.Serialization.XmlArrayItemAttribute("resource")] + public System.Collections.ObjectModel.Collection Resources + { + get + { + return _resources; + } + private set + { + _resources = value; + } + } + + /// + /// Gets a value indicating whether the Resources collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ResourcesSpecified + { + get + { + return (this.Resources.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildBase() + { + this._resources = new System.Collections.ObjectModel.Collection(); + this._testResources = new System.Collections.ObjectModel.Collection(); + this._filters = new System.Collections.ObjectModel.Collection(); + this._plugins = new System.Collections.ObjectModel.Collection(); + } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _testResources; + + /// + /// 4.0.0+ + /// This element describes all of the classpath resources such as properties + /// files associated with a project's unit tests. + /// The default value is <code>src/test/resources</code>. + /// + [System.Xml.Serialization.XmlArrayAttribute("testResources")] + [System.Xml.Serialization.XmlArrayItemAttribute("testResource")] + public System.Collections.ObjectModel.Collection TestResources + { + get + { + return _testResources; + } + private set + { + _testResources = value; + } + } + + /// + /// Gets a value indicating whether the TestResources collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TestResourcesSpecified + { + get + { + return (this.TestResources.Count != 0); + } + } + + /// + /// 4.0.0+ + /// The directory where all files generated by the build are placed. + /// The default value is <code>target</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("directory")] + public string Directory { get; set; } + + /// + /// 4.0.0+ + /// The filename (excluding the extension, and with no path information) that + /// the produced artifact will be called. + /// The default value is <code>${artifactId}-${version}</code>. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("finalName")] + public string FinalName { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _filters; + + /// + /// 4.0.0+ + /// The list of filter properties files that are used when filtering is enabled. + /// + [System.Xml.Serialization.XmlArrayAttribute("filters")] + [System.Xml.Serialization.XmlArrayItemAttribute("filter")] + public System.Collections.ObjectModel.Collection Filters + { + get + { + return _filters; + } + private set + { + _filters = value; + } + } + + /// + /// Gets a value indicating whether the Filters collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FiltersSpecified + { + get + { + return (this.Filters.Count != 0); + } + } + + /// + /// 4.0.0+ + /// Default plugin information to be made available for reference by projects + /// derived from this one. This plugin configuration will not be resolved or bound to the + /// lifecycle unless referenced. Any local configuration for a given plugin will override + /// the plugin's entire definition here. + /// + [System.Diagnostics.CodeAnalysis.AllowNullAttribute()] + [System.Diagnostics.CodeAnalysis.MaybeNullAttribute()] + [System.Xml.Serialization.XmlElementAttribute("pluginManagement")] + public PluginManagement PluginManagement { get; set; } + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugins; + + /// + /// 4.0.0+ + /// The list of plugins to use. + /// + [System.Xml.Serialization.XmlArrayAttribute("plugins")] + [System.Xml.Serialization.XmlArrayItemAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugins + { + get + { + return _plugins; + } + private set + { + _plugins = value; + } + } + + /// + /// Gets a value indicating whether the Plugins collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginsSpecified + { + get + { + return (this.Plugins.Count != 0); + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildBaseResources", AnonymousType=true)] + public partial class BuildBaseResources + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _resource; + + [System.Xml.Serialization.XmlElementAttribute("resource")] + public System.Collections.ObjectModel.Collection Resource + { + get + { + return _resource; + } + private set + { + _resource = value; + } + } + + /// + /// Gets a value indicating whether the Resource collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ResourceSpecified + { + get + { + return (this.Resource.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildBaseResources() + { + this._resource = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildBaseTestResources", AnonymousType=true)] + public partial class BuildBaseTestResources + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _testResource; + + [System.Xml.Serialization.XmlElementAttribute("testResource")] + public System.Collections.ObjectModel.Collection TestResource + { + get + { + return _testResource; + } + private set + { + _testResource = value; + } + } + + /// + /// Gets a value indicating whether the TestResource collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TestResourceSpecified + { + get + { + return (this.TestResource.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildBaseTestResources() + { + this._testResource = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildBaseFilters", AnonymousType=true)] + public partial class BuildBaseFilters + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _filter; + + [System.Xml.Serialization.XmlElementAttribute("filter")] + public System.Collections.ObjectModel.Collection Filter + { + get + { + return _filter; + } + private set + { + _filter = value; + } + } + + /// + /// Gets a value indicating whether the Filter collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FilterSpecified + { + get + { + return (this.Filter.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildBaseFilters() + { + this._filter = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("BuildBasePlugins", AnonymousType=true)] + public partial class BuildBasePlugins + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _plugin; + + [System.Xml.Serialization.XmlElementAttribute("plugin")] + public System.Collections.ObjectModel.Collection Plugin + { + get + { + return _plugin; + } + private set + { + _plugin = value; + } + } + + /// + /// Gets a value indicating whether the Plugin collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginSpecified + { + get + { + return (this.Plugin.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public BuildBasePlugins() + { + this._plugin = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ProfileModules", AnonymousType=true)] + public partial class ProfileModules + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _module; + + [System.Xml.Serialization.XmlElementAttribute("module")] + public System.Collections.ObjectModel.Collection Module + { + get + { + return _module; + } + private set + { + _module = value; + } + } + + /// + /// Gets a value indicating whether the Module collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ModuleSpecified + { + get + { + return (this.Module.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ProfileModules() + { + this._module = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ProfileProperties", AnonymousType=true)] + public partial class ProfileProperties + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ProfileProperties() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ProfileDependencies", AnonymousType=true)] + public partial class ProfileDependencies + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _dependency; + + [System.Xml.Serialization.XmlElementAttribute("dependency")] + public System.Collections.ObjectModel.Collection Dependency + { + get + { + return _dependency; + } + private set + { + _dependency = value; + } + } + + /// + /// Gets a value indicating whether the Dependency collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DependencySpecified + { + get + { + return (this.Dependency.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ProfileDependencies() + { + this._dependency = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ProfileRepositories", AnonymousType=true)] + public partial class ProfileRepositories + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _repository; + + [System.Xml.Serialization.XmlElementAttribute("repository")] + public System.Collections.ObjectModel.Collection Repository + { + get + { + return _repository; + } + private set + { + _repository = value; + } + } + + /// + /// Gets a value indicating whether the Repository collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RepositorySpecified + { + get + { + return (this.Repository.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ProfileRepositories() + { + this._repository = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ProfilePluginRepositories", AnonymousType=true)] + public partial class ProfilePluginRepositories + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _pluginRepository; + + [System.Xml.Serialization.XmlElementAttribute("pluginRepository")] + public System.Collections.ObjectModel.Collection PluginRepository + { + get + { + return _pluginRepository; + } + private set + { + _pluginRepository = value; + } + } + + /// + /// Gets a value indicating whether the PluginRepository collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PluginRepositorySpecified + { + get + { + return (this.PluginRepository.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ProfilePluginRepositories() + { + this._pluginRepository = new System.Collections.ObjectModel.Collection(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "2.1.1057.0")] + [System.Xml.Serialization.XmlTypeAttribute("ProfileReports", AnonymousType=true)] + public partial class ProfileReports + { + + [System.Xml.Serialization.XmlIgnoreAttribute()] + private System.Collections.ObjectModel.Collection _any; + + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Collections.ObjectModel.Collection Any + { + get + { + return _any; + } + private set + { + _any = value; + } + } + + /// + /// Gets a value indicating whether the Any collection is empty. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AnySpecified + { + get + { + return (this.Any.Count != 0); + } + } + + /// + /// Initializes a new instance of the class. + /// + public ProfileReports() + { + this._any = new System.Collections.ObjectModel.Collection(); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/ResolvedDependency.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/ResolvedDependency.cs new file mode 100644 index 00000000000..884372b4b94 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/ResolvedDependency.cs @@ -0,0 +1,125 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Java.Interop.Tools.Maven.Extensions; + +namespace Java.Interop.Tools.Maven.Models; + +public class ResolvedDependency +{ + public ResolvedProject Project { get; } + public string ArtifactId { get; } + public string? Classifier { get; } + public string GroupId { get; } + public string? Optional { get; } + public string Scope { get; } + public string? Type { get; } + public string Version { get; } + + public string ArtifactString => $"{GroupId}:{ArtifactId}"; + public string VersionedArtifactString => $"{GroupId}:{ArtifactId}:{Version}"; + + public ResolvedDependency (ResolvedProject project, Dependency dependency) + : this (project, dependency, false) + { } + + internal ResolvedDependency (ResolvedProject project, Dependency dependency, bool shallow) + { + Project = project; + + // First fill these in with values from the dependency + ArtifactId = dependency.ArtifactId.OrEmpty (); + GroupId = dependency.GroupId.OrEmpty (); + Classifier = dependency.Classifier; + Optional = dependency.Optional.OrEmpty (); + Scope = dependency.Scope.OrEmpty (); + Type = dependency.Type; + Version = dependency.Version.OrEmpty (); + + // If we're not shallow, fill in any still missing properties with parent values + if (!shallow) { + if (!Classifier.HasValue ()) + Classifier = GetInheritedProperty (this, project, d => d.Classifier); + + if (!Optional.HasValue ()) + Optional = GetInheritedProperty (this, project, d => d.Optional); + + if (!Scope.HasValue ()) + Scope = GetInheritedProperty (this, project, d => d.Scope); + + if (!Type.HasValue ()) + Type = GetInheritedProperty (this, project, d => d.Type); + + if (!Version.HasValue ()) + Version = GetInheritedProperty (this, project, d => d.Version); + } + + // Default scope to "compile" if not specified + if (!Scope.HasValue ()) + Scope = "compile"; + + // Default optional to "false" if not specified + if (!Optional.HasValue ()) + Optional = "false"; + } + + public override string ToString () => $"{VersionedArtifactString} - {Scope}"; + + static string GetInheritedProperty (ResolvedDependency dependency, ResolvedProject project, Func property) + { + // Check our section + if (CheckDependencyManagementSection (project, dependency, property, out var result)) + return result; + + // Check imported POMs + foreach (var imported in project.ImportedPomProjects) { + var value = GetInheritedProperty (dependency, imported, property); + + if (value.HasValue ()) + return value; + } + + // Check parent POM + if (project.Parent is not null && !project.Parent.IsSuperPom) + return GetInheritedProperty (dependency, project.Parent, property); + + return string.Empty; + } + + static bool CheckImportedPoms (ResolvedDependency dependency, ResolvedProject project, Func property, [NotNullWhen (true)] out string? result) + { + result = null; + + foreach (var imported in project.ImportedPomProjects) { + var imported_dep = imported.Resolved.DependencyManagement?.Dependencies.FirstOrDefault (x => x.ArtifactId == dependency.ArtifactId && x.GroupId == dependency.GroupId); + + if (imported_dep != null) { + result = property (new ResolvedDependency (imported, imported_dep, true)); + + if (result.HasValue ()) + return true; + } + + // Recurse, as imported POMs can also import POMs + if (CheckImportedPoms (dependency, imported, property, out result)) + return true; + } + + return false; + } + + static bool CheckDependencyManagementSection (ResolvedProject project, ResolvedDependency dependency, Func property, [NotNullWhen (true)] out string? result) + { + result = null; + + // Check + var dep_man = project.Resolved.DependencyManagement?.Dependencies.FirstOrDefault (x => x.ArtifactId == dependency.ArtifactId && x.GroupId == dependency.GroupId); + + if (dep_man != null) { + result = property (new ResolvedDependency (project, dep_man, true)) ?? string.Empty; + return result.HasValue (); + } + + return false; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/ResolvedProject.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/ResolvedProject.cs new file mode 100644 index 00000000000..9b089966b80 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Models/ResolvedProject.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Java.Interop.Tools.Maven.Extensions; + +namespace Java.Interop.Tools.Maven.Models; + +public class ResolvedProject +{ + readonly ResolvedProject? parent; + readonly IProjectResolver? resolver; + + Project? resolved_project; + + public Project Raw { get; } + public Project Resolved => resolved_project ?? throw new InvalidOperationException ("Call the Resolve method before accessing this."); + + public virtual bool IsSuperPom => false; + public string ArtifactId => Resolved.ArtifactId.OrEmpty (); + public string GroupId => Resolved.GroupId.HasValue () || IsSuperPom ? Resolved.GroupId.OrEmpty () : Parent.GroupId; + public string Version => Resolved.Version.HasValue () || IsSuperPom ? Resolved.Version.OrEmpty () : Parent.Version; + public string Name => Resolved.Name.HasValue () || IsSuperPom ? Resolved.Name.OrEmpty () : Parent.Name; + + public List Dependencies { get; } = new List (); + public List ImportedPomProjects { get; } = new (); // Projects imported via a scope = "import", type = "pom" dependencyManagement section + + public ResolvedProject Parent { + get { + if (parent is null && IsSuperPom) + throw new InvalidOperationException ("Super POM does not have a parent, check IsSuperPom before calling"); + + return parent ?? throw new InvalidOperationException ("Parent should not be null"); + } + } + + public ResolvedProject (Project project, ResolvedProject parent, IProjectResolver resolver) + { + Raw = project; + this.parent = parent; + this.resolver = resolver; + } + + public void Resolve () => ResolveCore (new PropertyStack ()); + + public static ResolvedProject FromArtifact (Artifact artifact, IProjectResolver resolver) + { + var project = FromArtifactCore (artifact, resolver); + project.Resolve (); + + return project; + } + + static ResolvedProject FromArtifactCore (Artifact artifact, IProjectResolver resolver) + { + var raw = resolver.Resolve (artifact); + + // POM has a parent, resolve it + if (raw.TryGetParentPomArtifact (out var parentArtifact)) { + var parent = FromArtifactCore (parentArtifact, resolver); + return new ResolvedProject (raw, parent, resolver); + } + + var project = new ResolvedProject (raw, SuperPom.Instance, resolver); + + return project; + } + + void ResolveCore (PropertyStack properties) + { + if (IsSuperPom) + return; + + // A newly constructed ResolvedProject contains only raw values. We need to + // go through every Project value and replace any specified properties + // (ex: ${project.version} or ${mavenVersion}) with the resolved values. This has to + // start at the child and work its way up to the parent, because properties + // specified in the child override those in the parent. + var xml = Raw.ToXml (); + xml = ReplaceProperties (xml, this, properties); + + resolved_project = Project.Parse (xml); + + properties.Push (Raw.Properties); + parent?.ResolveCore (properties); + + // Now that we've resolved all properties, we can figure out our dependencies. + ImportDependencyManagementPoms (); + ResolveDependencies (); + } + + [return: NotNullIfNotNull (nameof (value))] + string? ReplaceProperties (string? value, ResolvedProject project, PropertyStack properties) + { + if (value is null) + return null; + + if (!value.Contains ("${") || project.IsSuperPom) + return value; + + properties.Push (project.Raw.Properties); + + var old_value = string.Empty; + + // Properties can be nested, so we need to keep replacing until we don't find any more. + // We check against the old value to make sure we don't get stuck in an infinite loop. + while (value.Contains ("${") && value != old_value) { + old_value = value; + + // Replace ${project.*} properties + value = ReplaceProjectProperties (value, project); + + // Replace explicit properties + value = properties.Apply (value); + } + + value = ReplaceProperties (value, project.Parent, properties); + properties.Pop (); + + return value; + } + + string ReplaceProjectProperties (string value, ResolvedProject project) + { + // Technically this can be any element in the XML, but we're only going to suppport + // some common ones for now to keep things simple. + if (project.Raw.GroupId.HasValue ()) + value = value.Replace ("${project.groupId}", project.Raw.GroupId); + + if (project.Raw.ArtifactId.HasValue ()) + value = value.Replace ("${project.artifactId}", project.Raw.ArtifactId); + + if (project.Raw.Version.HasValue ()) + value = value.Replace ("${project.version}", project.Raw.Version); + + if (project.Raw.Name.HasValue ()) + value = value.Replace ("${project.name}", project.Raw.Name); + + if (project.Raw.Parent?.Version.HasValue () == true) + value = value.Replace ("${project.parent.version}", project.Raw.Parent.Version); + + if (project.Raw.Parent?.GroupId.HasValue () == true) + value = value.Replace ("${project.parent.groupId}", project.Raw.Parent.GroupId); + + return value; + } + + void ImportDependencyManagementPoms () + { + if (resolver is null) + return; + + foreach (var pom_import in GetPomImportDependencies ()) { + var pom = FromArtifact (pom_import.ToArtifact (), resolver); + pom.Resolve (); + ImportedPomProjects.Add (pom); + } + } + + IEnumerable GetPomImportDependencies () + => Resolved.DependencyManagement?.Dependencies.Where (x => x.Type == "pom" && x.Scope == "import") ?? Array.Empty (); + + void ResolveDependencies () + { + // Add _our_ specified dependencies + foreach (var dependency in Resolved.Dependencies) + Dependencies.Add (new ResolvedDependency (this, dependency)); + + // Add dependencies from our parent (the null check is for the super POM) + if (parent is ResolvedProject rp && !rp.IsSuperPom) + foreach (var dependency in parent!.Dependencies) + Dependencies.Add (dependency); + } +} + +// Sentinel class for the super POM, which every POM implicitly inherits if it doesn't specify a parent +public class SuperPom : ResolvedProject +{ + SuperPom () : base (new Project (), null!, null!) + { + } + + public override bool IsSuperPom => true; + + public static SuperPom Instance { get; } = new SuperPom (); +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/CachedMavenRepository.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/CachedMavenRepository.cs new file mode 100644 index 00000000000..3d1f00bfb62 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/CachedMavenRepository.cs @@ -0,0 +1,111 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven.Repositories; + +/// +/// Wraps an and caches files in a local directory. +/// +public class CachedMavenRepository : IMavenRepository +{ + public string CacheDirectory { get; } + + public string Name => repository.Name; + + readonly IMavenRepository repository; + + public CachedMavenRepository (string directory, IMavenRepository repository) + { + CacheDirectory = directory; + this.repository = repository; + } + + public bool TryGetFile (Artifact artifact, string filename, [NotNullWhen (true)] out Stream? stream) + { + stream = null; + + if (TryGetFilePath (artifact, filename, out var path)) { + stream = File.OpenRead (path); + return true; + } + + return false; + } + + public bool TryGetFilePath (Artifact artifact, string filename, [NotNullWhen (true)] out string? path) + { + path = null; + + var file = GetArtifactFilePath (artifact, filename); + + if (File.Exists (file)) { + path = file; + return true; + } + + if (repository.TryGetFile (artifact, filename, out var repo_stream)) { + Directory.CreateDirectory (GetArtifactDirectory (artifact)); + + using (var sw = File.Create (file)) + using (repo_stream) + repo_stream.CopyTo (sw); + + path = file; + return true; + } + + return false; + } + + public async Task GetFilePathAsync (Artifact artifact, string filename, CancellationToken cancellationToken) + { + var file = GetArtifactFilePath (artifact, filename); + + if (File.Exists (file)) + return file; + + if (repository.TryGetFile (artifact, filename, out var repo_stream)) { + Directory.CreateDirectory (GetArtifactDirectory (artifact)); + + using (var sw = File.Create (file)) + using (repo_stream) + await repo_stream.CopyToAsync (sw, 81920, cancellationToken); + + + return file; + } + + return null; + } + + /// + /// Returns the on-disk path where the given + + /// would be cached under . Does not download or check for existence. + /// Throws if the resolved path would not be under + /// . + /// + public string GetArtifactFilePath (Artifact artifact, string filename) + { + var directory = GetArtifactDirectory (artifact); + var file = Path.Combine (directory, filename); + var full_file = Path.GetFullPath (file); + var full_cache = Path.GetFullPath (CacheDirectory); + if (!full_cache.EndsWith (Path.DirectorySeparatorChar.ToString ()) && !full_cache.EndsWith (Path.AltDirectorySeparatorChar.ToString ())) + full_cache += Path.DirectorySeparatorChar; + if (!full_file.StartsWith (full_cache, StringComparison.Ordinal)) + throw new InvalidOperationException ($"Resolved Maven cache path '{full_file}' escapes cache directory '{full_cache}'."); + return full_file; + } + + string GetArtifactDirectory (Artifact artifact) + { + var version = artifact.Version; + var output_directory = Path.Combine (CacheDirectory, repository.Name, artifact.GroupId, artifact.Id, version); + + return output_directory; + } +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/IMavenRepository.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/IMavenRepository.cs new file mode 100644 index 00000000000..d09ba0ac3c7 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/IMavenRepository.cs @@ -0,0 +1,13 @@ +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven.Repositories; + +public interface IMavenRepository +{ + // The on-disk cache for this repository will be in a sub-directory with this name, and thus must be + // compatible with file system naming rules. For example, "central" or "google". + string Name { get; } + bool TryGetFile (Artifact artifact, string filename, [NotNullWhen (true)] out Stream? stream); +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/MavenRepository.cs b/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/MavenRepository.cs new file mode 100644 index 00000000000..9b54887b92f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.Maven/Repositories/MavenRepository.cs @@ -0,0 +1,33 @@ +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Net.Http; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven.Repositories; + +public class MavenRepository : IMavenRepository +{ + readonly string base_url; + static readonly HttpClient client = new HttpClient (); + + public string Name { get; } + + public MavenRepository (string baseUrl, string name) + { + Name = name; + base_url = baseUrl.TrimEnd ('/'); + } + + public bool TryGetFile (Artifact artifact, string filename, [NotNullWhen (true)] out Stream? stream) + { + // ex: https://repo1.maven.org/maven2/dev/chrisbanes/snapper/snapper/0.3.0/{filename} + var file = $"{base_url}/{artifact.GroupId.Replace ('.', '/')}/{artifact.Id}/{artifact.Version}/{filename}"; + stream = client.GetStreamAsync (file).Result; + + return true; + } + + public static readonly MavenRepository Google = new MavenRepository ("https://dl.google.com/android/maven2/", "google"); + + public static readonly MavenRepository Central = new MavenRepository ("https://repo1.maven.org/maven2/", "central"); +} diff --git a/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.csproj b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.csproj new file mode 100644 index 00000000000..b5a852d6508 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.csproj @@ -0,0 +1,27 @@ + + + $(DotNetTargetFramework) + enable + true + $(DefineConstants);JCW_ONLY_TYPE_NAMES;HAVE_CECIL + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.projitems b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.projitems new file mode 100644 index 00000000000..0abb80b9c90 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.projitems @@ -0,0 +1,14 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {E706B6F2-5562-4765-8F07-8CF84A797B30} + + + Java.Interop.Tools.TypeNameMappings + + + + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.shproj b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.shproj new file mode 100644 index 00000000000..8f5a83df9a3 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings.shproj @@ -0,0 +1,13 @@ + + + + 8.0.30703 + 2.0 + {E706B6F2-5562-4765-8F07-8CF84A797B30} + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs new file mode 100644 index 00000000000..efffef22e4f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs @@ -0,0 +1,790 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using Android.Runtime; +using Java.Interop.Tools.JavaCallableWrappers; + +#if HAVE_CECIL +using Mono.Cecil; +using Java.Interop.Tools.Cecil; +#endif // HAVE_CECIL + +namespace Java.Interop.Tools.TypeNameMappings +{ + +#if HAVE_CECIL + public +#endif + enum PackageNamingPolicy { + [Obsolete ("No longer supported. Use PackageNamingPolicy.LowercaseCrc64 instead.", error: true)] + LowercaseHash = 0, + Lowercase = 1, + LowercaseWithAssemblyName = 2, + [Obsolete ("No longer supported. Use PackageNamingPolicy.LowercaseCrc64 instead.", error: true)] + LowercaseMD5 = LowercaseHash, + LowercaseCrc64 = 3, + } + +#if HAVE_CECIL + public +#endif + class JniTypeName + { + string? type; + public string Type { + get => type ?? throw new InvalidOperationException ("`Type` must be set before accessing it!"); + internal set => type = value; + } + public bool IsKeyword { get; internal set; } + } + +#if HAVE_CECIL + public +#endif + static class JavaNativeTypeManager { + const string CRC_PREFIX = "crc64"; + + public static PackageNamingPolicy PackageNamingPolicy { get; set; } = PackageNamingPolicy.LowercaseCrc64; + + public static string? ApplicationJavaClass { get; set; } + + public static JniTypeName? Parse (string? jniType) + { + int _ = 0; + return ExtractType (jniType, ref _); + } + + public static IEnumerable FromSignature (string signature) + { + if (signature.StartsWith ("(", StringComparison.Ordinal)) { + int e = signature.IndexOf (')'); + signature = signature.Substring (1, e >= 0 ? e-1 : signature.Length-1); + } + int i = 0; + JniTypeName t; + while ((t = ExtractType (signature, ref i)) != null) + yield return t; + } + + [return: NotNullIfNotNull ("signature")] + public static JniTypeName? ReturnTypeFromSignature (string? signature) + { + if (signature == null) { + return null; + } + int idx = signature.LastIndexOf (')') + 1; + return ExtractType (signature, ref idx); + } + + // as per: http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/types.html + [return: NotNullIfNotNull ("signature")] + static JniTypeName? ExtractType (string? signature, ref int index) + { + if (signature is null || index >= signature.Length) + return null; + var i = index++; + switch (signature [i]) { + case '[': { + ++i; + if (i >= signature.Length) + throw new InvalidOperationException ("Missing array type after '[' at index " + i + " in: " + signature); + var r = ExtractType (signature, ref index); + return new JniTypeName { Type = r.Type + "[]", IsKeyword = r.IsKeyword }; + } + case 'B': + return new JniTypeName { Type = "byte", IsKeyword = true }; + case 'C': + return new JniTypeName { Type = "char", IsKeyword = true }; + case 'D': + return new JniTypeName { Type = "double", IsKeyword = true }; + case 'F': + return new JniTypeName { Type = "float", IsKeyword = true }; + case 'I': + return new JniTypeName { Type = "int", IsKeyword = true }; + case 'J': + return new JniTypeName { Type = "long", IsKeyword = true }; + case 'L': { + var e = signature.IndexOf (';', index); + if (e <= 0) + throw new InvalidOperationException ("Missing reference type after 'L' at index " + i + "in: " + signature); + var s = index; + index = e + 1; + return new JniTypeName { + Type = signature.Substring (s, e - s).Replace ("/", ".").Replace ("$", "."), + IsKeyword = false, + }; + } + case 'S': + return new JniTypeName { Type = "short", IsKeyword = true }; + case 'V': + return new JniTypeName { Type = "void", IsKeyword = true }; + case 'Z': + return new JniTypeName { Type = "boolean", IsKeyword = true }; + default: + throw new InvalidOperationException ("Unknown JNI Type '" + signature [i] + "' within: " + signature); + } + } + + public static string ToCliType (string jniType) + { + if (string.IsNullOrEmpty (jniType)) + return jniType; + string[] parts = jniType.Split ('/'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = ToCliTypePart (parts [i]); + } + return string.Join (".", parts); + } + + static string ToCliTypePart (string part) + { + if (part.IndexOf ('$') < 0) + return ToPascalCase (part, 2); + string[] parts = part.Split ('$'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = ToPascalCase (parts [i], 1); + } + return string.Join ("+", parts); + } + + static string ToPascalCase (string value, int minLength) + { + return value.Length <= minLength + ? value.ToUpperInvariant () + : char.ToUpperInvariant (value [0]) + value.Substring (1); + } + + // Keep in sync with ToJniName(TypeDefinition) + public static string ToJniName (Type type) + { + return ToJniName (type, ExportParameterKind.Unspecified) ?? + "java/lang/Object"; + } + + static string? ToJniName (Type type, ExportParameterKind exportKind) + { + if (type == null) + throw new ArgumentNullException ("type"); + + if (type.IsValueType) + return GetPrimitiveClass (type); + + if (type == typeof (string)) + return "java/lang/String"; + + if (ShouldCheckSpecialExportJniType (type)) + return GetSpecialExportJniType (type.FullName!, exportKind); + + return ToJniName (type, t => t.DeclaringType!, t => t.Name, GetPackageName, t => { + return ToJniNameFromAttributes (t); + }, _ => false); + } + +#if !NETSTANDARD2_0 + static readonly Lazy IJavaPeerableType = new Lazy (() => + Type.GetType ("Java.Interop.IJavaPeerable, Java.Interop", throwOnError: true)! + ); +#endif + + // NOTE: NETSTANDARD2_0 could be running in an MSBuild context where Java.Interop.dll is not available. + // Trimming warnings are not enabled for netstandard2.0 in this project. + static bool ShouldCheckSpecialExportJniType (Type type) => +#if NETSTANDARD2_0 + !type.GetInterfaces ().Any (t => t.FullName == "Java.Interop.IJavaPeerable"); +#else + !IJavaPeerableType.Value.IsAssignableFrom (type); +#endif + + public static string ToJniName (string jniType, int rank) + { + if (rank == 0) + return jniType; + + if (jniType.Length > 1 && jniType [0] != '[') + jniType = "L" + jniType + ";"; + return new string ('[', rank) + jniType; + } + + static bool IsPackageNamePreservedForAssembly (string assemblyName) + { + return assemblyName == "Mono.Android"; + } + + public static string GetPackageName (Type type) + { + string assemblyName = GetAssemblyName (type.Assembly); + if (IsPackageNamePreservedForAssembly (assemblyName)) + return type.Namespace!.ToLowerInvariant (); + return GetPackageName (type.Namespace ?? "", assemblyName); + } + + /// + /// Generates a package name from a namespace and assembly name. + /// + /// The namespace of the type. + /// The assembly name. + /// A package name based on the current . + public static string GetPackageName (string ns, string assemblyName) + { + switch (PackageNamingPolicy) { + case PackageNamingPolicy.Lowercase: + return ns.ToLowerInvariant (); + case PackageNamingPolicy.LowercaseWithAssemblyName: + return "assembly_" + (assemblyName.Replace ('.', '_') + "." + ns).ToLowerInvariant (); + case PackageNamingPolicy.LowercaseCrc64: + return CRC_PREFIX + ToCrc64 (ns + ":" + assemblyName); + default: + throw new NotSupportedException ($"PackageNamingPolicy.{PackageNamingPolicy} is no longer supported."); + } + } + + /// + /// A more performant equivalent of `Assembly.GetName().Name` + /// + static string GetAssemblyName (Assembly assembly) + { + var name = assembly.FullName!; + int index = name.IndexOf (','); + if (index != -1) { + return name.Substring (0, index); + } + return name; + } + + public static int GetArrayInfo (Type type, out Type elementType) + { + elementType = type; + int rank = 0; + while (type.IsArray) { + rank++; + elementType = type = type.GetElementType ()!; + } + return rank; + } + + static string? GetPrimitiveClass (Type type) + { + if (type.IsEnum) + return GetPrimitiveClass (Enum.GetUnderlyingType (type)); + if (type == typeof (byte)) + return "B"; + if (type == typeof (char)) + return "C"; + if (type == typeof (double)) + return "D"; + if (type == typeof (float)) + return "F"; + if (type == typeof (int)) + return "I"; + if (type == typeof (uint)) + return "I"; + if (type == typeof (long)) + return "J"; + if (type == typeof (ulong)) + return "J"; + if (type == typeof (short)) + return "S"; + if (type == typeof (ushort)) + return "S"; + if (type == typeof (bool)) + return "Z"; + return null; + } + + static string? GetSpecialExportJniType (string typeName, ExportParameterKind exportKind) + { + switch (exportKind) { + case ExportParameterKind.InputStream: + if (typeName != "System.IO.Stream") + throw new ArgumentException ("ExportParameterKind.InputStream is valid only for System.IO.Stream parameter type"); + return "java/io/InputStream"; + case ExportParameterKind.OutputStream: + if (typeName != "System.IO.Stream") + throw new ArgumentException ("ExportParameterKind.OutputStream is valid only for System.IO.Stream parameter type"); + return "java/io/OutputStream"; + case ExportParameterKind.XmlPullParser: + if (typeName != "System.Xml.XmlReader") + throw new ArgumentException ("ExportParameterKind.XmlPullParser is valid only for System.Xml.XmlReader parameter type"); + return "org/xmlpull/v1/XmlPullParser"; + case ExportParameterKind.XmlResourceParser: + if (typeName != "System.Xml.XmlReader") + throw new ArgumentException ("ExportParameterKind.XmlResourceParser is valid only for System.Xml.XmlReader parameter type"); + return "android/content/res/XmlResourceParser"; + } + // FIXME: this *must* error out here, instead of returning null. + // Either Droidinator must be fixed to not reach here, or a global flag that skips this error check must be added. + return null; + } + + // Keep in sync with ToJniNameFromAttributes(TypeDefinition) + public static string? ToJniNameFromAttributes (Type type) + { + var aa = (IJniNameProviderAttribute []) type.GetCustomAttributes (typeof (IJniNameProviderAttribute), inherit: false); + return aa.Length > 0 && !string.IsNullOrEmpty (aa [0].Name) ? aa [0].Name.Replace ('.', '/') : null; + } + + /* + * Semantics: return `null` on "failure", DO NOT throw an exception. + * + * Why? tools/msbuild/Generator/JavaTypeInfo.cs!AddConstructors() attempts + * to generate (non-[Export]) constructors, and to determine whether or + * not the constructor CAN be declared it calls + * JniType.GetJniSignature(MethodDefinition). If GetJniSignature() returns + * null, it can't be exported, and the method is skipped. + * + * Callers of GetJniSignature() MUST check for `null` and behave + * appropriately. + */ + static string? GetJniSignature (IEnumerable

parameters, Func getParameterType, Func getExportKind, T returnType, ExportParameterKind returnExportKind, Func getJniTypeName, bool isConstructor) + { + StringBuilder sb = new StringBuilder ().Append ("("); + foreach (P p in parameters) { + var jniType = getJniTypeName (getParameterType (p), getExportKind (p)); + if (jniType == null) + return null; + sb.Append (jniType); + } + sb.Append (')'); + if (isConstructor) + sb.Append ("V"); + else { + var jniType = getJniTypeName (returnType, returnExportKind); + if (jniType == null) + return null; + sb.Append (jniType); + } + return sb.ToString (); + } + + static string? GetJniTypeName (TR typeRef, ExportParameterKind exportKind, Func resolve, Func> getArrayInfo, Func getFullName, Func toJniName) + { + TD ptype = resolve (typeRef); + var p = getArrayInfo (typeRef); + int rank = p.Key; + TR etype = p.Value; + ptype = resolve (etype); + if (ptype == null) { + // Likely caused by generic parameters, which we probably can't bind anyway. + return null; + } + if (getFullName (ptype) == "System.Void") + return "V"; + if (getFullName (ptype) == "System.IntPtr") + // Probably a (IntPtr, JniHandleOwnership) parameter; skip + return null; + + var pJniName = toJniName (ptype, exportKind); + if (pJniName == null) { + return null; + } + return (rank == 0 && pJniName.Length > 1 && pJniName[0] != '[') + ? "L" + pJniName + ";" + : ToJniName (pJniName, rank); + } + + static ExportParameterKind GetExportKind (System.Reflection.ICustomAttributeProvider p) + { + foreach (ExportParameterAttribute a in p.GetCustomAttributes (typeof (ExportParameterAttribute), false)) + return a.Kind; + return ExportParameterKind.Unspecified; + } + + public static string? GetJniSignature (MethodInfo method) + { + return GetJniSignature (method.GetParameters (), + p => p.ParameterType, + p => GetExportKind (p), + method.ReturnType, + GetExportKind (method.ReturnParameter), + (t, k) => GetJniTypeName (t, k), + method.IsConstructor); + } + + public static string? GetJniTypeName (Type typeRef) + { + return GetJniTypeName (typeRef, ExportParameterKind.Unspecified); + } + + internal static string? GetJniTypeName (Type typeRef, ExportParameterKind exportKind) + { + return GetJniTypeName (typeRef, exportKind, t => t, t => { + Type etype; + int rank = GetArrayInfo (t, out etype); + return new KeyValuePair (rank, etype); + }, t => t.FullName!, (t, k) => ToJniNameWhichShouldReplaceExistingToJniName (t, k)); + } + + static string? ToJniNameWhichShouldReplaceExistingToJniName (Type type, ExportParameterKind exportKind) + { + // we need some method that exactly does the same as ToJniName(TypeDefinition) + var ret = ToJniNameFromAttributes (type); + return ret ?? ToJniName (type, exportKind); + } + +#if HAVE_CECIL + + internal static ExportParameterKind GetExportKind (Mono.Cecil.ICustomAttributeProvider p) + { + foreach (CustomAttribute a in p.GetCustomAttributes (typeof (ExportParameterAttribute))) + return ToExportParameterAttribute (a).Kind; + return ExportParameterKind.Unspecified; + } + + internal static ExportParameterAttribute ToExportParameterAttribute (CustomAttribute attr) + { + return new ExportParameterAttribute ((ExportParameterKind)attr.ConstructorArguments [0].Value); + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static bool IsApplication (TypeDefinition type) => throw new NotSupportedException (); + + public static bool IsApplication (TypeDefinition type, TypeDefinitionCache cache) => + IsApplication (type, (IMetadataResolver) cache); + + public static bool IsApplication (TypeDefinition type, IMetadataResolver resolver) + { + return type.GetBaseTypes (resolver).Any (b => b.FullName == "Android.App.Application"); + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static bool IsInstrumentation (TypeDefinition type) => throw new NotSupportedException (); + + public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache cache) => + IsInstrumentation (type, (IMetadataResolver) cache); + + public static bool IsInstrumentation (TypeDefinition type, IMetadataResolver resolver) + { + return type.GetBaseTypes (resolver).Any (b => b.FullName == "Android.App.Instrumentation"); + } + + // moved from JavaTypeInfo + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string? GetJniSignature (MethodDefinition method) => throw new NotSupportedException (); + + public static string? GetJniSignature (MethodDefinition method, TypeDefinitionCache cache) => + GetJniSignature (method, (IMetadataResolver) cache); + + public static string? GetJniSignature (MethodDefinition method, IMetadataResolver resolver) + { + return GetJniSignature ( + method.Parameters, + p => p.ParameterType, + p => GetExportKind (p), + method.ReturnType, + GetExportKind (method.MethodReturnType), + (t, k) => GetJniTypeName (t, k, resolver), + method.IsConstructor); + } + + // moved from JavaTypeInfo + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string? GetJniTypeName (TypeReference typeRef) => throw new NotSupportedException (); + + public static string? GetJniTypeName (TypeReference typeRef, TypeDefinitionCache cache) => + GetJniTypeName (typeRef, (IMetadataResolver) cache); + + public static string? GetJniTypeName (TypeReference typeRef, IMetadataResolver resolver) + { + return GetJniTypeName (typeRef, ExportParameterKind.Unspecified, resolver); + } + + internal static string? GetJniTypeName (TypeReference typeRef, ExportParameterKind exportKind, IMetadataResolver cache) + { + return GetJniTypeName (typeRef, exportKind, t => cache.Resolve (t), t => { + TypeReference etype; + int rank = GetArrayInfo (typeRef, out etype); + return new KeyValuePair (rank,etype); + }, t => t.FullName, (t, k) => ToJniName (t, k, cache)); + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string ToCompatJniName (TypeDefinition type) => throw new NotSupportedException (); + + public static string ToCompatJniName (TypeDefinition type, TypeDefinitionCache cache) => + ToCompatJniName (type, (IMetadataResolver) cache); + + public static string ToCompatJniName (TypeDefinition type, IMetadataResolver resolver) + { + return ToJniName ( + type: type, + decl: t => t.DeclaringType, + name: t => t.Name, + ns: ToCompatPackageName, + overrideName: t => ToJniNameFromAttributes (t, resolver), + shouldUpdateName: t => IsNonStaticInnerClass (t as TypeDefinition, resolver) + ); + } + + static string ToCompatPackageName (TypeDefinition type) + { + return type.Namespace; + } + + // Keep in sync with ToJniNameFromAttributes(Type) and ToJniName(Type) + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string ToJniName (TypeDefinition type) => throw new NotSupportedException (); + + public static string ToJniName (TypeDefinition type, TypeDefinitionCache cache) => + ToJniName (type, (IMetadataResolver) cache); + + public static string ToJniName (TypeDefinition type, IMetadataResolver resolver) + { + var x = ToJniName (type, ExportParameterKind.Unspecified, resolver) ?? + "java/lang/Object"; + return x; + } + + static string? ToJniName (TypeDefinition type, ExportParameterKind exportKind, IMetadataResolver cache) + { + if (type == null) + throw new ArgumentNullException ("type"); + + if (type.IsValueType) + return GetPrimitiveClass (type, cache); + + if (type.FullName == "System.String") + return "java/lang/String"; + + if (!type.ImplementsInterface ("Android.Runtime.IJavaObject", cache) && + !type.ImplementsInterface ("Java.Interop.IJavaPeerable", cache)) { + return GetSpecialExportJniType (type.FullName, exportKind); + } + + return ToJniName ( + type: type, + decl: t => t.DeclaringType, + name: t => t.Name, + ns: t => GetPackageName (t, cache), + overrideName: t => ToJniNameFromAttributes (t, cache), + shouldUpdateName: t => IsNonStaticInnerClass (t as TypeDefinition, cache) + ); + } + + static string? ToJniNameFromAttributes (TypeDefinition type, IMetadataResolver resolver) + { + return ToJniNameFromAttributesForAndroid (type, resolver) ?? + ToJniNameFromAttributesForInterop (type, resolver); + } + + static string? ToJniNameFromAttributesForInterop (TypeDefinition type, IMetadataResolver resolver) + { + var attr = type.CustomAttributes.FirstOrDefault (a => + resolver.Resolve (a.AttributeType) + .FullName == "Java.Interop.JniTypeSignatureAttribute"); + if (attr == null) { + return null; + } + var carg = attr.ConstructorArguments.FirstOrDefault (); + if (carg.Type == null || carg.Type.FullName != "System.String") + return null; + var jniType = (string) carg.Value; + var isKeyProp = attr.Properties.FirstOrDefault (p => p.Name == "IsKeyword"); + var isKeyword = isKeyProp.Name != null && ((bool) isKeyProp.Argument.Value) == true; + var arrRankProp = attr.Properties.FirstOrDefault (p => p.Name == "ArrayRank"); + var arrayRank = arrRankProp.Name != null && arrRankProp.Argument.Value is int rank ? rank : 0; + jniType = arrayRank == 0 + ? jniType + : new string ('[', arrayRank) + (isKeyword ? jniType : "L" + jniType + ";"); + return jniType; + } + + static string? ToJniNameFromAttributesForAndroid (TypeDefinition type, IMetadataResolver resolver) + { + if (!type.HasCustomAttributes) + return null; + foreach (var attr in type.CustomAttributes) { + if (!IsIJniNameProviderAttribute (attr, resolver)) + continue; + var ap = attr.HasProperties ? attr.Properties.FirstOrDefault (p => p.Name == "Name") : default; + string? name = null; + if (ap.Name == null) { + var ca = attr.ConstructorArguments.FirstOrDefault (); + if (ca.Type == null || ca.Type.FullName != "System.String") + continue; + name = (string) ca.Value; + } else + name = (string) ap.Argument.Value; + if (!string.IsNullOrEmpty (name)) + return name.Replace ('.', '/'); + } + return null; + } + + static readonly HashSet KnownIJniNameProviders = new HashSet (StringComparer.Ordinal) { + "Android.App.ActivityAttribute", + "Android.App.ApplicationAttribute", + "Android.App.InstrumentationAttribute", + "Android.App.ServiceAttribute", + "Android.Content.BroadcastReceiverAttribute", + "Android.Content.ContentProviderAttribute", + "Android.Runtime.RegisterAttribute", + }; + + static bool IsIJniNameProviderAttribute (CustomAttribute attr, IMetadataResolver resolver) + { + // Fast path for a list of known IJniNameProviderAttribute implementations + if (KnownIJniNameProviders.Contains (attr.AttributeType.FullName)) + return true; + + // Slow path resolves the type, looking for IJniNameProviderAttribute + var attributeType = resolver.Resolve (attr.AttributeType); + if (!attributeType.HasInterfaces) + return false; + return attributeType.Interfaces.Any (it => it.InterfaceType.FullName == typeof (IJniNameProviderAttribute).FullName); + } + + public static int GetArrayInfo (Mono.Cecil.TypeReference type, out Mono.Cecil.TypeReference elementType) + { + elementType = type; + int rank = 0; + while (type.IsArray) { + rank++; + elementType = type = type.GetElementType (); + } + return rank; + } + + static string? GetPrimitiveClass (Mono.Cecil.TypeDefinition type, IMetadataResolver cache) + { + if (type.IsEnum) + return GetPrimitiveClass (cache.Resolve (type.Fields.First (f => f.IsSpecialName).FieldType), cache); + if (type.FullName == "System.Byte") + return "B"; + if (type.FullName == "System.Char") + return "C"; + if (type.FullName == "System.Double") + return "D"; + if (type.FullName == "System.Single") + return "F"; + if (type.FullName == "System.Int32") + return "I"; + if (type.FullName == "System.Int64") + return "J"; + if (type.FullName == "System.Int16") + return "S"; + if (type.FullName == "System.Boolean") + return "Z"; + return null; + } + + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static string GetPackageName (TypeDefinition type) => throw new NotSupportedException (); + + public static string GetPackageName (TypeDefinition type, TypeDefinitionCache cache) => + GetPackageName (type, (IMetadataResolver) cache); + + public static string GetPackageName (TypeDefinition type, IMetadataResolver resolver) + { + if (IsPackageNamePreservedForAssembly (type.GetPartialAssemblyName (resolver))) + return type.Namespace.ToLowerInvariant (); + return GetPackageName (type.Namespace, type.GetPartialAssemblyName (resolver)); + } +#endif + + static string ToJniName (T type, Func decl, Func name, Func ns, Func overrideName, Func shouldUpdateName) + where T : class + { + var nameParts = new List (); + var typeName = (string?) null; + var nsType = type; + + for (var declType = type ; declType != null; declType = decl (declType)) { + nsType = declType; + typeName = overrideName (declType); + if (typeName != null) { + break; + } + var n = name (declType).Replace ('`', '_'); + if (shouldUpdateName (declType)) { + n = "$" + name (decl (declType)) + "_" + n; + } + nameParts.Add (n); + } + + if (nameParts.Count == 0 && typeName != null) + return typeName; + + nameParts.Reverse (); + + var nestedSuffix = string.Join ("_", nameParts.ToArray ()).Replace ("_$", "$"); + if (typeName != null) + return (typeName + "_" + nestedSuffix).Replace ("_$", "$");; + + // Results in namespace/parts/OuterType_InnerType + // We do this to simplify monodroid type generation + typeName = nestedSuffix; + var _ns = ToLowerCase (ns (nsType)); + return string.IsNullOrEmpty (_ns) + ? typeName + : _ns.Replace ('.', '/') + "/" + typeName; + } + +#if HAVE_CECIL + internal static bool IsNonStaticInnerClass (TypeDefinition? type, IMetadataResolver cache) + { + if (type == null) + return false; + if (!type.IsNested) + return false; + + if (!type.DeclaringType.HasJavaPeer (cache)) + return false; + + foreach (var baseType in type.GetBaseTypes (cache)) { + if (baseType == null) + continue; + if (!HasTypeRegistrationAttribute (baseType)) + continue; + + foreach (var method in baseType.Methods) { + if (!method.IsConstructor || method.IsStatic) + continue; + if (method.Parameters.Any (p => p.Name == "__self")) + return true; + } + + // Stop at the first base type with [Register] + break; + } + + return false; + } + + static bool HasTypeRegistrationAttribute (TypeDefinition type) + { + if (!type.HasCustomAttributes) + return false; + return type.AnyCustomAttributes (typeof (RegisterAttribute)) || + type.AnyCustomAttributes ("Java.Interop.JniTypeSignatureAttribute"); + } +#endif // HAVE_CECIL + + static string ToCrc64 (string value) + { + var data = Encoding.UTF8.GetBytes (value); + var hash = Crc64Helper.Compute (data); + var buf = new StringBuilder (hash.Length * 2); + foreach (var b in hash) + buf.AppendFormat ("{0:x2}", b); + return buf.ToString (); + } + + static string ToLowerCase (string value) + { + if (string.IsNullOrEmpty (value)) + return value; + string[] parts = value.Split ('.'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = parts [i].ToLowerInvariant (); + } + return string.Join (".", parts); + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/.editorconfig b/external/Java.Interop/src/Java.Interop/.editorconfig new file mode 100644 index 00000000000..a6f41a4aa3c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/.editorconfig @@ -0,0 +1,154 @@ +# This files sets all rules from Gendarme as Code Analysis errors +# via: https://github.com/spouliot/gendarme/wiki/GendarmeToFxCop(git) + +[*.cs] +dotnet_diagnostic.CA2001.severity = error +dotnet_diagnostic.CA2214.severity = error +dotnet_diagnostic.CA2222.severity = error +dotnet_diagnostic.CA1065.severity = error +dotnet_diagnostic.CA1041.severity = error +dotnet_diagnostic.CA2230.severity = error +dotnet_diagnostic.CA2006.severity = error +dotnet_diagnostic.CA2002.severity = error +dotnet_diagnostic.CA2211.severity = error +dotnet_diagnostic.CA2243.severity = error +dotnet_diagnostic.CA1053.severity = error +# dotnet_diagnostic.CA1062.severity = error CheckParametersNullityInVisibleMethodsRule - We'll use NRT instead +dotnet_diagnostic.CA2213.severity = error +dotnet_diagnostic.CA2242.severity = error +dotnet_diagnostic.CA2000.severity = error +dotnet_diagnostic.CA2220.severity = error +dotnet_diagnostic.CA2241.severity = error +dotnet_diagnostic.CA1012.severity = error +dotnet_diagnostic.CA1019.severity = error +dotnet_diagnostic.CA1040.severity = error +dotnet_diagnostic.CA1023.severity = error +dotnet_diagnostic.CA1044.severity = error +dotnet_diagnostic.CA1020.severity = error +dotnet_diagnostic.CA1051.severity = error +dotnet_diagnostic.CA1034.severity = error +dotnet_diagnostic.CA1024.severity = error +dotnet_diagnostic.CA1052.severity = error +dotnet_diagnostic.CA1009.severity = error +dotnet_diagnostic.CA2216.severity = error +dotnet_diagnostic.CA1047.severity = error +dotnet_diagnostic.CA2227.severity = error +dotnet_diagnostic.CA1048.severity = error +dotnet_diagnostic.CA2226.severity = error +dotnet_diagnostic.CA1038.severity = error +dotnet_diagnostic.CA1008.severity = error +dotnet_diagnostic.CA1028.severity = error +dotnet_diagnostic.CA2221.severity = error +dotnet_diagnostic.CA2218.severity = error +dotnet_diagnostic.CA1036.severity = error +dotnet_diagnostic.CA1039.severity = error +dotnet_diagnostic.CA1016.severity = error +dotnet_diagnostic.CA1014.severity = error +dotnet_diagnostic.CA1017.severity = error +dotnet_diagnostic.CA1018.severity = error +dotnet_diagnostic.CA1013.severity = error +dotnet_diagnostic.CA2231.severity = error +dotnet_diagnostic.CA2224.severity = error +dotnet_diagnostic.CA1030.severity = error +dotnet_diagnostic.CA1043.severity = error +dotnet_diagnostic.CA1054.severity = error +dotnet_diagnostic.CA1055.severity = error +dotnet_diagnostic.CA1056.severity = error +dotnet_diagnostic.CA1059.severity = error +dotnet_diagnostic.CA2225.severity = error +dotnet_diagnostic.CA1035.severity = error +dotnet_diagnostic.CA1050.severity = error +dotnet_diagnostic.CA1001.severity = error +dotnet_diagnostic.CA1049.severity = error +dotnet_diagnostic.CA1027.severity = error +dotnet_diagnostic.CA1005.severity = error +dotnet_diagnostic.CA1004.severity = error +dotnet_diagnostic.CA1000.severity = error +dotnet_diagnostic.CA1006.severity = error +dotnet_diagnostic.CA1010.severity = error +dotnet_diagnostic.CA1007.severity = error +dotnet_diagnostic.CA1003.severity = error +dotnet_diagnostic.CA2201.severity = error +dotnet_diagnostic.CA2200.severity = error +dotnet_diagnostic.CA1031.severity = error +dotnet_diagnostic.CA2219.severity = error +dotnet_diagnostic.CA1065.severity = error +dotnet_diagnostic.CA2201.severity = error +dotnet_diagnostic.CA1064.severity = error +dotnet_diagnostic.CA2208.severity = error +dotnet_diagnostic.CA1032.severity = error +dotnet_diagnostic.CA1060.severity = error +dotnet_diagnostic.CA1404.severity = error +dotnet_diagnostic.CA1414.severity = error +dotnet_diagnostic.CA2101.severity = error +dotnet_diagnostic.CA1401.severity = error +dotnet_diagnostic.CA2205.severity = error +dotnet_diagnostic.CA1403.severity = error +dotnet_diagnostic.CA1406.severity = error +dotnet_diagnostic.CA1413.severity = error +dotnet_diagnostic.CA1402.severity = error +dotnet_diagnostic.CA1407.severity = error +dotnet_diagnostic.CA1405.severity = error +dotnet_diagnostic.CA1409.severity = error +dotnet_diagnostic.CA1408.severity = error +dotnet_diagnostic.CA1412.severity = error +dotnet_diagnostic.CA1410.severity = error +dotnet_diagnostic.CA1411.severity = error +dotnet_diagnostic.CA1501.severity = error +dotnet_diagnostic.CA1011.severity = error +dotnet_diagnostic.CA1504.severity = error +dotnet_diagnostic.CA1500.severity = error +dotnet_diagnostic.CA1707.severity = error +dotnet_diagnostic.CA1724.severity = error +dotnet_diagnostic.CA1713.severity = error +dotnet_diagnostic.CA1712.severity = error +dotnet_diagnostic.CA1700.severity = error +dotnet_diagnostic.CA1725.severity = error +dotnet_diagnostic.CA1709.severity = error +dotnet_diagnostic.CA1715.severity = error +dotnet_diagnostic.CA1722.severity = error +dotnet_diagnostic.CA1710.severity = error +dotnet_diagnostic.CA1711.severity = error +dotnet_diagnostic.CA1714.severity = error +dotnet_diagnostic.CA1726.severity = error +dotnet_diagnostic.CA1809.severity = error +dotnet_diagnostic.CA1800.severity = error +dotnet_diagnostic.CA1819.severity = error +dotnet_diagnostic.CA1811.severity = error +dotnet_diagnostic.CA1812.severity = error +dotnet_diagnostic.CA1805.severity = error +dotnet_diagnostic.CA1813.severity = error +dotnet_diagnostic.CA1801.severity = error +dotnet_diagnostic.CA1823.severity = error +dotnet_diagnostic.CA1820.severity = error +dotnet_diagnostic.CA1806.severity = error +dotnet_diagnostic.CA1815.severity = error +dotnet_diagnostic.CA1802.severity = error +dotnet_diagnostic.CA1821.severity = error +dotnet_diagnostic.CA1804.severity = error +dotnet_diagnostic.CA2105.severity = error +dotnet_diagnostic.CA2111.severity = error +dotnet_diagnostic.CA2121.severity = error +dotnet_diagnostic.CA2126.severity = error +dotnet_diagnostic.CA2112.severity = error +dotnet_diagnostic.CA2122.severity = error +dotnet_diagnostic.CA2114.severity = error +dotnet_diagnostic.CA2118.severity = error +dotnet_diagnostic.CA2236.severity = error +dotnet_diagnostic.CA2239.severity = error +dotnet_diagnostic.CA2240.severity = error +dotnet_diagnostic.CA2235.severity = error +dotnet_diagnostic.CA2237.severity = error +dotnet_diagnostic.CA2229.severity = error +dotnet_diagnostic.CA2238.severity = error +dotnet_diagnostic.CA2232.severity = error + +# Disable some default Code Analysis warnings we aren't interested in +dotnet_diagnostic.CA1033.severity = none # Interface methods should be callable by child types +dotnet_diagnostic.CA1062.severity = none # Validate arguments of public methods (we'll use nullable reference types instead) +dotnet_diagnostic.CA1063.severity = none # Implement IDisposable correctly +dotnet_diagnostic.CA1303.severity = none # Do not pass literals as localized parameters +dotnet_diagnostic.CA1305.severity = none # Specify IFormatProvider +dotnet_diagnostic.CA1502.severity = none # 'Method' has a cyclomatic complexity of 'XX'. Rewrite or refactor the code to decrease its complexity below 'YY'. +dotnet_diagnostic.CA1810.severity = none # Initialize reference type static fields inline +dotnet_diagnostic.CA1816.severity = none # Call GC.SuppressFinalize correctly diff --git a/external/Java.Interop/src/Java.Interop/.gitignore b/external/Java.Interop/src/Java.Interop/.gitignore new file mode 100644 index 00000000000..f11d52d7fe0 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/.gitignore @@ -0,0 +1,2 @@ +Java.Interop/JniEnvironment.g.cs +obj-MonoAndroid diff --git a/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/IJavaPeerable.xml b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/IJavaPeerable.xml new file mode 100644 index 00000000000..9cc8523bc85 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/IJavaPeerable.xml @@ -0,0 +1,369 @@ + + + +

+ Support for using Java object instances. + + + + The IJavaPeerable interface provides access to a Java object + instance, invocation of members on that Java instance, control over + the lifetime of that object instance, and callbacks for when the + wrapper is being disposed or finalized. + The following operations are permitted: + + + + Object instance access is available through the + + property. + + + Member access and invocation is available through the + + property. + + + Object lifetime control through + and + + methods. + + + Value visibilty is controlled through + . + + + Disposal and finalization callbacks through the + and + methods. + + + + DO NOT IMPLEMENT THIS INTERFACE. + + Implementations of this interface are useless without a + + implementation which returns + a non-default(JniObjectReference) value, which + corresponds to in the Java VM. + While this can be done, it frequently isn't, resulting in + "unexpected" NullPointerException errors from Java. + Additionally, even though you can implement PeerReference, + any implementation won't fit in with a garbage collector, resulting + in either memory leaks or additional work to clean values up. + + + + + + Called when the instance has been disposed. + + + The Disposed method is invoked after the + method has + been invoked on the instance. + The + property is still valid when Disposed is invoked. + + + This method should only be invoked by the + instance which will + be managing the IJavaPeerable value. + + + + If the type is following the typical IDisposable + pattern, then the Disposed method should delegate to + the Dispose(bool) method. + The proscribed implementation template is: + + +[JniTypeSignature ("my/Example")] +partial class ExampleBinding : IJavaPeerable { + + public void Dispose () + { + JniEnvironment.Runtime.ValueManager.Dispose (this); + } + + protected virtual void Dispose (bool disposing) + { + } + + void IJavaPeerable.Disposed () + { + Dispose (disposing: true); + } +} + + + + + + + If there are no outstanding references to this instance, then + calls Dispose(); otherwise, does nothing. + + + + Call this method when you would like to allow instances to be + collectable as soon as possible, but not if the current instance + is referenced anywhere else. + + + "not referenced anywhere else" may mean "is not registered". + + + + The proscribed implementation template is: + + +[JniTypeSignature ("my/Example")] +partial class ExampleBinding : IJavaPeerable { + + public void DisposeUnlessReferenced () + { + JniEnvironment.Runtime.ValueManager.DisposeUnlessReferenced (this); + } +} + + + + + + + Called when the instance has been finalized. + + + The Finalized method is invoked after the finalizer + has been invoked on the instance. + The + property is NOT valid when Finalized is invoked. + + + This method should only be invoked by the + instance which will + be managing the IJavaPeerable value. + + + + If the type is following the typical IDisposable + pattern, then the Finalized method should delegate to + the Dispose(bool) method. + The proscribed implementation template is: + + +[JniTypeSignature ("my/Example")] +partial class ExampleBinding : IJavaPeerable { + + ~ExampleBinding () + { + JniEnvironment.Runtime.ValueManager.TryCollectObject (this); + } + + protected virtual void Dispose (bool disposing) + { + } + + void IJavaPeerable.Finalized () + { + Dispose (disposing: false); + } +} + + + + + + + + Returns the value of java.lang.System.identityHashCode() + for the wrapped instance. + + + + This property will not throw a + after the instance + has been disposed. + + + The JniIdentityHashCode property should return the value + last passed to + . + + + + > + + State of the managed peer. + + + A value providing + the state of the current Managed Peer instance. + + (Definitions) + + + + + + + Member access and invocation support. + + + + This property will not throw a + after the instance + has been disposed. + + + + The JniPeerMembers property may be accessed before the + constructor has executed, as common behavior is for the + JniPeerMembers to be access virtually to permit caching + of constructor jmethodIDs. + + + The proscribed implementation template is: + + +[JniTypeSignature ("my/Example")] +partial class ExampleBinding { + static readonly JniPeerMembers _members = new JniPeerMembers ("my/Example", typeof (ExampleBinding)); + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } +} + + + + + + + Returns a + of the wrapped + Java object instance. + + + + This property will not throw a + after the instance + has been disposed. + + + + THIS VALUE WILL CHANGE OVER TIME. It is NOT stable. + It may potentially change during any future GC. + DO NOT use this value as a key in a dictionary. + The + property may be used for that purpose. + + + While the value can change, the PeerReference property + should always refer to the same Java instance. + (Multiple different JNI handle values may refer to the same + Java instance.) + + + + The JniIdentityHashCode property should return the value + last passed to + . + + + + > + + Set the value returned by JniIdentityHashCode. + + A which contains the value that future + invocations of the + + property should return. + + + + The SetJniIdentityHashCode method is invoked to alter + the value returned by future access to the + + property. + + + This method should only be invoked by the + instance which will + be managing the IJavaPeerable value. + + + + + + Set the state of the managed peer. + + A value providing + the state of the current Managed Peer instance. + + + + This should only be called from a + instance. + + + + + + Set the value returned by PeerReference. + + A which contains the + value that future invocations of the + + property should return. + + + + The SetPeerReference method is invoked to alter + the value returned by future access to the + + property. + + + This method should only be invoked by the + instance which will + be managing the IJavaPeerable value. + + + + + + + Unregister this instance so that the runtime will not return + it from future + + invocations. + + + + Call this method when you would like to prevent this instance + from being returned by future + + invocations. + + + + The proscribed implementation template is: + + +[JniTypeSignature ("my/Example")] +partial class ExampleBinding : IJavaPeerable { + + public void UnregisterFromRuntime () + { + JniEnvironment.Runtime.ValueManager.UnRegisterObject (this); + } +} + + + + + diff --git a/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JavaPeerableExtensions.xml b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JavaPeerableExtensions.xml new file mode 100644 index 00000000000..49d0c854cb8 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JavaPeerableExtensions.xml @@ -0,0 +1,121 @@ + + + + + Extension methods on . + + + + + Gets the JNI name of the type of the instance . + + The instance + to get the JNI type name of. + + + + The JNI type name is the name of the Java type, as it would be + used in Java Native Interface (JNI) API calls. For example, + instead of the Java name java.lang.Object, the JNI name + is java/lang/Object. + + + + + + The type to coerce to. + + + A instance + to coerce to type . + + + When this method returns, contains a value of type + if can be + coerced to the Java type corresponding to , + or null if the coercion is not valid. + + + Try to coerce to type , + checking that the coercion is valid on the Java side. + + + if was converted successfully; + otherwise, . + + + + Implementations of consist + of two halves: a Java peer and a managed peer. + The property + associates the managed peer to the Java peer. + + + The or + custom attributes are + used to associated a managed type to a Java type. + + + + + The Java peer type for could not be found. + + + + + The type or a Invoker type for + does not provide an + activation constructor, a constructor with a singature of + (ref JniObjectReference, JniObjectReferenceOptions) or + (IntPtr, JniHandleOwnership). + + + + + + + The type to coerce to. + + + A instance + to coerce to type . + + + Try to coerce to type , + checking that the coercion is valid on the Java side. + + + A value of type if the Java peer to + can be coerced to the Java type corresponding + to ; otherwise, null. + + + + Implementations of consist + of two halves: a Java peer and a managed peer. + The property + associates the managed peer to the Java peer. + + + The or + custom attributes are + used to associated a managed type to a Java type. + + + + + The Java peer type for could not be found. + + + + + The type or a Invoker type for + does not provide an + activation constructor, a constructor with a singature of + (ref JniObjectReference, JniObjectReferenceOptions) or + (IntPtr, JniHandleOwnership). + + + + + diff --git a/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniEnvironment.References.xml b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniEnvironment.References.xml new file mode 100644 index 00000000000..59d7efc50a7 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniEnvironment.References.xml @@ -0,0 +1,62 @@ + + + + + JNI Reference-related functionality. + + + + The JniEnvironment.References class exposes JNI Global, Local, + Weak-Global-related functionality which is not exposed by the + class, particularly + JNI reference creation and destruction. + + + + + Account for the creation of a JNI Reference. + + A value containing + a JNI Reference that was created. + + + is not a JNI Local Reference. + + + + The + property provides an advisory value of the number of + JNI Local References which Java.Interop has created. The + + property provides an advisory value of the number of + JNI Global References which Java.Interop has created. The + + property contains an advisory value of the number of + JNI Weak Global References which Java.Interop has created. + These counts are incremented whenever a JNI reference is created, + e.g. from + or , + and this count is decremented whenever a JNI Local Reference is + destroyed, e.g. from + . + + + This accounting assumes a worldview in which Java.Interop can intervene + wherever a JNI Local Reference can be created. This is not the case, + as there are some scenarios where JNI Local References can be created + without Java.Interop knowing about it. One such notable example is when + using Platform Invoke to invoke a native Java_ C function + which returns a JNI Local Reference (). + When such untrackable JNI Local References are created, this may result + in future assertions failing within + + when the tracked JNI Local Reference count becomes negative. + + + Use the CreatedLocalReference to notify Java.Interop that a + JNI Local Reference has been created externally, so that the + JNI Local Reference accounting doesn't generate future assertions. + + + + diff --git a/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniManagedPeerStates.xml b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniManagedPeerStates.xml new file mode 100644 index 00000000000..cc9edb88a1b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniManagedPeerStates.xml @@ -0,0 +1,34 @@ + + + + + Managed peer states. + + + + + Managed peer is eligeable for activation. + + + + A managed peer is activatable if it the native peer was + constructed first and a forthcoming constructor invocation is + assumed to be forthcoming. + + + + + + Managed peer is replaceable. + + + + A managed peer is replaceable if it was created through + . + Being "replaceable" means that if another peer instance is created + around the same Java instance, the newly created instance will replace + the replaceable peer in the Java-to-managed instance mapping. + + + + diff --git a/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniRuntime.JniTypeManager.xml b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniRuntime.JniTypeManager.xml new file mode 100644 index 00000000000..5adca3ecef1 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Documentation/Java.Interop/JniRuntime.JniTypeManager.xml @@ -0,0 +1,28 @@ + + + + + Manages bound Java types. + + + + + + Gets the Invoker type for + + + An Invoker type is a concrete type which can be constructed, + which is used to invoke instances of abstract type that cannot be constructed. + For example, the interface type Java.Lang.IRunnable cannot be constructed, + but if a java.lang.Runnable instance enters managed code, + a Invoker must be constructed around the instance so that it may be used. + + + + If is an interface or abstract class, returns the + type which should be constructed around instances of . + If no such type exists, or if is a concrete type, + then is returned. + + + diff --git a/external/Java.Interop/src/Java.Interop/GlobalSuppressions.cs b/external/Java.Interop/src/Java.Interop/GlobalSuppressions.cs new file mode 100644 index 00000000000..5c93185167d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/GlobalSuppressions.cs @@ -0,0 +1,99 @@ +using System.Diagnostics.CodeAnalysis; + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. +[assembly: SuppressMessage ("Design", "CA1001:Types that own disposable fields should be disposable", Justification = "JniEnvironmentInfo.Runtime is IDisposable, but JniRuntime will dispose JniEnvironmentInfo.", Scope = "type", Target = "~T:Java.Interop.JniPeerMembers.JniInstanceMethods")] + +[assembly: SuppressMessage ("Design", "CA1008:Enums should have zero value", Justification = "No thanks", Scope = "type", Target = "~T:Java.Interop.JniVersion")] + +[assembly: SuppressMessage ("Design", "CA1012:Abstract types should not have constructors", Justification = "Public API checker in flux - Can change later", Scope = "type", Target = "~T:Java.Interop.JniRuntime.JniObjectReferenceManager")] + +[assembly: SuppressMessage ("Design", "CA1030:Use events where appropriate", Justification = "This isn't 'raising' an event; it's 'raising' a pending exception within the JVM.", Scope = "member", Target = "~M:Java.Interop.JniRuntime.RaisePendingException(System.Exception)")] + +[assembly: SuppressMessage ("Design", "CA1024:Use properties where appropriate", Justification = "", Scope = "member", Target = "~M:Java.Interop.JniRuntime.GetRegisteredRuntimes()")] + +[assembly: SuppressMessage ("Design", "CA1032:Implement standard exception constructors", Justification = "System.Runtime.Serialization.SerializationInfo doesn't exist in our targeted PCL profile, so we can't provide the (SerializationInfo, StreamingContext) constructor.", Scope = "type", Target = "~T:Java.Interop.JavaProxyThrowable")] +[assembly: SuppressMessage ("Design", "CA1032:Implement standard exception constructors", Justification = "System.Runtime.Serialization.SerializationInfo doesn't exist in our targeted PCL profile, so we can't provide the (SerializationInfo, StreamingContext) constructor.", Scope = "type", Target = "~T:Java.Interop.JniLocationException")] + +// See: 045b8af7, 6a42bb89, f60906cf, e10f7cb0, etc. +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Exceptions")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniPeerMembers.JniStaticMethods")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.JniMarshalMemberBuilder")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniPeerMembers.JniStaticFields")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.JniValueManager")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.References")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.JniTypeManager")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.ReflectionJniTypeManager")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.ReflectionJniValueManager")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniPeerMembers.JniInstanceMethods")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniPeerMembers.JniInstanceFields")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.CreationOptions")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.JniObjectReferenceManager")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Monitors")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Object")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Strings")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Types")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.InstanceFields")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.InstanceMethods")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.StaticFields")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.StaticMethods")] + +[assembly: SuppressMessage ("Design", "CA1051:Do not declare visible instance fields", Justification = "This type is passed to native code, and should use fields, not properties.", Scope = "member", Target = "~F:Java.Interop.JniNativeMethodRegistration.Name")] +[assembly: SuppressMessage ("Design", "CA1051:Do not declare visible instance fields", Justification = "This type is passed to native code, and should use fields, not properties.", Scope = "member", Target = "~F:Java.Interop.JniNativeMethodRegistration.Signature")] +[assembly: SuppressMessage ("Design", "CA1051:Do not declare visible instance fields", Justification = "This type is passed to native code, and should use fields, not properties.", Scope = "member", Target = "~F:Java.Interop.JniNativeMethodRegistration.Marshaler")] + +[assembly: SuppressMessage ("Design", "CA1064:Exceptions should be public", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniLocationException")] + +[assembly: SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniVersion")] +[assembly: SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "", Scope = "member", Target = "~P:Java.Interop.JniRuntime.CreationOptions.ClassLoader_LoadClass_id")] + +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaObjectArray`1")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaArray`1")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaPrimitiveArray`1")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaBooleanArray")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaSByteArray")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaCharArray")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaInt16Array")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaInt32Array")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaInt64Array")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaSingleArray")] +[assembly: SuppressMessage ("Naming", "CA1710:Identifiers should have correct suffix", Justification = "These represent Java arrays, not collections", Scope = "type", Target = "~T:Java.Interop.JavaDoubleArray")] + +[assembly: SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Can't break API", Scope = "member", Target = "~M:Java.Interop.JniEnvironment.Exceptions.ThrowNew(Java.Interop.JniObjectReference,System.String)")] + +[assembly: SuppressMessage ("Naming", "CA1716:Identifiers should not match keywords", Justification = "'Object' is needed for 'Java.Lang.Object'", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Object")] + +[assembly: SuppressMessage ("Naming", "CA1720:Identifiers should not contain type names", Justification = "'Object' is needed for 'Java.Lang.Object'", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Object")] + +[assembly: SuppressMessage ("Usage", "CA1801:Review unused parameters", Justification = "Used in DEBUG configuration", Scope = "member", Target = "~M:Java.Interop.JniMethodInfo.#ctor(System.String,System.String,System.IntPtr,System.Boolean)")] +[assembly: SuppressMessage ("Usage", "CA1801:Review unused parameters", Justification = "Used in DEBUG configuration", Scope = "member", Target = "~M:Java.Interop.JniFieldInfo.#ctor(System.String,System.String,System.IntPtr,System.Boolean)")] + +[assembly: SuppressMessage ("Performance", "CA1813:Avoid unsealed attributes", Justification = "Can't break public API", Scope = "type", Target = "~T:Java.Interop.JniValueMarshalerAttribute")] + +[assembly: SuppressMessage ("Performance", "CA1815:Override equals and operator equals on value types", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniNativeMethodRegistration")] +[assembly: SuppressMessage ("Performance", "CA1815:Override equals and operator equals on value types", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniNativeMethod")] +[assembly: SuppressMessage ("Performance", "CA1815:Override equals and operator equals on value types", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniNativeMethodRegistrationArguments")] +[assembly: SuppressMessage ("Performance", "CA1815:Override equals and operator equals on value types", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniTransition")] + +[assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:Java.Interop.JniRuntime.JniValueManager.GetJniIdentityHashCode(Java.Interop.JniObjectReference)~System.Int32")] +[assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~P:Java.Interop.JniFieldInfo.Name")] +[assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~P:Java.Interop.JniFieldInfo.Signature")] +[assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~P:Java.Interop.JniMethodInfo.Name")] +[assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~P:Java.Interop.JniMethodInfo.Signature")] + +[assembly: SuppressMessage ("Performance", "CA1823:Avoid unused private fields", Justification = "Used for native interop", Scope = "type", Target = "~T:Java.Interop.JavaException")] +[assembly: SuppressMessage ("Performance", "CA1823:Avoid unused private fields", Justification = "Used for native interop", Scope = "type", Target = "~T:Java.Interop.JavaObject")] +[assembly: SuppressMessage ("Performance", "CA1823:Avoid unused private fields", Justification = "Used for native interop", Scope = "type", Target = "~T:Java.Interop.JniRuntime")] + +[assembly: SuppressMessage ("Reliability", "CA2000:Dispose objects before losing scope", Justification = "We don't *want* to dispose the value!", Scope = "member", Target = "~M:Java.Interop.JniEnvironment.Exceptions.Throw(System.Exception)")] +[assembly: SuppressMessage ("Reliability", "CA2000:Dispose objects before losing scope", Justification = "We don't *want* to dispose the value!", Scope = "member", Target = "~M:Java.Interop.JniRuntime.UnTrack(System.IntPtr)")] +[assembly: SuppressMessage ("Reliability", "CA2000:Dispose objects before losing scope", Justification = "We don't *want* to dispose the value!", Scope = "member", Target = "~M:Java.Interop.ProxyValueMarshaler.CreateGenericObjectReferenceArgumentState(System.Object,System.Reflection.ParameterAttributes)~Java.Interop.JniValueMarshalerState")] +[assembly: SuppressMessage ("Reliability", "CA2000:Dispose objects before losing scope", Justification = "We don't *want* to dispose the value!", Scope = "member", Target = "~M:Java.Interop.ManagedPeer.RegisterNativeMembers(System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr,System.IntPtr)")] +[assembly: SuppressMessage ("Reliability", "CA2000:Dispose objects before losing scope", Justification = "We don't *want* to dispose the value!", Scope = "member", Target = "~M:Java.Interop.JniRuntime.#ctor(Java.Interop.JniRuntime.CreationOptions)")] + +[assembly: SuppressMessage ("Usage", "CA2208:Instantiate argument exceptions correctly", Justification = "", Scope = "member", Target = "~M:Java.Interop.JniEnvironment.Exceptions.Throw(Java.Interop.JniObjectReference)")] +[assembly: SuppressMessage ("Usage", "CA2208:Instantiate argument exceptions correctly", Justification = "", Scope = "member", Target = "~M:Java.Interop.JniEnvironment.Exceptions.ThrowNew(Java.Interop.JniObjectReference,System.String)")] + +[assembly: SuppressMessage ("Usage", "CA2213:Disposable fields should be disposed", Justification = "", Scope = "member", Target = "~F:Java.Interop.JniRuntime.valueManager")] diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop.csproj b/external/Java.Interop/src/Java.Interop/Java.Interop.csproj new file mode 100644 index 00000000000..9c9b6467a43 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop.csproj @@ -0,0 +1,105 @@ + + + + ..\..\bin\Build$(Configuration)\XAConfig.props + + + + $(DotNetTargetFramework) + + + $(NoWarn);1591 + true + ..\..\product.snk + true + enable + true + NU1702 + + + DEBUG;$(DefineConstants) + + + + + INTEROP;$(JavaInteropDefineConstants) + $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\ + $(ToolOutputFullPath) + $(ToolOutputFullPath)Java.Interop.xml + $(BuildToolOutputFullPath) + $(JICoreLibVersion) + true + + + FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS;$(DefineConstants) + FEATURE_JNIENVIRONMENT_JI_PINVOKES;$(DefineConstants) + + + FEATURE_JNIENVIRONMENT_JI_PINVOKES;$(DefineConstants) + + + + + + + BuildJniEnvironment_g_cs; + BuildInteropJar; + $(BuildDependsOn) + + + + + TextTemplatingFileGenerator + JavaPrimitiveArrays.cs + + + TextTemplatingFileGenerator + JniBuiltinMarshalers.cs + + + TextTemplatingFileGenerator + JniPeerMembers.JniInstanceMethods_Invoke.cs + + + TextTemplatingFileGenerator + JniMarshal.SafeInvoke.cs + + + TextTemplatingFileGenerator + JniPeerMembers.JniFields.cs + + + + + + + + + JavaPrimitiveArrays.tt + + + JniBuiltinMarshalers.tt + + + JniPeerMembers.JniFields.tt + + + JniPeerMembers.JniInstanceMethods_Invoke.tt + + + JniMarshal.SafeInvoke.tt + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop.targets b/external/Java.Interop/src/Java.Interop/Java.Interop.targets new file mode 100644 index 00000000000..32a234c1b23 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop.targets @@ -0,0 +1,35 @@ + + + + + + + + + + + PreserveNewest + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/IJavaPeerable.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/IJavaPeerable.cs new file mode 100644 index 00000000000..a1888e7e8b1 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/IJavaPeerable.cs @@ -0,0 +1,44 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + /// + public interface IJavaPeerable : IDisposable + { + /// + int JniIdentityHashCode {get;} + /// + void SetJniIdentityHashCode (int value); + + /// + JniObjectReference PeerReference {get;} + + /// + void SetPeerReference (JniObjectReference reference); + + /// + JniPeerMembers JniPeerMembers {get;} + + /// + JniManagedPeerStates JniManagedPeerState {get;} + + /// + void SetJniManagedPeerState (JniManagedPeerStates value); + + // Lifetime management + /// + void UnregisterFromRuntime (); + /// + void DisposeUnlessReferenced (); + + /// + void Disposed (); + /// + void Finalized (); + + IntPtr JniObjectReferenceControlBlock => IntPtr.Zero; + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaArray.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaArray.cs new file mode 100644 index 00000000000..c7dd8cdd6b2 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaArray.cs @@ -0,0 +1,420 @@ +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; + +namespace Java.Interop +{ + [JniTypeSignature ("java/lang/Object", ArrayRank=1, GenerateJavaPeer=false)] + public abstract class JavaArray : JavaObject, IList, IList + { + internal delegate TArray ArrayCreator (ref JniObjectReference reference, JniObjectReferenceOptions transfer) + where TArray : JavaArray; + + // Value was created via CreateMarshalCollection, and thus can + // be disposed of with impunity when no longer needed. + internal bool forMarshalCollection; + + internal JavaArray (ref JniObjectReference handle, JniObjectReferenceOptions transfer) + : base (ref handle, transfer) + { + } + + public int Length { + get {return JniEnvironment.Arrays.GetArrayLength (PeerReference);} + } + + [MaybeNull] + public abstract T this [int index] { + // Keep this until nullable annotations can fully express this indexer contract. +#pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes). + get; +#pragma warning restore CS8766 + set; + } + + public abstract void Clear (); + public abstract void CopyTo (T[] array, int arrayIndex); + public abstract int IndexOf (T item); + + public virtual bool Contains (T item) + { + return IndexOf (item) >= 0; + } + + public bool IsReadOnly { + get { + return false; + } + } + + public T[] ToArray () + { + var a = new T [Length]; + CopyTo (a, 0); + return a; + } + + public virtual IEnumerator GetEnumerator () + { + int len = Length; + for (int i = 0; i < len; ++i) +#pragma warning disable CS8603 // Possible null reference return. + yield return this [i]; +#pragma warning restore CS8603 // Possible null reference return. + } + + internal static void CheckArrayCopy (int sourceIndex, int sourceLength, int destinationIndex, int destinationLength, int length) + { + if (sourceIndex < 0) + throw new ArgumentOutOfRangeException (nameof (sourceIndex), $"source index must be >= 0; was {sourceIndex}."); + if (sourceIndex != 0 && sourceIndex >= sourceLength) + throw new ArgumentException ("source index is > source length.", nameof (sourceIndex)); + if (checked(sourceIndex + length) > sourceLength) + throw new ArgumentException ("source index + length >= source length", nameof (length)); + if (destinationIndex < 0) + throw new ArgumentOutOfRangeException (nameof (destinationIndex), $"destination index must be >= 0; was {destinationIndex}."); + if (destinationIndex != 0 && destinationIndex >= destinationLength) + throw new ArgumentException ("destination index is > destination length.", nameof (destinationIndex)); + if (checked (destinationIndex + length) > destinationLength) + throw new ArgumentException ("destination index + length >= destination length", nameof (length)); + } + + internal static int CheckLength (int length) + { + if (length < 0) + throw new ArgumentException ("'length' cannot be negative.", nameof (length)); + return length; + } + + internal static int CheckLength (IList value) + { + if (value == null) + throw new ArgumentNullException (nameof (value)); + return value.Count; + } + + internal static IList ToList (IEnumerable value) + { + if (value == null) + throw new ArgumentNullException (nameof (value)); + if (value is IList list) + return list; + return value.ToList (); + } + + internal IList ToTargetType (Type? targetType, bool dispose) + { + if (TargetTypeIsCurrentType (targetType)) + return this; + if (targetType == typeof (T[]) || targetType.IsAssignableFrom (typeof (IList))) { + try { + return ToArray (); + } finally { + if (dispose) + Dispose (); + } + } + throw CreateMarshalNotSupportedException (GetType (), targetType); + } + + internal virtual bool TargetTypeIsCurrentType ([NotNullWhen (false)]Type? targetType) + { + return targetType == null || targetType == typeof (JavaArray); + } + + internal static Exception CreateMarshalNotSupportedException (Type sourceType, Type? targetType) + { + return new NotSupportedException ( + string.Format ("Do not know how to marshal a `{0}`{1}.", + sourceType.FullName, + targetType != null ? $" into a `{targetType.FullName}`" : "")); + } + + internal static IList CreateValue (ref JniObjectReference reference, JniObjectReferenceOptions transfer, Type? targetType, ArrayCreator creator) + where TArray : JavaArray + { + return creator (ref reference, transfer) + .ToTargetType (targetType, dispose: true); + } + + internal static JniValueMarshalerState CreateArgumentState (IList? value, ParameterAttributes synchronize, Func, bool, TArray> creator) + where TArray : JavaArray + { + if (value == null) + return new JniValueMarshalerState (); + if (value is TArray v) { + return new JniValueMarshalerState (v); + } + var list = value as IList; + if (list == null) + throw CreateMarshalNotSupportedException (value.GetType (), typeof (TArray)); + synchronize = GetCopyDirection (synchronize); + var c = (synchronize & ParameterAttributes.In) == ParameterAttributes.In; + var a = creator (list, c); + return new JniValueMarshalerState (a); + } + + internal static void DestroyArgumentState (IList? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + where TArray : JavaArray + { + var source = (TArray?) state.PeerableValue; + if (source == null) + return; + + synchronize = GetCopyDirection (synchronize); + if ((synchronize & ParameterAttributes.Out) == ParameterAttributes.Out) { + var arrayDest = value as T[]; + var listDest = value as IList; + if (arrayDest != null) + source.CopyTo (arrayDest, 0); + else if (listDest != null) + source.CopyToList (listDest, 0); + } + + if (source.forMarshalCollection) { + source.Dispose (); + } + + state = new JniValueMarshalerState (); + } + + internal static ParameterAttributes GetCopyDirection (ParameterAttributes value) + { + // If .In or .Out are specified, use as-is. + // Otherwise, we should copy both directions. + const ParameterAttributes inout = ParameterAttributes.In | ParameterAttributes.Out; + if ((value & inout) != 0) + return (value & inout); + return inout; + } + + internal virtual void CopyToList (IList list, int index) + { + int len = Length; + for (int i = 0; i < len; i++) { +#pragma warning disable CS8601 // Possible null reference assignment. + list [index + i] = this [i]; +#pragma warning restore CS8601 // Possible null reference assignment. + } + } + + bool ICollection.IsSynchronized { + get { + return false; + } + } + + object ICollection.SyncRoot { + get { + return this; + } + } + + int ICollection.Count { + get {return Length;} + } + + int ICollection.Count { + get {return Length;} + } + + bool IList.IsFixedSize { + get { + return true; + } + } + + object? IList.this [int index] { + get {return this [index];} +#pragma warning disable 8600,8601 + set {this [index] = (T) value;} +#pragma warning restore 8600,8601 + } + + void ICollection.CopyTo (Array array, int index) + { + if (array == null) + throw new ArgumentNullException (nameof (array)); + CheckArrayCopy (0, Length, index, array.Length, Length); + int len = Length; + for (int i = 0; i < len; i++) + array.SetValue (this [i], index + i); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + + void ICollection.Add (T item) + { + throw new NotSupportedException (); + } + + bool ICollection.Remove (T item) + { + throw new NotSupportedException (); + } + + bool IList.Contains (object? value) + { + if (value is T) + return Contains ((T) value); + return false; + } + + int IList.IndexOf (object? value) + { + if (value is T) + return IndexOf ((T) value); + return -1; + } + + int IList.Add (object? value) + { + throw new NotSupportedException (); + } + + void IList.Insert (int index, object? value) + { + throw new NotSupportedException (); + } + + void IList.Remove (object? value) + { + throw new NotSupportedException (); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException (); + } + + void IList.Insert (int index, T item) + { + throw new NotSupportedException (); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException (); + } + } + + public abstract class JniArrayElements : IDisposable { + + IntPtr elements; + int size; + + internal JniArrayElements (IntPtr elements, int size) + { + if (elements == IntPtr.Zero) + throw new ArgumentException ("'elements' must not be IntPtr.Zero.", nameof (elements)); + this.elements = elements; + this.size = size; + } + + internal bool IsDisposed { + get {return elements == IntPtr.Zero;} + } + + public IntPtr Elements { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + return elements; + } + } + + public int Size { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + return size; + } + } + + protected abstract void Synchronize (JniReleaseArrayElementsMode releaseMode); + + public void CopyToJava () + { + Synchronize (JniReleaseArrayElementsMode.Commit); + } + + public void Release (JniReleaseArrayElementsMode releaseMode) + { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + Synchronize (releaseMode); + elements = IntPtr.Zero; + } + + public void Dispose () + { + if (IsDisposed) + return; + Release (JniReleaseArrayElementsMode.Default); + } + } + + [JniTypeSignature ("java/lang/Object", ArrayRank=1, GenerateJavaPeer=false)] + public abstract class JavaPrimitiveArray : JavaArray + { + + internal JavaPrimitiveArray (ref JniObjectReference reference, JniObjectReferenceOptions transfer) + : base (ref reference, transfer) + { + } + + public override void DisposeUnlessReferenced () + { + if (forMarshalCollection) { + Dispose (); + return; + } + base.DisposeUnlessReferenced (); + } + + public abstract void CopyTo (int sourceIndex, T[] destinationArray, int destinationIndex, int length); + public abstract void CopyFrom (T[] sourceArray, int sourceIndex, int destinationIndex, int length); + + protected abstract JniArrayElements CreateElements (); + + public override T this [int index] { + get { + var buf = new T [1]; + CopyTo (index, buf, 0, buf.Length); + return buf [0]; + } + set { + if (index >= Length) + throw new ArgumentOutOfRangeException (nameof (index), "index >= Length"); + var buf = new T []{ value }; + CopyFrom (buf, 0, index, buf.Length); + } + } + + public JniArrayElements GetElements () + { + return CreateElements (); + } + + public override void CopyTo (T[] array, int arrayIndex) + { + CopyTo (0, array, arrayIndex, Length); + } + + internal static T[] ToArray (IEnumerable value) + { + if (value is T [] array) + return array; + return value.ToArray (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaException.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaException.cs new file mode 100644 index 00000000000..0aafd45d109 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaException.cs @@ -0,0 +1,283 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + unsafe public partial class JavaException : Exception, IJavaPeerable + { + internal const string JniTypeName = "java/lang/Throwable"; + readonly static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaException)); + + public string? JavaStackTrace { get; private set; } + public int JniIdentityHashCode { get; private set; } + public JniManagedPeerStates JniManagedPeerState { get; private set; } + + unsafe JniObjectReferenceControlBlock* jniObjectReferenceControlBlock; + + protected static readonly JniObjectReference* InvalidJniObjectReference = null; + + public unsafe JavaException () + : this (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + if (PeerReference.IsValid) + return; + + var peer = JniPeerMembers.InstanceMethods.StartCreateInstance ("()V", GetType (), null); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + JniPeerMembers.InstanceMethods.FinishCreateInstance ("()V", this, null); + SetJavaStackTrace (); + } + + public unsafe JavaException (string message) + : base (message) + { + const string signature = "(Ljava/lang/String;)V"; + var native_message = JniEnvironment.Strings.NewString (message); + try { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (native_message); + var peer = JniPeerMembers.InstanceMethods.StartCreateInstance (signature, GetType (), args); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + JniPeerMembers.InstanceMethods.FinishCreateInstance (signature, this, args); + } finally { + JniObjectReference.Dispose (ref native_message, JniObjectReferenceOptions.CopyAndDispose); + } + SetJavaStackTrace (); + } + + public unsafe JavaException (string message, Exception innerException) + : base (message, innerException) + { + const string signature = "(Ljava/lang/String;)V"; + var native_message = JniEnvironment.Strings.NewString (message); + try { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (native_message); + var peer = JniPeerMembers.InstanceMethods.StartCreateInstance (signature, GetType (), args); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + JniPeerMembers.InstanceMethods.FinishCreateInstance (signature, this, args); + } finally { + JniObjectReference.Dispose (ref native_message, JniObjectReferenceOptions.CopyAndDispose); + } + SetJavaStackTrace (); + } + + protected JavaException (ref JniObjectReference reference, JniObjectReferenceOptions transfer, JniObjectReference throwableOverride) + : base (GetMessage (throwableOverride), GetCause (throwableOverride)) + { + Construct (ref reference, transfer); + SetJavaStackTrace (throwableOverride); + } + + public JavaException (ref JniObjectReference reference, JniObjectReferenceOptions transfer) + : base (GetMessage (ref reference, transfer), GetCause (ref reference, transfer)) + { + Construct (ref reference, transfer); + if (PeerReference.IsValid) + SetJavaStackTrace (); + } + + protected void Construct (ref JniObjectReference reference, JniObjectReferenceOptions options) + { + JniEnvironment.Runtime.ValueManager.ConstructPeer (this, ref reference, options); + } + + ~JavaException () + { + JniEnvironment.Runtime.ValueManager.FinalizePeer (this); + } + + public JniObjectReference PeerReference { + get { + var c = jniObjectReferenceControlBlock; + if (c == null) { + return default; + } + return new JniObjectReference (c->handle, (JniObjectReferenceType) c->handle_type); + } + } + + // Note: JniPeerMembers is invoked virtually from the constructor; + // it MUST be valid before the derived constructor executes! + // The pattern MUST be followed. + public virtual JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public override string StackTrace { + get { + return base.StackTrace + Environment.NewLine + + " --- End of managed " + GetType ().FullName + " stack trace ---" + Environment.NewLine + + JavaStackTrace; + } + } + + protected void SetPeerReference (ref JniObjectReference reference, JniObjectReferenceOptions options) + { + if (options == JniObjectReferenceOptions.None) { + ((IJavaPeerable) this).SetPeerReference (new JniObjectReference ()); + return; + } + + var c = jniObjectReferenceControlBlock; + if (c == null) { + c = jniObjectReferenceControlBlock = + Java.Interop.JniObjectReferenceControlBlock.Alloc (reference); + } else { + c->handle = reference.Handle; + c->handle_type = (int) reference.Type; + } + + JniObjectReference.Dispose (ref reference, options); + } + + public void UnregisterFromRuntime () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + JniEnvironment.Runtime.ValueManager.RemovePeer (this); + } + + public void Dispose () + { + JniEnvironment.Runtime.ValueManager.DisposePeer (this); + } + + public void DisposeUnlessReferenced () + { + JniEnvironment.Runtime.ValueManager.DisposePeerUnlessReferenced (this); + } + + protected virtual void Dispose (bool disposing) + { + var inner = InnerException as JavaException; + if (inner != null) { + inner.Dispose (); + } + } + + public override bool Equals (object? obj) + { + JniPeerMembers.AssertSelf (this); + + if (object.ReferenceEquals (obj, this)) + return true; + var o = obj as IJavaPeerable; + if (o != null) + return JniEnvironment.Types.IsSameObject (PeerReference, o.PeerReference); + return false; + } + + public override unsafe int GetHashCode () + { + return _members.InstanceMethods.InvokeVirtualInt32Method ("hashCode.()I", this, null); + } + + static string? GetMessage (ref JniObjectReference reference, JniObjectReferenceOptions transfer) + { + if (transfer == JniObjectReferenceOptions.None) + return null; + return GetMessage (reference); + } + + static string? GetMessage (JniObjectReference reference) + { + if (!reference.IsValid) + return null; + + var m = _members.InstanceMethods.GetMethodInfo ("getMessage.()Ljava/lang/String;"); + var s = JniEnvironment.InstanceMethods.CallObjectMethod (reference, m); + return JniEnvironment.Strings.ToString (ref s, JniObjectReferenceOptions.CopyAndDispose); + } + + static Exception? GetCause (ref JniObjectReference reference, JniObjectReferenceOptions transfer) + { + if (transfer == JniObjectReferenceOptions.None) + return null; + return GetCause (reference); + } + + static Exception? GetCause (JniObjectReference reference) + { + if (!reference.IsValid) + return null; + + var m = _members.InstanceMethods.GetMethodInfo ("getCause.()Ljava/lang/Throwable;"); + var e = JniEnvironment.InstanceMethods.CallObjectMethod (reference, m); + return JniEnvironment.Runtime.GetExceptionForThrowable (ref e, JniObjectReferenceOptions.CopyAndDispose); + } + + protected void SetJavaStackTrace (JniObjectReference peerReferenceOverride = default) + { + if (!peerReferenceOverride.IsValid) { + peerReferenceOverride = PeerReference; + } + if (!peerReferenceOverride.IsValid) { + return; + } + JavaStackTrace = GetJavaStack (peerReferenceOverride); + } + + unsafe string? GetJavaStack (JniObjectReference handle) + { + using (var StringWriter_class = new JniType ("java/io/StringWriter")) + using (var PrintWriter_class = new JniType ("java/io/PrintWriter")) { + var StringWriter_init = StringWriter_class.GetConstructor ("()V"); + var PrintWriter_init = PrintWriter_class.GetConstructor ("(Ljava/io/Writer;)V"); + var swriter = StringWriter_class.NewObject (StringWriter_init, null); + try { + var pwriter_args = stackalloc JniArgumentValue [1]; + pwriter_args [0] = new JniArgumentValue (swriter); + var pwriter = PrintWriter_class.NewObject (PrintWriter_init, pwriter_args); + try { + var pst = _members.InstanceMethods.GetMethodInfo ("printStackTrace.(Ljava/io/PrintWriter;)V"); + var pst_args = stackalloc JniArgumentValue [1]; + pst_args [0] = new JniArgumentValue (pwriter); + JniEnvironment.InstanceMethods.CallVoidMethod (handle, pst, pst_args); + var s = JniEnvironment.Object.ToString (swriter); + return JniEnvironment.Strings.ToString (ref s, JniObjectReferenceOptions.CopyAndDispose); + } finally { + JniObjectReference.Dispose (ref pwriter, JniObjectReferenceOptions.CopyAndDispose); + } + } finally { + JniObjectReference.Dispose (ref swriter, JniObjectReferenceOptions.CopyAndDispose); + } + } + } + + void IJavaPeerable.Disposed () + { + JniManagedPeerState |= Disposed; + Dispose (disposing: true); + } + + void IJavaPeerable.Finalized () + { + JniManagedPeerState |= Disposed; + Dispose (disposing: false); + } + + void IJavaPeerable.SetJniIdentityHashCode (int value) + { + JniIdentityHashCode = value; + } + + void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value) + { + JniManagedPeerState = value; + } + + void IJavaPeerable.SetPeerReference (JniObjectReference reference) + { + SetPeerReference (ref reference, JniObjectReferenceOptions.Copy); + if (!reference.IsValid && JniManagedPeerState.HasFlag (Disposed)) { + Java.Interop.JniObjectReferenceControlBlock.Free (ref jniObjectReferenceControlBlock); + } + } + + IntPtr IJavaPeerable.JniObjectReferenceControlBlock => + (IntPtr) jniObjectReferenceControlBlock; + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaObject.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaObject.cs new file mode 100644 index 00000000000..f31eda5b1c1 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaObject.cs @@ -0,0 +1,172 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; + +namespace Java.Interop +{ + [JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + [Serializable] + unsafe public partial class JavaObject : IJavaPeerable + { + internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + + readonly static JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (JavaObject)); + + [NonSerialized] int identityHashCode; + [NonSerialized] JniManagedPeerStates managedPeerState; + + public int JniIdentityHashCode => identityHashCode; + + public JniManagedPeerStates JniManagedPeerState => managedPeerState; + + [NonSerialized] unsafe JniObjectReferenceControlBlock* jniObjectReferenceControlBlock; + + protected static readonly JniObjectReference* InvalidJniObjectReference = null; + + ~JavaObject () + { + JniEnvironment.Runtime.ValueManager.FinalizePeer (this); + } + + public unsafe JniObjectReference PeerReference { + get { + var c = jniObjectReferenceControlBlock; + if (c == null) { + return default; + } + return new JniObjectReference (c->handle, (JniObjectReferenceType) c->handle_type); + } + } + + // Note: JniPeerMembers is invoked virtually from the constructor; + // it MUST be valid before the derived constructor executes! + // The pattern MUST be followed. + public virtual JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public JavaObject (ref JniObjectReference reference, JniObjectReferenceOptions options) + { + Construct (ref reference, options); + } + + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe JavaObject () + : this (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + if (PeerReference.IsValid) + return; + + var peer = JniPeerMembers.InstanceMethods.StartCreateInstance ("()V", GetType (), null); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + JniPeerMembers.InstanceMethods.FinishCreateInstance ("()V", this, null); + } + + protected void Construct (ref JniObjectReference reference, JniObjectReferenceOptions options) + { + JniEnvironment.Runtime.ValueManager.ConstructPeer (this, ref reference, options); + } + + protected void SetPeerReference (ref JniObjectReference reference, JniObjectReferenceOptions options) + { + if (options == JniObjectReferenceOptions.None) { + ((IJavaPeerable) this).SetPeerReference (new JniObjectReference ()); + return; + } + + var c = jniObjectReferenceControlBlock; + if (c == null) { + c = jniObjectReferenceControlBlock = + Java.Interop.JniObjectReferenceControlBlock.Alloc (reference); + } else { + c->handle = reference.Handle; + c->handle_type = (int) reference.Type; + } + + JniObjectReference.Dispose (ref reference, options); + } + + public void UnregisterFromRuntime () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + JniEnvironment.Runtime.ValueManager.RemovePeer (this); + } + + public void Dispose () + { + JniEnvironment.Runtime.ValueManager.DisposePeer (this); + } + + public virtual void DisposeUnlessReferenced () + { + JniEnvironment.Runtime.ValueManager.DisposePeerUnlessReferenced (this); + } + + protected virtual void Dispose (bool disposing) + { + } + + public override bool Equals (object? obj) + { + JniPeerMembers.AssertSelf (this); + + if (object.ReferenceEquals (obj, this)) + return true; + var o = obj as IJavaPeerable; + if (o != null) + return JniEnvironment.Types.IsSameObject (PeerReference, o.PeerReference); + return false; + } + + public override unsafe int GetHashCode () + { + return _members.InstanceMethods.InvokeVirtualInt32Method ("hashCode.()I", this, null); + } + + public override unsafe string? ToString () + { + var lref = _members.InstanceMethods.InvokeVirtualObjectMethod ( + "toString.()Ljava/lang/String;", + this, + null); + return JniEnvironment.Strings.ToString (ref lref, JniObjectReferenceOptions.CopyAndDispose); + } + + void IJavaPeerable.Disposed () + { + managedPeerState |= Disposed; + Dispose (disposing: true); + } + + void IJavaPeerable.Finalized () + { + managedPeerState |= Disposed; + Dispose (disposing: false); + } + + void IJavaPeerable.SetJniIdentityHashCode (int value) + { + identityHashCode = value; + } + + void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value) + { + managedPeerState = value; + } + + void IJavaPeerable.SetPeerReference (JniObjectReference reference) + { + SetPeerReference (ref reference, JniObjectReferenceOptions.Copy); + + if (!reference.IsValid && managedPeerState.HasFlag (Disposed)) { + Java.Interop.JniObjectReferenceControlBlock.Free (ref jniObjectReferenceControlBlock); + } + } + + IntPtr IJavaPeerable.JniObjectReferenceControlBlock => + (IntPtr) jniObjectReferenceControlBlock; + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaObjectArray.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaObjectArray.cs new file mode 100644 index 00000000000..b7c437365b4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaObjectArray.cs @@ -0,0 +1,218 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace Java.Interop +{ + [JniTypeSignature ("java/lang/Object", ArrayRank=1, GenerateJavaPeer=false)] + public class JavaObjectArray<[DynamicallyAccessedMembers (Constructors)] T> : JavaArray + { + internal static readonly ValueMarshaler Instance = new ValueMarshaler (); + + [SuppressMessage ("ApiDesign", "RS0022:Constructor make noninheritable base class inheritable", Justification = "Existing public API")] + public JavaObjectArray (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + static JniObjectReference NewArray (int length) + { + var info = JniEnvironment.Runtime.TypeManager.GetTypeSignature (typeof (T)); + if (info.SimpleReference == null) + info = new JniTypeSignature ("java/lang/Object", info.ArrayRank); + if (info.IsKeyword && info.ArrayRank == 0) { + info = info.GetPrimitivePeerTypeSignature (); + } + using (var t = new JniType (info.Name)) { + return JniEnvironment.Arrays.NewObjectArray (length, t.PeerReference, new JniObjectReference ()); + } + } + + [SuppressMessage ("ApiDesign", "RS0022:Constructor make noninheritable base class inheritable", Justification = "Existing public API")] + public unsafe JavaObjectArray (int length) + : this (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = NewArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + [SuppressMessage ("ApiDesign", "RS0022:Constructor make noninheritable base class inheritable", Justification = "Existing public API")] + public JavaObjectArray (IList value) + : this (CheckLength (value)) + { + for (int i = 0; i < value.Count; ++i) + SetElementAt (i, value [i]); + } + + [SuppressMessage ("ApiDesign", "RS0022:Constructor make noninheritable base class inheritable", Justification = "Existing public API")] + public JavaObjectArray (IEnumerable value) + : this (ToList (value)) + { + } + + public override void DisposeUnlessReferenced () + { + if (forMarshalCollection) { + Dispose (); + return; + } + base.DisposeUnlessReferenced (); + } + + [MaybeNull] + public override T this [int index] { + get { + if (index < 0 || index >= Length) + throw new ArgumentOutOfRangeException (nameof (index), "index < 0 || index >= Length"); + return GetElementAt (index); + } + set { + if (index < 0 || index >= Length) + throw new ArgumentOutOfRangeException (nameof (index), "index < 0 || index >= Length"); + SetElementAt (index, value); + } + } + + [return: MaybeNull] + T GetElementAt (int index) + { + var lref = JniEnvironment.Arrays.GetObjectArrayElement (PeerReference, index); + return JniEnvironment.Runtime.ValueManager.GetValue (ref lref, JniObjectReferenceOptions.CopyAndDispose); + } + + void SetElementAt (int index, T value) + { + var vm = JniEnvironment.Runtime.ValueManager; + var r = vm.CreateLocalObjectReferenceArgument (typeof (T), value); + try { + JniEnvironment.Arrays.SetObjectArrayElement (PeerReference, index, r); + } finally { + JniObjectReference.Dispose (ref r); + } + } + + public override IEnumerator GetEnumerator () + { + int len = Length; + for (int i = 0; i < len; ++i) { +#pragma warning disable CS8603 // Possible null reference return. + yield return GetElementAt (i); +#pragma warning restore CS8603 // Possible null reference return. + } + } + + public override void Clear () + { + int len = Length; + var nullReference = new JniObjectReference (); + for (int i = 0; i < len; i++) { + JniEnvironment.Arrays.SetObjectArrayElement (PeerReference, i, nullReference); + } + } + + public override int IndexOf (T item) + { + int len = Length; + for (int i = 0; i < len; i++) { + var at = GetElementAt (i); + try { +#pragma warning disable CS8604 // Possible null reference argument. + if (EqualityComparer.Default.Equals (item, at) || JniMarshal.RecursiveEquals (item, at)) +#pragma warning restore CS8604 // Possible null reference argument. + return i; + } finally { + var j = at as IJavaPeerable; + if (j != null) + j.DisposeUnlessReferenced (); + } + } + return -1; + } + + public override void CopyTo (T[] array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException (nameof (array)); + CheckArrayCopy (0, Length, arrayIndex, array.Length, Length); + CopyToList (array, arrayIndex); + } + + internal override void CopyToList (IList list, int index) + { + int len = Length; + for (int i = 0; i < len; i++) { + var item = GetElementAt (i); +#pragma warning disable CS8601 // Possible null reference assignment. + list [index + i] = item; +#pragma warning restore CS8601 // Possible null reference assignment. + if (forMarshalCollection) { + var d = item as IJavaPeerable; + if (d != null) + d.DisposeUnlessReferenced (); + } + } + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + targetType == typeof (JavaObjectArray); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue (ref reference, options, targetType, (ref JniObjectReference h, JniObjectReferenceOptions t) => new JavaObjectArray (ref h, t) { + forMarshalCollection = true, + }); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull]IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaObjectArray (list) + : new JavaObjectArray (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull]IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState> (value, ref state, synchronize); + } + } + } + + partial class JniEnvironment { + + [SuppressMessage ("Design", "CA1034", Justification = "https://github.com/xamarin/Java.Interop/commit/bb7ca5d02aa3fc2b447ad57af1256e74e5f954fa")] + partial class Arrays { + + public static JavaObjectArray? CreateMarshalObjectArray< + [DynamicallyAccessedMembers (JavaObject.Constructors)] + T + > ( + IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaObjectArray c) { + return c; + } + return new JavaObjectArray (value) { + forMarshalCollection = true, + }; + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPeerableExtensions.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPeerableExtensions.cs new file mode 100644 index 00000000000..8bb9dbb552f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPeerableExtensions.cs @@ -0,0 +1,51 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop { + + /// + public static class JavaPeerableExtensions { + + /// + public static string? GetJniTypeName (this IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + return JniEnvironment.Types.GetJniTypeNameFromInstance (self.PeerReference); + } + + /// + public static bool TryJavaCast< + [DynamicallyAccessedMembers (JavaObject.Constructors)] + TResult + > (this IJavaPeerable? self, [NotNullWhen (true)] out TResult? result) + where TResult : class, IJavaPeerable + { + result = JavaAs (self); + return result != null; + } + + /// + public static TResult? JavaAs< + [DynamicallyAccessedMembers (JavaObject.Constructors)] + TResult + > (this IJavaPeerable? self) + where TResult : class, IJavaPeerable + { + if (self == null || !self.PeerReference.IsValid) { + return null; + } + + if (self is TResult result) { + return result; + } + + var r = self.PeerReference; + return JniEnvironment.Runtime.ValueManager.CreatePeer ( + ref r, JniObjectReferenceOptions.Copy, + targetType: typeof (TResult)) + as TResult; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs new file mode 100644 index 00000000000..c2bd6e0109a --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs @@ -0,0 +1,1712 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +using Java.Interop.Expressions; +using System.Linq.Expressions; + +namespace Java.Interop { + + partial class JniRuntime { + + partial class ReflectionJniTypeManager { + readonly struct JniPrimitiveArrayInfo { + public readonly JniTypeSignature JniTypeSignature; + public readonly Type PrimitiveType; + public readonly Type[] ArrayTypes; + + public JniPrimitiveArrayInfo (string jniSimpleReference, Type primitiveType, params Type[] arrayTypes) + { + JniTypeSignature = new JniTypeSignature (jniSimpleReference, arrayRank: 1, keyword: true); + PrimitiveType = primitiveType; + ArrayTypes = arrayTypes; + } + } + + static readonly JniPrimitiveArrayInfo[] JniPrimitiveArrayTypes = new JniPrimitiveArrayInfo[]{ + new ("Z", typeof (Boolean), typeof (Boolean[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaBooleanArray)), + new ("B", typeof (SByte), typeof (SByte[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaSByteArray)), + new ("C", typeof (Char), typeof (Char[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaCharArray)), + new ("S", typeof (Int16), typeof (Int16[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaInt16Array)), + new ("I", typeof (Int32), typeof (Int32[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaInt32Array)), + new ("J", typeof (Int64), typeof (Int64[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaInt64Array)), + new ("F", typeof (Single), typeof (Single[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaSingleArray)), + new ("D", typeof (Double), typeof (Double[]), typeof (JavaArray), typeof (JavaPrimitiveArray), typeof (JavaDoubleArray)), + }; + + static bool GetBuiltInTypeArraySignature (Type type, ref JniTypeSignature signature) + { + foreach (var e in JniPrimitiveArrayTypes) { + if (Array.IndexOf (e.ArrayTypes, type) < 0) + continue; + signature = e.JniTypeSignature; + return true; + } + signature = default; + return false; + } + } + + static readonly Lazy[]> JniPrimitiveArrayMarshalers = new Lazy[]> (InitJniPrimitiveArrayMarshalers); + + static KeyValuePair[] InitJniPrimitiveArrayMarshalers () + { + return new [] { + new KeyValuePair(typeof (Boolean[]), JavaBooleanArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaBooleanArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaBooleanArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaBooleanArray), JavaBooleanArray.ArrayMarshaler), + new KeyValuePair(typeof (SByte[]), JavaSByteArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaSByteArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaSByteArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaSByteArray), JavaSByteArray.ArrayMarshaler), + new KeyValuePair(typeof (Char[]), JavaCharArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaCharArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaCharArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaCharArray), JavaCharArray.ArrayMarshaler), + new KeyValuePair(typeof (Int16[]), JavaInt16Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaInt16Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaInt16Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaInt16Array), JavaInt16Array.ArrayMarshaler), + new KeyValuePair(typeof (Int32[]), JavaInt32Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaInt32Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaInt32Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaInt32Array), JavaInt32Array.ArrayMarshaler), + new KeyValuePair(typeof (Int64[]), JavaInt64Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaInt64Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaInt64Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaInt64Array), JavaInt64Array.ArrayMarshaler), + new KeyValuePair(typeof (Single[]), JavaSingleArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaSingleArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaSingleArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaSingleArray), JavaSingleArray.ArrayMarshaler), + new KeyValuePair(typeof (Double[]), JavaDoubleArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray), JavaDoubleArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray), JavaDoubleArray.ArrayMarshaler), + new KeyValuePair(typeof (JavaDoubleArray), JavaDoubleArray.ArrayMarshaler), + }; + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaBooleanArray? CreateMarshalBooleanArray (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaBooleanArray c) { + return c; + } + return new JavaBooleanArray (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniBooleanArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniBooleanArrayElements (JniObjectReference arrayHandle, Boolean* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe Boolean* Elements { + get {return (Boolean*) base.Elements;} + } + + public ref Boolean this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseBooleanArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("Z", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaBooleanArray : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaBooleanArray (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaBooleanArray (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewBooleanArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaBooleanArray (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaBooleanArray (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniBooleanArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetBooleanArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetBooleanArrayElements()` returned NULL!"); + return new JniBooleanArrayElements (PeerReference, elements, Length*sizeof (Boolean)); + } + + public override unsafe int IndexOf (Boolean item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.Boolean.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (Boolean); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, Boolean[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (Boolean* b = destinationArray) + JniEnvironment.Arrays.GetBooleanArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (Boolean[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (Boolean* b = sourceArray) + JniEnvironment.Arrays.SetBooleanArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaBooleanArray) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaBooleanArray (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaBooleanArray (list) + : new JavaBooleanArray (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaBooleanArray.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaSByteArray? CreateMarshalSByteArray (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaSByteArray c) { + return c; + } + return new JavaSByteArray (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniSByteArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniSByteArrayElements (JniObjectReference arrayHandle, SByte* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe SByte* Elements { + get {return (SByte*) base.Elements;} + } + + public ref SByte this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseByteArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("B", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaSByteArray : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaSByteArray (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaSByteArray (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewByteArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaSByteArray (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaSByteArray (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniSByteArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetByteArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetByteArrayElements()` returned NULL!"); + return new JniSByteArrayElements (PeerReference, elements, Length*sizeof (SByte)); + } + + public override unsafe int IndexOf (SByte item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.SByte.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (SByte); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, SByte[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (SByte* b = destinationArray) + JniEnvironment.Arrays.GetByteArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (SByte[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (SByte* b = sourceArray) + JniEnvironment.Arrays.SetByteArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaSByteArray) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaSByteArray (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaSByteArray (list) + : new JavaSByteArray (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaSByteArray.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaCharArray? CreateMarshalCharArray (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaCharArray c) { + return c; + } + return new JavaCharArray (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniCharArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniCharArrayElements (JniObjectReference arrayHandle, Char* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe Char* Elements { + get {return (Char*) base.Elements;} + } + + public ref Char this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseCharArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("C", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaCharArray : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaCharArray (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaCharArray (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewCharArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaCharArray (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaCharArray (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniCharArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetCharArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetCharArrayElements()` returned NULL!"); + return new JniCharArrayElements (PeerReference, elements, Length*sizeof (Char)); + } + + public override unsafe int IndexOf (Char item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.Char.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (Char); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, Char[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (Char* b = destinationArray) + JniEnvironment.Arrays.GetCharArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (Char[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (Char* b = sourceArray) + JniEnvironment.Arrays.SetCharArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaCharArray) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaCharArray (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaCharArray (list) + : new JavaCharArray (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaCharArray.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaInt16Array? CreateMarshalInt16Array (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaInt16Array c) { + return c; + } + return new JavaInt16Array (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniInt16ArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniInt16ArrayElements (JniObjectReference arrayHandle, Int16* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe Int16* Elements { + get {return (Int16*) base.Elements;} + } + + public ref Int16 this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseShortArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("S", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaInt16Array : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaInt16Array (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaInt16Array (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewShortArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaInt16Array (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaInt16Array (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniInt16ArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetShortArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetShortArrayElements()` returned NULL!"); + return new JniInt16ArrayElements (PeerReference, elements, Length*sizeof (Int16)); + } + + public override unsafe int IndexOf (Int16 item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.Int16.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (Int16); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, Int16[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (Int16* b = destinationArray) + JniEnvironment.Arrays.GetShortArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (Int16[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (Int16* b = sourceArray) + JniEnvironment.Arrays.SetShortArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaInt16Array) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaInt16Array (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaInt16Array (list) + : new JavaInt16Array (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaInt16Array.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaInt32Array? CreateMarshalInt32Array (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaInt32Array c) { + return c; + } + return new JavaInt32Array (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniInt32ArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniInt32ArrayElements (JniObjectReference arrayHandle, Int32* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe Int32* Elements { + get {return (Int32*) base.Elements;} + } + + public ref Int32 this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseIntArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("I", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaInt32Array : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaInt32Array (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaInt32Array (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewIntArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaInt32Array (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaInt32Array (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniInt32ArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetIntArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetIntArrayElements()` returned NULL!"); + return new JniInt32ArrayElements (PeerReference, elements, Length*sizeof (Int32)); + } + + public override unsafe int IndexOf (Int32 item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.Int32.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (Int32); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, Int32[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (Int32* b = destinationArray) + JniEnvironment.Arrays.GetIntArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (Int32[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (Int32* b = sourceArray) + JniEnvironment.Arrays.SetIntArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaInt32Array) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaInt32Array (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaInt32Array (list) + : new JavaInt32Array (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaInt32Array.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaInt64Array? CreateMarshalInt64Array (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaInt64Array c) { + return c; + } + return new JavaInt64Array (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniInt64ArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniInt64ArrayElements (JniObjectReference arrayHandle, Int64* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe Int64* Elements { + get {return (Int64*) base.Elements;} + } + + public ref Int64 this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseLongArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("J", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaInt64Array : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaInt64Array (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaInt64Array (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewLongArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaInt64Array (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaInt64Array (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniInt64ArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetLongArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetLongArrayElements()` returned NULL!"); + return new JniInt64ArrayElements (PeerReference, elements, Length*sizeof (Int64)); + } + + public override unsafe int IndexOf (Int64 item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.Int64.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (Int64); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, Int64[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (Int64* b = destinationArray) + JniEnvironment.Arrays.GetLongArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (Int64[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (Int64* b = sourceArray) + JniEnvironment.Arrays.SetLongArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaInt64Array) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaInt64Array (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaInt64Array (list) + : new JavaInt64Array (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaInt64Array.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaSingleArray? CreateMarshalSingleArray (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaSingleArray c) { + return c; + } + return new JavaSingleArray (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniSingleArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniSingleArrayElements (JniObjectReference arrayHandle, Single* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe Single* Elements { + get {return (Single*) base.Elements;} + } + + public ref Single this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseFloatArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("F", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaSingleArray : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaSingleArray (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaSingleArray (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewFloatArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaSingleArray (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaSingleArray (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniSingleArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetFloatArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetFloatArrayElements()` returned NULL!"); + return new JniSingleArrayElements (PeerReference, elements, Length*sizeof (Single)); + } + + public override unsafe int IndexOf (Single item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.Single.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (Single); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, Single[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (Single* b = destinationArray) + JniEnvironment.Arrays.GetFloatArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (Single[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (Single* b = sourceArray) + JniEnvironment.Arrays.SetFloatArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaSingleArray) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaSingleArray (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaSingleArray (list) + : new JavaSingleArray (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaSingleArray.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + + partial class JniEnvironment { + + partial class Arrays { + + public static JavaDoubleArray? CreateMarshalDoubleArray (System.Collections.Generic.IEnumerable? value) + { + if (value == null) { + return null; + } + if (value is JavaDoubleArray c) { + return c; + } + return new JavaDoubleArray (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class JniDoubleArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe JniDoubleArrayElements (JniObjectReference arrayHandle, Double* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe Double* Elements { + get {return (Double*) base.Elements;} + } + + public ref Double this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.ReleaseDoubleArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("D", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class JavaDoubleArray : JavaPrimitiveArray { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public JavaDoubleArray (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe JavaDoubleArray (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.NewDoubleArray (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JavaDoubleArray (System.Collections.Generic.IList value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public JavaDoubleArray (System.Collections.Generic.IEnumerable value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe JniDoubleArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.GetDoubleArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.GetDoubleArrayElements()` returned NULL!"); + return new JniDoubleArrayElements (PeerReference, elements, Length*sizeof (Double)); + } + + public override unsafe int IndexOf (Double item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.Double.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (Double); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, Double[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (Double* b = destinationArray) + JniEnvironment.Arrays.GetDoubleArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (Double[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (Double* b = sourceArray) + JniEnvironment.Arrays.SetDoubleArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray) == targetType || + typeof (JavaDoubleArray) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler> { + + public override IList CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JavaArray.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new JavaDoubleArray (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList value, ParameterAttributes synchronize) + { + return JavaArray.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new JavaDoubleArray (list) + : new JavaDoubleArray (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = JavaDoubleArray.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt new file mode 100644 index 00000000000..36fef3d04c9 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt @@ -0,0 +1,298 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +using Java.Interop.Expressions; +using System.Linq.Expressions; + +namespace Java.Interop { + +<# + var arrayTypeInfo = new[]{ + new { JniType = "Z", JniMarshalType = "Boolean", ManagedType = "Boolean",TypeModifier = "Boolean" }, + new { JniType = "B", JniMarshalType = "Byte", ManagedType = "SByte", TypeModifier = "SByte" }, + new { JniType = "C", JniMarshalType = "Char", ManagedType = "Char", TypeModifier = "Char" }, + new { JniType = "S", JniMarshalType = "Short", ManagedType = "Int16", TypeModifier = "Int16" }, + new { JniType = "I", JniMarshalType = "Int", ManagedType = "Int32", TypeModifier = "Int32" }, + new { JniType = "J", JniMarshalType = "Long", ManagedType = "Int64", TypeModifier = "Int64" }, + new { JniType = "F", JniMarshalType = "Float", ManagedType = "Single", TypeModifier = "Single" }, + new { JniType = "D", JniMarshalType = "Double", ManagedType = "Double", TypeModifier = "Double" }, + }; +#> + partial class JniRuntime { + + partial class ReflectionJniTypeManager { + + readonly struct JniPrimitiveArrayInfo { + public readonly JniTypeSignature JniTypeSignature; + public readonly Type PrimitiveType; + public readonly Type[] ArrayTypes; + + public JniPrimitiveArrayInfo (string jniSimpleReference, Type primitiveType, params Type[] arrayTypes) + { + JniTypeSignature = new JniTypeSignature (jniSimpleReference, arrayRank: 1, keyword: true); + PrimitiveType = primitiveType; + ArrayTypes = arrayTypes; + } + } + + static readonly JniPrimitiveArrayInfo[] JniPrimitiveArrayTypes = new JniPrimitiveArrayInfo[]{ +<# + foreach (var type in arrayTypeInfo) { +#> + new ("<#= type.JniType #>", typeof (<#= type.ManagedType #>), typeof (<#= type.ManagedType #>[]), typeof (JavaArray<<#= type.ManagedType #>>), typeof (JavaPrimitiveArray<<#= type.ManagedType #>>), typeof (Java<#= type.ManagedType #>Array)), +<# + } +#> + }; + + static bool GetBuiltInTypeArraySignature (Type type, ref JniTypeSignature signature) + { + foreach (var e in JniPrimitiveArrayTypes) { + if (Array.IndexOf (e.ArrayTypes, type) < 0) + continue; + signature = e.JniTypeSignature; + return true; + } + signature = default; + return false; + } + } + + static readonly Lazy[]> JniPrimitiveArrayMarshalers = new Lazy[]> (InitJniPrimitiveArrayMarshalers); + + static KeyValuePair[] InitJniPrimitiveArrayMarshalers () + { + return new [] { +<# + foreach (var info in arrayTypeInfo) { +#> + new KeyValuePair(typeof (<#= info.ManagedType #>[]), Java<#= info.TypeModifier #>Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaArray<<#= info.ManagedType #>>), Java<#= info.TypeModifier #>Array.ArrayMarshaler), + new KeyValuePair(typeof (JavaPrimitiveArray<<#= info.ManagedType #>>), Java<#= info.TypeModifier #>Array.ArrayMarshaler), + new KeyValuePair(typeof (Java<#= info.TypeModifier #>Array), Java<#= info.TypeModifier #>Array.ArrayMarshaler), +<# + } +#> + }; + } + } + +<# + foreach (var info in arrayTypeInfo) { +#> + partial class JniEnvironment { + + partial class Arrays { + + public static Java<#= info.TypeModifier #>Array? CreateMarshal<#= info.TypeModifier #>Array (System.Collections.Generic.IEnumerable<<#= info.ManagedType #>>? value) + { + if (value == null) { + return null; + } + if (value is Java<#= info.TypeModifier #>Array c) { + return c; + } + return new Java<#= info.TypeModifier #>Array (value) { + forMarshalCollection = true, + }; + } + } + } + + public sealed class Jni<#= info.TypeModifier #>ArrayElements : JniArrayElements { + + JniObjectReference arrayHandle; + + internal unsafe Jni<#= info.TypeModifier #>ArrayElements (JniObjectReference arrayHandle, <#= info.ManagedType #>* elements, int size) + : base ((IntPtr) elements, size) + { + this.arrayHandle = arrayHandle; + } + + public new unsafe <#= info.ManagedType #>* Elements { + get {return (<#= info.ManagedType #>*) base.Elements;} + } + + public ref <#= info.ManagedType #> this [int index] { + get { + if (IsDisposed) + throw new ObjectDisposedException (GetType ().FullName); + unsafe { + return ref Elements [index]; + } + } + } + + protected override unsafe void Synchronize (JniReleaseArrayElementsMode releaseMode) + { + JniEnvironment.Arrays.Release<#= info.JniMarshalType #>ArrayElements (arrayHandle, Elements, releaseMode); + } + } + + [JniTypeSignature ("<#= info.JniType #>", ArrayRank=1, IsKeyword=true, GenerateJavaPeer=false)] + public sealed class Java<#= info.TypeModifier #>Array : JavaPrimitiveArray<<#= info.ManagedType #>> { + + internal static readonly ValueMarshaler ArrayMarshaler = new ValueMarshaler (); + + public Java<#= info.TypeModifier #>Array (ref JniObjectReference handle, JniObjectReferenceOptions options) + : base (ref handle, options) + { + } + + public unsafe Java<#= info.TypeModifier #>Array (int length) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + var peer = JniEnvironment.Arrays.New<#= info.JniMarshalType #>Array (CheckLength (length)); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public Java<#= info.TypeModifier #>Array (System.Collections.Generic.IList<<#= info.ManagedType #>> value) + : this (CheckLength (value)) + { + CopyFrom (ToArray (value), 0, 0, value.Count); + } + + public Java<#= info.TypeModifier #>Array (System.Collections.Generic.IEnumerable<<#= info.ManagedType #>> value) + : this (ToArray (value)) + { + } + + protected override JniArrayElements CreateElements () + { + return GetElements (); + } + + public new unsafe Jni<#= info.TypeModifier #>ArrayElements GetElements () + { + if (!PeerReference.IsValid) + throw JniEnvironment.CreateObjectDisposedException (this); + var elements = JniEnvironment.Arrays.Get<#= info.JniMarshalType #>ArrayElements (PeerReference, null); + if (elements == null) + throw new InvalidOperationException ("`JniEnvironment.Arrays.Get<#= info.JniMarshalType #>ArrayElements()` returned NULL!"); + return new Jni<#= info.TypeModifier #>ArrayElements (PeerReference, elements, Length*sizeof (<#= info.ManagedType #>)); + } + + public override unsafe int IndexOf (<#= info.ManagedType #> item) + { + int len = Length; + if (len == 0) + return -1; + using (var e = GetElements ()) { + Debug.Assert (e != null, "Java.<#= info.TypeModifier #>.Array.GetElements() returned null! OOM?"); + if (e == null) + return -1; // IList.IndexOf() documents no exceptions. :-/ + + for (int i = 0; i < len; ++i) { + if (e [i] == item) + return i; + } + } + return -1; + } + + public override unsafe void Clear () + { + int len = Length; + using (var e = GetElements ()) { + for (int i = 0; i < len; ++i) { + e [i] = default (<#= info.ManagedType #>); + } + } + } + + public override unsafe void CopyTo (int sourceIndex, <#= info.ManagedType #>[] destinationArray, int destinationIndex, int length) + { + if (destinationArray == null) + throw new ArgumentNullException (nameof (destinationArray)); + CheckArrayCopy (sourceIndex, Length, destinationIndex, destinationArray.Length, length); + if (destinationArray.Length == 0) + return; + + fixed (<#= info.ManagedType #>* b = destinationArray) + JniEnvironment.Arrays.Get<#= info.JniMarshalType #>ArrayRegion (PeerReference, sourceIndex, length, (b+destinationIndex)); + } + + public override unsafe void CopyFrom (<#= info.ManagedType #>[] sourceArray, int sourceIndex, int destinationIndex, int length) + { + if (sourceArray == null) + throw new ArgumentNullException (nameof (sourceArray)); + CheckArrayCopy (sourceIndex, sourceArray.Length, destinationIndex, Length, length); + if (sourceArray.Length == 0) + return; + + fixed (<#= info.ManagedType #>* b = sourceArray) + JniEnvironment.Arrays.Set<#= info.JniMarshalType #>ArrayRegion (PeerReference, destinationIndex, length, (b+sourceIndex)); + } + + internal override bool TargetTypeIsCurrentType (Type? targetType) + { + return base.TargetTypeIsCurrentType (targetType) || + typeof (JavaPrimitiveArray<<#= info.ManagedType #>>) == targetType || + typeof (Java<#= info.TypeModifier #>Array) == targetType; + } + + public static object? CreateMarshaledValue ( + IntPtr handle, + [DynamicallyAccessedMembers (ConstructorsAndInterfaces)] + Type? targetType) + { + return ArrayMarshaler.CreateValue (handle, targetType); + } + + internal sealed class ValueMarshaler : JniValueMarshaler>> { + + public override IList<<#= info.TypeModifier #>> CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (ConstructorsAndInterfaces)] + Type? targetType) + { + return JavaArray<<#= info.TypeModifier #>>.CreateValue ( + ref reference, + options, + targetType, + (ref JniObjectReference h, JniObjectReferenceOptions o) => new Java<#= info.TypeModifier #>Array (ref h, o)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] IList<<#= info.TypeModifier #>> value, ParameterAttributes synchronize) + { + return JavaArray<<#= info.TypeModifier #>>.CreateArgumentState (value, synchronize, (list, copy) => { + var a = copy + ? new Java<#= info.TypeModifier #>Array (list) + : new Java<#= info.TypeModifier #>Array (list.Count); + a.forMarshalCollection = true; + return a; + }); + } + + public override void DestroyGenericArgumentState ([AllowNull] IList<<#= info.TypeModifier #>> value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + JavaArray<<#= info.ManagedType #>>.DestroyArgumentStateArray> (value, ref state, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = Java<#= info.TypeModifier #>Array.CreateMarshaledValue; + + var call = Expression.Call (m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + } + } + +<# } #> +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaProxyObject.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaProxyObject.cs new file mode 100644 index 00000000000..909629b188b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaProxyObject.cs @@ -0,0 +1,139 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Java.Interop { + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + sealed class JavaProxyObject : JavaObject, IEquatable + { + internal const string JniTypeName = "net/dot/jni/internal/JavaProxyObject"; + + static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaProxyObject)); + static readonly ConditionalWeakTable CachedValues = new ConditionalWeakTable (); + + [JniAddNativeMethodRegistrationAttribute] + static void RegisterNativeMembers (JniNativeMethodRegistrationArguments args) + { + args.Registrations.Add (new JniNativeMethodRegistration ("equals", "(Ljava/lang/Object;)Z", new EqualsMarshalMethod (Equals))); + args.Registrations.Add (new JniNativeMethodRegistration ("hashCode", "()I", new GetHashCodeMarshalMethod (GetHashCode))); + args.Registrations.Add (new JniNativeMethodRegistration ("toString", "()Ljava/lang/String;", new ToStringMarshalMethod (ToString))); + } + + public override JniPeerMembers JniPeerMembers { + get { + return _members; + } + } + + JavaProxyObject (object value) + { + if (value == null) + throw new ArgumentNullException (nameof (value)); + Value = value; + } + + public object Value {get; private set;} + + public override int GetHashCode () + { + return Value.GetHashCode (); + } + + public override bool Equals (object? obj) + { + if (obj is JavaProxyObject other) + return object.Equals (Value, other.Value); + return object.Equals (Value, obj); + } + + public bool Equals (JavaProxyObject? other) => object.Equals (Value, other?.Value); + + public override string? ToString () + { + return Value.ToString (); + } + + [return: NotNullIfNotNull ("object")] + public static JavaProxyObject? GetProxy (object value) + { + if (value == null) + return null; + + lock (CachedValues) { + if (CachedValues.TryGetValue (value, out var proxy)) + return proxy; + proxy = new JavaProxyObject (value); + CachedValues.Add (value, proxy); + return proxy; + } + } + + // TODO: Keep in sync with the code generated by ExportedMemberBuilder + [UnmanagedFunctionPointer (CallingConvention.Winapi)] + delegate bool EqualsMarshalMethod (IntPtr jnienv, IntPtr n_self, IntPtr n_value); + static bool Equals (IntPtr jnienv, IntPtr n_self, IntPtr n_value) + { + var envp = new JniTransition (jnienv); + try { + var self = (JavaProxyObject?) JniEnvironment.Runtime.ValueManager.PeekPeer (new JniObjectReference (n_self)); + var r_value = new JniObjectReference (n_value); + var value = JniEnvironment.Runtime.ValueManager.GetValue (ref r_value, JniObjectReferenceOptions.Copy); + return self?.Equals (value) ?? false; + } + catch (Exception e) when (JniEnvironment.Runtime.ExceptionShouldTransitionToJni (e)) { + envp.SetPendingException (e); + return false; + } + finally { + envp.Dispose (); + } + } + + // TODO: Keep in sync with the code generated by ExportedMemberBuilder + [UnmanagedFunctionPointer (CallingConvention.Winapi)] + delegate int GetHashCodeMarshalMethod (IntPtr jnienv, IntPtr n_self); + static int GetHashCode (IntPtr jnienv, IntPtr n_self) + { + var envp = new JniTransition (jnienv); + try { + var self = (JavaProxyObject?) JniEnvironment.Runtime.ValueManager.PeekPeer (new JniObjectReference (n_self)); + return self?.GetHashCode () ?? 0; + } + catch (Exception e) when (JniEnvironment.Runtime.ExceptionShouldTransitionToJni (e)) { + envp.SetPendingException (e); + return 0; + } + finally { + envp.Dispose (); + } + } + + [UnmanagedFunctionPointer (CallingConvention.Winapi)] + delegate IntPtr ToStringMarshalMethod (IntPtr jnienv, IntPtr n_self); + static IntPtr ToString (IntPtr jnienv, IntPtr n_self) + { + var envp = new JniTransition (jnienv); + try { + var self = (JavaProxyObject?) JniEnvironment.Runtime.ValueManager.PeekPeer (new JniObjectReference (n_self)); + var s = self?.ToString (); + var r = JniEnvironment.Strings.NewString (s); + try { + return JniEnvironment.References.NewReturnToJniRef (r); + } finally { + JniObjectReference.Dispose (ref r); + } + } + catch (Exception e) when (JniEnvironment.Runtime.ExceptionShouldTransitionToJni (e)) { + envp.SetPendingException (e); + return IntPtr.Zero; + } + finally { + envp.Dispose (); + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaProxyThrowable.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaProxyThrowable.cs new file mode 100644 index 00000000000..3fb2cc7201f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaProxyThrowable.cs @@ -0,0 +1,28 @@ +#nullable enable + +using System; + +namespace Java.Interop { + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + sealed class JavaProxyThrowable : JavaException + { + new internal const string JniTypeName = "net/dot/jni/internal/JavaProxyThrowable"; + + public Exception Exception {get; private set;} + + public JavaProxyThrowable (Exception exception) + : base (GetMessage (exception)) + { + Exception = exception; + } + + static string GetMessage (Exception exception) + { + if (exception == null) + throw new ArgumentNullException (nameof (exception)); + return exception.ToString (); + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JavaTypeParametersAttribute.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaTypeParametersAttribute.cs new file mode 100644 index 00000000000..a40c89736cf --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JavaTypeParametersAttribute.cs @@ -0,0 +1,17 @@ +using System; + + +namespace Java.Interop +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method, + AllowMultiple=false)] + public sealed class JavaTypeParametersAttribute : Attribute + { + public JavaTypeParametersAttribute (string [] typeParameters) + { + TypeParameters = typeParameters; + } + + public string [] TypeParameters { get; } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniAddNativeMethodRegistrationAttribute.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniAddNativeMethodRegistrationAttribute.cs new file mode 100644 index 00000000000..80ac074c1c3 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniAddNativeMethodRegistrationAttribute.cs @@ -0,0 +1,11 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + [AttributeUsage (AttributeTargets.Method)] + public sealed class JniAddNativeMethodRegistrationAttribute : Attribute + { + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniArgumentValue.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniArgumentValue.cs new file mode 100644 index 00000000000..3613094c29b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniArgumentValue.cs @@ -0,0 +1,139 @@ +#nullable enable + +using System; +using System.Runtime.InteropServices; + +#if INTEROP +namespace Java.Interop +#else +namespace Android.Runtime +#endif +{ + + [StructLayout(LayoutKind.Explicit)] + public struct JniArgumentValue : IEquatable { +#pragma warning disable 0414 + [FieldOffset(0)] bool z; + [FieldOffset(0)] sbyte b; + [FieldOffset(0)] char c; + [FieldOffset(0)] short s; + [FieldOffset(0)] int i; + [FieldOffset(0)] long j; + [FieldOffset(0)] float f; + [FieldOffset(0)] double d; + [FieldOffset(0)] IntPtr l; +#pragma warning restore 0414 + + public JniArgumentValue (bool value) + { + this = new JniArgumentValue (); + z = value; + } + + public JniArgumentValue (sbyte value) + { + this = new JniArgumentValue (); + b = value; + } + + public JniArgumentValue (byte value) : this ((sbyte)value) { } + + public JniArgumentValue (char value) + { + this = new JniArgumentValue (); + c = value; + } + + public JniArgumentValue (short value) + { + this = new JniArgumentValue (); + s = value; + } + + public JniArgumentValue (ushort value) : this ((short)value) { } + + public JniArgumentValue (int value) + { + this = new JniArgumentValue (); + i = value; + } + + public JniArgumentValue (uint value) : this ((int)value) { } + + public JniArgumentValue (long value) + { + this = new JniArgumentValue (); + j = value; + } + + public JniArgumentValue (ulong value) : this ((long) value) { } + + public JniArgumentValue (float value) + { + this = new JniArgumentValue (); + f = value; + } + + public JniArgumentValue (double value) + { + this = new JniArgumentValue (); + d = value; + } + + public JniArgumentValue (IntPtr value) + { + this = new JniArgumentValue (); + l = value; + } + + public JniArgumentValue (JniObjectReference value) + { + this = new JniArgumentValue (); + l = value.Handle; + } + + public JniArgumentValue (IJavaPeerable? value) + { + this = new JniArgumentValue (); + if (value != null) + l = value.PeerReference.Handle; + else + l = IntPtr.Zero; + } + + public override int GetHashCode () + { + return j.GetHashCode (); + } + + public override bool Equals (object? obj) + { + var o = obj as JniArgumentValue?; + if (!o.HasValue) + return false; + return Equals (o.Value); + } + + public bool Equals (JniArgumentValue other) + { + return j == other.j; + } + + public static bool operator==(JniArgumentValue lhs, JniArgumentValue rhs) + { + return lhs.j == rhs.j; + } + + public static bool operator!=(JniArgumentValue lhs, JniArgumentValue rhs) + { + return lhs.j != rhs.j; + } + + public override string ToString () + { + return string.Format ("JniArgumentValue(z={0},b={1},c={2},s={3},i={4},j={5},f={6},d={7},l=0x{8})", + z, b, c, s, i, j, f, d, l.ToString ("x")); + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs new file mode 100644 index 00000000000..f51f6b2e8f0 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs @@ -0,0 +1,1313 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using System.Reflection; + +using Java.Interop.Expressions; + +namespace Java.Interop { + + partial class JniRuntime { + static JniTypeSignature __StringTypeSignature; + static JniTypeSignature __VoidTypeSignature; + static JniTypeSignature __BooleanTypeSignature; + static JniTypeSignature __BooleanNullableTypeSignature; + static JniTypeSignature __SByteTypeSignature; + static JniTypeSignature __SByteNullableTypeSignature; + static JniTypeSignature __CharTypeSignature; + static JniTypeSignature __CharNullableTypeSignature; + static JniTypeSignature __Int16TypeSignature; + static JniTypeSignature __Int16NullableTypeSignature; + static JniTypeSignature __Int32TypeSignature; + static JniTypeSignature __Int32NullableTypeSignature; + static JniTypeSignature __Int64TypeSignature; + static JniTypeSignature __Int64NullableTypeSignature; + static JniTypeSignature __SingleTypeSignature; + static JniTypeSignature __SingleNullableTypeSignature; + static JniTypeSignature __DoubleTypeSignature; + static JniTypeSignature __DoubleNullableTypeSignature; + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + static JniTypeSignature GetCachedTypeSignature (ref JniTypeSignature field, string signature, int arrayRank = 0, bool keyword = false) + { + if (!field.IsValid) + field = new JniTypeSignature (signature, arrayRank, keyword); + return field; + } + + static bool GetBuiltInTypeSignature (Type type, ref JniTypeSignature signature) + { + switch (Type.GetTypeCode (type)) { + case TypeCode.String: + signature = GetCachedTypeSignature (ref __StringTypeSignature, "java/lang/String"); + return true; + case TypeCode.Boolean: + signature = GetCachedTypeSignature (ref __BooleanTypeSignature, "Z", arrayRank: 0, keyword: true); + return true; + case TypeCode.Byte: + case TypeCode.SByte: + signature = GetCachedTypeSignature (ref __SByteTypeSignature, "B", arrayRank: 0, keyword: true); + return true; + case TypeCode.Char: + signature = GetCachedTypeSignature (ref __CharTypeSignature, "C", arrayRank: 0, keyword: true); + return true; + case TypeCode.UInt16: + case TypeCode.Int16: + signature = GetCachedTypeSignature (ref __Int16TypeSignature, "S", arrayRank: 0, keyword: true); + return true; + case TypeCode.UInt32: + case TypeCode.Int32: + signature = GetCachedTypeSignature (ref __Int32TypeSignature, "I", arrayRank: 0, keyword: true); + return true; + case TypeCode.UInt64: + case TypeCode.Int64: + signature = GetCachedTypeSignature (ref __Int64TypeSignature, "J", arrayRank: 0, keyword: true); + return true; + case TypeCode.Single: + signature = GetCachedTypeSignature (ref __SingleTypeSignature, "F", arrayRank: 0, keyword: true); + return true; + case TypeCode.Double: + signature = GetCachedTypeSignature (ref __DoubleTypeSignature, "D", arrayRank: 0, keyword: true); + return true; + case TypeCode.DateTime: + case TypeCode.DBNull: + case TypeCode.Decimal: + case TypeCode.Empty: + return false; + } + + if (type == typeof (void)) { + signature = GetCachedTypeSignature (ref __VoidTypeSignature, "V", arrayRank: 0, keyword: true); + return true; + } + + if (!type.IsValueType) + return false; + + if (type == typeof (Boolean?)) { + signature = GetCachedTypeSignature (ref __BooleanNullableTypeSignature, "java/lang/Boolean"); + return true; + } + if (type == typeof (SByte?)) { + signature = GetCachedTypeSignature (ref __SByteNullableTypeSignature, "java/lang/Byte"); + return true; + } + if (type == typeof (Char?)) { + signature = GetCachedTypeSignature (ref __CharNullableTypeSignature, "java/lang/Character"); + return true; + } + if (type == typeof (Int16?)) { + signature = GetCachedTypeSignature (ref __Int16NullableTypeSignature, "java/lang/Short"); + return true; + } + if (type == typeof (Int32?)) { + signature = GetCachedTypeSignature (ref __Int32NullableTypeSignature, "java/lang/Integer"); + return true; + } + if (type == typeof (Int64?)) { + signature = GetCachedTypeSignature (ref __Int64NullableTypeSignature, "java/lang/Long"); + return true; + } + if (type == typeof (Single?)) { + signature = GetCachedTypeSignature (ref __SingleNullableTypeSignature, "java/lang/Float"); + return true; + } + if (type == typeof (Double?)) { + signature = GetCachedTypeSignature (ref __DoubleNullableTypeSignature, "java/lang/Double"); + return true; + } + + return false; + } + + static readonly Lazy> JniBuiltinSimpleReferenceToType = new Lazy> (InitJniBuiltinSimpleReferenceToType); + + static Dictionary InitJniBuiltinSimpleReferenceToType () + { + return new Dictionary (StringComparer.Ordinal) { + {"java/lang/String", typeof (string)}, + {"net/dot/jni/internal/JavaProxyObject", typeof (JavaProxyObject)}, + {"net/dot/jni/internal/JavaProxyThrowable", typeof (JavaProxyThrowable)}, + {"V", typeof (void)}, + {"Z", typeof (Boolean)}, + {"java/lang/Boolean", typeof (Boolean?)}, + {"B", typeof (SByte)}, + {"java/lang/Byte", typeof (SByte?)}, + {"C", typeof (Char)}, + {"java/lang/Character", typeof (Char?)}, + {"S", typeof (Int16)}, + {"java/lang/Short", typeof (Int16?)}, + {"I", typeof (Int32)}, + {"java/lang/Integer", typeof (Int32?)}, + {"J", typeof (Int64)}, + {"java/lang/Long", typeof (Int64?)}, + {"F", typeof (Single)}, + {"java/lang/Float", typeof (Single?)}, + {"D", typeof (Double)}, + {"java/lang/Double", typeof (Double?)}, + }; + } + + partial class ReflectionJniValueManager + { + static readonly Lazy[]> JniBuiltinMarshalers = new Lazy[]> (InitJniBuiltinMarshalers); + + static KeyValuePair[] InitJniBuiltinMarshalers () + { + return new []{ + new KeyValuePair(typeof (string), JniStringValueMarshaler.Instance), + new KeyValuePair(typeof (JavaProxyObject), ProxyValueMarshaler.Instance), + new KeyValuePair(typeof (Boolean), JniBooleanValueMarshaler.Instance), + new KeyValuePair(typeof (Boolean?), JniNullableBooleanValueMarshaler.Instance), + new KeyValuePair(typeof (SByte), JniSByteValueMarshaler.Instance), + new KeyValuePair(typeof (SByte?), JniNullableSByteValueMarshaler.Instance), + new KeyValuePair(typeof (Char), JniCharValueMarshaler.Instance), + new KeyValuePair(typeof (Char?), JniNullableCharValueMarshaler.Instance), + new KeyValuePair(typeof (Int16), JniInt16ValueMarshaler.Instance), + new KeyValuePair(typeof (Int16?), JniNullableInt16ValueMarshaler.Instance), + new KeyValuePair(typeof (Int32), JniInt32ValueMarshaler.Instance), + new KeyValuePair(typeof (Int32?), JniNullableInt32ValueMarshaler.Instance), + new KeyValuePair(typeof (Int64), JniInt64ValueMarshaler.Instance), + new KeyValuePair(typeof (Int64?), JniNullableInt64ValueMarshaler.Instance), + new KeyValuePair(typeof (Single), JniSingleValueMarshaler.Instance), + new KeyValuePair(typeof (Single?), JniNullableSingleValueMarshaler.Instance), + new KeyValuePair(typeof (Double), JniDoubleValueMarshaler.Instance), + new KeyValuePair(typeof (Double?), JniNullableDoubleValueMarshaler.Instance), + }; + } + } + } + + static class JniBoolean { + internal const string JniTypeName = "java/lang/Boolean"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (Boolean value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(Z)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? booleanValue; + internal static Boolean GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (Boolean), "Expected targetType==typeof(Boolean); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref booleanValue, "booleanValue", "()Z"); + try { + return JniEnvironment.InstanceMethods.CallBooleanMethod (self, booleanValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniBooleanValueMarshaler : JniValueMarshaler { + + internal static readonly JniBooleanValueMarshaler Instance = new JniBooleanValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (Boolean);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override Boolean CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (Boolean); + + return JniBoolean.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] Boolean value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Boolean value, ParameterAttributes synchronize) + { + var r = JniBoolean.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (Boolean value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableBooleanValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableBooleanValueMarshaler Instance = new JniNullableBooleanValueMarshaler (); + + public override Boolean? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniBoolean.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Boolean? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniBoolean.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (Boolean? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } + + static class JniByte { + internal const string JniTypeName = "java/lang/Byte"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (SByte value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(B)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? byteValue; + internal static SByte GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (SByte), "Expected targetType==typeof(SByte); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref byteValue, "byteValue", "()B"); + try { + return JniEnvironment.InstanceMethods.CallByteMethod (self, byteValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniSByteValueMarshaler : JniValueMarshaler { + + internal static readonly JniSByteValueMarshaler Instance = new JniSByteValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (SByte);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override SByte CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (SByte); + + return JniByte.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] SByte value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] SByte value, ParameterAttributes synchronize) + { + var r = JniByte.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (SByte value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableSByteValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableSByteValueMarshaler Instance = new JniNullableSByteValueMarshaler (); + + public override SByte? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniByte.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] SByte? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniByte.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (SByte? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } + + static class JniCharacter { + internal const string JniTypeName = "java/lang/Character"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (Char value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(C)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? charValue; + internal static Char GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (Char), "Expected targetType==typeof(Char); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref charValue, "charValue", "()C"); + try { + return JniEnvironment.InstanceMethods.CallCharMethod (self, charValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniCharValueMarshaler : JniValueMarshaler { + + internal static readonly JniCharValueMarshaler Instance = new JniCharValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (Char);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override Char CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (Char); + + return JniCharacter.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] Char value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Char value, ParameterAttributes synchronize) + { + var r = JniCharacter.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (Char value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableCharValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableCharValueMarshaler Instance = new JniNullableCharValueMarshaler (); + + public override Char? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniCharacter.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Char? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniCharacter.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (Char? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } + + static class JniShort { + internal const string JniTypeName = "java/lang/Short"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (Int16 value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(S)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? shortValue; + internal static Int16 GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (Int16), "Expected targetType==typeof(Int16); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref shortValue, "shortValue", "()S"); + try { + return JniEnvironment.InstanceMethods.CallShortMethod (self, shortValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniInt16ValueMarshaler : JniValueMarshaler { + + internal static readonly JniInt16ValueMarshaler Instance = new JniInt16ValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (Int16);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override Int16 CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (Int16); + + return JniShort.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] Int16 value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Int16 value, ParameterAttributes synchronize) + { + var r = JniShort.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (Int16 value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableInt16ValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableInt16ValueMarshaler Instance = new JniNullableInt16ValueMarshaler (); + + public override Int16? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniShort.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Int16? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniShort.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (Int16? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } + + static class JniInteger { + internal const string JniTypeName = "java/lang/Integer"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (Int32 value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(I)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? intValue; + internal static Int32 GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (Int32), "Expected targetType==typeof(Int32); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref intValue, "intValue", "()I"); + try { + return JniEnvironment.InstanceMethods.CallIntMethod (self, intValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniInt32ValueMarshaler : JniValueMarshaler { + + internal static readonly JniInt32ValueMarshaler Instance = new JniInt32ValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (Int32);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override Int32 CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (Int32); + + return JniInteger.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] Int32 value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Int32 value, ParameterAttributes synchronize) + { + var r = JniInteger.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (Int32 value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableInt32ValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableInt32ValueMarshaler Instance = new JniNullableInt32ValueMarshaler (); + + public override Int32? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniInteger.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Int32? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniInteger.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (Int32? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } + + static class JniLong { + internal const string JniTypeName = "java/lang/Long"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (Int64 value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(J)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? longValue; + internal static Int64 GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (Int64), "Expected targetType==typeof(Int64); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref longValue, "longValue", "()J"); + try { + return JniEnvironment.InstanceMethods.CallLongMethod (self, longValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniInt64ValueMarshaler : JniValueMarshaler { + + internal static readonly JniInt64ValueMarshaler Instance = new JniInt64ValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (Int64);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override Int64 CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (Int64); + + return JniLong.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] Int64 value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Int64 value, ParameterAttributes synchronize) + { + var r = JniLong.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (Int64 value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableInt64ValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableInt64ValueMarshaler Instance = new JniNullableInt64ValueMarshaler (); + + public override Int64? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniLong.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Int64? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniLong.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (Int64? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } + + static class JniFloat { + internal const string JniTypeName = "java/lang/Float"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (Single value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(F)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? floatValue; + internal static Single GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (Single), "Expected targetType==typeof(Single); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref floatValue, "floatValue", "()F"); + try { + return JniEnvironment.InstanceMethods.CallFloatMethod (self, floatValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniSingleValueMarshaler : JniValueMarshaler { + + internal static readonly JniSingleValueMarshaler Instance = new JniSingleValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (Single);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override Single CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (Single); + + return JniFloat.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] Single value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Single value, ParameterAttributes synchronize) + { + var r = JniFloat.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (Single value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableSingleValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableSingleValueMarshaler Instance = new JniNullableSingleValueMarshaler (); + + public override Single? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniFloat.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Single? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniFloat.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (Single? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } + + static class JniDouble { + internal const string JniTypeName = "java/lang/Double"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (Double value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(D)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? doubleValue; + internal static Double GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (Double), "Expected targetType==typeof(Double); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref doubleValue, "doubleValue", "()D"); + try { + return JniEnvironment.InstanceMethods.CallDoubleMethod (self, doubleValue); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class JniDoubleValueMarshaler : JniValueMarshaler { + + internal static readonly JniDoubleValueMarshaler Instance = new JniDoubleValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (Double);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override Double CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (Double); + + return JniDouble.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] Double value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Double value, ParameterAttributes synchronize) + { + var r = JniDouble.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (Double value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullableDoubleValueMarshaler : JniValueMarshaler { + + internal static readonly JniNullableDoubleValueMarshaler Instance = new JniNullableDoubleValueMarshaler (); + + public override Double? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return JniDouble.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] Double? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = JniDouble.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (Double? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt b/external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt new file mode 100644 index 00000000000..61d0d25cf00 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt @@ -0,0 +1,289 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +#nullable enable + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using System.Reflection; + +using Java.Interop.Expressions; + +namespace Java.Interop { +<# + var types = new[]{ + new { Name = "Boolean", Type = "Boolean", UnsignedType = "", JniCallType = "Boolean", JniType = "Z", GetValue = "booleanValue" }, + new { Name = "Byte", Type = "SByte", UnsignedType = "Byte", JniCallType = "Byte", JniType = "B", GetValue = "byteValue" }, + new { Name = "Character", Type = "Char", UnsignedType = "", JniCallType = "Char", JniType = "C", GetValue = "charValue" }, + new { Name = "Short", Type = "Int16", UnsignedType = "UInt16", JniCallType = "Short", JniType = "S", GetValue = "shortValue" }, + new { Name = "Integer", Type = "Int32", UnsignedType = "UInt32", JniCallType = "Int", JniType = "I", GetValue = "intValue" }, + new { Name = "Long", Type = "Int64", UnsignedType = "UInt64", JniCallType = "Long", JniType = "J", GetValue = "longValue" }, + new { Name = "Float", Type = "Single", UnsignedType = "", JniCallType = "Float", JniType = "F", GetValue = "floatValue" }, + new { Name = "Double", Type = "Double", UnsignedType = "", JniCallType = "Double", JniType = "D", GetValue = "doubleValue" }, + }; +#> + + partial class JniRuntime { + static JniTypeSignature __StringTypeSignature; + static JniTypeSignature __VoidTypeSignature; +<# + foreach (var type in types) { +#> + static JniTypeSignature __<#= type.Type #>TypeSignature; + static JniTypeSignature __<#= type.Type #>NullableTypeSignature; +<# + } +#> + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + static JniTypeSignature GetCachedTypeSignature (ref JniTypeSignature field, string signature, int arrayRank = 0, bool keyword = false) + { + if (!field.IsValid) + field = new JniTypeSignature (signature, arrayRank, keyword); + return field; + } + + static bool GetBuiltInTypeSignature (Type type, ref JniTypeSignature signature) + { + switch (Type.GetTypeCode (type)) { + case TypeCode.String: + signature = GetCachedTypeSignature (ref __StringTypeSignature, "java/lang/String"); + return true; +<# + foreach (var type in types) { + if (!string.IsNullOrEmpty (type.UnsignedType)) { +#> + case TypeCode.<#= type.UnsignedType #>: +<# + } +#> + case TypeCode.<#= type.Type #>: + signature = GetCachedTypeSignature (ref __<#= type.Type #>TypeSignature, "<#= type.JniType #>", arrayRank: 0, keyword: true); + return true; +<# + } +#> + case TypeCode.DateTime: + case TypeCode.DBNull: + case TypeCode.Decimal: + case TypeCode.Empty: + return false; + } + + if (type == typeof (void)) { + signature = GetCachedTypeSignature (ref __VoidTypeSignature, "V", arrayRank: 0, keyword: true); + return true; + } + + if (!type.IsValueType) + return false; + +<# + foreach (var type in types) { +#> + if (type == typeof (<#= type.Type #>?)) { + signature = GetCachedTypeSignature (ref __<#= type.Type #>NullableTypeSignature, "java/lang/<#= type.Name #>"); + return true; + } +<# + } +#> + + return false; + } + + static readonly Lazy> JniBuiltinSimpleReferenceToType = new Lazy> (InitJniBuiltinSimpleReferenceToType); + + static Dictionary InitJniBuiltinSimpleReferenceToType () + { + return new Dictionary (StringComparer.Ordinal) { + {"java/lang/String", typeof (string)}, + {"net/dot/jni/internal/JavaProxyObject", typeof (JavaProxyObject)}, + {"net/dot/jni/internal/JavaProxyThrowable", typeof (JavaProxyThrowable)}, + {"V", typeof (void)}, +<# + foreach (var type in types) { +#> + {"<#= type.JniType #>", typeof (<#= type.Type #>)}, + {"java/lang/<#= type.Name #>", typeof (<#= type.Type #>?)}, +<# + } +#> + }; + } + + partial class ReflectionJniValueManager + { + static readonly Lazy[]> JniBuiltinMarshalers = new Lazy[]> (InitJniBuiltinMarshalers); + + static KeyValuePair[] InitJniBuiltinMarshalers () + { + return new []{ + new KeyValuePair(typeof (string), JniStringValueMarshaler.Instance), + new KeyValuePair(typeof (JavaProxyObject), ProxyValueMarshaler.Instance), +<# + foreach (var type in types) { +#> + new KeyValuePair(typeof (<#= type.Type #>), Jni<#= type.Type #>ValueMarshaler.Instance), + new KeyValuePair(typeof (<#= type.Type #>?), JniNullable<#= type.Type #>ValueMarshaler.Instance), +<# + } +#> + }; + } + } + } +<# + foreach (var type in types) { +#> + + static class Jni<#= type.Name #> { + internal const string JniTypeName = "java/lang/<#= type.Name #>"; + + static JniType? _TypeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);} + } + + static JniMethodInfo? init; + internal static unsafe JniObjectReference CreateLocalRef (<#= type.Type #> value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + TypeRef.GetCachedConstructor (ref init, "(<#= type.JniType #>)V"); + return TypeRef.NewObject (init, args); + } + + static JniMethodInfo? <#= type.GetValue #>; + internal static <#= type.Type #> GetValueFromJni (ref JniObjectReference self, JniObjectReferenceOptions transfer, Type? targetType) + { + Debug.Assert (targetType == null || targetType == typeof (<#= type.Type #>), "Expected targetType==typeof(<#= type.Type #>); was: " + targetType); + TypeRef.GetCachedInstanceMethod (ref <#= type.GetValue #>, "<#= type.GetValue #>", "()<#= type.JniType #>"); + try { + return JniEnvironment.InstanceMethods.Call<#= type.JniCallType #>Method (self, <#= type.GetValue #>); + } finally { + JniObjectReference.Dispose (ref self, transfer); + } + } + } + + sealed class Jni<#= type.Type #>ValueMarshaler : JniValueMarshaler<<#= type.Type #>> { + + internal static readonly Jni<#= type.Type #>ValueMarshaler Instance = new Jni<#= type.Type #>ValueMarshaler (); + + public override bool IsJniValueType { + get {return true;} + } + + public override Type MarshalType { + get {return typeof (<#= type.Type #>);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + return CreateGenericValue (ref reference, options, targetType); + } + + public override <#= type.Type #> CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return default (<#= type.Type #>); + + return Jni<#= type.Name #>.GetValueFromJni (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] <#= type.Type #> value, ParameterAttributes synchronize = ParameterAttributes.In) + { + return new JniValueMarshalerState (new JniArgumentValue (value)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] <#= type.Type #> value, ParameterAttributes synchronize) + { + var r = Jni<#= type.Name #>.CreateLocalRef (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + public override void DestroyGenericArgumentState (<#= type.Type #> value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return sourceValue; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return sourceValue; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return sourceValue; + } + } + + sealed class JniNullable<#= type.Type #>ValueMarshaler : JniValueMarshaler<<#= type.Type #>?> { + + internal static readonly JniNullable<#= type.Type #>ValueMarshaler Instance = new JniNullable<#= type.Type #>ValueMarshaler (); + + public override <#= type.Type #>? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + if (!reference.IsValid) + return null; + + return Jni<#= type.Name #>.GetValueFromJni (ref reference, options, targetType: null); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] <#= type.Type #>? value, ParameterAttributes synchronize) + { + if (!value.HasValue) + return new JniValueMarshalerState (); + var r = Jni<#= type.Name #>.CreateLocalRef (value.Value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (<#= type.Type #>? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } +<# + } +#> +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniConstructorSignatureAttribute.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniConstructorSignatureAttribute.cs new file mode 100644 index 00000000000..8a69057d005 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniConstructorSignatureAttribute.cs @@ -0,0 +1,17 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; + + +namespace Java.Interop +{ + [AttributeUsage (AttributeTargets.Constructor, AllowMultiple = false)] + public sealed class JniConstructorSignatureAttribute : JniMemberSignatureAttribute { + + public JniConstructorSignatureAttribute (string memberSignature) + : base (".ctor", memberSignature) + { + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Errors.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Errors.cs new file mode 100644 index 00000000000..8211771e629 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Errors.cs @@ -0,0 +1,46 @@ +#nullable enable + +using System; + +namespace Java.Interop { + partial class JniEnvironment { + + partial class Exceptions { + + public static void Throw (JniObjectReference toThrow) + { + if (!toThrow.IsValid) + throw new ArgumentException (nameof (toThrow)); + + int r = _Throw (toThrow); + if (r != 0) + throw new InvalidOperationException (string.Format ("Could not raise an exception; JNIEnv::Throw() returned {0}.", r)); + } + + + public static void ThrowNew (JniObjectReference klass, string message) + { + if (!klass.IsValid) + throw new ArgumentException (nameof (klass)); + if (message == null) + throw new ArgumentNullException (nameof (message)); + + int r = _ThrowNew (klass, message); + if (r != 0) + throw new InvalidOperationException (string.Format ("Could not raise an exception; JNIEnv::ThrowNew() returned {0}.", r)); + } + + public static void Throw (Exception e) + { + if (e == null) + throw new ArgumentNullException (nameof (e)); + var je = e as JavaException; + if (je == null) { + je = new JavaProxyThrowable (e); + } + Throw (je.PeerReference); + } + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Members.Utf8.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Members.Utf8.cs new file mode 100644 index 00000000000..05f6356c85f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Members.Utf8.cs @@ -0,0 +1,125 @@ +#nullable enable + +#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS +using System; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +namespace Java.Interop { + + partial class JniEnvironment { + + partial class InstanceFields { + + /// + /// Looks up a JNI instance field ID using null-terminated UTF-8 name and signature spans. + /// Use with "fieldName"u8 literals to avoid string marshalling overhead. + /// + public static unsafe JniFieldInfo GetFieldID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr __env = JniEnvironment.EnvironmentPointer; + fixed (byte* _name_ptr = name) + fixed (byte* _signature_ptr = signature) { + var tmp = JniNativeMethods.GetFieldID (__env, type.Handle, (IntPtr) _name_ptr, (IntPtr) _signature_ptr); + IntPtr thrown = JniNativeMethods.ExceptionOccurred (__env); + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (tmp == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetFieldID` should have thrown!"); + return new JniFieldInfo (tmp, isStatic: false); + } + } + } + + partial class InstanceMethods { + + /// + /// Looks up a JNI instance method ID using null-terminated UTF-8 name and signature spans. + /// Use with "methodName"u8 literals to avoid string marshalling overhead. + /// + public static unsafe JniMethodInfo GetMethodID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr __env = JniEnvironment.EnvironmentPointer; + fixed (byte* _name_ptr = name) + fixed (byte* _signature_ptr = signature) { + var tmp = JniNativeMethods.GetMethodID (__env, type.Handle, (IntPtr) _name_ptr, (IntPtr) _signature_ptr); + IntPtr thrown = JniNativeMethods.ExceptionOccurred (__env); + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (tmp == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetMethodID` should have thrown!"); + return new JniMethodInfo (tmp, isStatic: false); + } + } + } + + partial class StaticFields { + + /// + /// Looks up a JNI static field ID using null-terminated UTF-8 name and signature spans. + /// Use with "fieldName"u8 literals to avoid string marshalling overhead. + /// + public static unsafe JniFieldInfo GetStaticFieldID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr __env = JniEnvironment.EnvironmentPointer; + fixed (byte* _name_ptr = name) + fixed (byte* _signature_ptr = signature) { + var tmp = JniNativeMethods.GetStaticFieldID (__env, type.Handle, (IntPtr) _name_ptr, (IntPtr) _signature_ptr); + IntPtr thrown = JniNativeMethods.ExceptionOccurred (__env); + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (tmp == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetStaticFieldID` should have thrown!"); + return new JniFieldInfo (tmp, isStatic: true); + } + } + } + + partial class StaticMethods { + + /// + /// Looks up a JNI static method ID using null-terminated UTF-8 name and signature spans. + /// Use with "methodName"u8 literals to avoid string marshalling overhead. + /// + public static unsafe JniMethodInfo GetStaticMethodID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr __env = JniEnvironment.EnvironmentPointer; + fixed (byte* _name_ptr = name) + fixed (byte* _signature_ptr = signature) { + var tmp = JniNativeMethods.GetStaticMethodID (__env, type.Handle, (IntPtr) _name_ptr, (IntPtr) _signature_ptr); + IntPtr thrown = JniNativeMethods.ExceptionOccurred (__env); + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (tmp == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetStaticMethodID` should have thrown!"); + return new JniMethodInfo (tmp, isStatic: true); + } + } + } + } +} +#endif // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Monitors.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Monitors.cs new file mode 100644 index 00000000000..eaa458238d3 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Monitors.cs @@ -0,0 +1,34 @@ +#nullable enable + +using System; +using System.Runtime.ExceptionServices; + +namespace Java.Interop { + + partial class JniEnvironment { + + partial class Monitors { + + public static void MonitorEnter (JniObjectReference instance) + { + int r = _MonitorEnter (instance); + if (r != 0) { + throw new InvalidOperationException (string.Format ("Could not enter monitor; JNIEnv::MonitorEnter() returned {0}.", r)); + } + } + + public static void MonitorExit (JniObjectReference instance) + { + int r = _MonitorExit (instance); + if (r != 0) { + var e = JniEnvironment.GetExceptionForLastThrowable (); + if (e != null) { + ExceptionDispatchInfo.Capture (e).Throw (); + } + throw new InvalidOperationException (string.Format ("Could not exit monitor; JNIEnv::MonitorExit() returned {0}.", r)); + } + } + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Object.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Object.cs new file mode 100644 index 00000000000..894988bf09e --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Object.cs @@ -0,0 +1,49 @@ +#nullable enable + +using System; + +namespace Java.Interop { + + partial class JniEnvironment { + + public static partial class Object { + + static JniMethodInfo Object_toString; + + static Object () + { + using (var t = new JniType ("java/lang/Object")) { + Object_toString = t.GetInstanceMethod ("toString", "()Ljava/lang/String;"); + } + } + + public static JniObjectReference NewObject (JniObjectReference type, JniMethodInfo method) + { + JniEnvironment.WithinNewObjectScope = true; + try { + return _NewObject (type, method); + } + finally { + JniEnvironment.WithinNewObjectScope = false; + } + } + + public static unsafe JniObjectReference NewObject (JniObjectReference type, JniMethodInfo method, JniArgumentValue* args) + { + JniEnvironment.WithinNewObjectScope = true; + try { + return _NewObject (type, method, args); + } + finally { + JniEnvironment.WithinNewObjectScope = false; + } + } + + public static JniObjectReference ToString (JniObjectReference value) + { + return JniEnvironment.InstanceMethods.CallObjectMethod (value, Object_toString); + } + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.References.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.References.cs new file mode 100644 index 00000000000..974b5cfe570 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.References.cs @@ -0,0 +1,84 @@ +#nullable enable + +using System; +using System.Runtime.ExceptionServices; + +namespace Java.Interop +{ + partial class JniEnvironment { + + /// + static partial class References + { + /// + public static void CreatedReference (JniObjectReference value) + { + if (!value.IsValid) + return; + switch (value.Type) { + case JniObjectReferenceType.Local: + Runtime.ObjectReferenceManager.CreatedLocalReference (CurrentInfo, value); + break; + default: + throw new ArgumentException ("Only JNI Local References are currently supported.", nameof (value)); + } + } + + public static void GetJavaVM (out IntPtr invocationPointer) + { + int r = _GetJavaVM (out invocationPointer); + + if (r != 0) { + throw new InvalidOperationException (string.Format ("Could not get JavaVM; JNIEnv::GetJavaVM() returned {0}.", r)); + } + } + + public static void EnsureLocalCapacity (int capacity) + { + int r = _EnsureLocalCapacity (capacity); + if (r == 0) + return; + + var e = JniEnvironment.GetExceptionForLastThrowable (); + if (e != null) + ExceptionDispatchInfo.Capture (e).Throw (); + + throw new InvalidOperationException (string.Format ("Could not ensure capacity; JNIEnv::EnsureLocalCapacity() returned {0}.", r)); + } + + public static void PushLocalFrame (int capacity) + { + int r = _PushLocalFrame (capacity); + if (r == 0) + return; + + var e = JniEnvironment.GetExceptionForLastThrowable (); + if (e != null) + ExceptionDispatchInfo.Capture (e).Throw (); + + throw new InvalidOperationException (string.Format ("Could not push a frame; JNIEnv::PushLocalFrame() returned {0}.", r)); + } + + public static int GetIdentityHashCode (JniObjectReference value) + { + return JniSystem.IdentityHashCode (value); + } + + public static IntPtr NewReturnToJniRef (IJavaPeerable value) + { + if (value == null || !value.PeerReference.IsValid) + return IntPtr.Zero; + return NewReturnToJniRef (value.PeerReference); + } + + public static IntPtr NewReturnToJniRef (JniObjectReference value) + { + if (!value.IsValid) + return IntPtr.Zero; + var l = value.NewLocalRef (); + return JniEnvironment.Runtime.ObjectReferenceManager.ReleaseLocalReference (JniEnvironment.CurrentInfo, ref l); + } + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Strings.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Strings.cs new file mode 100644 index 00000000000..f04fbf01af6 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Strings.cs @@ -0,0 +1,52 @@ +#nullable enable + +using System; +using System.Diagnostics; + +namespace Java.Interop +{ + partial class JniEnvironment { + + partial class Strings { + + public static unsafe JniObjectReference NewString (string? value) + { + if (value == null) + return new JniObjectReference (); + fixed (char* s = value) + return NewString (s, value.Length); + } + + public static string? ToString (IntPtr reference) + { + return ToString (new JniObjectReference (reference)); + } + + internal static unsafe string? ToString (ref JniObjectReference reference, JniObjectReferenceOptions transfer, Type targetType) + { + Debug.Assert (targetType == typeof (string), "Expected targetType==typeof(string); was: " + targetType); + return ToString (ref reference, transfer); + } + + public static unsafe string? ToString (JniObjectReference value) + { + return ToString (ref value, JniObjectReferenceOptions.Copy); + } + + public static unsafe string? ToString (ref JniObjectReference value, JniObjectReferenceOptions transfer) + { + if (!value.IsValid) + return null; + int len = JniEnvironment.Strings.GetStringLength (value); + var p = JniEnvironment.Strings.GetStringChars (value, null); + try { + return new string ((char*) p, 0, len); + } finally { + JniEnvironment.Strings.ReleaseStringChars (value, p); + JniObjectReference.Dispose (ref value, transfer); + } + } + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs new file mode 100644 index 00000000000..32e6b625495 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs @@ -0,0 +1,448 @@ +#nullable enable + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Java.Interop +{ + partial class JniEnvironment { + static partial class Types { + + readonly static KeyValuePair[] BuiltinMappings = new KeyValuePair[] { + new KeyValuePair("byte", "B"), + new KeyValuePair("boolean", "Z"), + new KeyValuePair("char", "C"), + new KeyValuePair("double", "D"), + new KeyValuePair("float", "F"), + new KeyValuePair("int", "I"), + new KeyValuePair("long", "J"), + new KeyValuePair("short", "S"), + new KeyValuePair("void", "V"), + }; + + static readonly JniMethodInfo Class_getName; + static readonly JniMethodInfo Class_forName; + static readonly JniObjectReference Class_reference; + + static Types () + { + using (var t = new JniType ("java/lang/Class")) { + Class_reference = t.PeerReference.NewGlobalRef (); + Class_getName = t.GetInstanceMethod ("getName", "()Ljava/lang/String;"); + Class_forName = t.GetStaticMethod ("forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); + } + } + + public static JniObjectReference FindClass (string classname) + { + return TryFindClass (classname, throwOnError: true); + } + + static unsafe JniObjectReference TryFindClass (string classname, bool throwOnError) + { + if (classname == null) + throw new ArgumentNullException (nameof (classname)); + if (classname.Length == 0) + throw new ArgumentException ("'classname' cannot be a zero-length string.", nameof (classname)); + + var info = JniEnvironment.CurrentInfo; +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + // Convert dot-separated names (e.g. "java.lang.Object") to JNI form ("java/lang/Object") + // before calling FindClass, because ART's CheckJNI aborts the process on dot-separated names. + var jniClassName = classname.Contains ('.') ? classname.Replace ('.', '/') : classname; + if (TryRawFindClass (info.EnvironmentPointer, jniClassName, out var c, out var thrown)) { + var r = new JniObjectReference (c, JniObjectReferenceType.Local); + JniEnvironment.LogCreateLocalRef (r); + return r; + } + RawExceptionClear (info.EnvironmentPointer); + var java = info.ToJavaName (classname); + try { + if (TryLoadClassWithFallback (info, thrown, java, throwOnError, out var result)) + return result; + } finally { + JniObjectReference.Dispose (ref java); + } + if (!throwOnError) + return default; + + throw new InvalidOperationException ($"Could not find Java class '{classname}'."); +#else + throw new NotSupportedException ( + "Rebuild with FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS or FEATURE_JNIENVIRONMENT_JI_PINVOKES set!"); +#endif // !(FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS) + } + + static unsafe bool TryLoadClassWithFallback (JniEnvironmentInfo info, IntPtr thrown, JniObjectReference classNameJavaString, bool throwOnError, out JniObjectReference result) + { + result = default; + + if (Class_forName.IsValid) { + var __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (classNameJavaString); + __args [1] = new JniArgumentValue (true); // initialize the class + __args [2] = new JniArgumentValue (info.Runtime.ClassLoader); + + var c = RawCallStaticObjectMethodA (info.EnvironmentPointer, out var forNameThrown, Class_reference.Handle, Class_forName.ID, (IntPtr) __args); + if (forNameThrown == IntPtr.Zero) { + // Class.forName() succeeded; discard the FindClass throwable. + JniEnvironment.References.RawDeleteLocalRef (info.EnvironmentPointer, thrown); + result = new JniObjectReference (c, JniObjectReferenceType.Local); + JniEnvironment.LogCreateLocalRef (result); + return true; + } + RawExceptionClear (info.EnvironmentPointer); + JniEnvironment.References.RawDeleteLocalRef (info.EnvironmentPointer, forNameThrown); + } + + if (!throwOnError) { + JniEnvironment.References.RawDeleteLocalRef (info.EnvironmentPointer, thrown); + return false; + } + + // Both FindClass and Class.forName() failed; materialize a managed exception to throw. + var findClassThrown = new JniObjectReference (thrown, JniObjectReferenceType.Local); + LogCreateLocalRef (findClassThrown); + Exception? pendingException = info.Runtime.GetExceptionForThrowable (ref findClassThrown, JniObjectReferenceOptions.CopyAndDispose); + if (pendingException != null) + throw pendingException; + + return false; + } + +#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + static unsafe JniObjectReference NewJavaNameFromUtf8 (IntPtr env, ReadOnlySpan classname) + { + var terminator = classname.IndexOf ((byte) 0); + if (terminator >= 0) + classname = classname.Slice (0, terminator); + + // Class names here are binary/JNI names, so `NewStringUTF()` lets the fallback + // avoid a managed UTF-16 allocation while still calling `Class.forName()`. + Span javaName = classname.Length + 1 <= 256 + ? stackalloc byte [classname.Length + 1] + : new byte [classname.Length + 1]; + + for (int i = 0; i < classname.Length; ++i) + javaName [i] = classname [i] == (byte) '/' ? (byte) '.' : classname [i]; + javaName [classname.Length] = 0; + + fixed (byte* pJavaName = javaName) { + var s = (*((JNIEnv**) env))->NewStringUTF (env, (IntPtr) pJavaName); + var e = JniEnvironment.GetExceptionForLastThrowable (); + if (e != null) + ExceptionDispatchInfo.Capture (e).Throw (); + + var r = new JniObjectReference (s, JniObjectReferenceType.Local); + JniEnvironment.LogCreateLocalRef (r); + return r; + } + } +#endif + + static bool TryRawFindClass (IntPtr env, string classname, out IntPtr klass, out IntPtr thrown) + { +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES + klass = NativeMethods.java_interop_jnienv_find_class (env, out thrown, classname); + if (thrown == IntPtr.Zero) { + return true; + } +#endif // !FEATURE_JNIENVIRONMENT_JI_PINVOKES +#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + var _classname_ptr = Marshal.StringToCoTaskMemUTF8 (classname); + klass = JniNativeMethods.FindClass (env, _classname_ptr); + thrown = JniNativeMethods.ExceptionOccurred (env); + Marshal.ZeroFreeCoTaskMemUTF8 (_classname_ptr); + if (thrown == IntPtr.Zero) { + return true; + } +#endif // !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + return false; + } + + static void RawExceptionClear (IntPtr env) + { +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES + // If the Java-side exception stack trace is *lost* a'la 89a5a229, + // change `false` to `true` and rebuild+re-run. +#if false + NativeMethods.java_interop_jnienv_exception_describe (env); +#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES + + NativeMethods.java_interop_jnienv_exception_clear (env); +#elif FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + // If the Java-side exception stack trace is *lost* a'la 89a5a229, + // change `false` to `true` and rebuild+re-run. +#if false + JniNativeMethods.ExceptionDescribe (env); +#endif + JniNativeMethods.ExceptionClear (env); +#endif // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + } + + static IntPtr RawCallStaticObjectMethodA (IntPtr env, out IntPtr thrown, IntPtr clazz, IntPtr jmethodID, IntPtr args) + { +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES + return NativeMethods.java_interop_jnienv_call_static_object_method_a (env, out thrown, clazz, jmethodID, args); +#elif FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + var r = JniNativeMethods.CallStaticObjectMethodA (env, clazz, jmethodID, args); + thrown = JniNativeMethods.ExceptionOccurred (env); + return r; +#else // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + return IntPtr.Zero; +#endif // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + } + + public static bool TryFindClass (string classname, out JniObjectReference instance) + { + if (classname == null) + throw new ArgumentNullException (nameof (classname)); + if (classname.Length == 0) + throw new ArgumentException ("'classname' cannot be a zero-length string.", nameof (classname)); + + instance = TryFindClass (classname, throwOnError: false); + return instance.IsValid; + } + + public static JniType? GetTypeFromInstance (JniObjectReference instance) + { + if (!instance.IsValid) + return null; + + var lref = JniEnvironment.Types.GetObjectClass (instance); + if (lref.IsValid) + return new JniType (ref lref, JniObjectReferenceOptions.CopyAndDispose); + return null; + } + + public static string? GetJniTypeNameFromInstance (JniObjectReference instance) + { + if (!instance.IsValid) + return null; + + var lref = GetObjectClass (instance); + try { + return GetJniTypeNameFromClass (lref); + } + finally { + JniObjectReference.Dispose (ref lref, JniObjectReferenceOptions.CopyAndDispose); + } + } + + public static string? GetJniTypeNameFromClass (JniObjectReference type) + { + if (!type.IsValid) + return null; + + var s = JniEnvironment.InstanceMethods.CallObjectMethod (type, Class_getName); + return JavaClassToJniType (Strings.ToString (ref s, JniObjectReferenceOptions.CopyAndDispose)!); + } + + static string JavaClassToJniType (string value) + { + for (int i = 0; i < BuiltinMappings.Length; ++i) { + if (value == BuiltinMappings [i].Key) + return BuiltinMappings [i].Value; + } + return value.Replace ('.', '/'); + } + + [RequiresDynamicCode ("Native method registration via JniNativeMethodRegistration[] requires dynamic code generation. Use the blittable RegisterNatives(JniObjectReference, ReadOnlySpan) overload with statically-compiled function pointers for Native AOT compatibility.")] + public static void RegisterNatives (JniObjectReference type, JniNativeMethodRegistration [] methods) + { + RegisterNatives (type, methods, methods == null ? 0 : methods.Length); + } + + [RequiresDynamicCode ("Native method registration via JniNativeMethodRegistration[] requires dynamic code generation. Use the blittable RegisterNatives(JniObjectReference, ReadOnlySpan) overload with statically-compiled function pointers for Native AOT compatibility.")] + public static unsafe void RegisterNatives (JniObjectReference type, JniNativeMethodRegistration [] methods, int numMethods) + { + if ((numMethods < 0) || + (numMethods > (methods?.Length ?? 0))) { + throw new ArgumentOutOfRangeException (nameof (numMethods), numMethods, + $"`numMethods` must be between 0 and `methods.Length` ({methods?.Length ?? 0})!"); + } +#if DEBUG + for (int i = 0; methods != null && i < numMethods; ++i) { + var m = methods [i]; + if (m.Marshaler != null && m.Marshaler.GetType ().GenericTypeArguments.Length != 0) { + var method = m.Marshaler.Method; + Debug.WriteLine ($"JNIEnv::RegisterNatives() given a generic delegate type `{m.Marshaler.GetType()}`. .NET Core doesn't like this."); + Debug.WriteLine ($" Java: {m.Name}{m.Signature}"); + Debug.WriteLine ($" Marshaler Type={m.Marshaler.GetType ().FullName} Method={method.DeclaringType?.FullName}.{method.Name}"); + } + } +#endif // DEBUG + + if (numMethods == 0 || methods == null) { + return; + } + + // Marshal the non-blittable JniNativeMethodRegistration[] into blittable JniNativeMethod + // values and dispatch to the blittable overload, instead of invoking the JNI + // `RegisterNatives` function pointer with a non-blittable managed-array parameter. + // The runtime marshalling stub synthesized for such a `delegate* unmanaged<>` call is + // miscompiled by crossgen2 under composite ReadyToRun + PGO: the JniNativeMethod `name` + // pointers end up referencing the managed `string` objects instead of marshalled UTF-8 + // data, which corrupts the registered method names. See https://github.com/dotnet/android/issues/11633. + const int MaxStackAllocatedNativeMethods = 32; + bool useStackAllocatedBuffers = numMethods <= MaxStackAllocatedNativeMethods; + Span natives = useStackAllocatedBuffers + ? stackalloc JniNativeMethod [numMethods] + : new JniNativeMethod [numMethods]; + Span unmanagedStrings = useStackAllocatedBuffers + ? stackalloc IntPtr [numMethods * 2] + : new IntPtr [numMethods * 2]; + unmanagedStrings.Clear (); + try { + for (int i = 0; i < numMethods; ++i) { + var m = methods [i]; + if (m.Marshaler == null) + throw new ArgumentException ($"JniNativeMethodRegistration[{i}] ({m.Name}{m.Signature}) has a null Marshaler delegate.", nameof (methods)); + IntPtr name = Marshal.StringToCoTaskMemUTF8 (m.Name); + unmanagedStrings [i * 2] = name; + IntPtr sig = Marshal.StringToCoTaskMemUTF8 (m.Signature); + unmanagedStrings [i * 2 + 1] = sig; + natives [i] = new JniNativeMethod ((byte*) name, (byte*) sig, Marshal.GetFunctionPointerForDelegate (m.Marshaler)); + } + RegisterNatives (type, natives); + // Keep the Marshaler delegates alive at least until JNI has consumed the function pointers. + GC.KeepAlive (methods); + } finally { + for (int i = 0; i < unmanagedStrings.Length; ++i) { + if (unmanagedStrings [i] != IntPtr.Zero) + Marshal.ZeroFreeCoTaskMemUTF8 (unmanagedStrings [i]); + } + } + } + + /// + /// Registers JNI native methods using blittable structs + /// with raw function pointers and UTF-8 name/signature pointers. + /// Calls the JNI RegisterNatives function directly without delegate marshaling. + /// + public static unsafe void RegisterNatives (JniObjectReference type, ReadOnlySpan methods) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", nameof (type)); + + IntPtr env = JniEnvironment.EnvironmentPointer; + int r; + fixed (JniNativeMethod* methodsPtr = methods) { +#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + var registerNatives = (delegate* unmanaged) + (void*) (*((JNIEnv**)env))->RegisterNatives; +#else + var registerNatives = (delegate* unmanaged) + JniEnvironment.CurrentInfo.Invoker.env.RegisterNatives; +#endif + r = registerNatives (env, type.Handle, methodsPtr, methods.Length); + } + + // Surface (and clear) any pending Java exception raised by JNI::RegisterNatives() + // — e.g. NoSuchMethodError — before falling back to the return-code check, matching + // the behavior of the prior JniNativeMethodRegistration[] registration path. Leaving a pending + // exception in the JNIEnv would make subsequent JNI calls fail or abort. + var thrown = JniEnvironment.GetExceptionForLastThrowable (); + if (thrown != null) + ExceptionDispatchInfo.Capture (thrown).Throw (); + + if (r != 0) { + throw new InvalidOperationException ($"Could not register native methods for class '{GetJniTypeNameFromClass (type)}'; JNIEnv::RegisterNatives() returned {r}."); + } + } + + public static void UnregisterNatives (JniObjectReference type) + { + int r = _UnregisterNatives (type); + + if (r != 0) { + throw new InvalidOperationException ( + string.Format ("Could not unregister native methods for class '{0}'; JNIEnv::UnregisterNatives() returned {1}.", GetJniTypeNameFromClass (type), r)); + } + } + +#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + /// + /// Finds a Java class using a null-terminated UTF-8 class name span. + /// Use with "java/lang/Object"u8 literals to avoid string marshalling overhead. + /// + public static unsafe JniObjectReference FindClass (ReadOnlySpan classname) + { + return TryFindClass (classname, throwOnError: true); + } + + /// + /// Tries to find a Java class using a null-terminated UTF-8 class name span. + /// Returns true if the class was found, false otherwise. + /// + public static unsafe bool TryFindClass (ReadOnlySpan classname, out JniObjectReference instance) + { + instance = TryFindClass (classname, throwOnError: false); + return instance.IsValid; + } + + static unsafe JniObjectReference TryFindClass (ReadOnlySpan classname, bool throwOnError) + { + if (classname.Length == 0) + throw new ArgumentException ("'classname' cannot be a zero-length string.", nameof (classname)); + + var info = JniEnvironment.CurrentInfo; + + var terminator = classname.IndexOf ((byte) 0); + var nameLength = terminator >= 0 ? terminator : classname.Length; + + // Convert dot-separated names (e.g. "java.lang.Object"u8) to JNI form ("java/lang/Object") + // before calling FindClass, because ART's CheckJNI aborts the process on dot-separated names. + bool hasDots = classname.Slice (0, nameLength).IndexOf ((byte) '.') >= 0; + if (!hasDots) { + return TryFindClassFromPtr (info, classname, classname, terminator, throwOnError); + } + + Span jniClassName = nameLength + 1 <= 256 + ? stackalloc byte [nameLength + 1] + : new byte [nameLength + 1]; + for (int i = 0; i < nameLength; ++i) + jniClassName [i] = classname [i] == (byte) '.' ? (byte) '/' : classname [i]; + jniClassName [nameLength] = 0; + + return TryFindClassFromPtr (info, classname, jniClassName, terminator, throwOnError); + } + + static unsafe JniObjectReference TryFindClassFromPtr (JniEnvironmentInfo info, ReadOnlySpan classname, ReadOnlySpan findClassSpan, int terminator, bool throwOnError) + { + IntPtr c; + fixed (byte* _classname_ptr = findClassSpan) { + c = JniNativeMethods.FindClass (info.EnvironmentPointer, (IntPtr) _classname_ptr); + } + var thrown = JniNativeMethods.ExceptionOccurred (info.EnvironmentPointer); + if (thrown == IntPtr.Zero) { + var r = new JniObjectReference (c, JniObjectReferenceType.Local); + JniEnvironment.LogCreateLocalRef (r); + return r; + } + + RawExceptionClear (info.EnvironmentPointer); + var javaName = NewJavaNameFromUtf8 (info.EnvironmentPointer, classname); + try { + if (TryLoadClassWithFallback (info, thrown, javaName, throwOnError, out var result)) + return result; + } finally { + JniObjectReference.Dispose (ref javaName); + } + if (!throwOnError) + return default; + + var errorClassName = terminator >= 0 + ? Encoding.UTF8.GetString (classname.Slice (0, terminator)) + : Encoding.UTF8.GetString (classname); + throw new InvalidOperationException ($"Could not find Java class '{errorClassName}'."); + } +#endif // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.cs new file mode 100644 index 00000000000..7e362241cf7 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.cs @@ -0,0 +1,293 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Java.Interop { + + public static partial class JniEnvironment { + + internal static readonly ThreadLocal Info = new ThreadLocal (() => new JniEnvironmentInfo (), trackAllValues: true); + + internal static JniEnvironmentInfo CurrentInfo { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get { + var e = Info.Value!; + if (!e.IsValid) + throw new NotSupportedException ("JNI Environment Information has been invalidated on this thread."); + return e; + } + } + + public static JniRuntime Runtime { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get {return CurrentInfo.Runtime;} + } + + public static IntPtr EnvironmentPointer { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get {return CurrentInfo.EnvironmentPointer;} + } + + public static JniVersion JniVersion { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get {return (JniVersion) Versions.GetVersion ();} + } + + public static int LocalReferenceCount { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get {return CurrentInfo.LocalReferenceCount;} + } + + public static bool WithinNewObjectScope { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get {return CurrentInfo.WithinNewObjectScope;} + internal set {CurrentInfo.WithinNewObjectScope = value;} + } + + [global::System.Diagnostics.CodeAnalysis.SuppressMessage ( + "Design", + "CA1031:Do not catch general exception types", + Justification = "Exceptions cannot cross a JNI boundary.")] + public static bool BeginMarshalMethod (IntPtr jnienv, out JniTransition transition, [NotNullWhen (true)] out JniRuntime? runtime) + { + runtime = null; + Exception? ex = null; + try { + runtime = Info.Value?.Runtime; + } + catch (Exception e) { + ex = e; + } + if (runtime == null || ex != null) { + transition = default; + runtime = null; + Console.Error.WriteLine ("JNI Environment Information is not available on this thread."); + if (ex != null) { + Console.Error.WriteLine (ex); + } + return false; + } + + try { + runtime.OnEnterMarshalMethod (); + transition = new JniTransition (jnienv); + } + catch (Exception e) { + runtime = null; + transition = default; + + Console.Error.WriteLine ($"OnEnterMarshalMethod failed: {e}"); + return false; + } + + return true; + } + + public static void EndMarshalMethod (ref JniTransition transition) + { + transition.Dispose (); + } + + internal static void SetEnvironmentPointer (IntPtr environmentPointer) + { + CurrentInfo.EnvironmentPointer = environmentPointer; + } + + internal static void SetEnvironmentPointer (IntPtr environmentPointer, JniRuntime runtime) + { + if (!Info.IsValueCreated) { + Info.Value = new JniEnvironmentInfo (environmentPointer, runtime); + return; + } + CurrentInfo.EnvironmentPointer = environmentPointer; + } + + internal static void SetEnvironmentInfo (JniEnvironmentInfo info) + { + Info.Value = info; + } + + internal static Exception? GetExceptionForLastThrowable () + { + var e = JniEnvironment.Exceptions.ExceptionOccurred (); + if (!e.IsValid) + return null; + // JniEnvironment.Errors.ExceptionDescribe (); + JniEnvironment.Exceptions.ExceptionClear (); + JniEnvironment.LogCreateLocalRef (e); + return Runtime.GetExceptionForThrowable (ref e, JniObjectReferenceOptions.CopyAndDispose); + } + + internal static Exception? GetExceptionForLastThrowable (IntPtr thrown) + { + if (thrown == IntPtr.Zero) + return null; + var e = new JniObjectReference (thrown, JniObjectReferenceType.Local); + // JniEnvironment.Errors.ExceptionDescribe (); + JniEnvironment.Exceptions.ExceptionClear (); + JniEnvironment.LogCreateLocalRef (e); + return Runtime.GetExceptionForThrowable (ref e, JniObjectReferenceOptions.CopyAndDispose); + } + + internal static Exception CreateObjectDisposedException (IJavaPeerable value) + { + return new ObjectDisposedException (value.GetType ().FullName, + $"Cannot access disposed object with JniIdentityHashCode={value.JniIdentityHashCode}."); + } + + internal static void LogCreateLocalRef (JniObjectReference value) + { + if (!value.IsValid) + return; + Runtime.ObjectReferenceManager.CreatedLocalReference (CurrentInfo, value); + } + + internal static void LogCreateLocalRef (IntPtr value) + { + if (value == IntPtr.Zero) + return; + var r = new JniObjectReference (value, JniObjectReferenceType.Local); + LogCreateLocalRef (r); + } + + partial class References { + + internal static unsafe int GetJavaVM (IntPtr jnienv, out IntPtr vm) + { +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES + return NativeMethods.java_interop_jnienv_get_java_vm (jnienv, out vm); +#elif FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + IntPtr _vm; + int r = JniNativeMethods.GetJavaVM (jnienv, &_vm); + vm = _vm; + return r; +#else + Invoker = CreateInvoker (environmentPointer); + var r = Invoker.GetJavaVM (EnvironmentPointer, out vm); + return r; +#endif + } + + internal static void RawDeleteLocalRef (IntPtr env, IntPtr localRef) + { +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES + NativeMethods.java_interop_jnienv_delete_local_ref (env, localRef); +#elif FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + JniNativeMethods.DeleteLocalRef (env, localRef); +#endif // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + } + } + + } + + sealed class JniEnvironmentInfo : IDisposable { + + const int NameBufferLength = 512; + + IntPtr environmentPointer; + char[]? nameBuffer; + bool disposed; + JniRuntime? runtime; + + public int LocalReferenceCount {get; internal set;} + public bool WithinNewObjectScope {get; set;} + public JniRuntime Runtime { + get => runtime ?? throw new NotSupportedException (); + private set => runtime = value; + } + + public IntPtr EnvironmentPointer { + get {return environmentPointer;} + set { + if (disposed) + throw new ObjectDisposedException (nameof (JniEnvironmentInfo)); + if (environmentPointer == value) + return; + + environmentPointer = value; + IntPtr vmh = IntPtr.Zero; + int r = JniEnvironment.References.GetJavaVM (EnvironmentPointer, out vmh); + if (r < 0) + throw new InvalidOperationException ("JNIEnv::GetJavaVM() returned: " + r.ToString ()); + + var vm = JniRuntime.GetRegisteredRuntime (vmh); + if (vm == null) + throw new NotSupportedException ( + string.Format ("No JavaVM registered with handle 0x{0}.", + vmh.ToString ("x"))); + Runtime = vm; + } + } + + public bool IsValid { + get {return Runtime != null && environmentPointer != IntPtr.Zero;} + } + + public JniEnvironmentInfo () + { + Runtime = JniRuntime.CurrentRuntime; + EnvironmentPointer = Runtime._AttachCurrentThread (); + } + + internal JniEnvironmentInfo (IntPtr environmentPointer, JniRuntime runtime) + { + EnvironmentPointer = environmentPointer; + Runtime = runtime; + } + + internal unsafe JniObjectReference ToJavaName (string jniTypeName) + { + int index = jniTypeName.IndexOf ("/", StringComparison.Ordinal); + + if (index == -1) + return JniEnvironment.Strings.NewString (jniTypeName); + + int length = jniTypeName.Length; + if (length > NameBufferLength) + return JniEnvironment.Strings.NewString (jniTypeName.Replace ('/', '.')); + + if (nameBuffer == null) + nameBuffer = new char [NameBufferLength]; + + fixed (char* src = jniTypeName, dst = nameBuffer) { + char* src_ptr = src; + char* dst_ptr = dst; + char* end_ptr = src + length; + while (src_ptr < end_ptr) { + *dst_ptr = (*src_ptr == '/') ? '.' : *src_ptr; + src_ptr++; + dst_ptr++; + } + return JniEnvironment.Strings.NewString (dst, length); + } + } + + public void Dispose () + { + if (disposed) + return; + runtime = null; + environmentPointer = IntPtr.Zero; + nameBuffer = null; + LocalReferenceCount = 0; + disposed = true; + } + +#if !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES + internal JniEnvironmentInvoker Invoker {get; private set;} + + static unsafe JniEnvironmentInvoker CreateInvoker (IntPtr handle) + { + IntPtr p = Marshal.ReadIntPtr (handle); + return new JniEnvironmentInvoker ((JniNativeInterfaceStruct*) p); + } +#endif // !FEATURE_JNIENVIRONMENT_JI_PINVOKES + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniFieldInfo.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniFieldInfo.cs new file mode 100644 index 00000000000..a02ec4c8c4f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniFieldInfo.cs @@ -0,0 +1,73 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + public sealed class JniFieldInfo + { + public IntPtr ID {get; private set;} + + public bool IsStatic {get; private set;} + + internal bool IsValid { + get {return ID != IntPtr.Zero;} + } + +#if DEBUG + string? name, signature; +#endif // !DEBUG + + public string Name { +#if DEBUG + get => name ?? throw new NotSupportedException (); +#else // !DEBUG + get => throw new NotSupportedException (); +#endif // !DEBUG + } + + public string Signature { +#if DEBUG + get => signature ?? throw new NotSupportedException (); +#else // !DEBUG + get => throw new NotSupportedException (); +#endif // !DEBUG + } + + public JniFieldInfo (IntPtr fieldID, bool isStatic) + { + ID = fieldID; + + IsStatic = isStatic; + } + + public JniFieldInfo (string name, string signature, IntPtr fieldID, bool isStatic) + { + ID = fieldID; + IsStatic = isStatic; + +#if DEBUG + this.name = name; + this.signature = signature; +#endif // DEBUG + } + + public override string ToString () + { +#if DEBUG + bool haveName = !string.IsNullOrEmpty (name); + bool haveSig = !string.IsNullOrEmpty (signature); +#else // DEBUG + bool haveName = false; + bool haveSig = false; +#endif // DEBUG + return string.Format ("JniFieldInfo({0}{1}{2}{3}ID=0x{4})", + haveName ? "Name=" + Name : string.Empty, + haveName ? ", " : string.Empty, + haveSig ? "Signature=" + Signature : string.Empty, + haveName || haveSig ? ", " : string.Empty, + ID.ToString ("x")); + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniLocationException.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniLocationException.cs new file mode 100644 index 00000000000..04b95d5f495 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniLocationException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Java.Interop +{ + public class JniLocationException + { + public JniLocationException () + { + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniManagedPeerStates.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniManagedPeerStates.cs new file mode 100644 index 00000000000..b4f1fba3c67 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniManagedPeerStates.cs @@ -0,0 +1,22 @@ +using System; + +namespace Java.Interop +{ + /// + [Flags] + public enum JniManagedPeerStates { + None, + /// + Activatable = (1 << 0), + /// + Replaceable = (1 << 1), + } + + partial class JavaObject { + const JniManagedPeerStates Disposed = (JniManagedPeerStates) (1 << 2); + } + + partial class JavaException { + const JniManagedPeerStates Disposed = (JniManagedPeerStates) (1 << 2); + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.SafeInvoke.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.SafeInvoke.cs new file mode 100644 index 00000000000..df70759048c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.SafeInvoke.cs @@ -0,0 +1,559 @@ +#nullable enable + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop { + + [SuppressMessage ( + "Design", + "CA1031:Do not catch general exception types", + Justification = "Exceptions cannot cross a JNI boundary.")] + public static partial class JniMarshal { + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, T15 p15, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc (IntPtr jnienv, IntPtr self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, T15 p15, delegate* managed action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.SafeInvoke.tt b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.SafeInvoke.tt new file mode 100644 index 00000000000..4510484c45d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.SafeInvoke.tt @@ -0,0 +1,63 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +#nullable enable + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop { + + [SuppressMessage ( + "Design", + "CA1031:Do not catch general exception types", + Justification = "Exceptions cannot cross a JNI boundary.")] + public static partial class JniMarshal { +<# + for (int i = 0; i <= 16; ++i) { + var types = Enumerable.Range (0, i).Select (v => "T" + v).ToArray (); + var parameters = Enumerable.Range (0, i).Select (v => "p" + v).ToArray (); + string typeParams = i == 0 ? "" : "<" + string.Join (", ", types) + ">"; + string funcTypeParams = "<" + string.Join (", ", types.Concat (new [] { "TResult" })) + ">"; + string methodParams = i == 0 ? "" : ", " + string.Join (", ", types.Zip (parameters, (t, p) => t + " " + p)); + string delegateParams = i == 0 ? "" : ", " + string.Join (", ", types); + string invokeParams = i == 0 ? "" : ", " + string.Join (", ", parameters); +#> + + [DebuggerDisableUserUnhandledExceptions] + public static unsafe void SafeInvokeAction<#= typeParams #> (IntPtr jnienv, IntPtr self<#= methodParams #>, delegate* managed, void> action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + action (jnienv, self<#= invokeParams #>); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } + + [return: MaybeNull] + [DebuggerDisableUserUnhandledExceptions] + public static unsafe TResult SafeInvokeFunc<#= funcTypeParams #> (IntPtr jnienv, IntPtr self<#= methodParams #>, delegate* managed, TResult> action) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + return action (jnienv, self<#= invokeParams #>); + } catch (Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + JniEnvironment.EndMarshalMethod (ref __envp); + } + } +<# + } +#> + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.cs new file mode 100644 index 00000000000..acce99f2cdc --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMarshal.cs @@ -0,0 +1,47 @@ +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Java.Interop { + + public static partial class JniMarshal { + + public static bool RecursiveEquals (object? objA, object? objB) + { + if (object.Equals (objA, objB)) + return true; + var ae = objA as IEnumerable; + var be = objB as IEnumerable; + if (ae != null && be != null) { + var ai = ae.GetEnumerator (); + var bi = be.GetEnumerator (); + try { + bool am, bm; + do { + am = ai.MoveNext (); + bm = bi.MoveNext (); + if (!(am && bm)) + break; + if (!RecursiveEquals (ai.Current, bi.Current)) + return false; + } while (true); + return (am == bm); + } finally { + var ad = ai as IDisposable; + var bd = bi as IDisposable; + if (ad != null) + ad.Dispose (); + if (bd != null) + bd.Dispose (); + } + } + return false; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniMemberSignature.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMemberSignature.cs new file mode 100644 index 00000000000..dd6b71d4f17 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMemberSignature.cs @@ -0,0 +1,146 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace Java.Interop +{ + public struct JniMemberSignature : IEquatable + { + public static readonly JniMemberSignature Empty; + + string? memberName; + string? memberSignature; + + public string MemberName => memberName ?? throw new InvalidOperationException (); + public string MemberSignature => memberSignature ?? throw new InvalidOperationException (); + + public JniMemberSignature (string memberName, string memberSignature) + { + if (string.IsNullOrEmpty (memberName)) { + throw new ArgumentNullException (nameof (memberName)); + } + if (string.IsNullOrEmpty (memberSignature)) { + throw new ArgumentNullException (nameof (memberSignature)); + } + this.memberName = memberName; + this.memberSignature = memberSignature; + } + + internal static IEnumerable GetParameterTypesFromMethodSignature (string jniMethodSignature) + { + if (jniMethodSignature.Length < "()V".Length || jniMethodSignature [0] != '(' ) { + throw new ArgumentException ( + $"Member signature `{jniMethodSignature}` is not a method signature. Method signatures must start with `(`.", + nameof (jniMethodSignature)); + } + int index = 1; + while (index < jniMethodSignature.Length && + jniMethodSignature [index] != ')') { + var (start, length) = ExtractType (jniMethodSignature, ref index); + var jniType = jniMethodSignature.Substring (start, length); + yield return JniTypeSignature.Parse (jniType); + } + } + + public static int GetParameterCountFromMethodSignature (string jniMethodSignature) + { + if (jniMethodSignature.Length < "()V".Length || jniMethodSignature [0] != '(' ) { + throw new ArgumentException ( + $"Member signature `{jniMethodSignature}` is not a method signature. Method signatures must start with `(`.", + nameof (jniMethodSignature)); + } + int count = 0; + int index = 1; + while (index < jniMethodSignature.Length && + jniMethodSignature [index] != ')') { + ExtractType (jniMethodSignature, ref index); + count++; + } + return count; + } + + internal static (int StartIndex, int Length) ExtractType (string signature, ref int index) + { + AssertSignatureIndex (signature, index); + var i = index++; + switch (signature [i]) { + case '[': + if ((i+1) >= signature.Length) + throw new InvalidOperationException ($"Missing array type after '[' at index {i} in: `{signature}`"); + var rest = ExtractType (signature, ref index); + return (StartIndex: i, Length: index - i); + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'V': + case 'Z': + return (StartIndex: i, Length: 1); + case 'L': + int depth = 0; + int e = index; + while (e < signature.Length) { + var c = signature [e++]; + if (depth == 0 && c == ';') + break; + } + if (e > signature.Length) + throw new InvalidOperationException ($"Missing reference type after `{signature [i]}` at index {i} in `{signature}`!"); + index = e; + return (StartIndex: i, Length: (e - i)); + default: + throw new InvalidOperationException ($"Unknown JNI Type `{signature [i]}` within: `{signature}`!"); + } + } + + internal static void AssertSignatureIndex (string signature, int index) + { + if (signature == null) + throw new ArgumentNullException (nameof (signature)); + if (signature.Length == 0) + throw new ArgumentException ("Descriptor cannot be empty string", nameof (signature)); + if (index >= signature.Length) + throw new ArgumentException ("index >= descriptor.Length", nameof (index)); + } + + public override int GetHashCode () + { + return (memberName?.GetHashCode () ?? 0) ^ + (memberSignature?.GetHashCode () ?? 0); + } + + public override bool Equals (object? obj) + { + var v = obj as JniMemberSignature?; + if (v.HasValue) + return Equals (v.Value); + return false; + } + + public bool Equals (JniMemberSignature other) + { + return memberName == other.memberName && + memberSignature == other.memberSignature; + } + + public override string ToString () + { + return $"{nameof (JniMemberSignature)} {{ " + + $"{nameof (MemberName)} = {(memberName == null ? "null" : "\"" + memberName + "\"")}" + + $", {nameof (MemberSignature)} = {(memberSignature == null ? "null" : "\"" + memberSignature + "\"")}" + + $"}}"; + } + + public static bool operator== (JniMemberSignature a, JniMemberSignature b) => a.Equals (b); + public static bool operator!= (JniMemberSignature a, JniMemberSignature b) => !a.Equals (b); + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniMemberSignatureAttribute.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMemberSignatureAttribute.cs new file mode 100644 index 00000000000..f476d298704 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMemberSignatureAttribute.cs @@ -0,0 +1,24 @@ +#nullable enable + +using System; + + +namespace Java.Interop +{ + public abstract class JniMemberSignatureAttribute : Attribute { + + internal JniMemberSignatureAttribute (string memberName, string memberSignature) + { + if (string.IsNullOrEmpty (memberName)) + throw new ArgumentNullException (nameof (memberName)); + if (string.IsNullOrEmpty (memberSignature)) + throw new ArgumentNullException (nameof (memberSignature)); + + MemberName = memberName; + MemberSignature = memberSignature; + } + + public string MemberName {get;} + public string MemberSignature {get;} + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniMethodInfo.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMethodInfo.cs new file mode 100644 index 00000000000..928a53a902c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMethodInfo.cs @@ -0,0 +1,76 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + public sealed class JniMethodInfo + { + public IntPtr ID {get; private set;} + + public bool IsStatic {get; private set;} + + internal JniType? StaticRedirect; + internal int? ParameterCount; + + internal bool IsValid { + get {return ID != IntPtr.Zero;} + } + +#if DEBUG + string? name, signature; +#endif // !DEBUG + + public string Name { +#if DEBUG + get => name ?? throw new NotSupportedException (); +#else // !DEBUG + get => throw new NotSupportedException (); +#endif // !DEBUG + } + + public string Signature { +#if DEBUG + get => signature ?? throw new NotSupportedException (); +#else // !DEBUG + get => throw new NotSupportedException (); +#endif // !DEBUG + } + + public JniMethodInfo (IntPtr methodID, bool isStatic) + { + ID = methodID; + + IsStatic = isStatic; + } + + public JniMethodInfo (string name, string signature, IntPtr methodID, bool isStatic) + { + ID = methodID; + IsStatic = isStatic; + +#if DEBUG + this.name = name; + this.signature = signature; +#endif // DEBUG + } + + public override string ToString () + { +#if DEBUG + bool haveName = !string.IsNullOrEmpty (name); + bool haveSig = !string.IsNullOrEmpty (signature); +#else // DEBUG + bool haveName = false; + bool haveSig = false; +#endif // DEBUG + return string.Format ("JniMethodInfo({0}{1}{2}{3}ID=0x{4})", + haveName ? "Name=" + Name : string.Empty, + haveName ? ", " : string.Empty, + haveSig ? "Signature=" + Signature : string.Empty, + haveName || haveSig ? ", " : string.Empty, + ID.ToString ("x")); + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniMethodSignatureAttribute.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMethodSignatureAttribute.cs new file mode 100644 index 00000000000..379004a17fd --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniMethodSignatureAttribute.cs @@ -0,0 +1,17 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; + + +namespace Java.Interop +{ + [AttributeUsage (AttributeTargets.Method, AllowMultiple = false)] + public sealed class JniMethodSignatureAttribute : JniMemberSignatureAttribute { + + public JniMethodSignatureAttribute (string memberName, string memberSignature) + : base (memberName, memberSignature) + { + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniNativeMethodRegistration.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniNativeMethodRegistration.cs new file mode 100644 index 00000000000..212b8b48a92 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniNativeMethodRegistration.cs @@ -0,0 +1,43 @@ +#nullable enable + +using System; +using System.Runtime.InteropServices; +using System.Threading; + +using Java.Interop; + +namespace Java.Interop { + + public struct JniNativeMethodRegistration { + + public string Name; + public string Signature; + public Delegate Marshaler; + + public JniNativeMethodRegistration (string name, string signature, Delegate marshaler) + { + Name = name ?? throw new ArgumentNullException (nameof (name)); + Signature = signature ?? throw new ArgumentNullException (nameof (signature)); + Marshaler = marshaler ?? throw new ArgumentNullException (nameof (marshaler)); + } + } + + /// + /// Blittable JNI native method registration for use with raw function pointers. + /// Layout matches JNI's JNINativeMethod struct exactly. + /// + [StructLayout (LayoutKind.Sequential)] + public unsafe struct JniNativeMethod + { + byte* name; + byte* signature; + IntPtr functionPointer; + + public JniNativeMethod (byte* name, byte* signature, IntPtr functionPointer) + { + this.name = name; + this.signature = signature; + this.functionPointer = functionPointer; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniNativeMethodRegistrationArguments.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniNativeMethodRegistrationArguments.cs new file mode 100644 index 00000000000..49fbb11ec51 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniNativeMethodRegistrationArguments.cs @@ -0,0 +1,37 @@ +#nullable enable + +using System; +using System.Collections.Generic; + +namespace Java.Interop +{ + public struct JniNativeMethodRegistrationArguments + { + const string invalidStateMessage = nameof(JniNativeMethodRegistrationArguments) + " state is invalid. Please use constructor with parameters."; + + public ICollection Registrations { + get { return _registrations ?? throw new InvalidOperationException (invalidStateMessage); } + } + public string? Methods { get; } + ICollection _registrations; + + public JniNativeMethodRegistrationArguments (ICollection registrations, string? methods) + { + _registrations = registrations ?? throw new ArgumentNullException (nameof (registrations)); + Methods = methods; + } + + public void AddRegistrations (IEnumerable registrations) + { + if (_registrations == null) + throw new InvalidOperationException (invalidStateMessage); + + if (registrations is List list) { + list.AddRange (registrations); + } else { + foreach (var registration in registrations) + _registrations.Add (registration); + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReference.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReference.cs new file mode 100644 index 00000000000..3f9739eb936 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReference.cs @@ -0,0 +1,154 @@ +#nullable enable + +using System; +using System.Runtime.CompilerServices; + +namespace Java.Interop +{ + [Flags] + enum JniObjectReferenceFlags : uint { + None, + Alloc = 1 << 16, + } + + public partial struct JniObjectReference : IEquatable + { + const uint FlagsMask = 0xFFFF0000; + const uint TypeMask = 0x0000FFFF; + + public IntPtr Handle { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get; + private set; + } + + uint referenceInfo; + + public JniObjectReferenceType Type { + get {return (JniObjectReferenceType) (referenceInfo & TypeMask);} + } + + internal JniObjectReferenceFlags Flags { + get {return (JniObjectReferenceFlags) (referenceInfo & FlagsMask);} + set {referenceInfo |= (((uint) value) & FlagsMask);} + } + + public bool IsValid { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get { + return Handle != IntPtr.Zero; + } + } + + public JniObjectReference (IntPtr handle, JniObjectReferenceType type = JniObjectReferenceType.Invalid) + { + referenceInfo = (uint) type; + Handle = handle; + } + + public override int GetHashCode () + { + return Handle.GetHashCode (); + } + + public override bool Equals (object? obj) + { + var o = obj as JniObjectReference?; + if (o.HasValue) + return Equals (o.Value); + return false; + } + + public bool Equals (JniObjectReference other) + { + return Handle == other.Handle; + } + + public static bool operator == (JniObjectReference lhs, JniObjectReference rhs) + { + return lhs.Handle == rhs.Handle; + } + + public static bool operator != (JniObjectReference lhs, JniObjectReference rhs) + { + return lhs.Handle != rhs.Handle; + } + + public JniObjectReference NewGlobalRef () + { + return JniEnvironment.Runtime.ObjectReferenceManager.CreateGlobalReference (this); + } + + public JniObjectReference NewLocalRef () + { + return JniEnvironment.Runtime.ObjectReferenceManager.CreateLocalReference (JniEnvironment.CurrentInfo, this); + } + + public JniObjectReference NewWeakGlobalRef () + { + return JniEnvironment.Runtime.ObjectReferenceManager.CreateWeakGlobalReference (this); + } + + internal void Invalidate () + { + Handle = IntPtr.Zero; + + referenceInfo = 0; + } + + public override string ToString () + { + return "0x" + Handle.ToString ("x") + "/" + ToString (Type); + } + + + static string ToString (JniObjectReferenceType type) + { + switch (type) { + case JniObjectReferenceType.Global: return "G"; + case JniObjectReferenceType.Invalid: return "I"; + case JniObjectReferenceType.Local: return "L"; + case JniObjectReferenceType.WeakGlobal: return "W"; + } + return type.ToString (); + } + + public static void Dispose (ref JniObjectReference reference) + { + if (!reference.IsValid) + return; + + switch (reference.Type) { + case JniObjectReferenceType.Global: + JniEnvironment.Runtime.ObjectReferenceManager.DeleteGlobalReference (ref reference); + break; + case JniObjectReferenceType.Local: + JniEnvironment.Runtime.ObjectReferenceManager.DeleteLocalReference (JniEnvironment.CurrentInfo, ref reference); + break; + case JniObjectReferenceType.WeakGlobal: + JniEnvironment.Runtime.ObjectReferenceManager.DeleteWeakGlobalReference (ref reference); + break; + case JniObjectReferenceType.Invalid: + break; + default: + throw new NotImplementedException ("Do not know how to dispose: " + reference.Type.ToString () + "."); + } + + reference.Invalidate (); + } + + public static void Dispose (ref JniObjectReference reference, JniObjectReferenceOptions options) + { + if (options == JniObjectReferenceOptions.None) + return; + + if (!reference.IsValid) + return; + + if ((options & DisposeSource) == 0) + return; + + Dispose (ref reference); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceControlBlock.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceControlBlock.cs new file mode 100644 index 00000000000..3f2d6f8ec93 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceControlBlock.cs @@ -0,0 +1,30 @@ +using System; +using System.Runtime.InteropServices; + +namespace Java.Interop; + +internal struct JniObjectReferenceControlBlock { + public IntPtr handle; + public int handle_type; + public IntPtr weak_handle; + public int refs_added; + + public static readonly int Size = Marshal.SizeOf(); + + public static unsafe JniObjectReferenceControlBlock* Alloc (JniObjectReference reference) + { + var value = (JniObjectReferenceControlBlock*) NativeMemory.AllocZeroed (1, (uint) Size); + value->handle = reference.Handle; + value->handle_type = (int) reference.Type; + return value; + } + + public static unsafe void Free (ref JniObjectReferenceControlBlock* value) + { + if (value == null) { + return; + } + NativeMemory.Free (value); + value = null; + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceOptions.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceOptions.cs new file mode 100644 index 00000000000..3fcb3f82e76 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceOptions.cs @@ -0,0 +1,27 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + [Flags] + public enum JniObjectReferenceOptions + { + None = 0, + Copy = 1 << 0, // DoNotTransfer + // DisposeSource = 1 << 1, // See JniObjectReference.DisposeSource + CopyAndDispose = (1 << 1) + Copy, // Transfer + // DoNotRegisterTarget = 1 << 2, // See JniRuntime.JniValueManager.DoNotRegisterTarget + CopyAndDoNotRegister = (1 << 2) + Copy, + } + + partial struct JniObjectReference { + const JniObjectReferenceOptions DisposeSource = (JniObjectReferenceOptions) (1 << 1); + } + + partial class JniRuntime { + partial class ReflectionJniValueManager { + const JniObjectReferenceOptions DoNotRegisterTarget = (JniObjectReferenceOptions) (1 << 2); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceType.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceType.cs new file mode 100644 index 00000000000..3f25c58d25f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniObjectReferenceType.cs @@ -0,0 +1,14 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + public enum JniObjectReferenceType { + Invalid = 0, + Local = 1, + Global = 2, + WeakGlobal = 3, + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs new file mode 100644 index 00000000000..ea9d0cb5155 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs @@ -0,0 +1,310 @@ +#nullable enable + +using System; + +namespace Java.Interop { + + partial class JniPeerMembers { + partial class JniInstanceFields { + + public bool GetBooleanValue ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetBooleanField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, bool value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetBooleanField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public sbyte GetSByteValue ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetByteField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, sbyte value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetByteField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public char GetCharValue ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetCharField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, char value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetCharField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public short GetInt16Value ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetShortField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, short value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetShortField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public int GetInt32Value ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetIntField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, int value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetIntField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public long GetInt64Value ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetLongField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, long value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetLongField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public float GetSingleValue ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetFloatField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, float value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetFloatField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public double GetDoubleValue ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetDoubleField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, double value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetDoubleField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + + public JniObjectReference GetObjectValue ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.GetObjectField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, JniObjectReference value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.SetObjectField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + } + + partial class JniStaticFields { + + public bool GetBooleanValue (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticBooleanField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, bool value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticBooleanField (Members.JniPeerType.PeerReference, f, value); + } + + public sbyte GetSByteValue (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticByteField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, sbyte value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticByteField (Members.JniPeerType.PeerReference, f, value); + } + + public char GetCharValue (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticCharField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, char value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticCharField (Members.JniPeerType.PeerReference, f, value); + } + + public short GetInt16Value (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticShortField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, short value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticShortField (Members.JniPeerType.PeerReference, f, value); + } + + public int GetInt32Value (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticIntField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, int value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticIntField (Members.JniPeerType.PeerReference, f, value); + } + + public long GetInt64Value (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticLongField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, long value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticLongField (Members.JniPeerType.PeerReference, f, value); + } + + public float GetSingleValue (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticFloatField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, float value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticFloatField (Members.JniPeerType.PeerReference, f, value); + } + + public double GetDoubleValue (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticDoubleField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, double value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticDoubleField (Members.JniPeerType.PeerReference, f, value); + } + + public JniObjectReference GetObjectValue (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStaticObjectField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, JniObjectReference value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStaticObjectField (Members.JniPeerType.PeerReference, f, value); + } + }} +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt new file mode 100644 index 00000000000..f569b372b01 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt @@ -0,0 +1,77 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<# + var jniReturnTypes = new[]{ + new { JniCallType = "Boolean", ManagedType = "Boolean", ReturnType = "bool", ParameterType = "bool" }, + new { JniCallType = "Byte", ManagedType = "SByte", ReturnType = "sbyte", ParameterType = "sbyte" }, + new { JniCallType = "Char", ManagedType = "Char", ReturnType = "char", ParameterType = "char" }, + new { JniCallType = "Short", ManagedType = "Int16", ReturnType = "short", ParameterType = "short" }, + new { JniCallType = "Int", ManagedType = "Int32", ReturnType = "int", ParameterType = "int" }, + new { JniCallType = "Long", ManagedType = "Int64", ReturnType = "long", ParameterType = "long" }, + new { JniCallType = "Float", ManagedType = "Single", ReturnType = "float", ParameterType = "float" }, + new { JniCallType = "Double", ManagedType = "Double", ReturnType = "double", ParameterType = "double" }, + new { JniCallType = "Object", ManagedType = "Object", ReturnType = "JniObjectReference", ParameterType = "JniObjectReference" }, + }; + +#> +#nullable enable + +using System; + +namespace Java.Interop { + + partial class JniPeerMembers { + partial class JniInstanceFields { +<# + foreach (var info in jniReturnTypes) { +#> + + public <#= info.ReturnType #> Get<#= info.ManagedType #>Value ( + string encodedMember, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + var r = JniEnvironment.InstanceFields.Get<#= info.JniCallType #>Field (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (string encodedMember, IJavaPeerable self, <#= info.ParameterType #> value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (encodedMember); + JniEnvironment.InstanceFields.Set<#= info.JniCallType #>Field (self.PeerReference, f, value); + GC.KeepAlive (self); + } +<# + } +#> + } + + partial class JniStaticFields { +<# + foreach (var info in jniReturnTypes) { +#> + + public <#= info.ReturnType #> Get<#= info.ManagedType #>Value (string encodedMember) + { + var f = GetFieldInfo (encodedMember); + return JniEnvironment.StaticFields.GetStatic<#= info.JniCallType #>Field (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (string encodedMember, <#= info.ParameterType #> value) + { + var f = GetFieldInfo (encodedMember); + JniEnvironment.StaticFields.SetStatic<#= info.JniCallType #>Field (Members.JniPeerType.PeerReference, f, value); + } +<# + } +#> + }} +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs new file mode 100644 index 00000000000..e0a5ae40d87 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs @@ -0,0 +1,39 @@ +#nullable enable + +using System; +using System.Collections.Generic; + +namespace Java.Interop +{ + partial class JniPeerMembers { + public sealed partial class JniInstanceFields + { + internal JniInstanceFields (JniPeerMembers members) + { + Members = members; + } + + readonly JniPeerMembers Members; + + Dictionary InstanceFields = new Dictionary(StringComparer.Ordinal); + + internal void Dispose () + { + InstanceFields.Clear (); + } + + public JniFieldInfo GetFieldInfo (string encodedMember) + { + lock (InstanceFields) { + if (!InstanceFields.TryGetValue (encodedMember, out var f)) { + string field, signature; + JniPeerMembers.GetNameAndSignature (encodedMember, out field, out signature); + f = Members.JniPeerType.GetInstanceField (field, signature); + InstanceFields.Add (encodedMember, f); + } + return f; + } + } + }} +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs new file mode 100644 index 00000000000..6d8d14602ca --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs @@ -0,0 +1,202 @@ +#nullable enable + +using System; +using System.Collections.Generic; + +namespace Java.Interop +{ + partial class JniPeerMembers { + public sealed partial class JniInstanceMethods + { + internal JniInstanceMethods (JniPeerMembers members) + { + DeclaringType = members.ManagedPeerType; + this.members = members; + } + + JniInstanceMethods (Type declaringType) + { + var jvm = JniEnvironment.Runtime; + var info = jvm.TypeManager.GetTypeSignature (declaringType); + if (info.SimpleReference == null) + throw new NotSupportedException ( + string.Format ("Cannot create instance of type '{0}': no Java peer type found.", + declaringType.FullName)); + + DeclaringType = declaringType; + jniPeerType = new JniType (info.Name); + jniPeerType.RegisterWithRuntime (); + } + + JniPeerMembers? members; + JniType? jniPeerType; + + internal JniPeerMembers Members => members ?? throw new InvalidOperationException (); + + internal JniType JniPeerType { + get {return jniPeerType ?? Members?.JniPeerType ?? throw new InvalidOperationException ();} + } + + readonly Type DeclaringType; + + Dictionary InstanceMethods = new Dictionary(StringComparer.Ordinal); + Dictionary SubclassConstructors = new Dictionary (); + + internal void Dispose () + { + InstanceMethods.Clear (); + foreach (var p in SubclassConstructors.Values) + p.Dispose (); + SubclassConstructors.Clear (); + + if (jniPeerType != null) + jniPeerType.Dispose (); + jniPeerType = null; + } + + public JniMethodInfo GetConstructor (string signature) + { + if (signature == null) + throw new ArgumentNullException (nameof (signature)); + lock (InstanceMethods) { + if (!InstanceMethods.TryGetValue (signature, out var m)) { + m = JniPeerType.GetConstructor (signature); + InstanceMethods.Add (signature, m); + } + return m; + } + } + + internal JniInstanceMethods GetConstructorsForType (Type declaringType) + { + if (declaringType == DeclaringType) + return this; + + JniInstanceMethods? methods; + + lock (SubclassConstructors) { + if (SubclassConstructors.TryGetValue (declaringType, out methods)) + return methods; + } + // Init outside of `lock` in case we have recursive access: + // System.ArgumentException: An item with the same key has already been added. Key: Java.Interop.JavaProxyThrowable + // at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) + // at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) + // at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 80 + // at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 80 + // at Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(String constructorSignature, Type declaringType, JniArgumentValue* parameters) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 146 + // at Java.Interop.JavaException..ctor(String message) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JavaException.cs:line 52 + // at Java.Interop.JavaProxyThrowable..ctor(Exception exception) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JavaProxyThrowable.cs:line 15 + // at Java.Interop.JniEnvironment.Exceptions.Throw(Exception e) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Errors.cs:line 39 + // at Java.Interop.JniRuntime.RaisePendingException(Exception pendingException) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniRuntime.cs:line 444 + // at Java.Interop.JniTransition.Dispose() in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniTransition.cs:line 39 + // at Java.Interop.ManagedPeer.RegisterNativeMembers(IntPtr jnienv, IntPtr klass, IntPtr n_nativeClass, IntPtr n_methods) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/ManagedPeer.cs:line 195 + // at Java.Interop.NativeMethods.java_interop_jnienv_find_class(IntPtr jnienv, IntPtr& thrown, String classname) + // at Java.Interop.NativeMethods.java_interop_jnienv_find_class(IntPtr jnienv, IntPtr& thrown, String classname) + // at Java.Interop.JniEnvironment.Types.TryRawFindClass(IntPtr env, String classname, IntPtr& klass, IntPtr& thrown) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs:line 135 + // at Java.Interop.JniEnvironment.Types.TryFindClass(String classname, Boolean throwOnError) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs:line 49 + // at Java.Interop.JniEnvironment.Types.FindClass(String classname) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs:line 37 + // at Java.Interop.JniType..ctor(String classname) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniType.cs:line 51 + // at Java.Interop.JniPeerMembers.JniInstanceMethods..ctor(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 27 + // at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type declaringType) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 77 + // at Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(String constructorSignature, Type declaringType, JniArgumentValue* parameters) in /Users/jon/Developer/src/xamarin/java.interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 146 + methods = new JniInstanceMethods (declaringType); + lock (SubclassConstructors) { + if (SubclassConstructors.TryGetValue (declaringType, out var m)) + return m; + SubclassConstructors.Add (declaringType, methods); + return methods; + } + } + + public JniMethodInfo GetMethodInfo (string encodedMember) + { + lock (InstanceMethods) { + if (InstanceMethods.TryGetValue (encodedMember, out var m)) { + return m; + } + } + string method, signature; + JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature); + var info = GetMethodInfo (method, signature); + lock (InstanceMethods) { + if (InstanceMethods.TryGetValue (encodedMember, out var m)) { + return m; + } + InstanceMethods.Add (encodedMember, info); + } + return info; + } + + JniMethodInfo GetMethodInfo (string method, string signature) + { + var m = (JniMethodInfo?) null; + var newMethod = JniEnvironment.Runtime.TypeManager.GetReplacementMethodInfo (Members.JniPeerTypeName, method, signature); + if (newMethod.HasValue) { + var typeName = newMethod.Value.TargetJniType ?? Members.JniPeerTypeName; + var methodName = newMethod.Value.TargetJniMethodName ?? method; + var methodSig = newMethod.Value.TargetJniMethodSignature ?? signature; + + using var t = new JniType (typeName); + if (newMethod.Value.TargetJniMethodInstanceToStatic && + t.TryGetStaticMethod (methodName, methodSig, out m)) { + m.ParameterCount = newMethod.Value.TargetJniMethodParameterCount; + m.StaticRedirect = new JniType (typeName); + return m; + } + if (t.TryGetInstanceMethod (methodName, methodSig, out m)) { + return m; + } + Console.Error.WriteLine ($"warning: For declared method `{Members.JniPeerTypeName}.{method}.{signature}`, could not find requested method `{typeName}.{methodName}.{methodSig}`!"); + } + return JniPeerType.GetInstanceMethod (method, signature); + } + + public unsafe JniObjectReference StartCreateInstance (string constructorSignature, Type declaringType, JniArgumentValue* parameters) + { + #pragma warning disable CS1717 + parameters = parameters; // Silence CA1801 + #pragma warning restore CS1717 + + if (constructorSignature == null) + throw new ArgumentNullException (nameof (constructorSignature)); + if (declaringType == null) + throw new ArgumentNullException (nameof (declaringType)); + + var r = GetConstructorsForType (declaringType) + .JniPeerType + .AllocObject (); + r.Flags = JniObjectReferenceFlags.Alloc; + return r; + } + + internal JniObjectReference AllocObject (Type declaringType) + { + var r = GetConstructorsForType (declaringType) + .JniPeerType + .AllocObject (); + r.Flags = JniObjectReferenceFlags.Alloc; + return r; + } + + internal unsafe JniObjectReference NewObject (string constructorSignature, Type declaringType, JniArgumentValue* parameters) + { + var methods = GetConstructorsForType (declaringType); + var ctor = methods.GetConstructor (constructorSignature); + return methods.JniPeerType.NewObject (ctor, parameters); + } + + public unsafe void FinishCreateInstance (string constructorSignature, IJavaPeerable self, JniArgumentValue* parameters) + { + if (constructorSignature == null) + throw new ArgumentNullException (nameof (constructorSignature)); + if (self == null) + throw new ArgumentNullException (nameof (self)); + + var methods = GetConstructorsForType (self.GetType ()); + var ctor = methods.GetConstructor (constructorSignature); + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, methods.JniPeerType.PeerReference, ctor, parameters); + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs new file mode 100644 index 00000000000..e5d2a122e54 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs @@ -0,0 +1,863 @@ +#nullable enable + +using System; +using System.Diagnostics; + +namespace Java.Interop { + + partial class JniPeerMembers { + + partial class JniInstanceMethods { + +#pragma warning disable CA1801 + static unsafe bool TryInvokeVoidStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters) + { + + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + JniEnvironment.StaticMethods.CallStaticVoidMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe void InvokeAbstractVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeVoidStaticRedirect (m, self, parameters)) { + return; + } + + JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, parameters); + return; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe void InvokeVirtualVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeVoidStaticRedirect (m, self, parameters)) { + return; + } + JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, parameters); + return; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeVoidStaticRedirect (n, self, parameters)) { + return; + } + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe void InvokeNonvirtualVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeVoidStaticRedirect (m, self, parameters)) { + return; + } + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeBooleanStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out bool r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticBooleanMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe bool InvokeAbstractBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeBooleanStaticRedirect (m, self, parameters, out bool r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe bool InvokeVirtualBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeBooleanStaticRedirect (m, self, parameters, out bool r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeBooleanStaticRedirect (n, self, parameters, out bool r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe bool InvokeNonvirtualBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeBooleanStaticRedirect (m, self, parameters, out bool r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeSByteStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out sbyte r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticByteMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe sbyte InvokeAbstractSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeSByteStaticRedirect (m, self, parameters, out sbyte r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe sbyte InvokeVirtualSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeSByteStaticRedirect (m, self, parameters, out sbyte r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeSByteStaticRedirect (n, self, parameters, out sbyte r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe sbyte InvokeNonvirtualSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeSByteStaticRedirect (m, self, parameters, out sbyte r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeCharStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out char r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticCharMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe char InvokeAbstractCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeCharStaticRedirect (m, self, parameters, out char r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe char InvokeVirtualCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeCharStaticRedirect (m, self, parameters, out char r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeCharStaticRedirect (n, self, parameters, out char r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe char InvokeNonvirtualCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeCharStaticRedirect (m, self, parameters, out char r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeInt16StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out short r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticShortMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe short InvokeAbstractInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeInt16StaticRedirect (m, self, parameters, out short r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe short InvokeVirtualInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeInt16StaticRedirect (m, self, parameters, out short r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeInt16StaticRedirect (n, self, parameters, out short r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe short InvokeNonvirtualInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeInt16StaticRedirect (m, self, parameters, out short r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeInt32StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out int r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticIntMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe int InvokeAbstractInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeInt32StaticRedirect (m, self, parameters, out int r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe int InvokeVirtualInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeInt32StaticRedirect (m, self, parameters, out int r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeInt32StaticRedirect (n, self, parameters, out int r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe int InvokeNonvirtualInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeInt32StaticRedirect (m, self, parameters, out int r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeInt64StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out long r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticLongMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe long InvokeAbstractInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeInt64StaticRedirect (m, self, parameters, out long r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe long InvokeVirtualInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeInt64StaticRedirect (m, self, parameters, out long r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeInt64StaticRedirect (n, self, parameters, out long r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe long InvokeNonvirtualInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeInt64StaticRedirect (m, self, parameters, out long r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeSingleStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out float r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticFloatMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe float InvokeAbstractSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeSingleStaticRedirect (m, self, parameters, out float r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe float InvokeVirtualSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeSingleStaticRedirect (m, self, parameters, out float r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeSingleStaticRedirect (n, self, parameters, out float r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe float InvokeNonvirtualSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeSingleStaticRedirect (m, self, parameters, out float r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeDoubleStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out double r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticDoubleMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe double InvokeAbstractDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeDoubleStaticRedirect (m, self, parameters, out double r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe double InvokeVirtualDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeDoubleStaticRedirect (m, self, parameters, out double r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeDoubleStaticRedirect (n, self, parameters, out double r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe double InvokeNonvirtualDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeDoubleStaticRedirect (m, self, parameters, out double r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + +#pragma warning disable CA1801 + static unsafe bool TryInvokeObjectStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out JniObjectReference r) + { + r = default; + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + r = JniEnvironment.StaticMethods.CallStaticObjectMethod (method.StaticRedirect.PeerReference, method, p); + return true; + } +#pragma warning restore CA1801 + + public unsafe JniObjectReference InvokeAbstractObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvokeObjectStaticRedirect (m, self, parameters, out JniObjectReference r)) { + return r; + } + + r = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe JniObjectReference InvokeVirtualObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvokeObjectStaticRedirect (m, self, parameters, out JniObjectReference r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, parameters); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvokeObjectStaticRedirect (n, self, parameters, out JniObjectReference r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + return r; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe JniObjectReference InvokeNonvirtualObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvokeObjectStaticRedirect (m, self, parameters, out JniObjectReference r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters); + return r; + } + finally { + GC.KeepAlive (self); + } + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt new file mode 100644 index 00000000000..a326b6b1fa9 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt @@ -0,0 +1,133 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<# + var jniReturnTypes = new[]{ + new { JniCallType = "Void", ManagedType = "Void", ReturnType = "void" }, + new { JniCallType = "Boolean", ManagedType = "Boolean", ReturnType = "bool" }, + new { JniCallType = "Byte", ManagedType = "SByte", ReturnType = "sbyte" }, + new { JniCallType = "Char", ManagedType = "Char", ReturnType = "char" }, + new { JniCallType = "Short", ManagedType = "Int16", ReturnType = "short" }, + new { JniCallType = "Int", ManagedType = "Int32", ReturnType = "int" }, + new { JniCallType = "Long", ManagedType = "Int64", ReturnType = "long" }, + new { JniCallType = "Float", ManagedType = "Single", ReturnType = "float" }, + new { JniCallType = "Double", ManagedType = "Double", ReturnType = "double" }, + new { JniCallType = "Object", ManagedType = "Object", ReturnType = "JniObjectReference" }, + }; + +#> +#nullable enable + +using System; +using System.Diagnostics; + +namespace Java.Interop { + + partial class JniPeerMembers { + + partial class JniInstanceMethods { +<# + foreach (var returnType in jniReturnTypes) { + string byRefParamDecl = returnType.ReturnType == "void" ? "" : ", out " + returnType.ReturnType + " r"; + // string byRefParam = returnType.ReturnType == "void" ? "" : " r"; + string setByRefToDefault = returnType.ReturnType == "void" ? "" : "r = default;"; + string setByRefParam = returnType.ReturnType == "void" ? "" : "r = "; + string returnByRefParam = returnType.ReturnType == "void" ? "return" : "return r"; +#> + +#pragma warning disable CA1801 + static unsafe bool TryInvoke<#= returnType.ManagedType #>StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters<#= byRefParamDecl #>) + { + <#= setByRefToDefault #> +#if !NET + return false; +#else // NET + if (method.StaticRedirect == null || !method.ParameterCount.HasValue) { + return false; + } + + int c = method.ParameterCount.Value; + Debug.Assert (c > 0); + var p = stackalloc JniArgumentValue [c]; + p [0] = new JniArgumentValue (self); + for (int i = 0; i < c-1; ++i) { + p [i+1] = parameters [i]; + } + + <#= setByRefParam #>JniEnvironment.StaticMethods.CallStatic<#= returnType.JniCallType #>Method (method.StaticRedirect.PeerReference, method, p); + return true; +#endif // NET + } +#pragma warning restore CA1801 + + public unsafe <#= returnType.ReturnType #> InvokeAbstract<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (encodedMember); + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, parameters<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + + <#= setByRefParam #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, parameters); + <#= returnByRefParam #>; + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe <#= returnType.ReturnType #> InvokeVirtual<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (encodedMember); + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, parameters<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + <#= setByRefParam #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, parameters); + <#= returnByRefParam #>; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (encodedMember); + do { + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (n, self, parameters<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + <#= setByRefParam #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, j.JniPeerType.PeerReference, n, parameters); + <#= returnByRefParam #>; + } while (false); + } + finally { + GC.KeepAlive (self); + } + } + + public unsafe <#= returnType.ReturnType #> InvokeNonvirtual<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (encodedMember); + try { + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, parameters<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + <#= setByRefParam #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, JniPeerType.PeerReference, m, parameters); + <#= returnByRefParam #>; + } + finally { + GC.KeepAlive (self); + } + } +<# + } +#> + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs new file mode 100644 index 00000000000..7fe131b6206 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs @@ -0,0 +1,39 @@ +#nullable enable + +using System; +using System.Collections.Generic; + +namespace Java.Interop +{ + partial class JniPeerMembers { + public sealed partial class JniStaticFields + { + internal JniStaticFields (JniPeerMembers members) + { + Members = members; + } + + readonly JniPeerMembers Members; + + Dictionary StaticFields = new Dictionary(StringComparer.Ordinal); + + public JniFieldInfo GetFieldInfo (string encodedMember) + { + lock (StaticFields) { + if (!StaticFields.TryGetValue (encodedMember, out var f)) { + string field, signature; + JniPeerMembers.GetNameAndSignature (encodedMember, out field, out signature); + f = Members.JniPeerType.GetStaticField (field, signature); + StaticFields.Add (encodedMember, f); + } + return f; + } + } + + internal void Dispose () + { + StaticFields.Clear (); + } + }} +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs new file mode 100644 index 00000000000..00b391bc112 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs @@ -0,0 +1,163 @@ +#nullable enable + +using System; +using System.Collections.Generic; + +namespace Java.Interop +{ + partial class JniPeerMembers { + public sealed partial class JniStaticMethods { + + internal JniStaticMethods (JniPeerMembers members) + { + Members = members; + } + + internal readonly JniPeerMembers Members; + + Dictionary StaticMethods = new Dictionary(StringComparer.Ordinal); + + internal void Dispose () + { + StaticMethods.Clear (); + } + + public JniMethodInfo GetMethodInfo (string encodedMember) + { + lock (StaticMethods) { + if (StaticMethods.TryGetValue (encodedMember, out var m)) { + return m; + } + } + string method, signature; + JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature); + var info = GetMethodInfo (method, signature); + lock (StaticMethods) { + if (StaticMethods.TryGetValue (encodedMember, out var m)) { + return m; + } + StaticMethods.Add (encodedMember, info); + } + return info; + } + + JniMethodInfo GetMethodInfo (string method, string signature) + { + var m = (JniMethodInfo?) null; + var newMethod = JniEnvironment.Runtime.TypeManager.GetReplacementMethodInfo (Members.JniPeerTypeName, method, signature); + if (newMethod.HasValue) { + using var t = new JniType (newMethod.Value.TargetJniType ?? Members.JniPeerTypeName); + if (t.TryGetStaticMethod ( + newMethod.Value.TargetJniMethodName ?? method, + newMethod.Value.TargetJniMethodSignature ?? signature, + out m)) { + return m; + } + } + if (Members.JniPeerType.TryGetStaticMethod (method, signature, out m)) { + return m; + } + m = FindInFallbackTypes (method, signature); + if (m != null) { + return m; + } + return Members.JniPeerType.GetStaticMethod (method, signature); + } + +#pragma warning disable CA1801 + JniType GetMethodDeclaringType (JniMethodInfo method) + { + if (method.StaticRedirect != null) { + return method.StaticRedirect; + } + return Members.JniPeerType; + } +#pragma warning restore CA1801 + + JniMethodInfo? FindInFallbackTypes (string method, string signature) + { + var fallbackTypes = JniEnvironment.Runtime.TypeManager.GetStaticMethodFallbackTypes (Members.JniPeerTypeName); + if (fallbackTypes == null) { + return null; + } + foreach (var ft in fallbackTypes) { + JniType? t = null; + try { + if (!JniType.TryParse (ft, out t)) { + continue; + } + if (t.TryGetStaticMethod (method, signature, out var m)) { + m.StaticRedirect = t; + t = null; + return m; + } + } + finally { + t?.Dispose (); + } + } + return null; + } + + public unsafe void InvokeVoidMethod (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + JniEnvironment.StaticMethods.CallStaticVoidMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe bool InvokeBooleanMethod (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticBooleanMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe sbyte InvokeSByteMethod (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticByteMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe char InvokeCharMethod (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticCharMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe short InvokeInt16Method (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticShortMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe int InvokeInt32Method (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticIntMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe long InvokeInt64Method (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticLongMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe float InvokeSingleMethod (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticFloatMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe double InvokeDoubleMethod (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticDoubleMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + + public unsafe JniObjectReference InvokeObjectMethod (string encodedMember, JniArgumentValue* parameters) + { + var m = GetMethodInfo (encodedMember); + return JniEnvironment.StaticMethods.CallStaticObjectMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); + } + }} +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs new file mode 100644 index 00000000000..1b64266f9c8 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs @@ -0,0 +1,178 @@ +#nullable enable + +using System; +using System.Diagnostics; +using System.Collections.Generic; +using System.Reflection; + +namespace Java.Interop { + + public partial class JniPeerMembers { + + private bool isInterface; + + public JniPeerMembers (string jniPeerTypeName, Type managedPeerType, bool isInterface) + : this (jniPeerTypeName = GetReplacementType (jniPeerTypeName), managedPeerType, checkManagedPeerType: true, isInterface: isInterface) + { + } + + public JniPeerMembers (string jniPeerTypeName, Type managedPeerType) + : this (jniPeerTypeName = GetReplacementType (jniPeerTypeName), managedPeerType, checkManagedPeerType: true, isInterface: false) + { + } + + static string GetReplacementType (string jniPeerTypeName) + { + var replacement = JniEnvironment.Runtime.TypeManager.GetReplacementType (jniPeerTypeName); + if (replacement != null) + return replacement; + return jniPeerTypeName; + } + + JniPeerMembers (string jniPeerTypeName, Type managedPeerType, bool checkManagedPeerType, bool isInterface = false) + { + if (jniPeerTypeName == null) + throw new ArgumentNullException (nameof (jniPeerTypeName)); + + if (checkManagedPeerType) { + if (managedPeerType == null) + throw new ArgumentNullException (nameof (managedPeerType)); + if (!typeof (IJavaPeerable).IsAssignableFrom (managedPeerType)) + throw new ArgumentException ("'managedPeerType' must implement the IJavaPeerable interface.", nameof (managedPeerType)); + +#if DEBUG + var signatureFromType = JniEnvironment.Runtime.TypeManager.GetTypeSignature (managedPeerType); + if (signatureFromType.SimpleReference != jniPeerTypeName) { + Debug.WriteLine ("WARNING-Java.Interop: ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof({0})).JniTypeName=\"{1}\" != \"{2}\"", + managedPeerType.FullName, + signatureFromType.SimpleReference, + jniPeerTypeName); + Debug.WriteLine (new System.Diagnostics.StackTrace (true)); + } +#endif // DEBUG + } + + JniPeerTypeName = jniPeerTypeName; + ManagedPeerType = managedPeerType; + + this.isInterface = isInterface; + + instanceMethods = new JniInstanceMethods (this); + instanceFields = new JniInstanceFields (this); + staticMethods = new JniStaticMethods (this); + staticFields = new JniStaticFields (this); + } + + static JniPeerMembers CreatePeerMembers (string jniPeerTypeName, Type managedPeerType) + { + return new JniPeerMembers (jniPeerTypeName, managedPeerType, checkManagedPeerType: false); + } + + JniType? jniPeerType; + JniInstanceMethods instanceMethods; + JniInstanceFields instanceFields; + JniStaticMethods staticMethods; + JniStaticFields staticFields; + + public Type ManagedPeerType {get; private set;} + public string JniPeerTypeName {get; private set;} + public JniType JniPeerType { + get { + var t = JniType.GetCachedJniType (ref jniPeerType, JniPeerTypeName); + t.RegisterWithRuntime (); + return t; + } + } + + public JniInstanceMethods InstanceMethods { + get {return Assert (instanceMethods);} + } + + public JniInstanceFields InstanceFields { + get {return Assert (instanceFields);} + } + + public JniStaticMethods StaticMethods { + get {return Assert (staticMethods);} + } + + public JniStaticFields StaticFields { + get {return Assert (staticFields);} + } + + static T Assert(T value) + where T : class + { + if (value == null) + throw new ObjectDisposedException (nameof (JniPeerMembers)); + return value; + } + + protected virtual void Dispose (bool disposing) + { + if (!disposing || jniPeerType == null) + return; + + instanceMethods.Dispose (); + instanceFields.Dispose (); + staticMethods.Dispose (); + staticFields.Dispose (); + jniPeerType.Dispose (); + + jniPeerType = null; + } + + public static void Dispose (JniPeerMembers members) + { + if (members == null) + return; + members.Dispose (true); + } + + protected virtual bool UsesVirtualDispatch (IJavaPeerable value, Type? declaringType) + { + return value.GetType () == declaringType || + declaringType == null || + value.GetType () == value.JniPeerMembers.ManagedPeerType; + } + + protected virtual JniPeerMembers GetPeerMembers (IJavaPeerable value) + { + return isInterface ? this : value.JniPeerMembers; + } + + internal static void AssertSelf (IJavaPeerable self) + { + if (self == null) + throw new ArgumentNullException (nameof (self)); + + var peer = self.PeerReference; + if (!peer.IsValid) + throw JniEnvironment.CreateObjectDisposedException (self); + + } + + internal static int GetSignatureSeparatorIndex (string encodedMember) + { + if (encodedMember == null) + throw new ArgumentNullException (nameof (encodedMember)); + int n = encodedMember.IndexOf (".", StringComparison.Ordinal); + if (n < 0) + throw new ArgumentException ( + "Invalid encoding; 'encodedMember' should be encoded as \".\".", + nameof (encodedMember)); + if (encodedMember.Length <= (n+1)) + throw new ArgumentException ( + "Invalid encoding; 'encodedMember' is missing a JNI signature, and should be in the format \".\".", + nameof (encodedMember)); + return n; + } + + internal static void GetNameAndSignature (string encodedMember, out string name, out string signature) + { + int n = GetSignatureSeparatorIndex (encodedMember); + name = encodedMember.Substring (0, n); + signature = encodedMember.Substring (n + 1); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniReleaseArrayElementsMode.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniReleaseArrayElementsMode.cs new file mode 100644 index 00000000000..cd88d02bf59 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniReleaseArrayElementsMode.cs @@ -0,0 +1,13 @@ +#nullable enable + +using System; + +namespace Java.Interop { + + // http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Release_PrimitiveType_ArrayElements_routines + public enum JniReleaseArrayElementsMode { + Default = 0, // 0 + Commit = 1, // JNI_COMMIT + Abort = 2, // JNI_ABORT + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs new file mode 100644 index 00000000000..7d8de27ccbf --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs @@ -0,0 +1,94 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; + +namespace Java.Interop { + + partial class JniRuntime { + + partial class CreationOptions { + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This property will be removed in a future release.")] + public bool UseMarshalMemberBuilder {get; set;} + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This property will be removed in a future release.")] + public JniMarshalMemberBuilder? MarshalMemberBuilder {get; set;} + } + + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This property will be removed in a future release.")] + public JniMarshalMemberBuilder MarshalMemberBuilder { + get => throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); + } + + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This class will be removed in a future release.")] + public abstract class JniMarshalMemberBuilder : IDisposable, ISetRuntime + { + JniRuntime? runtime; + bool disposed; + + public JniRuntime Runtime { + get => runtime ?? throw new NotSupportedException (); + } + + protected JniMarshalMemberBuilder () + { + } + + public virtual void OnSetRuntime (JniRuntime runtime) + { + if (disposed) + throw new ObjectDisposedException (GetType ().Name); + + this.runtime = runtime; + } + + public void Dispose () + { + Dispose (false); + } + + protected virtual void Dispose (bool disposing) + { + disposed = true; + } + + public Delegate CreateMarshalToManagedDelegate (Delegate value) + { + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); + } + + public abstract LambdaExpression CreateMarshalToManagedExpression (MethodInfo method); + public abstract IEnumerable GetExportedMemberRegistrations (Type declaringType); + + public abstract Expression> CreateConstructActivationPeerExpression (ConstructorInfo constructor); + + public Func CreateConstructActivationPeerFunc (ConstructorInfo constructor) + { + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); + } + + public string GetJniMethodSignature (MethodBase member) + { + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); + } + + public JniValueMarshaler GetParameterMarshaler (ParameterInfo parameter) + { + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); + } + + // Heuristic: if first two parameters are IntPtr, this is a "direct" wrapper. + public bool IsDirectMethod (ParameterInfo[] methodParameters) + { + return methodParameters?.Length >= 2 && + methodParameters [0].ParameterType == typeof (IntPtr) && + methodParameters [1].ParameterType == typeof (IntPtr); + } + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniObjectReferenceManager.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniObjectReferenceManager.cs new file mode 100644 index 00000000000..1553c452bd6 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniObjectReferenceManager.cs @@ -0,0 +1,208 @@ +# nullable enable + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Java.Interop { + + partial class JniRuntime { + + public abstract class JniObjectReferenceManager : IDisposable, ISetRuntime { + + public JniObjectReferenceManager () + { + } + + JniRuntime? runtime; + public JniRuntime Runtime { + get => runtime ?? throw new NotSupportedException (); + } + + public virtual void OnSetRuntime (JniRuntime runtime) + { + this.runtime = runtime; + } + + public abstract int GlobalReferenceCount { + get; + } + + public abstract int WeakGlobalReferenceCount { + get; + } + + public virtual bool LogLocalReferenceMessages { + get {return false;} + } + + public virtual void WriteLocalReferenceLine (string format, params object[] args) + { + } + + internal JniObjectReference CreateLocalReference (JniEnvironmentInfo environment, JniObjectReference reference) + { + var lrefc = environment.LocalReferenceCount; + var r = CreateLocalReference (reference, ref lrefc); + environment.LocalReferenceCount = lrefc; + return r; + } + + public virtual JniObjectReference CreateLocalReference (JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return reference; + if (localReferenceCount < 0) + AssertCount(localReferenceCount, "LREF", reference.ToString()); + localReferenceCount++; + return JniEnvironment.References.NewLocalRef (reference); + } + + internal void DeleteLocalReference (JniEnvironmentInfo environment, ref JniObjectReference reference) + { + var lrefc = environment.LocalReferenceCount; + DeleteLocalReference (ref reference, ref lrefc); + environment.LocalReferenceCount = lrefc; + } + + public virtual void DeleteLocalReference (ref JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return; + AssertReferenceType (ref reference, JniObjectReferenceType.Local); + localReferenceCount--; + if (localReferenceCount < 0) + AssertCount(localReferenceCount, "LREF", reference.ToString()); + JniEnvironment.References.DeleteLocalRef (reference.Handle); + reference.Invalidate (); + } + + internal void CreatedLocalReference (JniEnvironmentInfo environment, JniObjectReference reference) + { + var lrefc = environment.LocalReferenceCount; + CreatedLocalReference (reference, ref lrefc); + environment.LocalReferenceCount = lrefc; + } + + public virtual void CreatedLocalReference (JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return; + if (localReferenceCount < 0) + AssertCount(localReferenceCount, "LREF", reference.ToString()); + localReferenceCount++ ; + } + + internal IntPtr ReleaseLocalReference (JniEnvironmentInfo environment, ref JniObjectReference reference) + { + var lrefc = environment.LocalReferenceCount; + var r = ReleaseLocalReference (ref reference, ref lrefc); + environment.LocalReferenceCount = lrefc; + return r; + } + + public virtual IntPtr ReleaseLocalReference (ref JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return IntPtr.Zero; + localReferenceCount--; + if (localReferenceCount < 0) + AssertCount (localReferenceCount, "LREF", reference.ToString ()); + var h = reference.Handle; + reference.Invalidate (); + return h; + } + + public virtual bool LogGlobalReferenceMessages { + get {return false;} + } + + public virtual void WriteGlobalReferenceLine (string format, params object?[] args) + { + } + + public virtual JniObjectReference CreateGlobalReference (JniObjectReference reference) + { + if (!reference.IsValid) + return reference; + var n = JniEnvironment.References.NewGlobalRef (reference); + if (GlobalReferenceCount < 0) + AssertCount (GlobalReferenceCount, "GREF", reference.ToString ()); + return n; + } + + public virtual void DeleteGlobalReference (ref JniObjectReference reference) + { + if (!reference.IsValid) + return; + AssertReferenceType (ref reference, JniObjectReferenceType.Global); + if (GlobalReferenceCount < 0) + AssertCount(GlobalReferenceCount, "GREF", reference.ToString()); + JniEnvironment.References.DeleteGlobalRef (reference.Handle); + reference.Invalidate (); + } + + public virtual JniObjectReference CreateWeakGlobalReference (JniObjectReference reference) + { + if (!reference.IsValid) + return reference; + var n = JniEnvironment.References.NewWeakGlobalRef (reference); + if (WeakGlobalReferenceCount < 0) + AssertCount(WeakGlobalReferenceCount, "WGREF", reference.ToString()); + return n; + } + + public virtual void DeleteWeakGlobalReference (ref JniObjectReference reference) + { + if (!reference.IsValid) + return; + AssertReferenceType (ref reference, JniObjectReferenceType.WeakGlobal); + if (WeakGlobalReferenceCount < 0) + AssertCount(WeakGlobalReferenceCount, "WGREF", reference.ToString()); + JniEnvironment.References.DeleteWeakGlobalRef (reference.Handle); + reference.Invalidate (); + } + + public void Dispose () + { + Dispose (false); + } + + protected virtual void Dispose (bool disposing) + { + } + + [Conditional ("DEBUG")] + static void AssertReferenceType (ref JniObjectReference reference, JniObjectReferenceType type) + { + if (reference.Type == type) + return; + + Debug.Assert (reference.Type == type, + string.Format ("Object reference {0} should be of type {1}, is instead {2}!", + reference.ToString (), type, reference.Type)); + } + + [Conditional ("DEBUG")] + void AssertCount (int count, string type, string value) + { + Debug.Assert (count >= 0, + string.Format ("{0} count is {1}, expected to be >= 0 when dealing with handle {2} on thread '{3}'({4}).", + type, count, value, Runtime.GetCurrentManagedThreadName (), Environment.CurrentManagedThreadId)); + if (count < 0) { + Debug.WriteLine ("Perhaps `Java.Interop.JniEnvironment.References.{0}()` should be used to note the creation of handle {1} on thread '{2}'({3})?", + nameof (JniEnvironment.References.CreatedReference), + value, + Runtime.GetCurrentManagedThreadName (), + Environment.CurrentManagedThreadId); + } + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs new file mode 100644 index 00000000000..6612957175d --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs @@ -0,0 +1,289 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using System.Threading; + +namespace Java.Interop { + + public partial class JniRuntime { + + [SuppressMessage ("Design", "CA1034:Nested types should not be visible", + Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`; see 045b8af7.")] + public struct ReplacementMethodInfo : IEquatable + { + public string? SourceJniType {get; set;} + public string? SourceJniMethodName {get; set;} + public string? SourceJniMethodSignature {get; set;} + public string? TargetJniType {get; set;} + public string? TargetJniMethodName {get; set;} + public string? TargetJniMethodSignature {get; set;} + public int? TargetJniMethodParameterCount {get; set;} + public bool TargetJniMethodInstanceToStatic {get; set;} + + public override bool Equals (object? obj) + { + if (obj is ReplacementMethodInfo o) { + return Equals (o); + } + return false; + } + + public bool Equals (ReplacementMethodInfo other) + { + return string.Equals (SourceJniType, other.SourceJniType) && + string.Equals (SourceJniMethodName, other.SourceJniMethodName) && + string.Equals (SourceJniMethodSignature, other.SourceJniMethodSignature) && + string.Equals (TargetJniType, other.TargetJniType) && + string.Equals (TargetJniMethodName, other.TargetJniMethodName) && + string.Equals (TargetJniMethodSignature, other.TargetJniMethodSignature) && + TargetJniMethodParameterCount == other.TargetJniMethodParameterCount && + TargetJniMethodInstanceToStatic == other.TargetJniMethodInstanceToStatic; + } + + public override int GetHashCode () + { + return (SourceJniType?.GetHashCode () ?? 0) ^ + (SourceJniMethodName?.GetHashCode () ?? 0) ^ + (SourceJniMethodSignature?.GetHashCode () ?? 0) ^ + (TargetJniType?.GetHashCode () ?? 0) ^ + (TargetJniMethodName?.GetHashCode () ?? 0) ^ + (TargetJniMethodSignature?.GetHashCode () ?? 0) ^ + (TargetJniMethodParameterCount?.GetHashCode () ?? 0) ^ + TargetJniMethodInstanceToStatic.GetHashCode (); + } + + public override string ToString () + { + return $"{nameof (ReplacementMethodInfo)} {{ " + + $"{nameof (SourceJniType)} = \"{SourceJniType}\"" + + $", {nameof (SourceJniMethodName)} = \"{SourceJniMethodName}\"" + + $", {nameof (SourceJniMethodSignature)} = \"{SourceJniMethodSignature}\"" + + $", {nameof (TargetJniType)} = \"{TargetJniType}\"" + + $", {nameof (TargetJniMethodName)} = \"{TargetJniMethodName}\"" + + $", {nameof (TargetJniMethodSignature)} = \"{TargetJniMethodSignature}\"" + + $", {nameof (TargetJniMethodParameterCount)} = {TargetJniMethodParameterCount?.ToString () ?? "null"}" + + $", {nameof (TargetJniMethodInstanceToStatic)} = {TargetJniMethodInstanceToStatic}" + + $"}}"; + } + + public static bool operator==(ReplacementMethodInfo a, ReplacementMethodInfo b) => a.Equals (b); + public static bool operator!=(ReplacementMethodInfo a, ReplacementMethodInfo b) => !a.Equals (b); + } + + /// + public partial class JniTypeManager : IDisposable, ISetRuntime { + + internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods; + internal const DynamicallyAccessedMemberTypes MethodsConstructors = Methods | Constructors; + + JniRuntime? runtime; + bool disposed; + + + public JniRuntime Runtime { + get => runtime ?? throw new NotSupportedException (); + } + + public virtual void OnSetRuntime (JniRuntime runtime) + { + AssertValid (); + this.runtime = runtime; + } + + public void Dispose () + { + Dispose (false); + } + + protected virtual void Dispose (bool disposing) + { + disposed = true; + } + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + private protected void AssertValid () + { + if (!disposed) + return; + throw new ObjectDisposedException (nameof (JniTypeManager)); + } + + internal static void AssertSimpleReference (string jniSimpleReference, string argumentName = "jniSimpleReference") + { + if (string.IsNullOrEmpty (jniSimpleReference)) + throw new ArgumentNullException (argumentName); + if (jniSimpleReference.IndexOf ('.') >= 0) + throw new ArgumentException ("JNI type names do not contain '.', they use '/'. Are you sure you're using a JNI type name?", argumentName); + switch (jniSimpleReference [0]) { + case '[': + throw new ArgumentException ("Arrays cannot be present in simplified type references.", argumentName); + case 'L': + if (jniSimpleReference [jniSimpleReference.Length - 1] == ';') + throw new ArgumentException ("JNI type references are not supported.", argumentName); + break; + default: + break; + } + } + + // NOTE: This method needs to be kept in sync with GetTypeSignatures() + // This version of the method has removed IEnumerable for performance reasons. + public JniTypeSignature GetTypeSignature (Type type) + { + AssertValid (); + + if (type == null) + throw new ArgumentNullException (nameof (type)); + + var builtIn = GetBuiltInTypeSignature (type); + return builtIn.IsValid ? builtIn : GetTypeSignatureCore (type); + } + + protected virtual JniTypeSignature GetTypeSignatureCore (Type type) => default; + + // NOTE: This method needs to be kept in sync with GetTypeSignature() + public IEnumerable GetTypeSignatures (Type type) + { + AssertValid (); + + if (type == null) + return []; + + var builtIn = GetBuiltInTypeSignature (type); + if (builtIn.IsValid) + return new [] { builtIn }; + + return GetTypeSignaturesCore (type); + } + + protected virtual IEnumerable GetTypeSignaturesCore (Type type) => []; + + public Type? GetType (JniTypeSignature typeSignature) + { + AssertValid (); + + if (!typeSignature.IsValid || typeSignature.SimpleReference == null) + return null; + + var builtIn = GetBuiltInType (typeSignature); + if (builtIn != null) + return builtIn; + + var type = GetTypeForSimpleReference (typeSignature.SimpleReference); + if (type == null) + return null; + if (typeSignature.ArrayRank == 0) + return type; + throw new NotSupportedException ($"DAM-annotated type lookup for array signature `{typeSignature}` is not supported. Use {nameof (GetTypes)} instead."); + } + + protected virtual string? GetSimpleReference (Type type) => null; + protected virtual IEnumerable GetSimpleReferences (Type type) => []; + protected virtual Type? GetTypeForSimpleReference (string jniSimpleReference) => null; + public virtual IEnumerable GetTypes (JniTypeSignature typeSignature) => []; + + protected virtual IEnumerable GetTypesForSimpleReference (string jniSimpleReference) => []; + + static JniTypeSignature GetBuiltInTypeSignature (Type type) + { + if (type == typeof (JavaProxyObject)) + return new JniTypeSignature (JavaProxyObject.JniTypeName, 0, false); + if (type == typeof (JavaProxyThrowable)) + return new JniTypeSignature (JavaProxyThrowable.JniTypeName, 0, false); + return default; + } + + static Type? GetBuiltInType (JniTypeSignature typeSignature) + { + if (typeSignature.ArrayRank != 0) + return null; + if (!typeSignature.IsKeyword) { + return typeSignature.SimpleReference switch { + JavaProxyObject.JniTypeName => typeof (JavaProxyObject), + JavaProxyThrowable.JniTypeName => typeof (JavaProxyThrowable), + ManagedPeer.JniTypeName => typeof (ManagedPeer), + _ => null, + }; + } + return typeSignature.SimpleReference switch { + "V" => typeof (void), + "Z" => typeof (bool), + "B" => typeof (sbyte), + "C" => typeof (char), + "S" => typeof (short), + "I" => typeof (int), + "J" => typeof (long), + "F" => typeof (float), + "D" => typeof (double), + _ => null, + }; + } + + /// + public Type? GetInvokerType (Type type) + { + if (type.IsAbstract || type.IsInterface) { + return GetInvokerTypeCore (type); + } + return null; + } + + protected virtual Type? GetInvokerTypeCore (Type type) => null; + + protected virtual IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimple) => null; + + public string? GetReplacementType (string jniSimpleReference) + { + AssertValid (); + AssertSimpleReference (jniSimpleReference, nameof (jniSimpleReference)); + + return GetReplacementTypeCore (jniSimpleReference); + } + + protected virtual string? GetReplacementTypeCore (string jniSimpleReference) => null; + + public IReadOnlyList? GetStaticMethodFallbackTypes (string jniSimpleReference) + { + AssertValid (); + AssertSimpleReference (jniSimpleReference, nameof (jniSimpleReference)); + + return GetStaticMethodFallbackTypesCore (jniSimpleReference); + } + + public ReplacementMethodInfo? GetReplacementMethodInfo (string jniSimpleReference, string jniMethodName, string jniMethodSignature) + { + AssertValid (); + AssertSimpleReference (jniSimpleReference, nameof (jniSimpleReference)); + if (string.IsNullOrEmpty (jniMethodName)) { + throw new ArgumentNullException (nameof (jniMethodName)); + } + if (string.IsNullOrEmpty (jniMethodSignature)) { + throw new ArgumentNullException (nameof (jniMethodSignature)); + } + + return GetReplacementMethodInfoCore (jniSimpleReference, jniMethodName, jniMethodSignature); + } + + protected virtual ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSimpleReference, string jniMethodName, string jniMethodSignature) => null; + + // Default implementation is a no-op. Derived classes (e.g. `ReflectionJniTypeManager`) + // provide reflection-based registration. Override to provide custom registration. + public virtual void RegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan methods) + { + } + + [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan)")] + public virtual void RegisterNativeMembers (JniType nativeClass, Type type, string? methods) + { + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs new file mode 100644 index 00000000000..d9901e64db0 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs @@ -0,0 +1,325 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Java.Interop +{ + public class JniSurfacedPeerInfo { + + public int JniIdentityHashCode {get; private set;} + public WeakReference SurfacedPeer {get; private set;} + + public JniSurfacedPeerInfo (int jniIdentityHashCode, WeakReference surfacedPeer) + { + JniIdentityHashCode = jniIdentityHashCode; + SurfacedPeer = surfacedPeer; + } + } + + partial class JniRuntime + { + partial class CreationOptions { + public JniValueManager? ValueManager {get; set;} + } + + internal JniValueManager? valueManager; + public JniValueManager ValueManager { + get => valueManager ?? throw new NotSupportedException (); + } + + partial void SetValueManager (CreationOptions options) + { + var manager = options.ValueManager; + if (manager == null) + throw new ArgumentException ( + "No JniValueManager specified in JniRuntime.CreationOptions.ValueManager.", + nameof (options)); + valueManager = SetRuntime (manager); + } + + public abstract partial class JniValueManager : ISetRuntime, IDisposable { + internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + + JniRuntime? runtime; + bool disposed; + public JniRuntime Runtime { + get => runtime ?? throw new NotSupportedException (); + } + + public virtual void OnSetRuntime (JniRuntime runtime) + { + if (disposed) + throw new ObjectDisposedException (GetType ().Name); + + this.runtime = runtime; + } + + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose (bool disposing) + { + disposed = true; + } + + protected void EnsureNotDisposed () + { + if (disposed) + throw new ObjectDisposedException (GetType ().Name); + } + + public abstract void WaitForGCBridgeProcessing (); + public abstract void CollectPeers (); + public abstract void AddPeer (IJavaPeerable value); + public abstract void RemovePeer (IJavaPeerable value); + public abstract void FinalizePeer (IJavaPeerable value); + public abstract IJavaPeerable? PeekPeer (JniObjectReference reference); + public abstract List GetSurfacedPeers (); + public abstract void ActivatePeer ( + JniObjectReference reference, + Type type, + ConstructorInfo cinfo, + object?[]? argumentValues); + + public void ConstructPeer (IJavaPeerable peer, ref JniObjectReference reference, JniObjectReferenceOptions options) + { + ConstructPeerCore (peer, ref reference, options); + } + + protected abstract void ConstructPeerCore (IJavaPeerable peer, ref JniObjectReference reference, JniObjectReferenceOptions options); + + public int GetJniIdentityHashCode (JniObjectReference reference) + { + return JniSystem.IdentityHashCode (reference); + } + + public virtual void DisposePeer (IJavaPeerable value) + { + EnsureNotDisposed (); + + if (value == null) + throw new ArgumentNullException (nameof (value)); + + if (!value.PeerReference.IsValid) + return; + + value.Disposed (); + RemovePeer (value); + + var h = value.PeerReference; + if (!h.IsValid) + return; + + DisposePeer (h, value); + } + + void DisposePeer (JniObjectReference h, IJavaPeerable value) + { + EnsureNotDisposed (); + + var o = Runtime.ObjectReferenceManager; + if (o.LogGlobalReferenceMessages) { + o.WriteGlobalReferenceLine ("Disposing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3} Java.Type={4}", + h.ToString (), + value.JniIdentityHashCode.ToString ("x"), + RuntimeHelpers.GetHashCode (value).ToString ("x"), + value.GetType ().ToString (), + JniEnvironment.Types.GetJniTypeNameFromInstance (h)); + } + JniObjectReference.Dispose (ref h); + value.SetPeerReference (new JniObjectReference ()); + GC.SuppressFinalize (value); + } + + public virtual void DisposePeerUnlessReferenced (IJavaPeerable value) + { + EnsureNotDisposed (); + + if (value == null) + throw new ArgumentNullException (nameof (value)); + + var h = value.PeerReference; + if (!h.IsValid) + return; + + var o = PeekPeer (h); + if (o != null && object.ReferenceEquals (o, value)) + return; + + DisposePeer (h, value); + } + + public object? PeekValue (JniObjectReference reference) + { + EnsureNotDisposed (); + + if (!reference.IsValid) + return null; + + var t = PeekPeer (reference); + if (t == null) + return t; + + object? r; + return TryUnboxPeerObject (t, out r) + ? r + : t; + } + + protected virtual bool TryUnboxPeerObject (IJavaPeerable value, [NotNullWhen (true)] out object? result) + { + result = null; + var p = value as JavaProxyObject; + if (p != null) { + result = p.Value; + return true; + } + var x = value as JavaProxyThrowable; + if (x != null) { + result = x.Exception; + return true; + } + return false; + } + + public IJavaPeerable? GetPeer ( + JniObjectReference reference, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + if (!reference.IsValid) { + return null; + } + + var peeked = PeekPeer (reference); + if (peeked != null && + (targetType == null || + targetType.IsAssignableFrom (peeked.GetType ()))) { + return peeked; + } + return CreatePeer (ref reference, JniObjectReferenceOptions.Copy, targetType); + } + + public abstract IJavaPeerable? CreatePeer ( + ref JniObjectReference reference, + JniObjectReferenceOptions transfer, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType); + + public object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + return CreateValueCore (ref reference, options, targetType); + } + + [return: MaybeNull] + public T CreateValue<[DynamicallyAccessedMembers (Constructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + return CreateValueCore (ref reference, options, targetType); + } + + [return: MaybeNull] + protected abstract T CreateValueCore<[DynamicallyAccessedMembers (Constructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null); + + protected abstract object? CreateValueCore ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null); + + public object? GetValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + return GetValueCore (ref reference, options, targetType); + } + + [return: MaybeNull] + public T GetValue<[DynamicallyAccessedMembers (Constructors)] T> (IntPtr handle) + { + var r = new JniObjectReference (handle); + return GetValue (ref r, JniObjectReferenceOptions.Copy); + } + + [return: MaybeNull] + public T GetValue<[DynamicallyAccessedMembers (Constructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + return GetValueCore (ref reference, options, targetType); + } + + [return: MaybeNull] + protected abstract T GetValueCore<[DynamicallyAccessedMembers (Constructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null); + + protected abstract object? GetValueCore ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null); + + internal Type? GetRuntimeType (JniObjectReference reference) + { + if (!reference.IsValid) + return null; + JniTypeSignature signature; + if (!JniTypeSignature.TryParse (JniEnvironment.Types.GetJniTypeNameFromInstance (reference)!, out signature)) + return null; + return Runtime.TypeManager.GetType (signature); + } + + public JniValueMarshaler GetValueMarshaler (Type type) => GetValueMarshalerCore (type); + protected abstract JniValueMarshaler GetValueMarshalerCore (Type type); + + public JniValueMarshaler GetValueMarshaler () => GetValueMarshalerCore (); + protected abstract JniValueMarshaler GetValueMarshalerCore (); + + internal JniObjectReference CreateLocalObjectReferenceArgument (Type type, object? value) + { + EnsureNotDisposed (); + + if (type == null) + throw new ArgumentNullException (nameof (type)); + return CreateLocalObjectReferenceArgumentCore (type, value); + } + + protected abstract JniObjectReference CreateLocalObjectReferenceArgumentCore (Type type, object? value); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniTypeManager.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniTypeManager.cs new file mode 100644 index 00000000000..8f8a47e3f9b --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniTypeManager.cs @@ -0,0 +1,469 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Threading; + +namespace Java.Interop { + + public partial class JniRuntime { + + [RequiresDynamicCode ("This JniTypeManager implementation is not compatible with Native AOT. Use a different JniTypeManager implementation that supports Native AOT.")] + [RequiresUnreferencedCode ("This JniTypeManager implementation is not compatible with Native AOT. Use a different JniTypeManager implementation that supports Native AOT.")] + public partial class ReflectionJniTypeManager : JniTypeManager { + + protected override JniTypeSignature GetTypeSignatureCore (Type type) + { + type = GetUnderlyingType (type, out int rank); + + JniTypeSignature signature = JniTypeSignature.Empty; + if (GetBuiltInTypeSignature (type, ref signature)) + return signature.AddArrayRank (rank); + if (GetBuiltInTypeArraySignature (type, ref signature)) + return signature.AddArrayRank (rank); + + var isGeneric = type.IsGenericType; + var genericDef = isGeneric ? type.GetGenericTypeDefinition () : type; + if (isGeneric) { + if (genericDef == typeof (JavaArray<>) || genericDef == typeof (JavaObjectArray<>)) { + var r = GetTypeSignature (type.GenericTypeArguments [0]); + return r.AddArrayRank (rank + 1); + } + + var genericSimpleRef = GetSimpleReference (genericDef); + if (genericSimpleRef != null) + return new JniTypeSignature (genericSimpleRef, rank, false); + } + + var simpleRef = GetSimpleReference (type); + if (simpleRef != null) + return new JniTypeSignature (simpleRef, rank, false); + + return default; + } + + protected override IEnumerable GetTypeSignaturesCore (Type type) + { + type = GetUnderlyingType (type, out int rank); + + var signature = JniTypeSignature.Empty; + if (GetBuiltInTypeSignature (type, ref signature)) + yield return signature.AddArrayRank (rank); + if (GetBuiltInTypeArraySignature (type, ref signature)) + yield return signature.AddArrayRank (rank); + + var isGeneric = type.IsGenericType; + var genericDef = isGeneric ? type.GetGenericTypeDefinition () : type; + if (isGeneric) { + if (genericDef == typeof (JavaArray<>) || genericDef == typeof (JavaObjectArray<>)) { + var r = GetTypeSignature (type.GenericTypeArguments [0]); + yield return r.AddArrayRank (rank + 1); + } + + foreach (var genericSimpleRef in GetSimpleReferences (genericDef)) { + if (genericSimpleRef == null) + continue; + yield return new JniTypeSignature (genericSimpleRef, rank, false); + } + } + + foreach (var simpleRef in GetSimpleReferences (type)) { + if (simpleRef == null) + continue; + yield return new JniTypeSignature (simpleRef, rank, false); + } + } + + static Type GetUnderlyingType (Type type, out int rank) + { + rank = 0; + var originalType = type; + while (type.IsArray) { + if (type.IsArray && type.GetArrayRank () > 1) + throw new ArgumentException ("Multidimensional array '" + originalType.FullName + "' is not supported.", nameof (type)); + rank++; + type = type.GetElementType () ?? throw new InvalidOperationException ("Array type has no element type."); + } + + if (type.IsEnum) + type = Enum.GetUnderlyingType (type); + + return type; + } + + // `type` will NOT be an array type. + protected override string? GetSimpleReference (Type type) + { + return GetSimpleReferences (type).FirstOrDefault (); + } + + // `type` will NOT be an array type. + protected override IEnumerable GetSimpleReferences (Type type) + { + AssertValid (); + + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (type.IsArray) + throw new ArgumentException ("Array type '" + type.FullName + "' is not supported.", nameof (type)); + + var name = type.GetCustomAttribute (inherit: false); + if (name != null) { + var altRef = GetReplacementType (name.SimpleReference); + if (altRef != null) { + yield return altRef; + } else { + yield return name.SimpleReference; + } + } + + yield break; + } + + static readonly Type[] EmptyTypeArray = []; + + readonly struct KnownArrayTypesInfo + { + public readonly Dictionary ArrayTypes; + public readonly Dictionary JavaObjectArrayTypes; + + public KnownArrayTypesInfo (Dictionary arrayTypes, Dictionary javaObjectArrayTypes) + { + ArrayTypes = arrayTypes; + JavaObjectArrayTypes = javaObjectArrayTypes; + } + } + + static readonly Lazy KnownArrayTypes = new Lazy (InitKnownArrayTypes); + + static KnownArrayTypesInfo InitKnownArrayTypes () + { + var arrayTypes = new Dictionary (); + var javaObjectArrayTypes = new Dictionary (); + + AddKnownArrayTypes (arrayTypes, javaObjectArrayTypes); + + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownPrimitiveArrayTypes (arrayTypes, javaObjectArrayTypes); + + return new KnownArrayTypesInfo (arrayTypes, javaObjectArrayTypes); + } + + static void AddKnownPrimitiveArrayTypes< + [DynamicallyAccessedMembers (Constructors)] + T, + [DynamicallyAccessedMembers (Constructors)] + TArray> (Dictionary arrayTypes, Dictionary javaObjectArrayTypes) + { + AddKnownArrayTypes (arrayTypes, javaObjectArrayTypes); + AddKnownArrayTypes> (arrayTypes, javaObjectArrayTypes); + AddKnownArrayTypes> (arrayTypes, javaObjectArrayTypes); + AddKnownArrayTypes (arrayTypes, javaObjectArrayTypes); + } + + static void AddKnownArrayTypes< + [DynamicallyAccessedMembers (Constructors)] + T> (Dictionary arrayTypes, Dictionary javaObjectArrayTypes) + { + arrayTypes [typeof (T)] = typeof (T[]); + arrayTypes [typeof (T[])] = typeof (T[][]); + arrayTypes [typeof (T[][])] = typeof (T[][][]); + javaObjectArrayTypes [typeof (T)] = typeof (JavaObjectArray); + javaObjectArrayTypes [typeof (JavaObjectArray)] = typeof (JavaObjectArray>); + } + + static bool TryMakeArrayType (Type type, out Type? arrayType) => + KnownArrayTypes.Value.ArrayTypes.TryGetValue (type, out arrayType); + + static bool TryMakeJavaObjectArrayType (Type type, out Type? arrayType) => + KnownArrayTypes.Value.JavaObjectArrayTypes.TryGetValue (type, out arrayType); + + static Type MakeArrayType (Type type) => + TryMakeArrayType (type, out var arrayType) + ? arrayType ?? throw new InvalidOperationException ("Should not be reached") + : type.MakeArrayType (); + + static Type MakeJavaObjectArrayType (Type type) => + TryMakeJavaObjectArrayType (type, out var arrayType) + ? arrayType ?? throw new InvalidOperationException ("Should not be reached") + : typeof (JavaObjectArray<>).MakeGenericType (type); + + protected override Type? GetTypeForSimpleReference (string jniSimpleReference) + { + AssertValid (); + AssertSimpleReference (jniSimpleReference); + + return jniSimpleReference switch { + "java/lang/String" => typeof (string), + "net/dot/jni/internal/JavaProxyObject" => typeof (JavaProxyObject), + "net/dot/jni/internal/JavaProxyThrowable" => typeof (JavaProxyThrowable), + "V" => typeof (void), + "Z" => typeof (Boolean), + "java/lang/Boolean" => typeof (Boolean?), + "B" => typeof (SByte), + "java/lang/Byte" => typeof (SByte?), + "C" => typeof (Char), + "java/lang/Character" => typeof (Char?), + "S" => typeof (Int16), + "java/lang/Short" => typeof (Int16?), + "I" => typeof (Int32), + "java/lang/Integer" => typeof (Int32?), + "J" => typeof (Int64), + "java/lang/Long" => typeof (Int64?), + "F" => typeof (Single), + "java/lang/Float" => typeof (Single?), + "D" => typeof (Double), + "java/lang/Double" => typeof (Double?), + _ => null, + }; + } + + public override IEnumerable GetTypes (JniTypeSignature typeSignature) + { + AssertValid (); + + if (typeSignature.SimpleReference == null) + return EmptyTypeArray; + return CreateGetTypesEnumerator (typeSignature); + } + + IEnumerable CreateGetTypesEnumerator (JniTypeSignature typeSignature) + { + if (!typeSignature.IsValid) + yield break; + foreach (var type in GetTypesForSimpleReference (typeSignature.SimpleReference ?? throw new InvalidOperationException ("Should not be reached"))) { + if (typeSignature.ArrayRank == 0) { + yield return type; + continue; + } + + if (typeSignature.IsKeyword) { + foreach (var t in GetPrimitiveArrayTypesForSimpleReference (typeSignature, type)) { + yield return t; + } + continue; + } + + if (typeSignature.ArrayRank > 0) { + var rank = typeSignature.ArrayRank; + var arrayType = type; + while (rank-- > 0) { + arrayType = MakeJavaObjectArrayType (arrayType); + } + yield return arrayType; + } + + if (typeSignature.ArrayRank > 0) { + var rank = typeSignature.ArrayRank; + var arrayType = type; + while (rank-- > 0) { + arrayType = MakeArrayType (arrayType); + } + yield return arrayType; + } + } + } + + IEnumerable GetPrimitiveArrayTypesForSimpleReference (JniTypeSignature typeSignature, Type type) + { + int index = -1; + for (int i = 0; i < JniPrimitiveArrayTypes.Length; ++i) { + if (JniPrimitiveArrayTypes [i].PrimitiveType == type) { + index = i; + break; + } + } + if (index == -1) { + throw new InvalidOperationException ($"Should not be reached; Could not find JniPrimitiveArrayInfo for {type}"); + } + foreach (var t in JniPrimitiveArrayTypes [index].ArrayTypes) { + var rank = typeSignature.ArrayRank-1; + var arrayType = t; + while (rank-- > 0) { + arrayType = MakeJavaObjectArrayType (arrayType); + } + yield return arrayType; + + rank = typeSignature.ArrayRank-1; + arrayType = t; + while (rank-- > 0) { + arrayType = MakeArrayType (arrayType); + } + yield return arrayType; + } + } + + protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) + { + AssertValid (); + AssertSimpleReference (jniSimpleReference); + + // Not sure why CS8604 is reported on following line when we check against null ~9 lines above... + return CreateGetTypesForSimpleReferenceEnumerator (jniSimpleReference!); + } + + IEnumerable CreateGetTypesForSimpleReferenceEnumerator (string jniSimpleReference) + { + if (JniBuiltinSimpleReferenceToType.Value.TryGetValue (jniSimpleReference, out var ret)) { + yield return ret; + } + if (RuntimeFeature.ManagedPeerNativeRegistration && jniSimpleReference == ManagedPeer.JniTypeName) { + yield return typeof (ManagedPeer); + } + yield break; + } + + protected override Type? GetInvokerTypeCore (Type type) + { + var signature = type.GetCustomAttribute (); + if (signature == null || signature.InvokerType == null) { + return null; + } + + Type[] arguments = type.GetGenericArguments (); + if (arguments.Length == 0) + return signature.InvokerType; + + throw new NotSupportedException ($"Generic invoker type construction for `{type}` is not supported."); + } + + protected override IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimple) => null; + + protected override string? GetReplacementTypeCore (string jniSimpleReference) => null; + + protected override ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSimpleReference, string jniMethodName, string jniMethodSignature) => null; + + public override void RegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan methods) + { + TryRegisterNativeMembers (nativeClass, type, methods); + } + + protected bool TryRegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan methods) + { + AssertValid (); + +#pragma warning disable CS1717 + methods = methods; +#pragma warning restore CS1717 + + return TryLoadJniMarshalMethods (nativeClass, type, null) || TryRegisterNativeMembers (nativeClass, type, null, null); + } + + [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan)")] + public override void RegisterNativeMembers (JniType nativeClass, Type type, string? methods) + { + TryRegisterNativeMembers (nativeClass, type, methods); + } + + [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan)")] + protected bool TryRegisterNativeMembers (JniType nativeClass, Type type, string? methods) + { + AssertValid (); + + return TryLoadJniMarshalMethods (nativeClass, type, methods) || TryRegisterNativeMembers (nativeClass, type, methods, null); + } + + static Type [] registerMethodParameters = new Type [] { typeof (JniNativeMethodRegistrationArguments) }; + + bool TryLoadJniMarshalMethods ( + JniType nativeClass, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] + Type type, + string? methods) + { + var marshalType = type?.GetNestedType ("__<$>_jni_marshal_methods", BindingFlags.NonPublic); + if (marshalType == null) { + return false; + } + + var registerMethod = marshalType.GetMethod ( + name: "__RegisterNativeMembers", + bindingAttr: BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, + binder: null, + callConvention: default, + types: registerMethodParameters, + modifiers: null); + return TryRegisterNativeMembers (nativeClass, marshalType, methods, registerMethod); + } + + static List sharedRegistrations = new List (); + + bool TryRegisterNativeMembers ( + JniType nativeClass, + [DynamicallyAccessedMembers (Methods)] + Type marshalType, + string? methods, + MethodInfo? registerMethod) + { + bool lockTaken = false; + bool rv = false; + + try { + Monitor.TryEnter (sharedRegistrations, ref lockTaken); + List registrations; + if (lockTaken) { + sharedRegistrations.Clear (); + registrations = sharedRegistrations; + } else { + registrations = new List (); + } + JniNativeMethodRegistrationArguments arguments = new JniNativeMethodRegistrationArguments (registrations, methods); + if (registerMethod != null) { + registerMethod.Invoke (null, new object [] { arguments }); + rv = true; + } else + rv = FindAndCallRegisterMethod (marshalType, arguments); + + if (registrations.Count > 0) + nativeClass.RegisterNativeMethods (registrations.ToArray ()); + } finally { + if (lockTaken) { + Monitor.Exit (sharedRegistrations); + } + } + + return rv; + } + + bool FindAndCallRegisterMethod ( + [DynamicallyAccessedMembers (Methods)] + Type marshalType, + JniNativeMethodRegistrationArguments arguments) + { + if (!Runtime.JniAddNativeMethodRegistrationAttributePresent) + return false; + + bool found = false; + + foreach (var methodInfo in marshalType.GetRuntimeMethods ()) { + if (methodInfo.GetCustomAttribute (typeof (JniAddNativeMethodRegistrationAttribute)) == null) { + continue; + } + + var declaringTypeName = methodInfo.DeclaringType?.FullName ?? ""; + + if ((methodInfo.Attributes & MethodAttributes.Static) != MethodAttributes.Static) { + throw new InvalidOperationException ($"The method `{declaringTypeName}.{methodInfo}` marked with [{nameof (JniAddNativeMethodRegistrationAttribute)}] must be static!"); + } + + var register = (Action)methodInfo.CreateDelegate (typeof (Action)); + register (arguments); + + found = true; + } + + return found; + } + + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs new file mode 100644 index 00000000000..56f836bd2e3 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs @@ -0,0 +1,733 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; + +using Java.Interop.Expressions; + +namespace Java.Interop +{ + partial class JniRuntime + { + [RequiresDynamicCode ("This JniValueManager implementation is not compatible with Native AOT. Use a different JniValueManager implementation that supports Native AOT.")] + [RequiresUnreferencedCode ("This JniValueManager implementation is not compatible with Native AOT. Use a different JniValueManager implementation that supports Native AOT.")] + public abstract partial class ReflectionJniValueManager : JniValueManager + { + public override void ActivatePeer ( + JniObjectReference reference, + Type type, + ConstructorInfo cinfo, + object?[]? argumentValues) + { + try { + var self = (IJavaPeerable) RuntimeHelpers.GetUninitializedObject (type); + self.SetPeerReference (reference); + cinfo.Invoke (self, argumentValues); + } catch (Exception e) { + var m = string.Format ( + CultureInfo.InvariantCulture, + "Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", + reference, + GetJniIdentityHashCode (reference).ToString ("x", CultureInfo.InvariantCulture), + JniEnvironment.Types.GetJniTypeNameFromInstance (reference), + type.FullName); + Debug.WriteLine (m); + + throw new NotSupportedException (m, e); + } + } + + protected override void ConstructPeerCore (IJavaPeerable peer, ref JniObjectReference reference, JniObjectReferenceOptions options) + { + if (peer == null) + throw new ArgumentNullException (nameof (peer)); + + var newRef = peer.PeerReference; + if (newRef.IsValid) { + JniObjectReference.Dispose (ref reference, options); + + // Activation? See ManagedPeer.Construct, CreatePeer + // Instance was already added, don't add again + if (peer.JniManagedPeerState.HasFlag (JniManagedPeerStates.Activatable)) { + return; + } + var orig = newRef; + newRef = orig.NewGlobalRef (); + JniObjectReference.Dispose (ref orig); + } else if (options == JniObjectReferenceOptions.None) { + // `reference` is likely *InvalidJniObjectReference, and can't be touched + return; + } else if (!reference.IsValid) { + throw new ArgumentException ("JNI Object Reference is invalid.", nameof (reference)); + } else { + newRef = reference; + + if ((options & JniObjectReferenceOptions.Copy) == JniObjectReferenceOptions.Copy) { + newRef = reference.NewGlobalRef (); + } + + JniObjectReference.Dispose (ref reference, options); + } + + peer.SetPeerReference (newRef); + peer.SetJniIdentityHashCode (JniSystem.IdentityHashCode (newRef)); + + var o = Runtime.ObjectReferenceManager; + if (o.LogGlobalReferenceMessages) { + o.WriteGlobalReferenceLine ("Created PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}, Java.Type={4}", + newRef.ToString (), + peer.JniIdentityHashCode.ToString ("x"), + RuntimeHelpers.GetHashCode (peer).ToString ("x"), + peer.GetType ().FullName, + JniEnvironment.Types.GetJniTypeNameFromInstance (newRef)); + } + + if ((options & DoNotRegisterTarget) != DoNotRegisterTarget) { + AddPeer (peer); + } + } + + // This base method implementation is NOT reachable in trimmable typemap - it is featureswitch guarded + public override IJavaPeerable? CreatePeer ( + ref JniObjectReference reference, + JniObjectReferenceOptions transfer, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType) + { + EnsureNotDisposed (); + + if (!reference.IsValid) { + return null; + } + + targetType = targetType ?? typeof (JavaObject); + targetType = GetPeerType (targetType); + + if (!typeof (IJavaPeerable).IsAssignableFrom (targetType)) + throw new ArgumentException ($"targetType `{targetType.AssemblyQualifiedName}` must implement IJavaPeerable!", nameof (targetType)); + + var targetSig = Runtime.TypeManager.GetTypeSignature (targetType); + if (!targetSig.IsValid || targetSig.SimpleReference == null) { + throw new ArgumentException ($"Could not determine Java type corresponding to `{targetType.AssemblyQualifiedName}`.", nameof (targetType)); + } + + var refClass = JniEnvironment.Types.GetObjectClass (reference); + JniObjectReference targetClass; + try { + targetClass = JniEnvironment.Types.FindClass (targetSig.SimpleReference); + } catch (Exception e) { + JniObjectReference.Dispose (ref refClass); + throw new ArgumentException ($"Could not find Java class `{targetSig.SimpleReference}`.", + nameof (targetType), + e); + } + + if (!JniEnvironment.Types.IsAssignableFrom (refClass, targetClass)) { + JniObjectReference.Dispose (ref refClass); + JniObjectReference.Dispose (ref targetClass); + return null; + } + + JniObjectReference.Dispose (ref targetClass); + + var peer = CreatePeerInstance (ref refClass, targetType, ref reference, transfer); + if (peer == null) { + throw new NotSupportedException (string.Format ("Could not find an appropriate constructable wrapper type for Java type '{0}', targetType='{1}'.", + JniEnvironment.Types.GetJniTypeNameFromInstance (reference), targetType)); + } + peer.SetJniManagedPeerState (peer.JniManagedPeerState | JniManagedPeerStates.Replaceable); + return peer; + } + + static Type GetPeerType (Type type) + { + if (type == typeof (object)) + return typeof (JavaObject); + if (type == typeof (IJavaPeerable)) + return typeof (JavaObject); + if (type == typeof (Exception)) + return typeof (JavaException); + return type; + } + + IJavaPeerable? CreatePeerInstance ( + ref JniObjectReference klass, + Type targetType, + ref JniObjectReference reference, + JniObjectReferenceOptions transfer) + { + var jniTypeName = JniEnvironment.Types.GetJniTypeNameFromClass (klass); + + while (jniTypeName != null) { + JniTypeSignature sig; + if (!JniTypeSignature.TryParse (jniTypeName, out sig)) + return null; + + Type? type = GetTypeAssignableTo (sig, targetType); + if (type != null) { + var peer = TryCreatePeerInstance (ref reference, transfer, type); + + if (peer != null) { + JniObjectReference.Dispose (ref klass); + return peer; + } + } + + var super = JniEnvironment.Types.GetSuperclass (klass); + jniTypeName = super.IsValid + ? JniEnvironment.Types.GetJniTypeNameFromClass (super) + : null; + + JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose); + klass = super; + } + JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose); + + return TryCreatePeerInstance (ref reference, transfer, targetType); + + Type? GetTypeAssignableTo (JniTypeSignature sig, Type targetType) + { + foreach (var t in Runtime.TypeManager.GetTypes (sig)) { + if (targetType.IsAssignableFrom (t)) { + return t; + } + } + return null; + } + } + + IJavaPeerable? TryCreatePeerInstance ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type type) + { + type = Runtime.TypeManager.GetInvokerType (type) ?? type; + + var self = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (type); + self.SetJniManagedPeerState (JniManagedPeerStates.Replaceable | JniManagedPeerStates.Activatable); + + var constructed = false; + try { + constructed = TryConstructPeer (self, ref reference, options, type); + } finally { + if (!constructed) { + GC.SuppressFinalize (self); + self = null; + } + } + return self; + } + + const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + static readonly Type ByRefJniObjectReference = typeof (JniObjectReference).MakeByRefType (); + static readonly Type[] JIConstructorSignature = new Type [] { ByRefJniObjectReference, typeof (JniObjectReferenceOptions) }; + + protected virtual bool TryConstructPeer ( + IJavaPeerable self, + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type type) + { + var c = type.GetConstructor (ActivationConstructorBindingFlags, null, JIConstructorSignature, null); + if (c != null) { + var args = new object[] { + reference, + options, + }; + c.Invoke (self, args); + reference = (JniObjectReference) args [0]; + JniObjectReference.Dispose (ref reference, options); + return true; + } + return false; + } + + protected override object? CreateValueCore ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + if (!reference.IsValid) + return null; + + if (targetType != null && typeof (IJavaPeerable).IsAssignableFrom (targetType)) { + return JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType); + } + + var boxed = PeekBoxedObject (reference); + if (boxed != null) { + JniObjectReference.Dispose (ref reference, options); + if (targetType != null) + return Convert.ChangeType (boxed, targetType); + return boxed; + } + + targetType = targetType ?? GetRuntimeType (reference); + if (targetType == null) { + // Let's hope this is an IJavaPeerable! + return JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType); + } + var marshaler = GetValueMarshaler (targetType); + return marshaler.CreateValue (ref reference, options, targetType); + } + + [return: MaybeNull] + protected override T CreateValueCore<[DynamicallyAccessedMembers (Constructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + if (!reference.IsValid) { + #pragma warning disable 8653 + return default (T); + #pragma warning restore 8653 + } + + if (targetType != null && !typeof (T).IsAssignableFrom (targetType)) + throw new ArgumentException ( + string.Format ("Requested runtime '{0}' value of '{1}' is not compatible with requested compile-time type T of '{2}'.", + nameof (targetType), + targetType, + typeof (T)), + nameof (targetType)); + + var boxed = PeekBoxedObject (reference); + if (boxed != null) { + JniObjectReference.Dispose (ref reference, options); + return (T) Convert.ChangeType (boxed, targetType ?? typeof (T)); + } + + targetType = targetType ?? typeof (T); + + if (typeof (IJavaPeerable).IsAssignableFrom (targetType)) { + #pragma warning disable CS8600,CS8601 // Possible null reference assignment. + return (T) JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType); + #pragma warning restore CS8600,CS8601 // Possible null reference assignment. + } + + var marshaler = GetValueMarshaler (); + return marshaler.CreateGenericValue (ref reference, options, targetType); + } + + object? PeekBoxedObject (JniObjectReference reference) + { + var t = PeekPeer (reference); + if (t == null) + return null; + object? r; + return TryUnboxPeerObject (t, out r) + ? r + : null; + } + + protected override object? GetValueCore ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + + if (!reference.IsValid) + return null; + + var existing = PeekValue (reference); + if (existing != null && (targetType == null || targetType.IsAssignableFrom (existing.GetType ()))) { + JniObjectReference.Dispose (ref reference, options); + return existing; + } + + if (targetType != null && typeof (IJavaPeerable).IsAssignableFrom (targetType)) { + return JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType); + } + + targetType = targetType ?? GetRuntimeType (reference); + if (targetType == null) { + // Let's hope this is an IJavaPeerable! + return JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType); + } + var marshaler = GetValueMarshaler (targetType); + return marshaler.CreateValue (ref reference, options, targetType); + } + + + [return: MaybeNull] + protected override T GetValueCore<[DynamicallyAccessedMembers (Constructors)] T> ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) + { + EnsureNotDisposed (); + if (!reference.IsValid) { + #pragma warning disable 8653 + return default (T); + #pragma warning restore 8653 + } + + if (targetType != null && !typeof (T).IsAssignableFrom (targetType)) + throw new ArgumentException ( + string.Format ("Requested runtime '{0}' value of '{1}' is not compatible with requested compile-time type T of '{2}'.", + nameof (targetType), + targetType, + typeof (T)), + nameof (targetType)); + + targetType = targetType ?? typeof (T); + + var existing = PeekValue (reference); + if (existing != null && (targetType == null || targetType.IsAssignableFrom (existing.GetType ()))) { + JniObjectReference.Dispose (ref reference, options); + return (T) existing; + } + + if (typeof (IJavaPeerable).IsAssignableFrom (targetType)) { + #pragma warning disable CS8600,CS8601 // Possible null reference assignment. + return (T) JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType); + #pragma warning restore CS8600,CS8601 // Possible null reference assignment. + } + + var marshaler = GetValueMarshaler (); + return marshaler.CreateGenericValue (ref reference, options, targetType); + } + + Dictionary Marshalers = new Dictionary (); + + protected override JniValueMarshaler GetValueMarshalerCore () + { + EnsureNotDisposed (); + + var m = GetValueMarshaler (typeof (T)); + var r = m as JniValueMarshaler; + if (r != null) + return r; + lock (Marshalers) { + if (!Marshalers.TryGetValue (typeof (T), out var d)) + Marshalers.Add (typeof (T), d = new DelegatingValueMarshaler (m)); + return (JniValueMarshaler) d; + } + } + + protected override JniValueMarshaler GetValueMarshalerCore (Type type) + { + EnsureNotDisposed (); + + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (type.ContainsGenericParameters) + throw new ArgumentException ("Generic type definitions are not supported.", nameof (type)); + + var marshalerAttr = type.GetCustomAttribute (); + if (marshalerAttr != null) + return (JniValueMarshaler) Activator.CreateInstance (marshalerAttr.MarshalerType)!; + + if (typeof (IJavaPeerable) == type) + return JavaPeerableValueMarshaler.Instance; + + if (typeof (void) == type) + return VoidValueMarshaler.Instance; + + foreach (var marshaler in JniBuiltinMarshalers.Value) { + if (marshaler.Key == type) + return marshaler.Value; + } + + + var listType = GetListType (type); + if (listType != null) { + var elementType = listType.GenericTypeArguments [0]; + if (elementType.IsValueType) { + foreach (var marshaler in JniPrimitiveArrayMarshalers.Value) { + if (type.IsAssignableFrom (marshaler.Key)) + return marshaler.Value; + } + } + + return GetObjectArrayMarshaler (elementType); + } + + if (typeof (IJavaPeerable).IsAssignableFrom (type)) { + return JavaPeerableValueMarshaler.Instance; + } + + return ProxyValueMarshaler.Instance; + } + + protected override JniObjectReference CreateLocalObjectReferenceArgumentCore ( + Type type, + object? value) + { + EnsureNotDisposed (); + var marshaler = GetValueMarshaler (type); + var state = marshaler.CreateObjectReferenceArgumentState (value); + try { + if (!state.ReferenceValue.IsValid) { + return new JniObjectReference (); + } + return state.ReferenceValue.NewLocalRef (); + } finally { + marshaler.DestroyArgumentState (value, ref state); + } + } + + static Type? GetListType (Type type) + { + foreach (var iface in type.GetInterfaces ().Concat (new [] { type })) { + if (typeof (IList<>).IsAssignableFrom (iface.IsGenericType ? iface.GetGenericTypeDefinition () : iface)) + return iface; + } + return null; + } + + static JniValueMarshaler GetObjectArrayMarshaler (Type elementType) + { + Func indirect = GetObjectArrayMarshalerHelper; + var reifiedMethodInfo = indirect.Method.GetGenericMethodDefinition ().MakeGenericMethod (elementType); + Func direct = (Func) Delegate.CreateDelegate (typeof (Func), reifiedMethodInfo); + return direct (); + } + + static JniValueMarshaler GetObjectArrayMarshalerHelper () + { + return JavaObjectArray.Instance; + } + + } + + sealed class VoidValueMarshaler : JniValueMarshaler { + + internal static VoidValueMarshaler Instance = new VoidValueMarshaler (); + + public override Type MarshalType { + get {return typeof (void);} + } + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + throw new NotSupportedException (); + } + + public override JniValueMarshalerState CreateObjectReferenceArgumentState (object? value, ParameterAttributes synchronize) + { + throw new NotSupportedException (); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + throw new NotSupportedException (); + } + } + } + + [RequiresUnreferencedCode ("Uses unconstrained reflection.")] + sealed class JavaPeerableValueMarshaler : JniValueMarshaler { + + internal static JavaPeerableValueMarshaler Instance = new JavaPeerableValueMarshaler (); + + [return: MaybeNull] + public override IJavaPeerable? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + var jvm = JniEnvironment.Runtime; + var marshaler = jvm.ValueManager.GetValueMarshaler (targetType ?? typeof(IJavaPeerable)); + if (marshaler != Instance) + return (IJavaPeerable) marshaler.CreateValue (ref reference, options, targetType)!; + return jvm.ValueManager.CreatePeer (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull]IJavaPeerable? value, ParameterAttributes synchronize) + { + if (value == null || !value.PeerReference.IsValid) + return new JniValueMarshalerState (); + var r = value.PeerReference.NewLocalRef (); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState ([MaybeNull]IJavaPeerable? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + var r = CreateIntermediaryExpressionFromManagedExpression (context, sourceValue); + var h = Expression.Variable (typeof (IntPtr), sourceValue.Name + "_handle"); + context.LocalVariables.Add (h); + context.CreationStatements.Add (Expression.Assign (h, Expression.Property (r, "Handle"))); + + return h; + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + Expression CreateIntermediaryExpressionFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + var r = Expression.Variable (typeof (JniObjectReference), sourceValue.Name + "_ref"); + context.LocalVariables.Add (r); + context.CreationStatements.Add ( + Expression.IfThenElse ( + test: Expression.Equal (Expression.Constant (null), sourceValue), + ifTrue: Expression.Assign (r, Expression.New (typeof (JniObjectReference))), + ifFalse: Expression.Assign (r, Expression.Property (Expression.Convert (sourceValue, typeof (IJavaPeerable)), "PeerReference")))); + + return r; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return ReturnObjectReferenceToJni (context, sourceValue.Name, CreateIntermediaryExpressionFromManagedExpression (context, sourceValue)); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + targetType ??= typeof (object); + + var r = Expression.Variable (targetType, sourceValue.Name + "_val"); + context.LocalVariables.Add (r); + context.CreationStatements.Add ( + Expression.Assign (r, + Expression.Call ( + context.ValueManager ?? Expression.Property (context.Runtime, "ValueManager"), + "GetValue", + new[]{targetType}, + sourceValue))); + return r; + } + } + + sealed class DelegatingValueMarshaler : JniValueMarshaler + { + + JniValueMarshaler ValueMarshaler; + + public DelegatingValueMarshaler (JniValueMarshaler valueMarshaler) + { + ValueMarshaler = valueMarshaler; + } + + [return: MaybeNull] + public override T CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return (T) ValueMarshaler.CreateValue (ref reference, options, targetType ?? typeof (T))!; + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull]T value, ParameterAttributes synchronize) + { + return ValueMarshaler.CreateObjectReferenceArgumentState (value, synchronize); + } + + public override void DestroyGenericArgumentState ([AllowNull]T value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + ValueMarshaler.DestroyArgumentState (value, ref state, synchronize); + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + return ValueMarshaler.CreateParameterFromManagedExpression (context, sourceValue, synchronize); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + return ValueMarshaler.CreateParameterToManagedExpression (context, sourceValue, synchronize, targetType); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + return ValueMarshaler.CreateReturnValueFromManagedExpression (context, sourceValue); + } + } + + [RequiresUnreferencedCode ("Uses unconstrained reflection.")] + sealed class ProxyValueMarshaler : JniValueMarshaler { + internal static ProxyValueMarshaler Instance = new ProxyValueMarshaler (); + + [return: MaybeNull] + public override object? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + var jvm = JniEnvironment.Runtime; + + if (targetType == null || targetType == typeof (object)) { + targetType = jvm.ValueManager.GetRuntimeType (reference); + } + if (targetType != null) { + var vm = jvm.ValueManager.GetValueMarshaler (targetType); + if (vm != Instance) { + return vm.CreateValue (ref reference, options, targetType)!; + } + } + + var target = jvm.ValueManager.PeekValue (reference); + if (target != null) { + JniObjectReference.Dispose (ref reference, options); + return target; + } + // Punt! Hope it's a java.lang.Object + return jvm.ValueManager.CreatePeer (ref reference, options, targetType); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull]object? value, ParameterAttributes synchronize) + { + if (value == null) + return new JniValueMarshalerState (); + + var jvm = JniEnvironment.Runtime; + + var vm = jvm.ValueManager.GetValueMarshaler (value.GetType ()); + if (vm != Instance) { + var s = vm.CreateObjectReferenceArgumentState (value, synchronize); + return new JniValueMarshalerState (s, vm); + } + + var p = JavaProxyObject.GetProxy (value); + return new JniValueMarshalerState (p!.PeerReference.NewLocalRef ()); + } + + public override void DestroyGenericArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var vm = state.Extra as JniValueMarshaler; + if (vm != null) { + vm.DestroyArgumentState (value, ref state, synchronize); + return; + } + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.cs new file mode 100644 index 00000000000..d1fc5fe4555 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.cs @@ -0,0 +1,462 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Java.Interop +{ + [SuppressMessage ("Performance", "CA1823:Avoid unused private fields", Justification = "Fields preserve the unmanaged JavaVM vtable layout.")] + // These fields are populated from native memory and some are only present to preserve the JavaVM vtable layout. +#pragma warning disable CS0169, CS0649 + unsafe struct JavaVMInterface { + IntPtr reserved0; + IntPtr reserved1; + IntPtr reserved2; + + delegate* unmanaged destroyJavaVM; + delegate* unmanaged attachCurrentThread; + delegate* unmanaged detachCurrentThread; + delegate* unmanaged getEnv; + delegate* unmanaged attachCurrentThreadAsDaemon; + + public int DestroyJavaVM (IntPtr javavm) + { + return destroyJavaVM (javavm); + } + + public int AttachCurrentThread (IntPtr javavm, out IntPtr env, ref JavaVMThreadAttachArgs args) + { + fixed (IntPtr* envp = &env) + fixed (JavaVMThreadAttachArgs* argsp = &args) + return attachCurrentThread (javavm, envp, argsp); + } + + public int GetEnv (IntPtr javavm, out IntPtr envptr, int version) + { + fixed (IntPtr* envp = &envptr) + return getEnv (javavm, envp, version); + } + } +#pragma warning restore CS0169, CS0649 + + public enum JniVersion { + // v1_1 = 0x00010001, + v1_2 = 0x00010002, + v1_4 = 0x00010004, + v1_6 = 0x00010006, + } + + struct JavaVMThreadAttachArgs { + public JniVersion version; /* must be >= JNI_VERSION_1_2 */ + public IntPtr name; /* NULL or name of thread as modified UTF-8 str */ + public IntPtr group; /* global ref of a ThreadGroup object, or NULL */ + } + + + partial class JniRuntime { + public partial class CreationOptions { + + public bool TrackIDs {get; set;} + public bool DestroyRuntimeOnDispose {get; set;} + + // Prefer JNIEnv::NewObject() over JNIEnv::AllocObject() + JNIEnv::CallNonvirtualVoidMethod() + [Obsolete ("No longer supported")] + public bool NewObjectRequired {get; set;} + + public JniVersion JniVersion {get; set;} + + public IntPtr InvocationPointer {get; set;} + public IntPtr EnvironmentPointer {get; set;} + + public JniObjectReference ClassLoader {get; set;} + [Obsolete ("No longer supported; Class.forName() is now used instead")] + public IntPtr ClassLoader_LoadClass_id {get; set;} + + public JniObjectReferenceManager? ObjectReferenceManager {get; set;} + public JniTypeManager? TypeManager {get; set;} + public string? JvmLibraryPath {get; set;} + public bool JniAddNativeMethodRegistrationAttributePresent { get; set; } = true; + + public CreationOptions () + { + JniVersion = JniVersion.v1_2; + } + } + } + + partial class JniRuntime { + + interface ISetRuntime { + void OnSetRuntime (JniRuntime runtime); + } + } + + public partial class JniRuntime : IDisposable + { + const int JNI_OK = 0; + const int JNI_EDETACHED = -2; + const int JNI_EVERSION = -3; + + static Dictionary Runtimes = new Dictionary (); + + public static IEnumerable GetRegisteredRuntimes () + { + return Runtimes.Values; + } + + public static JniRuntime? GetRegisteredRuntime (IntPtr invocationPointer) + { + lock (Runtimes) { + return Runtimes.TryGetValue (invocationPointer, out var vm) + ? vm + : null; + } + } + + [Obsolete ("Not sensible/usable at this level, and cannot work on e.g. Android. " + + "Please rethink your structure instead of relying on desktop/JRE-specific runtime helpers.", error: true)] + [SuppressMessage ("Design", "CA1024:Use properties where appropriate", + Justification = "ABI compatibility")] + public static IEnumerable GetAvailableInvocationPointers () + { + throw new NotSupportedException (); + } + + static JniRuntime? current; + public static JniRuntime CurrentRuntime { + get { + var c = current; + if (c != null) + return c; + int count = 0; + lock (Runtimes) { + foreach (var vm in Runtimes.Values) { + if (count++ == 0) + c = vm; + } + } + if (count == 1) { + Interlocked.CompareExchange (ref current, c, null); + return c!; + } + if (count > 1) + throw new NotSupportedException (string.Format ("Found {0} known Java Runtime instances. Don't know which to use. Use JniRuntime.SetCurrent().", count)); + Debug.Assert (count == 0); + throw new NotSupportedException ("No available Java runtime to attach to. Please create one."); + } + } + + public static void SetCurrent (JniRuntime newCurrent) + { + if (newCurrent == null) + throw new ArgumentNullException (nameof (newCurrent)); + lock (Runtimes) { + Runtimes [newCurrent.InvocationPointer] = newCurrent; + } + current = newCurrent; + } + + Dictionary TrackedInstances = new Dictionary (); + + JavaVMInterface Invoker; + bool DestroyRuntimeOnDispose; + + internal JniObjectReference ClassLoader; + + public IntPtr InvocationPointer {get; private set;} + + public JniVersion JniVersion {get; private set;} + + internal bool TrackIDs {get; private set;} + internal bool JniAddNativeMethodRegistrationAttributePresent { get; } + + protected JniRuntime (CreationOptions options) + { + if (options == null) + throw new ArgumentNullException (nameof (options)); + if (options.InvocationPointer == IntPtr.Zero && options.EnvironmentPointer == IntPtr.Zero) + throw new ArgumentException ("Need either options.InvocationPointer or options.EnvironmentPointer!", nameof (options)); + + TrackIDs = options.TrackIDs; + DestroyRuntimeOnDispose = options.DestroyRuntimeOnDispose; + JniAddNativeMethodRegistrationAttributePresent = options.JniAddNativeMethodRegistrationAttributePresent; + + JniVersion = options.JniVersion; + + if (options.InvocationPointer == IntPtr.Zero && options.EnvironmentPointer != IntPtr.Zero) { + InvocationPointer = GetInvocationPointerFromEnvironmentPointer (options.EnvironmentPointer); + } else { + InvocationPointer = options.InvocationPointer; + } + unsafe { + Invoker = *(JavaVMInterface*) Marshal.ReadIntPtr (InvocationPointer); + } + + SetValueManager (options); + + ObjectReferenceManager = SetRuntime (options.ObjectReferenceManager ?? throw new NotSupportedException ($"Please set {nameof (CreationOptions)}.{nameof (options.ObjectReferenceManager)}!")); + TypeManager = SetRuntime (options.TypeManager ?? throw new NotSupportedException ($"Please set {nameof (CreationOptions)}.{nameof (options.TypeManager)}!")); + + if (Interlocked.CompareExchange (ref current, this, null) != null) { + Debug.WriteLine ("WARNING: More than one JniRuntime instance created. This is DOOMED TO FAIL."); + } + + lock (Runtimes) { + Runtimes [InvocationPointer] = this; + } + + var envp = options.EnvironmentPointer; + if (envp == IntPtr.Zero && + Invoker.GetEnv (InvocationPointer, out envp, (int) JniVersion) != JNI_OK && + (envp = _AttachCurrentThread ()) == IntPtr.Zero) { + // Shouldn't be reached, as _AttachCurrentThread() throws + throw new InvalidOperationException ("Could not obtain JNIEnv* value!"); + } + var env = new JniEnvironmentInfo (envp, this); + JniEnvironment.SetEnvironmentInfo (env); + + ClassLoader = options.ClassLoader; + if (ClassLoader.IsValid) { + ClassLoader = ClassLoader.NewGlobalRef (); + } else { + using (var t = new JniType ("java/lang/ClassLoader")) { + var m = t.GetStaticMethod ("getSystemClassLoader", "()Ljava/lang/ClassLoader;"); + var loader = JniEnvironment.StaticMethods.CallStaticObjectMethod (t.PeerReference, m); + ClassLoader = loader.NewGlobalRef (); + JniObjectReference.Dispose (ref loader); + } + } + +#if !XA_JI_EXCLUDE + if (RuntimeFeature.ManagedPeerNativeRegistration) { + InitManagedPeer (); + } + + [UnconditionalSuppressMessage ("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The code is only executed when the feature is explicitly enabled.")] + static void InitManagedPeer () + { + ManagedPeer.Init (); + } +#endif // !XA_JI_EXCLUDE + } + + static unsafe IntPtr GetInvocationPointerFromEnvironmentPointer (IntPtr envp) + { + IntPtr vm = IntPtr.Zero; +#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + if (JniNativeMethods.GetJavaVM (envp, &vm) is int r && + r != JNI_OK) { + throw new InvalidOperationException ($"Could not obtain JavaVM* from JNIEnv*; JNIEnv::GetJavaVM() returned {r}!"); + } +#elif FEATURE_JNIENVIRONMENT_JI_PINVOKES + if (NativeMethods.java_interop_jnienv_get_java_vm (envp, out vm) is int r && + r != JNI_OK) { + throw new InvalidOperationException ($"Could not obtain JavaVM* from JNIEnv*; JNIEnv::GetJavaVM() returned {r}!"); + } +#else // !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES + throw new NotSupportedException ("Cannot obtain JavaVM* from JNIEnv*! " + + "Rebuild with FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS or FEATURE_JNIENVIRONMENT_JI_PINVOKES set!"); +#endif // !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES + return vm; + } + + T SetRuntime (T value) + where T : class, ISetRuntime + { + if (value == null) + throw new NotSupportedException (); + + value.OnSetRuntime (this); + return value; + } + + partial void SetValueManager (CreationOptions options); + + ~JniRuntime () + { + Dispose (false); + } + + public virtual string? GetCurrentManagedThreadName () + { + return null; + } + + public virtual string? GetCurrentManagedThreadStackTrace (int skipFrames = 0, bool fNeedFileInfo = false) + { + return null; + } + + public virtual void FailFast (string? message) + { + var m = typeof (Environment).GetMethod ("FailFast"); + + if (m is null) + Environment.Exit (1); + + m!.Invoke (null, new object?[]{ message }); + } + + public override string ToString () + { + return string.Format ("{0}(0x{1})", GetType ().FullName, InvocationPointer.ToString ("x")); + } + + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose (bool disposing) + { + if (InvocationPointer == IntPtr.Zero) + return; + + Interlocked.CompareExchange (ref current, null, this); + + lock (Runtimes) { + if (Runtimes.TryGetValue (InvocationPointer, out var vm) && vm == this) { + Runtimes.Remove (InvocationPointer); + } + } + + if (disposing) { + JniObjectReference.Dispose (ref ClassLoader); + + ClearTrackedReferences (); + ValueManager.Dispose (); + TypeManager.Dispose (); + ObjectReferenceManager.Dispose (); + + var environments = JniEnvironment.Info.Values; + for (int i = 0; i < environments.Count; ++i) { + var e = environments [i]; + if (e.Runtime != this) + continue; + environments [i].Dispose (); + } + } + + if (DestroyRuntimeOnDispose) { + DestroyRuntime (); + } + InvocationPointer = IntPtr.Zero; + Invoker = default (JavaVMInterface); + } + + public void AttachCurrentThread (string? name = null, JniObjectReference group = default (JniObjectReference)) + { + var jnienv = _AttachCurrentThread (name, group); + JniEnvironment.SetEnvironmentPointer (jnienv, this); + } + + internal IntPtr _AttachCurrentThread (string? name = null, JniObjectReference group = default (JniObjectReference)) + { + AssertValid (); + var threadArgs = new JavaVMThreadAttachArgs () { + version = JniVersion, + }; + try { + if (name != null) + threadArgs.name = Marshal.StringToHGlobalAnsi (name); + if (group.IsValid) + threadArgs.group = group.Handle; + IntPtr jnienv; + int r = Invoker.AttachCurrentThread (InvocationPointer, out jnienv, ref threadArgs); + if (r != JNI_OK) + throw new NotSupportedException ("AttachCurrentThread returned " + r.ToString ()); + return jnienv; + } finally { + Marshal.FreeHGlobal (threadArgs.name); + } + } + + void AssertValid () + { + if (InvocationPointer == IntPtr.Zero) + throw new ObjectDisposedException (nameof (JniRuntime)); + } + + public void DestroyRuntime () + { + AssertValid (); + Invoker.DestroyJavaVM (InvocationPointer); + } + + public virtual Exception? GetExceptionForThrowable (ref JniObjectReference reference, JniObjectReferenceOptions options) + { + return ValueManager.GetValue (ref reference, options); + } + + public int GlobalReferenceCount { + get {return ObjectReferenceManager.GlobalReferenceCount;} + } + + public int WeakGlobalReferenceCount { + get {return ObjectReferenceManager.WeakGlobalReferenceCount;} + } + + public JniObjectReferenceManager ObjectReferenceManager {get; private set;} + public JniTypeManager TypeManager {get; private set;} + + internal void Track (JniType value) + { + lock (TrackedInstances) { + if (!TrackedInstances.ContainsKey (value.PeerReference.Handle)) + TrackedInstances [value.PeerReference.Handle] = value; + } + } + + internal void UnTrack (IntPtr key) + { + lock (TrackedInstances) { + if (TrackedInstances.ContainsKey (key)) + TrackedInstances.Remove (key); + } + } + + void ClearTrackedReferences () + { + List values; + lock (TrackedInstances) { + values = new List (TrackedInstances.Values); + TrackedInstances.Clear (); + } + + foreach (var d in values) + d.Dispose (); + } + + public virtual bool ExceptionShouldTransitionToJni (Exception e) + { + return !Debugger.IsAttached; + } + } + + partial class JniRuntime { + + public virtual void OnEnterMarshalMethod () + { + ValueManager.WaitForGCBridgeProcessing (); + } + + public virtual void OnUserUnhandledException (ref JniTransition transition, Exception e) + { + transition.SetPendingException (e); + Debugger.BreakForUserUnhandledException (e); + } + + public virtual void RaisePendingException (Exception pendingException) + { + JniEnvironment.Exceptions.Throw (pendingException); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs new file mode 100644 index 00000000000..073e8fb0be7 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs @@ -0,0 +1,81 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; + +using Java.Interop.Expressions; + +namespace Java.Interop { + + sealed class JniStringValueMarshaler : JniValueMarshaler { + + internal static readonly JniStringValueMarshaler Instance = new JniStringValueMarshaler (); + + public override string? CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType) + { + return JniEnvironment.Strings.ToString (ref reference, options, targetType ?? typeof (string)); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull]string? value, ParameterAttributes synchronize) + { + var r = JniEnvironment.Strings.NewString (value); + return new JniValueMarshalerState (r); + } + + public override void DestroyGenericArgumentState (string? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + var r = state.ReferenceValue; + JniObjectReference.Dispose (ref r); + state = new JniValueMarshalerState (); + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + Func m = JniEnvironment.Strings.NewString; + + var obj = Expression.Variable (typeof (JniObjectReference), sourceValue.Name + "_ref"); + var hdl = Expression.Variable (MarshalType, sourceValue.Name + "_handle"); + context.LocalVariables.Add (obj); + context.LocalVariables.Add (hdl); + context.CreationStatements.Add (Expression.Assign (obj, Expression.Call (m.GetMethodInfo (), sourceValue))); + context.CreationStatements.Add (Expression.Assign (hdl, Expression.Property (obj, "Handle"))); + context.CleanupStatements.Add (DisposeObjectReference (obj)); + return hdl; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + Func m = JniEnvironment.Strings.NewString; + + var obj = Expression.Variable (typeof (JniObjectReference), sourceValue.Name + "_ref"); + context.LocalVariables.Add (obj); + context.CreationStatements.Add (Expression.Assign (obj, Expression.Call (m.GetMethodInfo (), sourceValue))); + context.CleanupStatements.Add (DisposeObjectReference (obj)); + return ReturnObjectReferenceToJni (context, sourceValue.Name, obj); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) + { + Func m = JniEnvironment.Strings.ToString; + + targetType ??= typeof (object); + + var value = Expression.Variable (targetType, sourceValue.Name + "_val"); + context.LocalVariables.Add (value); + context.CreationStatements.Add (Expression.Assign (value, Expression.Call (m.GetMethodInfo (), sourceValue))); + + return value; + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniSystem.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniSystem.cs new file mode 100644 index 00000000000..c15324730c4 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniSystem.cs @@ -0,0 +1,23 @@ +#nullable enable + +using System; + +namespace Java.Interop +{ + static class JniSystem { + static JniType? _typeRef; + static JniType TypeRef { + get {return JniType.GetCachedJniType (ref _typeRef, "java/lang/System");} + } + + static JniMethodInfo? _identityHashCode; + internal static unsafe int IdentityHashCode (JniObjectReference value) + { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + TypeRef.GetCachedStaticMethod (ref _identityHashCode, "identityHashCode", "(Ljava/lang/Object;)I"); + return JniEnvironment.StaticMethods.CallStaticIntMethod (TypeRef.PeerReference, _identityHashCode, args); + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniTransition.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniTransition.cs new file mode 100644 index 00000000000..cba9d8d6c16 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniTransition.cs @@ -0,0 +1,41 @@ +#nullable enable + +using System; + +namespace Java.Interop { + + public struct JniTransition : IDisposable { + + bool disposed; + Exception? pendingException; + + public JniTransition (IntPtr environmentPointer) + { + disposed = false; + pendingException = null; + + JniEnvironment.SetEnvironmentPointer (environmentPointer); + } + + public void SetPendingException (Exception exception) + { + if (disposed) + throw new ObjectDisposedException (nameof (JniTransition)); + + pendingException = exception; + } + + public void Dispose () + { + if (disposed) + return; + + disposed = true; + + if (pendingException != null) { + JniEnvironment.Runtime.RaisePendingException (pendingException); + pendingException = null; + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniType.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniType.cs new file mode 100644 index 00000000000..204c5630aa2 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniType.cs @@ -0,0 +1,488 @@ +#nullable enable + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +using Java.Interop; + +namespace Java.Interop { + + public sealed class JniType : IDisposable { + + [return: NotNullIfNotNull ("classFileData")] + public static unsafe JniType? DefineClass (string name, JniObjectReference loader, byte[] classFileData) + { + if (classFileData == null) + return null; + fixed (byte* buf = classFileData) { + var lref = JniEnvironment.Types.DefineClass (name, loader, (IntPtr) buf, classFileData.Length); + return new JniType (ref lref, JniObjectReferenceOptions.CopyAndDispose); + } + } + + public static bool TryParse (string name, [NotNullWhen (true)] out JniType? type) + { + if (!JniEnvironment.Types.TryFindClass (name, out var peerReference)) { + type = null; + return false; + } + type = new JniType (ref peerReference, JniObjectReferenceOptions.CopyAndDispose); + return true; + } + + bool registered; + JniObjectReference peerReference; + + public JniObjectReference PeerReference { + get {return peerReference;} + } + + public JniType (string classname) + { + var peer = JniEnvironment.Types.FindClass (classname); + Initialize (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public JniType (ref JniObjectReference peerReference, JniObjectReferenceOptions transfer) + { + Initialize (ref peerReference, transfer); + } + + void Initialize (ref JniObjectReference peerReference, JniObjectReferenceOptions transfer) + { + if (!peerReference.IsValid) + throw new ArgumentException ("handle must be valid.", nameof (peerReference)); + try { + this.peerReference = peerReference.NewGlobalRef (); + } finally { + JniObjectReference.Dispose (ref peerReference, transfer); + } + } + + public string Name { + get { + AssertValid (); + + return JniEnvironment.Types.GetJniTypeNameFromClass (PeerReference)!; + } + } + + public override string ToString () + { + return $"JniType(Name='{Name}' PeerReference={PeerReference})"; + } + + public void RegisterWithRuntime () + { + AssertValid (); + + if (registered) + return; + + JniEnvironment.Runtime.Track (this); + registered = true; + } + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + void AssertValid () + { + if (!PeerReference.IsValid) + throw new ObjectDisposedException (GetType ().FullName); + } + + public static JniType GetCachedJniType ([NotNull] ref JniType? cachedType, string classname) + { + if (cachedType != null && cachedType.PeerReference.IsValid) + return cachedType; + var t = new JniType (classname); + if (Interlocked.CompareExchange (ref cachedType, t, null) != null) + t.Dispose (); + cachedType.RegisterWithRuntime (); + return cachedType; + } + + public void Dispose () + { + if (!PeerReference.IsValid) + return; + if (registered) + JniEnvironment.Runtime.UnTrack (PeerReference.Handle); + if (methods != null) + UnregisterNativeMethods (); + JniObjectReference.Dispose (ref peerReference); + } + + public JniType? GetSuperclass () + { + AssertValid (); + + var lref = JniEnvironment.Types.GetSuperclass (PeerReference); + if (lref.IsValid) + return new JniType (ref lref, JniObjectReferenceOptions.CopyAndDispose); + return null; + } + + public bool IsAssignableFrom (JniType c) + { + AssertValid (); + + if (c == null) + throw new ArgumentNullException (nameof (c)); + if (!c.PeerReference.IsValid) + throw new ArgumentException ("'c' has an invalid handle.", nameof (c)); + + return JniEnvironment.Types.IsAssignableFrom (c.PeerReference, PeerReference); + } + + public bool IsInstanceOfType (JniObjectReference value) + { + AssertValid (); + + return JniEnvironment.Types.IsInstanceOf (value, PeerReference); + } + +#pragma warning disable 0414 + // This isn't used anywhere; it's just present so that the GC won't collect the referenced delegates. + JniNativeMethodRegistration[]? methods; +#pragma warning restore 0414 + + [RequiresDynamicCode ("Native method registration via JniNativeMethodRegistration[] requires dynamic code generation. Use the blittable RegisterNatives(JniObjectReference, ReadOnlySpan) overload with statically-compiled function pointers for Native AOT compatibility.")] + public void RegisterNativeMethods (params JniNativeMethodRegistration[] methods) + { + AssertValid (); + + if (methods == null) + throw new ArgumentNullException (nameof (methods)); + + JniEnvironment.Types.RegisterNatives (PeerReference, methods, checked ((int)methods.Length)); + // Prevents method delegates from being GC'd so long as this type remains + this.methods = methods; + RegisterWithRuntime (); + } + + public void UnregisterNativeMethods () + { + AssertValid (); + + JniEnvironment.Types.UnregisterNatives (PeerReference); + } + + public JniMethodInfo GetConstructor (string signature) + { + AssertValid (); + + return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, "", signature); + } + + public JniMethodInfo GetCachedConstructor ([NotNull] ref JniMethodInfo? cachedMethod, string signature) + { + AssertValid (); + + return GetCachedInstanceMethod (ref cachedMethod, "", signature); + } + + public JniObjectReference AllocObject () + { + AssertValid (); + + return JniEnvironment.Object.AllocObject (PeerReference); + } + + public unsafe JniObjectReference NewObject (JniMethodInfo constructor, JniArgumentValue* @parameters) + { + AssertValid (); + + return JniEnvironment.Object.NewObject (PeerReference, constructor, parameters); + } + + public JniFieldInfo GetInstanceField (string name, string signature) + { + AssertValid (); + + return JniEnvironment.InstanceFields.GetFieldID (PeerReference, name, signature); + } + + public JniFieldInfo GetCachedInstanceField ([NotNull] ref JniFieldInfo? cachedField, string name, string signature) + { + AssertValid (); + + if (cachedField != null && cachedField.IsValid) + return cachedField; + var m = GetInstanceField (name, signature); + if (Interlocked.CompareExchange (ref cachedField, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedField; + } + + public JniFieldInfo GetStaticField (string name, string signature) + { + AssertValid (); + + return JniEnvironment.StaticFields.GetStaticFieldID (PeerReference, name, signature); + } + + public JniFieldInfo GetCachedStaticField ([NotNull] ref JniFieldInfo? cachedField, string name, string signature) + { + AssertValid (); + + if (cachedField != null && cachedField.IsValid) + return cachedField; + var m = GetStaticField (name, signature); + if (Interlocked.CompareExchange (ref cachedField, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedField; + } + + public JniMethodInfo GetInstanceMethod (string name, string signature) + { + AssertValid (); + + return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, name, signature); + } + + internal bool TryGetInstanceMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method) + { + AssertValid (); + + IntPtr thrown; + method = null; + var env = JniEnvironment.EnvironmentPointer; + var id = RawGetMethodID (env, name, signature, out thrown); + if (thrown != IntPtr.Zero) { + JniEnvironment.Exceptions.ExceptionClear (); + JniEnvironment.References.RawDeleteLocalRef (env, thrown); + return false; + } + Debug.Assert (id != IntPtr.Zero); + if (id == IntPtr.Zero) { + // …huh? Should only happen if `thrown != IntPtr.Zero`, handled above. + return false; + } + method = new JniMethodInfo (name, signature, id, isStatic: false); + return true; + } + + IntPtr RawGetMethodID (IntPtr env, string name, string signature, out IntPtr thrown) + { +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES + return NativeMethods.java_interop_jnienv_get_method_id (env, out thrown, PeerReference.Handle, name, signature); +#elif FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + var _name = Marshal.StringToCoTaskMemUTF8 (name); + var _sig = Marshal.StringToCoTaskMemUTF8 (signature); + try { + var id = JniNativeMethods.GetMethodID (env, PeerReference.Handle, _name, _sig); + thrown = JniNativeMethods.ExceptionOccurred (env); + return id; + } + finally { + Marshal.ZeroFreeCoTaskMemUTF8 (_name); + Marshal.ZeroFreeCoTaskMemUTF8 (_sig); + } +#else +#error Unsupported backend +#endif + } + + public JniMethodInfo GetCachedInstanceMethod ([NotNull] ref JniMethodInfo? cachedMethod, string name, string signature) + { + AssertValid (); + + if (cachedMethod != null && cachedMethod.IsValid) + return cachedMethod; + var m = GetInstanceMethod (name, signature); + if (Interlocked.CompareExchange (ref cachedMethod, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedMethod; + } + + public JniMethodInfo GetStaticMethod (string name, string signature) + { + AssertValid (); + + return JniEnvironment.StaticMethods.GetStaticMethodID (PeerReference, name, signature); + } + + internal bool TryGetStaticMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method) + { + AssertValid (); + + IntPtr thrown; + method = null; + var env = JniEnvironment.EnvironmentPointer; + var id = RawGetStaticMethodID (env, name, signature, out thrown); + if (thrown != IntPtr.Zero) { + JniEnvironment.Exceptions.ExceptionClear (); + JniEnvironment.References.RawDeleteLocalRef (env, thrown); + return false; + } + Debug.Assert (id != IntPtr.Zero); + if (id == IntPtr.Zero) { + // …huh? Should only happen if `thrown != IntPtr.Zero`, handled above. + return false; + } + method = new JniMethodInfo (name, signature, id, isStatic: true); + return true; + } + + IntPtr RawGetStaticMethodID (IntPtr env, string name, string signature, out IntPtr thrown) + { +#if FEATURE_JNIENVIRONMENT_JI_PINVOKES + return NativeMethods.java_interop_jnienv_get_static_method_id (env, out thrown, PeerReference.Handle, name, signature); +#elif FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + var _name = Marshal.StringToCoTaskMemUTF8 (name); + var _sig = Marshal.StringToCoTaskMemUTF8 (signature); + try { + var id = JniNativeMethods.GetStaticMethodID (env, PeerReference.Handle, _name, _sig); + thrown = JniNativeMethods.ExceptionOccurred (env); + return id; + } + finally { + Marshal.ZeroFreeCoTaskMemUTF8 (_name); + Marshal.ZeroFreeCoTaskMemUTF8 (_sig); + } +#else +#error Unsupported backend +#endif + } + + public JniMethodInfo GetCachedStaticMethod ([NotNull] ref JniMethodInfo? cachedMethod, string name, string signature) + { + AssertValid (); + + if (cachedMethod != null && cachedMethod.IsValid) + return cachedMethod; + var m = GetStaticMethod (name, signature); + if (Interlocked.CompareExchange (ref cachedMethod, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedMethod; + } + +#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + /// + /// Creates a from a null-terminated UTF-8 class name span. + /// Use with "java/lang/Object"u8 literals to avoid string marshalling overhead. + /// + public JniType (ReadOnlySpan classname) + { + var peer = JniEnvironment.Types.FindClass (classname); + Initialize (ref peer, JniObjectReferenceOptions.CopyAndDispose); + } + + public static JniType GetCachedJniType ([NotNull] ref JniType? cachedType, ReadOnlySpan classname) + { + if (cachedType != null && cachedType.PeerReference.IsValid) + return cachedType; + var t = new JniType (classname); + if (Interlocked.CompareExchange (ref cachedType, t, null) != null) + t.Dispose (); + cachedType.RegisterWithRuntime (); + return cachedType; + } + + public JniMethodInfo GetConstructor (ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, ""u8, signature); + } + + public JniMethodInfo GetCachedConstructor ([NotNull] ref JniMethodInfo? cachedMethod, ReadOnlySpan signature) + { + AssertValid (); + + return GetCachedInstanceMethod (ref cachedMethod, ""u8, signature); + } + + public JniFieldInfo GetInstanceField (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.InstanceFields.GetFieldID (PeerReference, name, signature); + } + + public JniFieldInfo GetCachedInstanceField ([NotNull] ref JniFieldInfo? cachedField, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedField != null && cachedField.IsValid) + return cachedField; + var m = GetInstanceField (name, signature); + if (Interlocked.CompareExchange (ref cachedField, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedField; + } + + public JniFieldInfo GetStaticField (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.StaticFields.GetStaticFieldID (PeerReference, name, signature); + } + + public JniFieldInfo GetCachedStaticField ([NotNull] ref JniFieldInfo? cachedField, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedField != null && cachedField.IsValid) + return cachedField; + var m = GetStaticField (name, signature); + if (Interlocked.CompareExchange (ref cachedField, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedField; + } + + public JniMethodInfo GetInstanceMethod (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, name, signature); + } + + public JniMethodInfo GetCachedInstanceMethod ([NotNull] ref JniMethodInfo? cachedMethod, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedMethod != null && cachedMethod.IsValid) + return cachedMethod; + var m = GetInstanceMethod (name, signature); + if (Interlocked.CompareExchange (ref cachedMethod, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedMethod; + } + + public JniMethodInfo GetStaticMethod (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.StaticMethods.GetStaticMethodID (PeerReference, name, signature); + } + + public JniMethodInfo GetCachedStaticMethod ([NotNull] ref JniMethodInfo? cachedMethod, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedMethod != null && cachedMethod.IsValid) + return cachedMethod; + var m = GetStaticMethod (name, signature); + if (Interlocked.CompareExchange (ref cachedMethod, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedMethod; + } +#endif // FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniTypeSignature.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniTypeSignature.cs new file mode 100644 index 00000000000..743a936e5c2 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniTypeSignature.cs @@ -0,0 +1,212 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Java.Interop +{ + public struct JniTypeSignature : IEquatable + { + public static readonly JniTypeSignature Empty; + + internal bool IsKeyword {get; private set;} + + public string? SimpleReference {get; private set;} + public int ArrayRank {get; private set;} + + public bool IsValid { + get {return SimpleReference != null;} + } + + public string QualifiedReference { + get { + string typename = IsKeyword + ? SimpleReference ?? throw new InvalidOperationException () + : "L" + SimpleReference + ";"; + return ArrayRank == 0 + ? typename + : new string ('[', ArrayRank) + typename; + } + } + + public string Name { + get {return ArrayRank == 0 ? SimpleReference ?? throw new InvalidOperationException (): QualifiedReference;} + } + + public JniTypeSignature (string? simpleReference, int arrayRank = 0, bool keyword = false) + { + if (simpleReference != null) { + if (simpleReference.Length < 1) + throw new ArgumentException ("The empty string is not a valid JNI simple reference.", nameof (simpleReference)); + if (simpleReference.IndexOf ('.') >= 0) + throw new ArgumentException ("JNI type names do not contain '.', they use '/'. Are you sure you're using a JNI type name?", nameof (simpleReference)); + if (simpleReference [0] == '[') + throw new ArgumentException ("To specify an array, use the ArrayRank property.", nameof (simpleReference)); + if (simpleReference [0] == 'L' && simpleReference [simpleReference.Length-1] == ';' ) + throw new ArgumentException ("JNI type references are not supported.", nameof (simpleReference)); + } + + SimpleReference = simpleReference; + ArrayRank = arrayRank; + IsKeyword = keyword; + } + + public JniTypeSignature AddArrayRank (int rank) + { + if (SimpleReference == null) + throw new InvalidOperationException (); + return new JniTypeSignature (SimpleReference, ArrayRank + rank, IsKeyword); + } + + public JniTypeSignature GetPrimitivePeerTypeSignature () + { + if (!IsKeyword) + return this; + switch (SimpleReference) { + case "V": return new JniTypeSignature ("java/lang/Void", ArrayRank); + case "Z": return new JniTypeSignature ("java/lang/Boolean", ArrayRank); + case "B": return new JniTypeSignature ("java/lang/Byte", ArrayRank); + case "C": return new JniTypeSignature ("java/lang/Character", ArrayRank); + case "S": return new JniTypeSignature ("java/lang/Short", ArrayRank); + case "I": return new JniTypeSignature ("java/lang/Integer", ArrayRank); + case "J": return new JniTypeSignature ("java/lang/Long", ArrayRank); + case "F": return new JniTypeSignature ("java/lang/Float", ArrayRank); + case "D": return new JniTypeSignature ("java/lang/Double", ArrayRank); + default: + throw new InvalidOperationException (string.Format ("SimpleReference '{0}' isn't a known keyword reference, yet is a keyword.", SimpleReference)); + } + } + + public static JniTypeSignature Parse (string signature) + { + JniTypeSignature r; + var e = TryParseWithException (signature, out r); + if (e != null) + throw e; + return r; + } + + public static bool TryParse (string signature, [NotNullWhen (true)] out JniTypeSignature result) + { + var e = TryParseWithException (signature, out result); + if (e != null) + return false; + return true; + } + + static Exception? TryParseWithException (string signature, out JniTypeSignature result) + { + result = default (JniTypeSignature); + + if (signature == null) + return new ArgumentNullException (nameof (signature)); + if (signature.Length < 1) + return new ArgumentException ("The empty string is not a valid JNI simple reference.", nameof (signature)); + + int i = 0; + int r = 0; + var n = (string?) null; + var k = false; + while (i < signature.Length && signature [i] == '[') { + i++; + r++; + } + switch (signature [i]) { + case 'B': + case 'C': + case 'D': + case 'I': + case 'F': + case 'J': + case 'S': + case 'Z': + if (signature.Length - i > 1) + n = signature.Substring (i); + else { + n = signature [i].ToString (); + k = true; + } + break; + case 'L': + int s = signature.IndexOf (';', i); + if (s >= i && s != signature.Length-1) + return new ArgumentException ( + string.Format ("Malformed JNI type reference: trailing text after ';' in '{0}'.", signature), + nameof (signature)); + if (i == 0) { + n = s > i + ? signature.Substring (i + 1, s - i - 1) + : signature; + } else { + if (s < i) + return new ArgumentException ( + string.Format ("Malformed JNI type reference; no terminating ';' for type ref: '{0}'.", signature.Substring (i)), + nameof (signature)); + if (s != signature.Length - 1) + return new ArgumentException ( + string.Format ("Malformed jNI type reference: invalid trailing text: '{0}'.", signature.Substring (i)), + nameof (signature)); + n = signature.Substring (i + 1, s - i - 1); + } + break; + default: + if (i != 0) + return new ArgumentException ( + string.Format ("Malformed JNI type reference: found unrecognized char '{0}' in '{1}'.", + signature [i], signature), + nameof (signature)); + n = signature; + break; + } + int bad = n.IndexOfAny (new[]{ '.', ';' }); + if (bad >= 0) + return new ArgumentException ( + string.Format ("Malformed JNI type reference: contains '{0}': {1}", n [bad], signature), + nameof (signature)); + result = new JniTypeSignature (n, r, k); + return null; + } + + public override int GetHashCode () + { + return QualifiedReference.GetHashCode (StringComparison.Ordinal); + } + + public override bool Equals (object? obj) + { + var v = obj as JniTypeSignature?; + if (v.HasValue) + return Equals (v.Value); + return false; + } + + public bool Equals (JniTypeSignature other) + { + return IsKeyword == other.IsKeyword && + SimpleReference == other.SimpleReference && + ArrayRank == other.ArrayRank; + } + + public override string ToString () + { + return string.Format ("JniTypeSignature(TypeName={0} ArrayRank={1} Keyword={2})", SimpleReference, ArrayRank, IsKeyword); + } + + public static bool operator== (JniTypeSignature lhs, JniTypeSignature rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (JniTypeSignature lhs, JniTypeSignature rhs) + { + return !lhs.Equals (rhs); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs new file mode 100644 index 00000000000..6fc4814c543 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs @@ -0,0 +1,40 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] + public sealed class JniTypeSignatureAttribute : Attribute { + + int arrayRank; + + public JniTypeSignatureAttribute (string simpleReference) + { +#if !JCW_ONLY_TYPE_NAMES + JniRuntime.JniTypeManager.AssertSimpleReference (simpleReference, nameof (simpleReference)); +#endif // !JCW_ONLY_TYPE_NAMES + + SimpleReference = simpleReference; + } + + public bool IsKeyword {get; set;} + + public string SimpleReference {get; private set;} + public int ArrayRank { + get {return arrayRank; } + set { + if (value < 0) + throw new ArgumentException ("ArrayRank cannot be less than zero.", nameof (value)); + arrayRank = value; + } + } + + public bool GenerateJavaPeer {get; set;} + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + public Type? InvokerType {get; set;} + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniValueMarshaler.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniValueMarshaler.cs new file mode 100644 index 00000000000..f36e55ea46c --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniValueMarshaler.cs @@ -0,0 +1,272 @@ +#nullable enable + +using System; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; + +using Java.Interop.Expressions; + +namespace Java.Interop.Expressions { + + sealed class VariableCollection : KeyedCollection { + + protected override string GetKeyForItem (ParameterExpression item) + { + return item.Name!; + } + } + + public sealed class JniValueMarshalerContext { + public Expression Runtime {get;} + public Expression? ValueManager {get;} + + public KeyedCollection LocalVariables {get;} = new VariableCollection (); + public Collection CreationStatements {get;} = new Collection (); + public Collection CleanupStatements {get;} = new Collection (); + + public JniValueMarshalerContext (Expression runtime) + : this (runtime, null) + { + } + + public JniValueMarshalerContext (Expression runtime, Expression? vm) + { + Runtime = runtime ?? throw new ArgumentNullException (nameof (runtime)); + ValueManager = vm; + } + } +} + +namespace Java.Interop { + + public struct JniValueMarshalerState : IEquatable { + + public JniArgumentValue JniArgumentValue {get; private set;} + public JniObjectReference ReferenceValue {get; private set;} + public IJavaPeerable? PeerableValue {get; private set;} + public object? Extra {get; private set;} + + [SuppressMessage ("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Existing public API")] + public JniValueMarshalerState (JniArgumentValue jniArgumentValue, object? extra = null) + { + JniArgumentValue = jniArgumentValue; + ReferenceValue = default (JniObjectReference); + PeerableValue = null; + Extra = extra; + } + + [SuppressMessage ("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Existing public API")] + public JniValueMarshalerState (JniObjectReference referenceValue, object? extra = null) + { + JniArgumentValue = new JniArgumentValue (referenceValue); + ReferenceValue = referenceValue; + PeerableValue = null; + Extra = extra; + } + + [SuppressMessage ("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Existing public API")] + public JniValueMarshalerState (IJavaPeerable? peerableValue, object? extra = null) + { + PeerableValue = peerableValue; + ReferenceValue = peerableValue == null ? default (JniObjectReference) : peerableValue.PeerReference; + JniArgumentValue = new JniArgumentValue (ReferenceValue); + Extra = extra; + } + + internal JniValueMarshalerState (JniValueMarshalerState copy, object? extra = null) + { + JniArgumentValue = copy.JniArgumentValue; + ReferenceValue = copy.ReferenceValue; + PeerableValue = copy.PeerableValue; + Extra = extra ?? copy.Extra; + } + + public override int GetHashCode () + { + return JniArgumentValue.GetHashCode (); + } + + public override bool Equals (object? obj) + { + var o = obj as JniValueMarshalerState?; + if (!o.HasValue) + return false; + return Equals (o.Value); + } + + public bool Equals (JniValueMarshalerState other) + { + return JniArgumentValue.Equals (other.JniArgumentValue) && + ReferenceValue.Equals (other.ReferenceValue) && + object.ReferenceEquals (PeerableValue, other.PeerableValue) && + object.ReferenceEquals (Extra, other.Extra); + } + + public static bool operator == (JniValueMarshalerState a, JniValueMarshalerState b) => a.Equals (b); + public static bool operator != (JniValueMarshalerState a, JniValueMarshalerState b) => !a.Equals (b); + + public override string ToString () + { + return string.Format ("JniValueMarshalerState({0}, ReferenceValue={1}, PeerableValue=0x{2}, Extra={3})", + JniArgumentValue.ToString (), + ReferenceValue.ToString (), + RuntimeHelpers.GetHashCode (PeerableValue!).ToString ("x"), + Extra); + } + } + + public abstract class JniValueMarshaler { + internal const string ExpressionRequiresUnreferencedCode = "System.Linq.Expression usage may trim away required code."; + + public virtual bool IsJniValueType { + get {return false;} + } + + static readonly Type IntPtr_type = typeof(IntPtr); + public virtual Type MarshalType { + get {return IntPtr_type;} + } + + public abstract object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType = null); + + public virtual JniValueMarshalerState CreateArgumentState (object? value, ParameterAttributes synchronize = 0) + { + return CreateObjectReferenceArgumentState (value, synchronize); + } + + public abstract JniValueMarshalerState CreateObjectReferenceArgumentState (object? value, ParameterAttributes synchronize = 0); + public abstract void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize = 0); + + internal object? CreateValue ( + IntPtr handle, + Type? targetType) + { + var r = new JniObjectReference (handle); + return CreateValue (ref r, JniObjectReferenceOptions.Copy, targetType); + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public virtual Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize = 0, Type? targetType = null) + { + Func m = CreateValue; + + var self = CreateSelf (context, sourceValue); + + var call = Expression.Call (self, m.GetMethodInfo (), sourceValue, Expression.Constant (targetType, typeof (Type))); + return targetType == null + ? (Expression) call + : Expression.Convert (call, targetType); + } + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + Expression CreateSelf (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + var self = Expression.Variable (GetType (), sourceValue.Name + "_marshaler"); + context.LocalVariables.Add (self); + context.CreationStatements.Add (Expression.Assign (self, Expression.New (GetType ()))); + return self; + } + + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public virtual Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) + { + CreateParameterFromManagedExpression (context, sourceValue, 0); + var s = context.LocalVariables [sourceValue.Name + "_state"]; + return ReturnObjectReferenceToJni (context, sourceValue.Name, Expression.Property (s, "ReferenceValue")); + } + + protected Expression ReturnObjectReferenceToJni (JniValueMarshalerContext context, string? namePrefix, Expression sourceValue) + { + Func m = JniEnvironment.References.NewReturnToJniRef; + var r = Expression.Variable (MarshalType, namePrefix + "_rtn"); + if (context == null) + throw new ArgumentNullException (nameof (context)); + context.LocalVariables.Add (r); + context.CreationStatements.Add ( + Expression.Assign (r, + Expression.Call (m.GetMethodInfo (), sourceValue))); + return r; + } + + delegate void DestroyArgumentStateCb (object value, ref JniValueMarshalerState state, ParameterAttributes synchronize); + + [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] + public virtual Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) + { + Func c = CreateArgumentState; + DestroyArgumentStateCb d = DestroyArgumentState; + + var self = CreateSelf (context, sourceValue); + var state = Expression.Variable (typeof(JniValueMarshalerState), sourceValue.Name + "_state"); + var ret = Expression.Variable (MarshalType, sourceValue.Name + "_val"); + + context.LocalVariables.Add (state); + context.LocalVariables.Add (ret); + context.CreationStatements.Add (Expression.Assign (state, Expression.Call (self, c.GetMethodInfo (), Expression.Convert (sourceValue, typeof (object)), Expression.Constant (synchronize, typeof (ParameterAttributes))))); + context.CreationStatements.Add ( + Expression.Assign (ret, + Expression.Property ( + Expression.Property (state, "ReferenceValue"), + "Handle"))); + context.CleanupStatements.Add (Expression.Call (self, d.GetMethodInfo (), Expression.Convert (sourceValue, typeof (object)), state, Expression.Constant (synchronize))); + + return ret; + } + + delegate void DisposeObjRef (ref JniObjectReference r); + protected static Expression DisposeObjectReference (Expression sourceValue) + { + DisposeObjRef m = JniObjectReference.Dispose; + return Expression.Call (m.GetMethodInfo (), sourceValue); + } + } + + public abstract class JniValueMarshaler : JniValueMarshaler + { + + [return: MaybeNull] + public abstract T CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType = null); + + public virtual JniValueMarshalerState CreateGenericArgumentState ([MaybeNull] T value, ParameterAttributes synchronize = 0) + { + return CreateGenericObjectReferenceArgumentState (value, synchronize); + } + + public abstract JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull] T value, ParameterAttributes synchronize = 0); + public abstract void DestroyGenericArgumentState ([AllowNull] T value, ref JniValueMarshalerState state, ParameterAttributes synchronize = 0); + + public override object? CreateValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type? targetType = null) + { + return CreateGenericValue (ref reference, options, targetType ?? typeof (T)); + } + + public override JniValueMarshalerState CreateArgumentState (object? value, ParameterAttributes synchronize = 0) + { + return CreateGenericArgumentState ((T) value!, synchronize); + } + + public override JniValueMarshalerState CreateObjectReferenceArgumentState (object? value, ParameterAttributes synchronize = 0) + { + return CreateGenericObjectReferenceArgumentState ((T) value!, synchronize); + } + + public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize = 0) + { + DestroyGenericArgumentState ((T) value!, ref state, synchronize); + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/JniValueMarshalerAttribute.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/JniValueMarshalerAttribute.cs new file mode 100644 index 00000000000..717fb30c65f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/JniValueMarshalerAttribute.cs @@ -0,0 +1,38 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace Java.Interop { + + [AttributeUsage (Targets, AllowMultiple=false)] + public class JniValueMarshalerAttribute : Attribute { + const DynamicallyAccessedMemberTypes ParameterlessConstructors = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor; + + const AttributeTargets Targets = + AttributeTargets.Class | AttributeTargets.Enum | + AttributeTargets.Interface | AttributeTargets.Struct | + AttributeTargets.Parameter | AttributeTargets.ReturnValue; + + public JniValueMarshalerAttribute ( + [DynamicallyAccessedMembers (ParameterlessConstructors)] + Type marshalerType) + { + if (marshalerType == null) + throw new ArgumentNullException (nameof (marshalerType)); + if (!typeof (JniValueMarshaler).IsAssignableFrom (marshalerType)) + throw new ArgumentException ( + string.Format ("`{0}` must inherit from JniValueMarshaler!", marshalerType.FullName), + nameof (marshalerType)); + + MarshalerType = marshalerType; + } + + [DynamicallyAccessedMembers (ParameterlessConstructors)] + public Type MarshalerType { + get; + } + } +} + diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/ManagedPeer.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/ManagedPeer.cs new file mode 100644 index 00000000000..d026789a180 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/ManagedPeer.cs @@ -0,0 +1,340 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; + +namespace Java.Interop { + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + [RequiresUnreferencedCode ("Uses reflection to find constructors and invoke them.")] + /* static */ sealed class ManagedPeer : JavaObject { + + internal const string JniTypeName = "net/dot/jni/ManagedPeer"; + internal const DynamicallyAccessedMemberTypes ConstructorsMethodsNestedTypes = Constructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; + + + static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (ManagedPeer)); + + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "ManagedPeer is not compatible with Native AOT; it's only used by reflection-based JniRuntime.JniValueManager implementations.")] + static ManagedPeer () + { + _members.JniPeerType.RegisterNativeMethods ( + new JniNativeMethodRegistration ( + "construct", + ConstructSignature, + new ConstructMarshalMethod (Construct)), + new JniNativeMethodRegistration ( + "registerNativeMembers", + RegisterNativeMembersSignature, + new RegisterMarshalMethod (RegisterNativeMembers)) + ); + } + + ManagedPeer () + { + } + + internal static void Init () + { + // Present so that JniRuntime has _something_ to reference to + // prompt invocation of the static constructor & registration + } + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + const string ConstructSignature = "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V"; + + // TODO: Keep in sync with the code generated by ExportedMemberBuilder + [UnmanagedFunctionPointer (CallingConvention.Winapi)] + delegate void ConstructMarshalMethod (IntPtr jnienv, + IntPtr klass, + IntPtr n_self, + IntPtr n_constructorSignature, + IntPtr n_constructorArguments); + [global::System.Diagnostics.CodeAnalysis.SuppressMessage ( + "Design", + "CA1031:Do not catch general exception types", + Justification = "Exceptions cannot cross a JNI boundary.")] + static void Construct ( + IntPtr jnienv, + IntPtr klass, + IntPtr n_self, + IntPtr n_constructorSignature, + IntPtr n_constructorArguments) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var envp, out var __r)) { + Console.WriteLine ($"error: could not begin ManagedPeer.Construct!"); + return; + } + + try { + var runtime = JniEnvironment.Runtime; + var r_self = new JniObjectReference (n_self); + var self = runtime.ValueManager.PeekPeer (r_self); + if (self != null) { + var state = self.JniManagedPeerState; + if ((state & JniManagedPeerStates.Activatable) != JniManagedPeerStates.Activatable && + (state & JniManagedPeerStates.Replaceable) != JniManagedPeerStates.Replaceable) { + return; + } + } + + if (JniEnvironment.WithinNewObjectScope) { + if (runtime.ObjectReferenceManager.LogGlobalReferenceMessages) { + runtime.ObjectReferenceManager.WriteGlobalReferenceLine ( + "Warning: Skipping managed constructor invocation for PeerReference={0} IdentityHashCode=0x{1} Java.Type={2}. " + + "Please use JniPeerMembers.InstanceMethods.StartCreateInstance() + JniPeerMembers.InstanceMethods.FinishCreateInstance() instead of " + + "JniEnvironment.Object.NewObject().", + r_self, + runtime.ValueManager.GetJniIdentityHashCode (r_self).ToString ("x"), + JniEnvironment.Types.GetJniTypeNameFromInstance (r_self)); + } + return; + } + + var typeSig = new JniTypeSignature (JniEnvironment.Types.GetJniTypeNameFromInstance (r_self)); + var type = GetTypeFromSignature (runtime.TypeManager, typeSig); + + if (type.IsGenericTypeDefinition) { + throw new NotSupportedException ( + "Constructing instances of generic types from Java is not supported, as the type parameters cannot be determined.", + CreateJniLocationException ()); + } + + var ctorSig = JniEnvironment.Strings.ToString (n_constructorSignature) ?? "()V"; + var cinfo = GetConstructor (type, typeSig.SimpleReference!, ctorSig) ?? + throw CreateMissingConstructorException (type, ctorSig); + var pvalues = GetValues (runtime, new JniObjectReference (n_constructorArguments), cinfo); + + if (self != null) { + cinfo.Invoke (self, pvalues); + return; + } + + JniEnvironment.Runtime.ValueManager.ActivatePeer (new JniObjectReference (n_self), type, cinfo, pvalues); + } + catch (Exception e) { + __r?.OnUserUnhandledException (ref envp, e); + } + finally { + JniEnvironment.EndMarshalMethod (ref envp); + } + } + + static Exception CreateMissingConstructorException (Type type, string signature) + { + var message = new StringBuilder (); + message.Append ("Unable to find constructor for type `"); + message.Append (type.FullName); + message.Append ("` with JNI signature `"); + message.Append (signature); + message.Append ("`. Please provide the missing constructor."); + + return new NotSupportedException (message.ToString (), CreateJniLocationException ()); + } + + static Exception CreateJniLocationException () + { + using (var e = new JavaException ()) { + return new JniLocationException (e.ToString ()); + } + } + + static Dictionary ConstructorCache = new Dictionary (); + + static ConstructorInfo? GetConstructor ( + [DynamicallyAccessedMembers (Constructors)] + Type type, + string jniTypeName, + string signature) + { + var ctorCacheKey = jniTypeName + "." + signature; + lock (ConstructorCache) { + if (ConstructorCache.TryGetValue (ctorCacheKey, out var ctor)) { + return ctor; + } + } + + var candidateParameterTypes = GetConstructorCandidateParameterTypes (signature); + if (candidateParameterTypes.Length == 0) { + return CacheConstructor (ctorCacheKey, type.GetConstructor (Array.Empty ())); + } + + var constructors = new List(type.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)); + + // Filter out wrong parameter count + for (int c = constructors.Count; c > 0; --c) { + if (constructors [c-1].GetParameters ().Length != candidateParameterTypes.Length) { + constructors.RemoveAt (c-1); + } + } + + // Filter out mismatched types + for (int c = constructors.Count; c > 0; --c) { + var parameters = constructors [c-1].GetParameters (); + for (int i = 0; i < parameters.Length; ++i) { + if (!candidateParameterTypes [i].Contains (parameters [i].ParameterType)) { + constructors.RemoveAt (c-1); + break; + } + } + } + + if (constructors.Count == 0) + return CacheConstructor (ctorCacheKey, null); + + if (constructors.Count != 1) { + var message = new StringBuilder ($"Found {constructors.Count} constructors matching JNI signature {signature}:") + .Append (Environment.NewLine); + foreach (var c in constructors) { + message.Append (" ").Append (c).Append (Environment.NewLine); + } + throw new NotSupportedException (message.ToString (), CreateJniLocationException ()); + } + + return CacheConstructor (ctorCacheKey, constructors [0]); + } + + static ConstructorInfo? CacheConstructor (string cacheKey, ConstructorInfo? ctor) + { + lock (ConstructorCache) { + if (ConstructorCache.TryGetValue (cacheKey, out var existing)) { + return existing; + } + ConstructorCache.Add (cacheKey, ctor); + } + return ctor; + } + + static List[] GetConstructorCandidateParameterTypes (string signature) + { + var parameterCount = JniMemberSignature.GetParameterCountFromMethodSignature (signature); + if (parameterCount == 0) { + return Array.Empty> (); + } + var typeManager = JniEnvironment.Runtime.TypeManager; + var candidateParameterTypes = new List[parameterCount]; + int i = 0; + foreach (var jniType in JniMemberSignature.GetParameterTypesFromMethodSignature (signature)) { + var possibleTypes = new List (typeManager.GetTypes (jniType)); + if (possibleTypes.Count == 0) { + throw new NotSupportedException ( + $"Could not find System.Type corresponding to Java type `{jniType}` within constructor signature `{signature}`.", + CreateJniLocationException ()); + } + candidateParameterTypes [i++] = possibleTypes; + } + return candidateParameterTypes; + } + + static object?[]? GetValues (JniRuntime runtime, JniObjectReference values, ConstructorInfo cinfo) + { + if (!values.IsValid) + return null; + + var parameters = cinfo.GetParameters (); + + int len = JniEnvironment.Arrays.GetArrayLength (values); + Debug.Assert (len == parameters.Length, + $"Unexpected number of parameter types! Expected {parameters.Length}, got {len}"); + var pvalues = new object? [len]; + for (int i = 0; i < len; ++i) { + var n_value = JniEnvironment.Arrays.GetObjectArrayElement (values, i); + var value = runtime.ValueManager.GetValue (ref n_value, JniObjectReferenceOptions.CopyAndDispose, parameters [i].ParameterType); + pvalues [i] = value; + } + + return pvalues; + } + + const string RegisterNativeMembersSignature = "(Ljava/lang/Class;Ljava/lang/String;)V"; + + [UnmanagedFunctionPointer (CallingConvention.Winapi)] + delegate void RegisterMarshalMethod (IntPtr jnienv, + IntPtr klass, + IntPtr n_nativeClass, + IntPtr n_methods); + [global::System.Diagnostics.CodeAnalysis.SuppressMessage ( + "Design", + "CA1031:Do not catch general exception types", + Justification = "Exceptions cannot cross a JNI boundary.")] + static unsafe void RegisterNativeMembers ( + IntPtr jnienv, + IntPtr klass, + IntPtr n_nativeClass, + IntPtr n_methods) + { + if (!JniEnvironment.BeginMarshalMethod (jnienv, out var envp, out var __r)) { + Console.WriteLine ($"error: could not begin ManagedPeer.RegisterNativePeers!"); + return; + } + + try { + var r_nativeClass = new JniObjectReference (n_nativeClass); +#pragma warning disable CA2000 + var nativeClass = new JniType (ref r_nativeClass, JniObjectReferenceOptions.Copy); +#pragma warning restore CA2000 + + var methodsRef = new JniObjectReference (n_methods); + + var typeSig = new JniTypeSignature (nativeClass.Name); + var type = GetTypeFromSignature (JniEnvironment.Runtime.TypeManager, typeSig); + + int methodsLength = JniEnvironment.Strings.GetStringLength (methodsRef); + var methodsChars = JniEnvironment.Strings.GetStringChars (methodsRef, null); + var methods = new ReadOnlySpan(methodsChars, methodsLength); + try { + JniEnvironment.Runtime.TypeManager.RegisterNativeMembers (nativeClass, type, methods); + } + catch (Exception e) { + throw new NotSupportedException ( + $"Unable to register native members for Java type `{nativeClass.Name}` <=> managed type `{type?.AssemblyQualifiedName}`.", + e); + } + finally { + JniEnvironment.Strings.ReleaseStringChars (methodsRef, methodsChars); + } + + } + catch (Exception e) { + __r?.OnUserUnhandledException (ref envp, e); + } + finally { + JniEnvironment.EndMarshalMethod (ref envp); + } + } + + static Type GetTypeFromSignature (JniRuntime.JniTypeManager typeManager, JniTypeSignature typeSignature, string? context = null) + { + return typeManager.GetType (typeSignature) ?? + throw new NotSupportedException ($"Could not find System.Type corresponding to Java type {typeSignature} {(context == null ? "" : "within `" + context + "`")}."); + } + } + + sealed class JniLocationException : Exception { + + string stackTrace; + + public JniLocationException (string stackTrace) + { + this.stackTrace = stackTrace; + } + + public override string StackTrace { + get { + return stackTrace; + } + } + } +} diff --git a/external/Java.Interop/src/Java.Interop/Java.Interop/RuntimeFeature.cs b/external/Java.Interop/src/Java.Interop/Java.Interop/RuntimeFeature.cs new file mode 100644 index 00000000000..afc27a26d32 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Java.Interop/RuntimeFeature.cs @@ -0,0 +1,18 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Java.Interop +{ + static class RuntimeFeature + { + const bool ManagedPeerNativeRegistrationEnabledByDefault = true; + const string FeatureSwitchPrefix = "Java.Interop.RuntimeFeature."; + + [FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (ManagedPeerNativeRegistration)}")] + [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] + internal static bool ManagedPeerNativeRegistration { get; } = + AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (ManagedPeerNativeRegistration)}", out bool isEnabled) + ? isEnabled + : ManagedPeerNativeRegistrationEnabledByDefault; + } +} diff --git a/external/Java.Interop/src/Java.Interop/Properties/AssemblyInfo.cs b/external/Java.Interop/src/Java.Interop/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..c19d92da43f --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/Properties/AssemblyInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: DefaultDllImportSearchPathsAttribute (DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyCulture ("")] +[assembly: AssemblyTrademark ("Microsoft Corporation")] + +[assembly: InternalsVisibleTo ( + "Java.Interop-Tests, PublicKey=" + + "0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf1" + + "6cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2" + + "814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0" + + "d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b" + + "2c9733db")] diff --git a/external/Java.Interop/src/Java.Interop/PublicAPI.Shipped.txt b/external/Java.Interop/src/Java.Interop/PublicAPI.Shipped.txt new file mode 100644 index 00000000000..e1a94839717 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/PublicAPI.Shipped.txt @@ -0,0 +1,926 @@ +#nullable enable +abstract Java.Interop.JavaArray.Clear() -> void +abstract Java.Interop.JavaArray.CopyTo(T[]! array, int arrayIndex) -> void +abstract Java.Interop.JavaArray.IndexOf(T item) -> int +abstract Java.Interop.JavaArray.this[int index].get -> T +abstract Java.Interop.JavaArray.this[int index].set -> void +abstract Java.Interop.JavaPrimitiveArray.CopyFrom(T[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +abstract Java.Interop.JavaPrimitiveArray.CopyTo(int sourceIndex, T[]! destinationArray, int destinationIndex, int length) -> void +abstract Java.Interop.JniRuntime.JniMarshalMemberBuilder.CreateConstructActivationPeerExpression(System.Reflection.ConstructorInfo! constructor) -> System.Linq.Expressions.Expression!>! +abstract Java.Interop.JniRuntime.JniMarshalMemberBuilder.CreateMarshalToManagedExpression(System.Reflection.MethodInfo! method) -> System.Linq.Expressions.LambdaExpression! +abstract Java.Interop.JniRuntime.JniMarshalMemberBuilder.GetExportedMemberRegistrations(System.Type! declaringType) -> System.Collections.Generic.IEnumerable! +abstract Java.Interop.JniRuntime.JniObjectReferenceManager.GlobalReferenceCount.get -> int +abstract Java.Interop.JniRuntime.JniObjectReferenceManager.WeakGlobalReferenceCount.get -> int +abstract Java.Interop.JniRuntime.JniValueManager.ActivatePeer(Java.Interop.IJavaPeerable? self, Java.Interop.JniObjectReference reference, System.Reflection.ConstructorInfo! cinfo, object?[]? argumentValues) -> void +abstract Java.Interop.JniRuntime.JniValueManager.AddPeer(Java.Interop.IJavaPeerable! value) -> void +abstract Java.Interop.JniRuntime.JniValueManager.CollectPeers() -> void +abstract Java.Interop.JniRuntime.JniValueManager.FinalizePeer(Java.Interop.IJavaPeerable! value) -> void +abstract Java.Interop.JniRuntime.JniValueManager.GetSurfacedPeers() -> System.Collections.Generic.List! +abstract Java.Interop.JniRuntime.JniValueManager.PeekPeer(Java.Interop.JniObjectReference reference) -> Java.Interop.IJavaPeerable? +abstract Java.Interop.JniRuntime.JniValueManager.RemovePeer(Java.Interop.IJavaPeerable! value) -> void +abstract Java.Interop.JniRuntime.JniValueManager.WaitForGCBridgeProcessing() -> void +abstract Java.Interop.JniValueMarshaler.CreateObjectReferenceArgumentState(object? value, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> Java.Interop.JniValueMarshalerState +abstract Java.Interop.JniValueMarshaler.CreateValue(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +abstract Java.Interop.JniValueMarshaler.DestroyArgumentState(object? value, ref Java.Interop.JniValueMarshalerState state, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> void +abstract Java.Interop.JniValueMarshaler.CreateGenericObjectReferenceArgumentState(T value, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> Java.Interop.JniValueMarshalerState +abstract Java.Interop.JniValueMarshaler.CreateGenericValue(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> T +abstract Java.Interop.JniValueMarshaler.DestroyGenericArgumentState(T value, ref Java.Interop.JniValueMarshalerState state, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> void +Java.Interop.Expressions.JniValueMarshalerContext +Java.Interop.Expressions.JniValueMarshalerContext.CleanupStatements.get -> System.Collections.ObjectModel.Collection! +Java.Interop.Expressions.JniValueMarshalerContext.CreationStatements.get -> System.Collections.ObjectModel.Collection! +Java.Interop.Expressions.JniValueMarshalerContext.JniValueMarshalerContext(System.Linq.Expressions.Expression! runtime) -> void +Java.Interop.Expressions.JniValueMarshalerContext.JniValueMarshalerContext(System.Linq.Expressions.Expression! runtime, System.Linq.Expressions.Expression? vm) -> void +Java.Interop.Expressions.JniValueMarshalerContext.LocalVariables.get -> System.Collections.ObjectModel.KeyedCollection! +Java.Interop.Expressions.JniValueMarshalerContext.Runtime.get -> System.Linq.Expressions.Expression! +Java.Interop.Expressions.JniValueMarshalerContext.ValueManager.get -> System.Linq.Expressions.Expression? +Java.Interop.IJavaPeerable +Java.Interop.IJavaPeerable.Disposed() -> void +Java.Interop.IJavaPeerable.DisposeUnlessReferenced() -> void +Java.Interop.IJavaPeerable.Finalized() -> void +Java.Interop.IJavaPeerable.JniIdentityHashCode.get -> int +Java.Interop.IJavaPeerable.JniManagedPeerState.get -> Java.Interop.JniManagedPeerStates +Java.Interop.IJavaPeerable.JniPeerMembers.get -> Java.Interop.JniPeerMembers! +Java.Interop.IJavaPeerable.PeerReference.get -> Java.Interop.JniObjectReference +Java.Interop.IJavaPeerable.SetJniIdentityHashCode(int value) -> void +Java.Interop.IJavaPeerable.SetJniManagedPeerState(Java.Interop.JniManagedPeerStates value) -> void +Java.Interop.IJavaPeerable.SetPeerReference(Java.Interop.JniObjectReference reference) -> void +Java.Interop.IJavaPeerable.UnregisterFromRuntime() -> void +Java.Interop.JavaArray +Java.Interop.JavaArray.IsReadOnly.get -> bool +Java.Interop.JavaArray.Length.get -> int +Java.Interop.JavaArray.ToArray() -> T[]! +Java.Interop.JavaBooleanArray +Java.Interop.JavaBooleanArray.GetElements() -> Java.Interop.JniBooleanArrayElements! +Java.Interop.JavaBooleanArray.JavaBooleanArray(int length) -> void +Java.Interop.JavaBooleanArray.JavaBooleanArray(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaBooleanArray.JavaBooleanArray(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaBooleanArray.JavaBooleanArray(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaCharArray +Java.Interop.JavaCharArray.GetElements() -> Java.Interop.JniCharArrayElements! +Java.Interop.JavaCharArray.JavaCharArray(int length) -> void +Java.Interop.JavaCharArray.JavaCharArray(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaCharArray.JavaCharArray(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaCharArray.JavaCharArray(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaDoubleArray +Java.Interop.JavaDoubleArray.GetElements() -> Java.Interop.JniDoubleArrayElements! +Java.Interop.JavaDoubleArray.JavaDoubleArray(int length) -> void +Java.Interop.JavaDoubleArray.JavaDoubleArray(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaDoubleArray.JavaDoubleArray(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaDoubleArray.JavaDoubleArray(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaException +Java.Interop.JavaException.Construct(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaException.Dispose() -> void +Java.Interop.JavaException.DisposeUnlessReferenced() -> void +Java.Interop.JavaException.JavaException() -> void +Java.Interop.JavaException.JavaException(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions transfer) -> void +Java.Interop.JavaException.JavaException(string! message) -> void +Java.Interop.JavaException.JavaException(string! message, System.Exception! innerException) -> void +Java.Interop.JavaException.JavaStackTrace.get -> string? +Java.Interop.JavaException.JniIdentityHashCode.get -> int +Java.Interop.JavaException.JniManagedPeerState.get -> Java.Interop.JniManagedPeerStates +Java.Interop.JavaException.PeerReference.get -> Java.Interop.JniObjectReference +Java.Interop.JavaException.SetPeerReference(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaException.UnregisterFromRuntime() -> void +Java.Interop.JavaException.~JavaException() -> void +Java.Interop.JavaInt16Array +Java.Interop.JavaInt16Array.GetElements() -> Java.Interop.JniInt16ArrayElements! +Java.Interop.JavaInt16Array.JavaInt16Array(int length) -> void +Java.Interop.JavaInt16Array.JavaInt16Array(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaInt16Array.JavaInt16Array(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaInt16Array.JavaInt16Array(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaInt32Array +Java.Interop.JavaInt32Array.GetElements() -> Java.Interop.JniInt32ArrayElements! +Java.Interop.JavaInt32Array.JavaInt32Array(int length) -> void +Java.Interop.JavaInt32Array.JavaInt32Array(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaInt32Array.JavaInt32Array(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaInt32Array.JavaInt32Array(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaInt64Array +Java.Interop.JavaInt64Array.GetElements() -> Java.Interop.JniInt64ArrayElements! +Java.Interop.JavaInt64Array.JavaInt64Array(int length) -> void +Java.Interop.JavaInt64Array.JavaInt64Array(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaInt64Array.JavaInt64Array(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaInt64Array.JavaInt64Array(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaObject +Java.Interop.JavaObject.Construct(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaObject.Dispose() -> void +Java.Interop.JavaObject.JavaObject() -> void +Java.Interop.JavaObject.JavaObject(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaObject.JniIdentityHashCode.get -> int +Java.Interop.JavaObject.JniManagedPeerState.get -> Java.Interop.JniManagedPeerStates +Java.Interop.JavaObject.PeerReference.get -> Java.Interop.JniObjectReference +Java.Interop.JavaObject.SetPeerReference(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaObject.UnregisterFromRuntime() -> void +Java.Interop.JavaObject.~JavaObject() -> void +Java.Interop.JavaObjectArray +Java.Interop.JavaObjectArray.JavaObjectArray(int length) -> void +Java.Interop.JavaObjectArray.JavaObjectArray(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaObjectArray.JavaObjectArray(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaObjectArray.JavaObjectArray(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaPeerableExtensions +Java.Interop.JavaPrimitiveArray +Java.Interop.JavaPrimitiveArray.GetElements() -> Java.Interop.JniArrayElements! +Java.Interop.JavaSByteArray +Java.Interop.JavaSByteArray.GetElements() -> Java.Interop.JniSByteArrayElements! +Java.Interop.JavaSByteArray.JavaSByteArray(int length) -> void +Java.Interop.JavaSByteArray.JavaSByteArray(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaSByteArray.JavaSByteArray(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaSByteArray.JavaSByteArray(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaSingleArray +Java.Interop.JavaSingleArray.GetElements() -> Java.Interop.JniSingleArrayElements! +Java.Interop.JavaSingleArray.JavaSingleArray(int length) -> void +Java.Interop.JavaSingleArray.JavaSingleArray(ref Java.Interop.JniObjectReference handle, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JavaSingleArray.JavaSingleArray(System.Collections.Generic.IEnumerable! value) -> void +Java.Interop.JavaSingleArray.JavaSingleArray(System.Collections.Generic.IList! value) -> void +Java.Interop.JavaTypeParametersAttribute +Java.Interop.JavaTypeParametersAttribute.JavaTypeParametersAttribute(string![]! typeParameters) -> void +Java.Interop.JavaTypeParametersAttribute.TypeParameters.get -> string![]! +Java.Interop.JniAddNativeMethodRegistrationAttribute +Java.Interop.JniAddNativeMethodRegistrationAttribute.JniAddNativeMethodRegistrationAttribute() -> void +Java.Interop.JniArgumentValue +Java.Interop.JniArgumentValue.Equals(Java.Interop.JniArgumentValue other) -> bool +Java.Interop.JniArgumentValue.JniArgumentValue() -> void +Java.Interop.JniArgumentValue.JniArgumentValue(bool value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(byte value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(char value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(double value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(float value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(int value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(Java.Interop.IJavaPeerable? value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(Java.Interop.JniObjectReference value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(long value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(nint value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(sbyte value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(short value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(uint value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(ulong value) -> void +Java.Interop.JniArgumentValue.JniArgumentValue(ushort value) -> void +Java.Interop.JniArrayElements +Java.Interop.JniArrayElements.CopyToJava() -> void +Java.Interop.JniArrayElements.Dispose() -> void +Java.Interop.JniArrayElements.Elements.get -> nint +Java.Interop.JniArrayElements.Release(Java.Interop.JniReleaseArrayElementsMode releaseMode) -> void +Java.Interop.JniArrayElements.Size.get -> int +Java.Interop.JniBooleanArrayElements +Java.Interop.JniBooleanArrayElements.Elements.get -> bool* +Java.Interop.JniBooleanArrayElements.this[int index].get -> bool +Java.Interop.JniCharArrayElements +Java.Interop.JniCharArrayElements.Elements.get -> char* +Java.Interop.JniCharArrayElements.this[int index].get -> char +Java.Interop.JniConstructorSignatureAttribute +Java.Interop.JniConstructorSignatureAttribute.JniConstructorSignatureAttribute(string! memberSignature) -> void +Java.Interop.JniDoubleArrayElements +Java.Interop.JniDoubleArrayElements.Elements.get -> double* +Java.Interop.JniDoubleArrayElements.this[int index].get -> double +Java.Interop.JniEnvironment +Java.Interop.JniEnvironment.Arrays +Java.Interop.JniEnvironment.Exceptions +Java.Interop.JniEnvironment.InstanceFields +Java.Interop.JniEnvironment.InstanceMethods +Java.Interop.JniEnvironment.IO +Java.Interop.JniEnvironment.Monitors +Java.Interop.JniEnvironment.Object +Java.Interop.JniEnvironment.References +Java.Interop.JniEnvironment.StaticFields +Java.Interop.JniEnvironment.StaticMethods +Java.Interop.JniEnvironment.Strings +Java.Interop.JniEnvironment.Types +Java.Interop.JniFieldInfo +Java.Interop.JniFieldInfo.ID.get -> nint +Java.Interop.JniFieldInfo.IsStatic.get -> bool +Java.Interop.JniFieldInfo.JniFieldInfo(nint fieldID, bool isStatic) -> void +Java.Interop.JniFieldInfo.JniFieldInfo(string! name, string! signature, nint fieldID, bool isStatic) -> void +Java.Interop.JniFieldInfo.Name.get -> string! +Java.Interop.JniFieldInfo.Signature.get -> string! +Java.Interop.JniInt16ArrayElements +Java.Interop.JniInt16ArrayElements.Elements.get -> short* +Java.Interop.JniInt16ArrayElements.this[int index].get -> short +Java.Interop.JniInt32ArrayElements +Java.Interop.JniInt32ArrayElements.Elements.get -> int* +Java.Interop.JniInt32ArrayElements.this[int index].get -> int +Java.Interop.JniInt64ArrayElements +Java.Interop.JniInt64ArrayElements.Elements.get -> long* +Java.Interop.JniInt64ArrayElements.this[int index].get -> long +Java.Interop.JniManagedPeerStates +Java.Interop.JniManagedPeerStates.Activatable = 1 -> Java.Interop.JniManagedPeerStates +Java.Interop.JniManagedPeerStates.None = 0 -> Java.Interop.JniManagedPeerStates +Java.Interop.JniManagedPeerStates.Replaceable = 2 -> Java.Interop.JniManagedPeerStates +Java.Interop.JniMarshal +Java.Interop.JniMemberSignature +Java.Interop.JniMemberSignature.Equals(Java.Interop.JniMemberSignature other) -> bool +Java.Interop.JniMemberSignature.JniMemberSignature() -> void +Java.Interop.JniMemberSignature.JniMemberSignature(string! memberName, string! memberSignature) -> void +Java.Interop.JniMemberSignature.MemberName.get -> string! +Java.Interop.JniMemberSignature.MemberSignature.get -> string! +Java.Interop.JniMemberSignatureAttribute +Java.Interop.JniMemberSignatureAttribute.MemberName.get -> string! +Java.Interop.JniMemberSignatureAttribute.MemberSignature.get -> string! +Java.Interop.JniMethodInfo +Java.Interop.JniMethodInfo.ID.get -> nint +Java.Interop.JniMethodInfo.IsStatic.get -> bool +Java.Interop.JniMethodInfo.JniMethodInfo(nint methodID, bool isStatic) -> void +Java.Interop.JniMethodInfo.JniMethodInfo(string! name, string! signature, nint methodID, bool isStatic) -> void +Java.Interop.JniMethodInfo.Name.get -> string! +Java.Interop.JniMethodInfo.Signature.get -> string! +Java.Interop.JniMethodSignatureAttribute +Java.Interop.JniMethodSignatureAttribute.JniMethodSignatureAttribute(string! memberName, string! memberSignature) -> void +Java.Interop.JniNativeMethodRegistration +Java.Interop.JniNativeMethodRegistration.JniNativeMethodRegistration() -> void +Java.Interop.JniNativeMethodRegistration.JniNativeMethodRegistration(string! name, string! signature, System.Delegate! marshaler) -> void +Java.Interop.JniNativeMethodRegistration.Marshaler -> System.Delegate! +Java.Interop.JniNativeMethodRegistration.Name -> string! +Java.Interop.JniNativeMethodRegistration.Signature -> string! +Java.Interop.JniNativeMethodRegistrationArguments +Java.Interop.JniNativeMethodRegistrationArguments.AddRegistrations(System.Collections.Generic.IEnumerable! registrations) -> void +Java.Interop.JniNativeMethodRegistrationArguments.JniNativeMethodRegistrationArguments() -> void +Java.Interop.JniNativeMethodRegistrationArguments.JniNativeMethodRegistrationArguments(System.Collections.Generic.ICollection! registrations, string? methods) -> void +Java.Interop.JniNativeMethodRegistrationArguments.Methods.get -> string? +Java.Interop.JniNativeMethodRegistrationArguments.Registrations.get -> System.Collections.Generic.ICollection! +Java.Interop.JniObjectReference +Java.Interop.JniObjectReference.Equals(Java.Interop.JniObjectReference other) -> bool +Java.Interop.JniObjectReference.Handle.get -> nint +Java.Interop.JniObjectReference.IsValid.get -> bool +Java.Interop.JniObjectReference.JniObjectReference() -> void +Java.Interop.JniObjectReference.JniObjectReference(nint handle, Java.Interop.JniObjectReferenceType type = Java.Interop.JniObjectReferenceType.Invalid) -> void +Java.Interop.JniObjectReference.NewGlobalRef() -> Java.Interop.JniObjectReference +Java.Interop.JniObjectReference.NewLocalRef() -> Java.Interop.JniObjectReference +Java.Interop.JniObjectReference.NewWeakGlobalRef() -> Java.Interop.JniObjectReference +Java.Interop.JniObjectReference.Type.get -> Java.Interop.JniObjectReferenceType +Java.Interop.JniObjectReferenceOptions +Java.Interop.JniObjectReferenceOptions.Copy = 1 -> Java.Interop.JniObjectReferenceOptions +Java.Interop.JniObjectReferenceOptions.CopyAndDispose = 3 -> Java.Interop.JniObjectReferenceOptions +Java.Interop.JniObjectReferenceOptions.CopyAndDoNotRegister = 5 -> Java.Interop.JniObjectReferenceOptions +Java.Interop.JniObjectReferenceOptions.None = 0 -> Java.Interop.JniObjectReferenceOptions +Java.Interop.JniObjectReferenceType +Java.Interop.JniObjectReferenceType.Global = 2 -> Java.Interop.JniObjectReferenceType +Java.Interop.JniObjectReferenceType.Invalid = 0 -> Java.Interop.JniObjectReferenceType +Java.Interop.JniObjectReferenceType.Local = 1 -> Java.Interop.JniObjectReferenceType +Java.Interop.JniObjectReferenceType.WeakGlobal = 3 -> Java.Interop.JniObjectReferenceType +Java.Interop.JniPeerMembers +Java.Interop.JniPeerMembers.InstanceFields.get -> Java.Interop.JniPeerMembers.JniInstanceFields! +Java.Interop.JniPeerMembers.InstanceMethods.get -> Java.Interop.JniPeerMembers.JniInstanceMethods! +Java.Interop.JniPeerMembers.JniInstanceFields +Java.Interop.JniPeerMembers.JniInstanceFields.GetBooleanValue(string! encodedMember, Java.Interop.IJavaPeerable! self) -> bool +Java.Interop.JniPeerMembers.JniInstanceFields.GetCharValue(string! encodedMember, Java.Interop.IJavaPeerable! self) -> char +Java.Interop.JniPeerMembers.JniInstanceFields.GetDoubleValue(string! encodedMember, Java.Interop.IJavaPeerable! self) -> double +Java.Interop.JniPeerMembers.JniInstanceFields.GetFieldInfo(string! encodedMember) -> Java.Interop.JniFieldInfo! +Java.Interop.JniPeerMembers.JniInstanceFields.GetInt16Value(string! encodedMember, Java.Interop.IJavaPeerable! self) -> short +Java.Interop.JniPeerMembers.JniInstanceFields.GetInt32Value(string! encodedMember, Java.Interop.IJavaPeerable! self) -> int +Java.Interop.JniPeerMembers.JniInstanceFields.GetInt64Value(string! encodedMember, Java.Interop.IJavaPeerable! self) -> long +Java.Interop.JniPeerMembers.JniInstanceFields.GetObjectValue(string! encodedMember, Java.Interop.IJavaPeerable! self) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceFields.GetSByteValue(string! encodedMember, Java.Interop.IJavaPeerable! self) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceFields.GetSingleValue(string! encodedMember, Java.Interop.IJavaPeerable! self) -> float +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, bool value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, char value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, double value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, float value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, int value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniObjectReference value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, long value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, sbyte value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(string! encodedMember, Java.Interop.IJavaPeerable! self, short value) -> void +Java.Interop.JniPeerMembers.JniInstanceMethods +Java.Interop.JniPeerMembers.JniInstanceMethods.FinishCreateInstance(string! constructorSignature, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> void +Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructor(string! signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniPeerMembers.JniInstanceMethods.GetMethodInfo(string! encodedMember) -> Java.Interop.JniMethodInfo! +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractBooleanMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> bool +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractCharMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> char +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractDoubleMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> double +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractInt16Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> short +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractInt32Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> int +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractInt64Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> long +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractObjectMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractSByteMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractSingleMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> float +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractVoidMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> void +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualBooleanMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> bool +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualCharMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> char +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualDoubleMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> double +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualInt16Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> short +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualInt32Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> int +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualInt64Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> long +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualObjectMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualSByteMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualSingleMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> float +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualVoidMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> void +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualBooleanMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> bool +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualCharMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> char +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualDoubleMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> double +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualInt16Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> short +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualInt32Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> int +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualInt64Method(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> long +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualObjectMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualSByteMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualSingleMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> float +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(string! encodedMember, Java.Interop.IJavaPeerable! self, Java.Interop.JniArgumentValue* parameters) -> void +Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(string! constructorSignature, System.Type! declaringType, Java.Interop.JniArgumentValue* parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniPeerMembers(string! jniPeerTypeName, System.Type! managedPeerType) -> void +Java.Interop.JniPeerMembers.JniPeerMembers(string! jniPeerTypeName, System.Type! managedPeerType, bool isInterface) -> void +Java.Interop.JniPeerMembers.JniPeerType.get -> Java.Interop.JniType! +Java.Interop.JniPeerMembers.JniPeerTypeName.get -> string! +Java.Interop.JniPeerMembers.JniStaticFields +Java.Interop.JniPeerMembers.JniStaticFields.GetBooleanValue(string! encodedMember) -> bool +Java.Interop.JniPeerMembers.JniStaticFields.GetCharValue(string! encodedMember) -> char +Java.Interop.JniPeerMembers.JniStaticFields.GetDoubleValue(string! encodedMember) -> double +Java.Interop.JniPeerMembers.JniStaticFields.GetFieldInfo(string! encodedMember) -> Java.Interop.JniFieldInfo! +Java.Interop.JniPeerMembers.JniStaticFields.GetInt16Value(string! encodedMember) -> short +Java.Interop.JniPeerMembers.JniStaticFields.GetInt32Value(string! encodedMember) -> int +Java.Interop.JniPeerMembers.JniStaticFields.GetInt64Value(string! encodedMember) -> long +Java.Interop.JniPeerMembers.JniStaticFields.GetObjectValue(string! encodedMember) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniStaticFields.GetSByteValue(string! encodedMember) -> sbyte +Java.Interop.JniPeerMembers.JniStaticFields.GetSingleValue(string! encodedMember) -> float +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, bool value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, char value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, double value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, float value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, int value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, Java.Interop.JniObjectReference value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, long value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, sbyte value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(string! encodedMember, short value) -> void +Java.Interop.JniPeerMembers.JniStaticMethods +Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(string! encodedMember) -> Java.Interop.JniMethodInfo! +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeBooleanMethod(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> bool +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeCharMethod(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> char +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeDoubleMethod(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> double +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeInt16Method(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> short +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeInt32Method(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> int +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeInt64Method(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> long +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeObjectMethod(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeSByteMethod(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> sbyte +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeSingleMethod(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> float +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeVoidMethod(string! encodedMember, Java.Interop.JniArgumentValue* parameters) -> void +Java.Interop.JniPeerMembers.ManagedPeerType.get -> System.Type! +Java.Interop.JniPeerMembers.StaticFields.get -> Java.Interop.JniPeerMembers.JniStaticFields! +Java.Interop.JniPeerMembers.StaticMethods.get -> Java.Interop.JniPeerMembers.JniStaticMethods! +Java.Interop.JniReleaseArrayElementsMode +Java.Interop.JniReleaseArrayElementsMode.Abort = 2 -> Java.Interop.JniReleaseArrayElementsMode +Java.Interop.JniReleaseArrayElementsMode.Commit = 1 -> Java.Interop.JniReleaseArrayElementsMode +Java.Interop.JniReleaseArrayElementsMode.Default = 0 -> Java.Interop.JniReleaseArrayElementsMode +Java.Interop.JniRuntime +Java.Interop.JniRuntime.AttachCurrentThread(string? name = null, Java.Interop.JniObjectReference group = default(Java.Interop.JniObjectReference)) -> void +Java.Interop.JniRuntime.CreationOptions +Java.Interop.JniRuntime.CreationOptions.ClassLoader.get -> Java.Interop.JniObjectReference +Java.Interop.JniRuntime.CreationOptions.ClassLoader.set -> void +Java.Interop.JniRuntime.CreationOptions.ClassLoader_LoadClass_id.get -> nint +Java.Interop.JniRuntime.CreationOptions.ClassLoader_LoadClass_id.set -> void +Java.Interop.JniRuntime.CreationOptions.CreationOptions() -> void +Java.Interop.JniRuntime.CreationOptions.DestroyRuntimeOnDispose.get -> bool +Java.Interop.JniRuntime.CreationOptions.DestroyRuntimeOnDispose.set -> void +Java.Interop.JniRuntime.CreationOptions.EnvironmentPointer.get -> nint +Java.Interop.JniRuntime.CreationOptions.EnvironmentPointer.set -> void +Java.Interop.JniRuntime.CreationOptions.InvocationPointer.get -> nint +Java.Interop.JniRuntime.CreationOptions.InvocationPointer.set -> void +Java.Interop.JniRuntime.CreationOptions.JniAddNativeMethodRegistrationAttributePresent.get -> bool +Java.Interop.JniRuntime.CreationOptions.JniAddNativeMethodRegistrationAttributePresent.set -> void +Java.Interop.JniRuntime.CreationOptions.JniVersion.get -> Java.Interop.JniVersion +Java.Interop.JniRuntime.CreationOptions.JniVersion.set -> void +Java.Interop.JniRuntime.CreationOptions.JvmLibraryPath.get -> string? +Java.Interop.JniRuntime.CreationOptions.JvmLibraryPath.set -> void +Java.Interop.JniRuntime.CreationOptions.MarshalMemberBuilder.get -> Java.Interop.JniRuntime.JniMarshalMemberBuilder? +Java.Interop.JniRuntime.CreationOptions.MarshalMemberBuilder.set -> void +Java.Interop.JniRuntime.CreationOptions.NewObjectRequired.get -> bool +Java.Interop.JniRuntime.CreationOptions.NewObjectRequired.set -> void +Java.Interop.JniRuntime.CreationOptions.ObjectReferenceManager.get -> Java.Interop.JniRuntime.JniObjectReferenceManager? +Java.Interop.JniRuntime.CreationOptions.ObjectReferenceManager.set -> void +Java.Interop.JniRuntime.CreationOptions.TrackIDs.get -> bool +Java.Interop.JniRuntime.CreationOptions.TrackIDs.set -> void +Java.Interop.JniRuntime.CreationOptions.TypeManager.get -> Java.Interop.JniRuntime.JniTypeManager? +Java.Interop.JniRuntime.CreationOptions.TypeManager.set -> void +Java.Interop.JniRuntime.CreationOptions.UseMarshalMemberBuilder.get -> bool +Java.Interop.JniRuntime.CreationOptions.UseMarshalMemberBuilder.set -> void +Java.Interop.JniRuntime.CreationOptions.ValueManager.get -> Java.Interop.JniRuntime.JniValueManager? +Java.Interop.JniRuntime.CreationOptions.ValueManager.set -> void +Java.Interop.JniRuntime.DestroyRuntime() -> void +Java.Interop.JniRuntime.Dispose() -> void +Java.Interop.JniRuntime.GlobalReferenceCount.get -> int +Java.Interop.JniRuntime.InvocationPointer.get -> nint +Java.Interop.JniRuntime.JniMarshalMemberBuilder +Java.Interop.JniRuntime.JniMarshalMemberBuilder.CreateConstructActivationPeerFunc(System.Reflection.ConstructorInfo! constructor) -> System.Func! +Java.Interop.JniRuntime.JniMarshalMemberBuilder.CreateMarshalToManagedDelegate(System.Delegate! value) -> System.Delegate! +Java.Interop.JniRuntime.JniMarshalMemberBuilder.Dispose() -> void +Java.Interop.JniRuntime.JniMarshalMemberBuilder.GetJniMethodSignature(System.Reflection.MethodBase! member) -> string! +Java.Interop.JniRuntime.JniMarshalMemberBuilder.GetParameterMarshaler(System.Reflection.ParameterInfo! parameter) -> Java.Interop.JniValueMarshaler! +Java.Interop.JniRuntime.JniMarshalMemberBuilder.IsDirectMethod(System.Reflection.ParameterInfo![]! methodParameters) -> bool +Java.Interop.JniRuntime.JniMarshalMemberBuilder.JniMarshalMemberBuilder() -> void +Java.Interop.JniRuntime.JniMarshalMemberBuilder.Runtime.get -> Java.Interop.JniRuntime! +Java.Interop.JniRuntime.JniObjectReferenceManager +Java.Interop.JniRuntime.JniObjectReferenceManager.Dispose() -> void +Java.Interop.JniRuntime.JniObjectReferenceManager.JniObjectReferenceManager() -> void +Java.Interop.JniRuntime.JniObjectReferenceManager.Runtime.get -> Java.Interop.JniRuntime! +Java.Interop.JniRuntime.JniRuntime(Java.Interop.JniRuntime.CreationOptions! options) -> void +Java.Interop.JniRuntime.JniTypeManager +Java.Interop.JniRuntime.JniTypeManager.Dispose() -> void +Java.Interop.JniRuntime.JniTypeManager.GetReplacementMethodInfo(string! jniSimpleReference, string! jniMethodName, string! jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? +Java.Interop.JniRuntime.JniTypeManager.GetReplacementType(string! jniSimpleReference) -> string? +Java.Interop.JniRuntime.JniTypeManager.GetStaticMethodFallbackTypes(string! jniSimpleReference) -> System.Collections.Generic.IReadOnlyList? +Java.Interop.JniRuntime.JniTypeManager.GetType(Java.Interop.JniTypeSignature typeSignature) -> System.Type? +Java.Interop.JniRuntime.JniTypeManager.GetTypeSignature(System.Type! type) -> Java.Interop.JniTypeSignature +Java.Interop.JniRuntime.JniTypeManager.GetTypeSignatures(System.Type! type) -> System.Collections.Generic.IEnumerable! +Java.Interop.JniRuntime.JniTypeManager.JniTypeManager() -> void +Java.Interop.JniRuntime.JniTypeManager.Runtime.get -> Java.Interop.JniRuntime! +Java.Interop.JniRuntime.JniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, string? methods) -> bool +Java.Interop.JniRuntime.JniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, System.ReadOnlySpan methods) -> bool +Java.Interop.JniRuntime.JniValueManager +Java.Interop.JniRuntime.JniValueManager.ConstructPeer(Java.Interop.IJavaPeerable! peer, ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +Java.Interop.JniRuntime.JniValueManager.CreateValue(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +Java.Interop.JniRuntime.JniValueManager.CreateValue(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> T +Java.Interop.JniRuntime.JniValueManager.Dispose() -> void +Java.Interop.JniRuntime.JniValueManager.GetJniIdentityHashCode(Java.Interop.JniObjectReference reference) -> int +Java.Interop.JniRuntime.JniValueManager.GetValue(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +Java.Interop.JniRuntime.JniValueManager.GetValue(nint handle) -> T +Java.Interop.JniRuntime.JniValueManager.GetValue(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> T +Java.Interop.JniRuntime.JniValueManager.GetValueMarshaler(System.Type! type) -> Java.Interop.JniValueMarshaler! +Java.Interop.JniRuntime.JniValueManager.GetValueMarshaler() -> Java.Interop.JniValueMarshaler! +Java.Interop.JniRuntime.JniValueManager.JniValueManager() -> void +Java.Interop.JniRuntime.JniValueManager.PeekValue(Java.Interop.JniObjectReference reference) -> object? +Java.Interop.JniRuntime.JniValueManager.Runtime.get -> Java.Interop.JniRuntime! +Java.Interop.JniRuntime.JniVersion.get -> Java.Interop.JniVersion +Java.Interop.JniRuntime.MarshalMemberBuilder.get -> Java.Interop.JniRuntime.JniMarshalMemberBuilder! +Java.Interop.JniRuntime.ObjectReferenceManager.get -> Java.Interop.JniRuntime.JniObjectReferenceManager! +Java.Interop.JniRuntime.ReplacementMethodInfo +Java.Interop.JniRuntime.ReplacementMethodInfo.Equals(Java.Interop.JniRuntime.ReplacementMethodInfo other) -> bool +Java.Interop.JniRuntime.ReplacementMethodInfo.ReplacementMethodInfo() -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.SourceJniMethodName.get -> string? +Java.Interop.JniRuntime.ReplacementMethodInfo.SourceJniMethodName.set -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.SourceJniMethodSignature.get -> string? +Java.Interop.JniRuntime.ReplacementMethodInfo.SourceJniMethodSignature.set -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.SourceJniType.get -> string? +Java.Interop.JniRuntime.ReplacementMethodInfo.SourceJniType.set -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodInstanceToStatic.get -> bool +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodInstanceToStatic.set -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodName.get -> string? +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodName.set -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodParameterCount.get -> int? +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodParameterCount.set -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodSignature.get -> string? +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniMethodSignature.set -> void +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniType.get -> string? +Java.Interop.JniRuntime.ReplacementMethodInfo.TargetJniType.set -> void +Java.Interop.JniRuntime.TypeManager.get -> Java.Interop.JniRuntime.JniTypeManager! +Java.Interop.JniRuntime.ValueManager.get -> Java.Interop.JniRuntime.JniValueManager! +Java.Interop.JniRuntime.WeakGlobalReferenceCount.get -> int +Java.Interop.JniRuntime.~JniRuntime() -> void +Java.Interop.JniSByteArrayElements +Java.Interop.JniSByteArrayElements.Elements.get -> sbyte* +Java.Interop.JniSByteArrayElements.this[int index].get -> sbyte +Java.Interop.JniSingleArrayElements +Java.Interop.JniSingleArrayElements.Elements.get -> float* +Java.Interop.JniSingleArrayElements.this[int index].get -> float +Java.Interop.JniSurfacedPeerInfo +Java.Interop.JniSurfacedPeerInfo.JniIdentityHashCode.get -> int +Java.Interop.JniSurfacedPeerInfo.JniSurfacedPeerInfo(int jniIdentityHashCode, System.WeakReference! surfacedPeer) -> void +Java.Interop.JniSurfacedPeerInfo.SurfacedPeer.get -> System.WeakReference! +Java.Interop.JniTransition +Java.Interop.JniTransition.Dispose() -> void +Java.Interop.JniTransition.JniTransition() -> void +Java.Interop.JniTransition.JniTransition(nint environmentPointer) -> void +Java.Interop.JniTransition.SetPendingException(System.Exception! exception) -> void +Java.Interop.JniType +Java.Interop.JniType.AllocObject() -> Java.Interop.JniObjectReference +Java.Interop.JniType.Dispose() -> void +Java.Interop.JniType.GetCachedConstructor(ref Java.Interop.JniMethodInfo? cachedMethod, string! signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetCachedInstanceField(ref Java.Interop.JniFieldInfo? cachedField, string! name, string! signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetCachedInstanceMethod(ref Java.Interop.JniMethodInfo? cachedMethod, string! name, string! signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetCachedStaticField(ref Java.Interop.JniFieldInfo? cachedField, string! name, string! signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetCachedStaticMethod(ref Java.Interop.JniMethodInfo? cachedMethod, string! name, string! signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetConstructor(string! signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetInstanceField(string! name, string! signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetInstanceMethod(string! name, string! signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetStaticField(string! name, string! signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetStaticMethod(string! name, string! signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetSuperclass() -> Java.Interop.JniType? +Java.Interop.JniType.IsAssignableFrom(Java.Interop.JniType! c) -> bool +Java.Interop.JniType.IsInstanceOfType(Java.Interop.JniObjectReference value) -> bool +Java.Interop.JniType.JniType(ref Java.Interop.JniObjectReference peerReference, Java.Interop.JniObjectReferenceOptions transfer) -> void +Java.Interop.JniType.JniType(string! classname) -> void +Java.Interop.JniType.Name.get -> string! +Java.Interop.JniType.NewObject(Java.Interop.JniMethodInfo! constructor, Java.Interop.JniArgumentValue* parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniType.PeerReference.get -> Java.Interop.JniObjectReference +Java.Interop.JniType.RegisterNativeMethods(params Java.Interop.JniNativeMethodRegistration[]! methods) -> void +Java.Interop.JniType.RegisterWithRuntime() -> void +Java.Interop.JniType.UnregisterNativeMethods() -> void +Java.Interop.JniTypeSignature +Java.Interop.JniTypeSignature.AddArrayRank(int rank) -> Java.Interop.JniTypeSignature +Java.Interop.JniTypeSignature.ArrayRank.get -> int +Java.Interop.JniTypeSignature.Equals(Java.Interop.JniTypeSignature other) -> bool +Java.Interop.JniTypeSignature.GetPrimitivePeerTypeSignature() -> Java.Interop.JniTypeSignature +Java.Interop.JniTypeSignature.IsValid.get -> bool +Java.Interop.JniTypeSignature.JniTypeSignature() -> void +Java.Interop.JniTypeSignature.JniTypeSignature(string? simpleReference, int arrayRank = 0, bool keyword = false) -> void +Java.Interop.JniTypeSignature.Name.get -> string! +Java.Interop.JniTypeSignature.QualifiedReference.get -> string! +Java.Interop.JniTypeSignature.SimpleReference.get -> string? +Java.Interop.JniTypeSignatureAttribute +Java.Interop.JniTypeSignatureAttribute.ArrayRank.get -> int +Java.Interop.JniTypeSignatureAttribute.ArrayRank.set -> void +Java.Interop.JniTypeSignatureAttribute.GenerateJavaPeer.get -> bool +Java.Interop.JniTypeSignatureAttribute.GenerateJavaPeer.set -> void +Java.Interop.JniTypeSignatureAttribute.IsKeyword.get -> bool +Java.Interop.JniTypeSignatureAttribute.IsKeyword.set -> void +Java.Interop.JniTypeSignatureAttribute.JniTypeSignatureAttribute(string! simpleReference) -> void +Java.Interop.JniTypeSignatureAttribute.SimpleReference.get -> string! +Java.Interop.JniValueMarshaler +Java.Interop.JniValueMarshaler.JniValueMarshaler() -> void +Java.Interop.JniValueMarshaler.ReturnObjectReferenceToJni(Java.Interop.Expressions.JniValueMarshalerContext! context, string? namePrefix, System.Linq.Expressions.Expression! sourceValue) -> System.Linq.Expressions.Expression! +Java.Interop.JniValueMarshaler +Java.Interop.JniValueMarshaler.JniValueMarshaler() -> void +Java.Interop.JniValueMarshalerAttribute +Java.Interop.JniValueMarshalerAttribute.JniValueMarshalerAttribute(System.Type! marshalerType) -> void +Java.Interop.JniValueMarshalerAttribute.MarshalerType.get -> System.Type! +Java.Interop.JniValueMarshalerState +Java.Interop.JniValueMarshalerState.Equals(Java.Interop.JniValueMarshalerState other) -> bool +Java.Interop.JniValueMarshalerState.Extra.get -> object? +Java.Interop.JniValueMarshalerState.JniArgumentValue.get -> Java.Interop.JniArgumentValue +Java.Interop.JniValueMarshalerState.JniValueMarshalerState() -> void +Java.Interop.JniValueMarshalerState.JniValueMarshalerState(Java.Interop.IJavaPeerable? peerableValue, object? extra = null) -> void +Java.Interop.JniValueMarshalerState.JniValueMarshalerState(Java.Interop.JniArgumentValue jniArgumentValue, object? extra = null) -> void +Java.Interop.JniValueMarshalerState.JniValueMarshalerState(Java.Interop.JniObjectReference referenceValue, object? extra = null) -> void +Java.Interop.JniValueMarshalerState.PeerableValue.get -> Java.Interop.IJavaPeerable? +Java.Interop.JniValueMarshalerState.ReferenceValue.get -> Java.Interop.JniObjectReference +Java.Interop.JniVersion +Java.Interop.JniVersion.v1_2 = 65538 -> Java.Interop.JniVersion +Java.Interop.JniVersion.v1_4 = 65540 -> Java.Interop.JniVersion +Java.Interop.JniVersion.v1_6 = 65542 -> Java.Interop.JniVersion +override Java.Interop.JavaBooleanArray.Clear() -> void +override Java.Interop.JavaBooleanArray.CopyFrom(bool[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaBooleanArray.CopyTo(int sourceIndex, bool[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaBooleanArray.IndexOf(bool item) -> int +override Java.Interop.JavaCharArray.Clear() -> void +override Java.Interop.JavaCharArray.CopyFrom(char[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaCharArray.CopyTo(int sourceIndex, char[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaCharArray.IndexOf(char item) -> int +override Java.Interop.JavaDoubleArray.Clear() -> void +override Java.Interop.JavaDoubleArray.CopyFrom(double[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaDoubleArray.CopyTo(int sourceIndex, double[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaDoubleArray.IndexOf(double item) -> int +override Java.Interop.JavaException.Equals(object? obj) -> bool +override Java.Interop.JavaException.GetHashCode() -> int +override Java.Interop.JavaException.StackTrace.get -> string! +override Java.Interop.JavaInt16Array.Clear() -> void +override Java.Interop.JavaInt16Array.CopyFrom(short[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaInt16Array.CopyTo(int sourceIndex, short[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaInt16Array.IndexOf(short item) -> int +override Java.Interop.JavaInt32Array.Clear() -> void +override Java.Interop.JavaInt32Array.CopyFrom(int[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaInt32Array.CopyTo(int sourceIndex, int[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaInt32Array.IndexOf(int item) -> int +override Java.Interop.JavaInt64Array.Clear() -> void +override Java.Interop.JavaInt64Array.CopyFrom(long[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaInt64Array.CopyTo(int sourceIndex, long[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaInt64Array.IndexOf(long item) -> int +override Java.Interop.JavaObject.Equals(object? obj) -> bool +override Java.Interop.JavaObject.GetHashCode() -> int +override Java.Interop.JavaObject.ToString() -> string? +override Java.Interop.JavaObjectArray.Clear() -> void +override Java.Interop.JavaObjectArray.CopyTo(T[]! array, int arrayIndex) -> void +override Java.Interop.JavaObjectArray.DisposeUnlessReferenced() -> void +override Java.Interop.JavaObjectArray.GetEnumerator() -> System.Collections.Generic.IEnumerator! +override Java.Interop.JavaObjectArray.IndexOf(T item) -> int +override Java.Interop.JavaObjectArray.this[int index].get -> T +override Java.Interop.JavaObjectArray.this[int index].set -> void +override Java.Interop.JavaPrimitiveArray.CopyTo(T[]! array, int arrayIndex) -> void +override Java.Interop.JavaPrimitiveArray.DisposeUnlessReferenced() -> void +override Java.Interop.JavaPrimitiveArray.this[int index].get -> T +override Java.Interop.JavaPrimitiveArray.this[int index].set -> void +override Java.Interop.JavaSByteArray.Clear() -> void +override Java.Interop.JavaSByteArray.CopyFrom(sbyte[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaSByteArray.CopyTo(int sourceIndex, sbyte[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaSByteArray.IndexOf(sbyte item) -> int +override Java.Interop.JavaSingleArray.Clear() -> void +override Java.Interop.JavaSingleArray.CopyFrom(float[]! sourceArray, int sourceIndex, int destinationIndex, int length) -> void +override Java.Interop.JavaSingleArray.CopyTo(int sourceIndex, float[]! destinationArray, int destinationIndex, int length) -> void +override Java.Interop.JavaSingleArray.IndexOf(float item) -> int +override Java.Interop.JniArgumentValue.Equals(object? obj) -> bool +override Java.Interop.JniArgumentValue.GetHashCode() -> int +override Java.Interop.JniArgumentValue.ToString() -> string! +override Java.Interop.JniFieldInfo.ToString() -> string! +override Java.Interop.JniMemberSignature.Equals(object? obj) -> bool +override Java.Interop.JniMemberSignature.GetHashCode() -> int +override Java.Interop.JniMemberSignature.ToString() -> string! +override Java.Interop.JniMethodInfo.ToString() -> string! +override Java.Interop.JniObjectReference.Equals(object? obj) -> bool +override Java.Interop.JniObjectReference.GetHashCode() -> int +override Java.Interop.JniObjectReference.ToString() -> string! +override Java.Interop.JniRuntime.ReplacementMethodInfo.Equals(object? obj) -> bool +override Java.Interop.JniRuntime.ReplacementMethodInfo.GetHashCode() -> int +override Java.Interop.JniRuntime.ReplacementMethodInfo.ToString() -> string! +override Java.Interop.JniRuntime.ToString() -> string! +override Java.Interop.JniType.ToString() -> string! +override Java.Interop.JniTypeSignature.Equals(object? obj) -> bool +override Java.Interop.JniTypeSignature.GetHashCode() -> int +override Java.Interop.JniTypeSignature.ToString() -> string! +override Java.Interop.JniValueMarshaler.CreateArgumentState(object? value, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> Java.Interop.JniValueMarshalerState +override Java.Interop.JniValueMarshaler.CreateObjectReferenceArgumentState(object? value, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> Java.Interop.JniValueMarshalerState +override Java.Interop.JniValueMarshaler.CreateValue(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +override Java.Interop.JniValueMarshaler.DestroyArgumentState(object? value, ref Java.Interop.JniValueMarshalerState state, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> void +override Java.Interop.JniValueMarshalerState.Equals(object? obj) -> bool +override Java.Interop.JniValueMarshalerState.GetHashCode() -> int +override Java.Interop.JniValueMarshalerState.ToString() -> string! +static Java.Interop.JavaBooleanArray.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JavaCharArray.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JavaDoubleArray.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JavaInt16Array.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JavaInt32Array.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JavaInt64Array.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JavaPeerableExtensions.GetJniTypeName(this Java.Interop.IJavaPeerable! self) -> string? +static Java.Interop.JavaPeerableExtensions.JavaAs(this Java.Interop.IJavaPeerable? self) -> TResult? +static Java.Interop.JavaPeerableExtensions.TryJavaCast(this Java.Interop.IJavaPeerable? self, out TResult? result) -> bool +static Java.Interop.JavaSByteArray.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JavaSingleArray.CreateMarshaledValue(nint handle, System.Type? targetType) -> object? +static Java.Interop.JniArgumentValue.operator !=(Java.Interop.JniArgumentValue lhs, Java.Interop.JniArgumentValue rhs) -> bool +static Java.Interop.JniArgumentValue.operator ==(Java.Interop.JniArgumentValue lhs, Java.Interop.JniArgumentValue rhs) -> bool +static Java.Interop.JniEnvironment.Arrays.CreateMarshalBooleanArray(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaBooleanArray? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalCharArray(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaCharArray? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalDoubleArray(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaDoubleArray? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalInt16Array(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaInt16Array? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalInt32Array(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaInt32Array? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalInt64Array(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaInt64Array? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalObjectArray(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaObjectArray? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaSByteArray? +static Java.Interop.JniEnvironment.Arrays.CreateMarshalSingleArray(System.Collections.Generic.IEnumerable? value) -> Java.Interop.JavaSingleArray? +static Java.Interop.JniEnvironment.Arrays.GetArrayLength(Java.Interop.JniObjectReference array) -> int +static Java.Interop.JniEnvironment.Arrays.GetBooleanArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> bool* +static Java.Interop.JniEnvironment.Arrays.GetBooleanArrayRegion(Java.Interop.JniObjectReference array, int start, int length, bool* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.GetByteArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> sbyte* +static Java.Interop.JniEnvironment.Arrays.GetByteArrayRegion(Java.Interop.JniObjectReference array, int start, int length, sbyte* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.GetCharArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> char* +static Java.Interop.JniEnvironment.Arrays.GetCharArrayRegion(Java.Interop.JniObjectReference array, int start, int length, char* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.GetDoubleArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> double* +static Java.Interop.JniEnvironment.Arrays.GetDoubleArrayRegion(Java.Interop.JniObjectReference array, int start, int length, double* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.GetFloatArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> float* +static Java.Interop.JniEnvironment.Arrays.GetFloatArrayRegion(Java.Interop.JniObjectReference array, int start, int length, float* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.GetIntArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> int* +static Java.Interop.JniEnvironment.Arrays.GetIntArrayRegion(Java.Interop.JniObjectReference array, int start, int length, int* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.GetLongArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> long* +static Java.Interop.JniEnvironment.Arrays.GetLongArrayRegion(Java.Interop.JniObjectReference array, int start, int length, long* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.GetObjectArrayElement(Java.Interop.JniObjectReference array, int index) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.GetPrimitiveArrayCritical(Java.Interop.JniObjectReference array, bool* isCopy) -> nint +static Java.Interop.JniEnvironment.Arrays.GetShortArrayElements(Java.Interop.JniObjectReference array, bool* isCopy) -> short* +static Java.Interop.JniEnvironment.Arrays.GetShortArrayRegion(Java.Interop.JniObjectReference array, int start, int length, short* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.NewBooleanArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewByteArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewCharArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewDoubleArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewFloatArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewIntArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewLongArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewObjectArray(int length, Java.Interop.JniObjectReference elementClass, Java.Interop.JniObjectReference initialElement) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.NewShortArray(int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Arrays.ReleaseBooleanArrayElements(Java.Interop.JniObjectReference array, bool* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleaseByteArrayElements(Java.Interop.JniObjectReference array, sbyte* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleaseCharArrayElements(Java.Interop.JniObjectReference array, char* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleaseDoubleArrayElements(Java.Interop.JniObjectReference array, double* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleaseFloatArrayElements(Java.Interop.JniObjectReference array, float* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleaseIntArrayElements(Java.Interop.JniObjectReference array, int* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleaseLongArrayElements(Java.Interop.JniObjectReference array, long* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleasePrimitiveArrayCritical(Java.Interop.JniObjectReference array, nint carray, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.ReleaseShortArrayElements(Java.Interop.JniObjectReference array, short* elements, Java.Interop.JniReleaseArrayElementsMode mode) -> void +static Java.Interop.JniEnvironment.Arrays.SetBooleanArrayRegion(Java.Interop.JniObjectReference array, int start, int length, bool* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.SetByteArrayRegion(Java.Interop.JniObjectReference array, int start, int length, sbyte* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.SetCharArrayRegion(Java.Interop.JniObjectReference array, int start, int length, char* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.SetDoubleArrayRegion(Java.Interop.JniObjectReference array, int start, int length, double* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.SetFloatArrayRegion(Java.Interop.JniObjectReference array, int start, int length, float* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.SetIntArrayRegion(Java.Interop.JniObjectReference array, int start, int length, int* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.SetLongArrayRegion(Java.Interop.JniObjectReference array, int start, int length, long* buffer) -> void +static Java.Interop.JniEnvironment.Arrays.SetObjectArrayElement(Java.Interop.JniObjectReference array, int index, Java.Interop.JniObjectReference value) -> void +static Java.Interop.JniEnvironment.Arrays.SetShortArrayRegion(Java.Interop.JniObjectReference array, int start, int length, short* buffer) -> void +static Java.Interop.JniEnvironment.EnvironmentPointer.get -> nint +static Java.Interop.JniEnvironment.Exceptions.ExceptionCheck() -> bool +static Java.Interop.JniEnvironment.Exceptions.ExceptionClear() -> void +static Java.Interop.JniEnvironment.Exceptions.ExceptionDescribe() -> void +static Java.Interop.JniEnvironment.Exceptions.ExceptionOccurred() -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Exceptions.FatalError(string! message) -> void +static Java.Interop.JniEnvironment.Exceptions.Throw(Java.Interop.JniObjectReference toThrow) -> void +static Java.Interop.JniEnvironment.Exceptions.Throw(System.Exception! e) -> void +static Java.Interop.JniEnvironment.Exceptions.ThrowNew(Java.Interop.JniObjectReference klass, string! message) -> void +static Java.Interop.JniEnvironment.InstanceFields.GetBooleanField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> bool +static Java.Interop.JniEnvironment.InstanceFields.GetByteField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> sbyte +static Java.Interop.JniEnvironment.InstanceFields.GetCharField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> char +static Java.Interop.JniEnvironment.InstanceFields.GetDoubleField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> double +static Java.Interop.JniEnvironment.InstanceFields.GetFieldID(Java.Interop.JniObjectReference type, string! name, string! signature) -> Java.Interop.JniFieldInfo! +static Java.Interop.JniEnvironment.InstanceFields.GetFloatField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> float +static Java.Interop.JniEnvironment.InstanceFields.GetIntField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> int +static Java.Interop.JniEnvironment.InstanceFields.GetLongField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> long +static Java.Interop.JniEnvironment.InstanceFields.GetObjectField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.InstanceFields.GetShortField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field) -> short +static Java.Interop.JniEnvironment.InstanceFields.SetBooleanField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, bool value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetByteField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, sbyte value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetCharField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, char value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetDoubleField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, double value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetFloatField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, float value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetIntField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, int value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetLongField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, long value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetObjectField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, Java.Interop.JniObjectReference value) -> void +static Java.Interop.JniEnvironment.InstanceFields.SetShortField(Java.Interop.JniObjectReference instance, Java.Interop.JniFieldInfo! field, short value) -> void +static Java.Interop.JniEnvironment.InstanceMethods.CallBooleanMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> bool +static Java.Interop.JniEnvironment.InstanceMethods.CallBooleanMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> bool +static Java.Interop.JniEnvironment.InstanceMethods.CallByteMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> sbyte +static Java.Interop.JniEnvironment.InstanceMethods.CallByteMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> sbyte +static Java.Interop.JniEnvironment.InstanceMethods.CallCharMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> char +static Java.Interop.JniEnvironment.InstanceMethods.CallCharMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> char +static Java.Interop.JniEnvironment.InstanceMethods.CallDoubleMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> double +static Java.Interop.JniEnvironment.InstanceMethods.CallDoubleMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> double +static Java.Interop.JniEnvironment.InstanceMethods.CallFloatMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> float +static Java.Interop.JniEnvironment.InstanceMethods.CallFloatMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> float +static Java.Interop.JniEnvironment.InstanceMethods.CallIntMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> int +static Java.Interop.JniEnvironment.InstanceMethods.CallIntMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> int +static Java.Interop.JniEnvironment.InstanceMethods.CallLongMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> long +static Java.Interop.JniEnvironment.InstanceMethods.CallLongMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> long +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> bool +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> bool +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualByteMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> sbyte +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualByteMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> sbyte +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualCharMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> char +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualCharMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> char +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> double +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> double +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> float +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> float +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualIntMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> int +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualIntMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> int +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualLongMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> long +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualLongMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> long +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualShortMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> short +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualShortMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> short +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> void +static Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> void +static Java.Interop.JniEnvironment.InstanceMethods.CallObjectMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.InstanceMethods.CallObjectMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.InstanceMethods.CallShortMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> short +static Java.Interop.JniEnvironment.InstanceMethods.CallShortMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> short +static Java.Interop.JniEnvironment.InstanceMethods.CallVoidMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method) -> void +static Java.Interop.JniEnvironment.InstanceMethods.CallVoidMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> void +static Java.Interop.JniEnvironment.InstanceMethods.GetMethodID(Java.Interop.JniObjectReference type, string! name, string! signature) -> Java.Interop.JniMethodInfo! +static Java.Interop.JniEnvironment.IO.GetDirectBufferAddress(Java.Interop.JniObjectReference buffer) -> nint +static Java.Interop.JniEnvironment.IO.GetDirectBufferCapacity(Java.Interop.JniObjectReference buffer) -> long +static Java.Interop.JniEnvironment.IO.NewDirectByteBuffer(nint address, long capacity) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.JniVersion.get -> Java.Interop.JniVersion +static Java.Interop.JniEnvironment.LocalReferenceCount.get -> int +static Java.Interop.JniEnvironment.Monitors.MonitorEnter(Java.Interop.JniObjectReference instance) -> void +static Java.Interop.JniEnvironment.Monitors.MonitorExit(Java.Interop.JniObjectReference instance) -> void +static Java.Interop.JniEnvironment.Object.AllocObject(Java.Interop.JniObjectReference type) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Object.NewObject(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Object.NewObject(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Object.ToString(Java.Interop.JniObjectReference value) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.References.CreatedReference(Java.Interop.JniObjectReference value) -> void +static Java.Interop.JniEnvironment.References.EnsureLocalCapacity(int capacity) -> void +static Java.Interop.JniEnvironment.References.GetIdentityHashCode(Java.Interop.JniObjectReference value) -> int +static Java.Interop.JniEnvironment.References.GetJavaVM(out nint invocationPointer) -> void +static Java.Interop.JniEnvironment.References.NewReturnToJniRef(Java.Interop.IJavaPeerable! value) -> nint +static Java.Interop.JniEnvironment.References.NewReturnToJniRef(Java.Interop.JniObjectReference value) -> nint +static Java.Interop.JniEnvironment.References.PopLocalFrame(Java.Interop.JniObjectReference result) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.References.PushLocalFrame(int capacity) -> void +static Java.Interop.JniEnvironment.Runtime.get -> Java.Interop.JniRuntime! +static Java.Interop.JniEnvironment.StaticFields.GetStaticBooleanField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> bool +static Java.Interop.JniEnvironment.StaticFields.GetStaticByteField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> sbyte +static Java.Interop.JniEnvironment.StaticFields.GetStaticCharField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> char +static Java.Interop.JniEnvironment.StaticFields.GetStaticDoubleField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> double +static Java.Interop.JniEnvironment.StaticFields.GetStaticFieldID(Java.Interop.JniObjectReference type, string! name, string! signature) -> Java.Interop.JniFieldInfo! +static Java.Interop.JniEnvironment.StaticFields.GetStaticFloatField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> float +static Java.Interop.JniEnvironment.StaticFields.GetStaticIntField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> int +static Java.Interop.JniEnvironment.StaticFields.GetStaticLongField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> long +static Java.Interop.JniEnvironment.StaticFields.GetStaticObjectField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.StaticFields.GetStaticShortField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field) -> short +static Java.Interop.JniEnvironment.StaticFields.SetStaticBooleanField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, bool value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticByteField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, sbyte value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticCharField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, char value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticDoubleField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, double value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticFloatField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, float value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticIntField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, int value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticLongField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, long value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticObjectField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, Java.Interop.JniObjectReference value) -> void +static Java.Interop.JniEnvironment.StaticFields.SetStaticShortField(Java.Interop.JniObjectReference type, Java.Interop.JniFieldInfo! field, short value) -> void +static Java.Interop.JniEnvironment.StaticMethods.CallStaticBooleanMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> bool +static Java.Interop.JniEnvironment.StaticMethods.CallStaticBooleanMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> bool +static Java.Interop.JniEnvironment.StaticMethods.CallStaticByteMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> sbyte +static Java.Interop.JniEnvironment.StaticMethods.CallStaticByteMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> sbyte +static Java.Interop.JniEnvironment.StaticMethods.CallStaticCharMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> char +static Java.Interop.JniEnvironment.StaticMethods.CallStaticCharMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> char +static Java.Interop.JniEnvironment.StaticMethods.CallStaticDoubleMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> double +static Java.Interop.JniEnvironment.StaticMethods.CallStaticDoubleMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> double +static Java.Interop.JniEnvironment.StaticMethods.CallStaticFloatMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> float +static Java.Interop.JniEnvironment.StaticMethods.CallStaticFloatMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> float +static Java.Interop.JniEnvironment.StaticMethods.CallStaticIntMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> int +static Java.Interop.JniEnvironment.StaticMethods.CallStaticIntMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> int +static Java.Interop.JniEnvironment.StaticMethods.CallStaticLongMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> long +static Java.Interop.JniEnvironment.StaticMethods.CallStaticLongMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> long +static Java.Interop.JniEnvironment.StaticMethods.CallStaticObjectMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.StaticMethods.CallStaticObjectMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.StaticMethods.CallStaticShortMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> short +static Java.Interop.JniEnvironment.StaticMethods.CallStaticShortMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> short +static Java.Interop.JniEnvironment.StaticMethods.CallStaticVoidMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method) -> void +static Java.Interop.JniEnvironment.StaticMethods.CallStaticVoidMethod(Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo! method, Java.Interop.JniArgumentValue* args) -> void +static Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(Java.Interop.JniObjectReference type, string! name, string! signature) -> Java.Interop.JniMethodInfo! +static Java.Interop.JniEnvironment.Strings.GetStringChars(Java.Interop.JniObjectReference stringInstance, bool* isCopy) -> char* +static Java.Interop.JniEnvironment.Strings.GetStringLength(Java.Interop.JniObjectReference stringInstance) -> int +static Java.Interop.JniEnvironment.Strings.NewString(char* unicodeChars, int length) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Strings.NewString(string? value) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Strings.ReleaseStringChars(Java.Interop.JniObjectReference stringInstance, char* chars) -> void +static Java.Interop.JniEnvironment.Strings.ToString(Java.Interop.JniObjectReference value) -> string? +static Java.Interop.JniEnvironment.Strings.ToString(nint reference) -> string? +static Java.Interop.JniEnvironment.Strings.ToString(ref Java.Interop.JniObjectReference value, Java.Interop.JniObjectReferenceOptions transfer) -> string? +static Java.Interop.JniEnvironment.Types.DefineClass(string! name, Java.Interop.JniObjectReference loader, nint buffer, int bufferLength) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Types.FindClass(string! classname) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Types.GetJniTypeNameFromClass(Java.Interop.JniObjectReference type) -> string? +static Java.Interop.JniEnvironment.Types.GetJniTypeNameFromInstance(Java.Interop.JniObjectReference instance) -> string? +static Java.Interop.JniEnvironment.Types.GetObjectClass(Java.Interop.JniObjectReference instance) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Types.GetSuperclass(Java.Interop.JniObjectReference type) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Types.GetTypeFromInstance(Java.Interop.JniObjectReference instance) -> Java.Interop.JniType? +static Java.Interop.JniEnvironment.Types.IsAssignableFrom(Java.Interop.JniObjectReference class1, Java.Interop.JniObjectReference class2) -> bool +static Java.Interop.JniEnvironment.Types.IsInstanceOf(Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type) -> bool +static Java.Interop.JniEnvironment.Types.IsSameObject(Java.Interop.JniObjectReference object1, Java.Interop.JniObjectReference object2) -> bool +static Java.Interop.JniEnvironment.Types.RegisterNatives(Java.Interop.JniObjectReference type, Java.Interop.JniNativeMethodRegistration[]! methods) -> void +static Java.Interop.JniEnvironment.Types.RegisterNatives(Java.Interop.JniObjectReference type, Java.Interop.JniNativeMethodRegistration[]! methods, int numMethods) -> void +static Java.Interop.JniEnvironment.Types.TryFindClass(string! classname, out Java.Interop.JniObjectReference instance) -> bool +static Java.Interop.JniEnvironment.Types.UnregisterNatives(Java.Interop.JniObjectReference type) -> void +static Java.Interop.JniEnvironment.WithinNewObjectScope.get -> bool +static Java.Interop.JniMarshal.RecursiveEquals(object? objA, object? objB) -> bool +static Java.Interop.JniMemberSignature.GetParameterCountFromMethodSignature(string! jniMethodSignature) -> int +static Java.Interop.JniMemberSignature.operator !=(Java.Interop.JniMemberSignature a, Java.Interop.JniMemberSignature b) -> bool +static Java.Interop.JniMemberSignature.operator ==(Java.Interop.JniMemberSignature a, Java.Interop.JniMemberSignature b) -> bool +static Java.Interop.JniObjectReference.Dispose(ref Java.Interop.JniObjectReference reference) -> void +static Java.Interop.JniObjectReference.Dispose(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +static Java.Interop.JniObjectReference.operator !=(Java.Interop.JniObjectReference lhs, Java.Interop.JniObjectReference rhs) -> bool +static Java.Interop.JniObjectReference.operator ==(Java.Interop.JniObjectReference lhs, Java.Interop.JniObjectReference rhs) -> bool +static Java.Interop.JniPeerMembers.Dispose(Java.Interop.JniPeerMembers! members) -> void +static Java.Interop.JniRuntime.CurrentRuntime.get -> Java.Interop.JniRuntime! +static Java.Interop.JniRuntime.GetAvailableInvocationPointers() -> System.Collections.Generic.IEnumerable! +static Java.Interop.JniRuntime.GetRegisteredRuntime(nint invocationPointer) -> Java.Interop.JniRuntime? +static Java.Interop.JniRuntime.GetRegisteredRuntimes() -> System.Collections.Generic.IEnumerable! +static Java.Interop.JniRuntime.ReplacementMethodInfo.operator !=(Java.Interop.JniRuntime.ReplacementMethodInfo a, Java.Interop.JniRuntime.ReplacementMethodInfo b) -> bool +static Java.Interop.JniRuntime.ReplacementMethodInfo.operator ==(Java.Interop.JniRuntime.ReplacementMethodInfo a, Java.Interop.JniRuntime.ReplacementMethodInfo b) -> bool +static Java.Interop.JniRuntime.SetCurrent(Java.Interop.JniRuntime! newCurrent) -> void +static Java.Interop.JniType.DefineClass(string! name, Java.Interop.JniObjectReference loader, byte[]! classFileData) -> Java.Interop.JniType? +static Java.Interop.JniType.GetCachedJniType(ref Java.Interop.JniType? cachedType, string! classname) -> Java.Interop.JniType! +static Java.Interop.JniType.TryParse(string! name, out Java.Interop.JniType? type) -> bool +static Java.Interop.JniTypeSignature.operator !=(Java.Interop.JniTypeSignature lhs, Java.Interop.JniTypeSignature rhs) -> bool +static Java.Interop.JniTypeSignature.operator ==(Java.Interop.JniTypeSignature lhs, Java.Interop.JniTypeSignature rhs) -> bool +static Java.Interop.JniTypeSignature.Parse(string! signature) -> Java.Interop.JniTypeSignature +static Java.Interop.JniTypeSignature.TryParse(string! signature, out Java.Interop.JniTypeSignature result) -> bool +static Java.Interop.JniValueMarshaler.DisposeObjectReference(System.Linq.Expressions.Expression! sourceValue) -> System.Linq.Expressions.Expression! +static Java.Interop.JniValueMarshalerState.operator !=(Java.Interop.JniValueMarshalerState a, Java.Interop.JniValueMarshalerState b) -> bool +static Java.Interop.JniValueMarshalerState.operator ==(Java.Interop.JniValueMarshalerState a, Java.Interop.JniValueMarshalerState b) -> bool +static readonly Java.Interop.JavaException.InvalidJniObjectReference -> Java.Interop.JniObjectReference* +static readonly Java.Interop.JavaObject.InvalidJniObjectReference -> Java.Interop.JniObjectReference* +static readonly Java.Interop.JniMemberSignature.Empty -> Java.Interop.JniMemberSignature +static readonly Java.Interop.JniTypeSignature.Empty -> Java.Interop.JniTypeSignature +virtual Java.Interop.JavaArray.Contains(T item) -> bool +virtual Java.Interop.JavaArray.GetEnumerator() -> System.Collections.Generic.IEnumerator! +virtual Java.Interop.JavaException.Dispose(bool disposing) -> void +virtual Java.Interop.JavaException.JniPeerMembers.get -> Java.Interop.JniPeerMembers! +virtual Java.Interop.JavaObject.Dispose(bool disposing) -> void +virtual Java.Interop.JavaObject.DisposeUnlessReferenced() -> void +virtual Java.Interop.JavaObject.JniPeerMembers.get -> Java.Interop.JniPeerMembers! +virtual Java.Interop.JniPeerMembers.Dispose(bool disposing) -> void +virtual Java.Interop.JniPeerMembers.GetPeerMembers(Java.Interop.IJavaPeerable! value) -> Java.Interop.JniPeerMembers! +virtual Java.Interop.JniPeerMembers.UsesVirtualDispatch(Java.Interop.IJavaPeerable! value, System.Type? declaringType) -> bool +virtual Java.Interop.JniRuntime.Dispose(bool disposing) -> void +virtual Java.Interop.JniRuntime.ExceptionShouldTransitionToJni(System.Exception! e) -> bool +virtual Java.Interop.JniRuntime.FailFast(string? message) -> void +virtual Java.Interop.JniRuntime.GetCurrentManagedThreadName() -> string? +virtual Java.Interop.JniRuntime.GetCurrentManagedThreadStackTrace(int skipFrames = 0, bool fNeedFileInfo = false) -> string? +virtual Java.Interop.JniRuntime.GetExceptionForThrowable(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> System.Exception? +virtual Java.Interop.JniRuntime.JniMarshalMemberBuilder.Dispose(bool disposing) -> void +virtual Java.Interop.JniRuntime.JniMarshalMemberBuilder.OnSetRuntime(Java.Interop.JniRuntime! runtime) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.CreatedLocalReference(Java.Interop.JniObjectReference reference, ref int localReferenceCount) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.CreateGlobalReference(Java.Interop.JniObjectReference reference) -> Java.Interop.JniObjectReference +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.CreateLocalReference(Java.Interop.JniObjectReference reference, ref int localReferenceCount) -> Java.Interop.JniObjectReference +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.CreateWeakGlobalReference(Java.Interop.JniObjectReference reference) -> Java.Interop.JniObjectReference +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.DeleteGlobalReference(ref Java.Interop.JniObjectReference reference) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.DeleteLocalReference(ref Java.Interop.JniObjectReference reference, ref int localReferenceCount) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.DeleteWeakGlobalReference(ref Java.Interop.JniObjectReference reference) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.Dispose(bool disposing) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.LogGlobalReferenceMessages.get -> bool +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.LogLocalReferenceMessages.get -> bool +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.OnSetRuntime(Java.Interop.JniRuntime! runtime) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.ReleaseLocalReference(ref Java.Interop.JniObjectReference reference, ref int localReferenceCount) -> nint +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.WriteGlobalReferenceLine(string! format, params object?[]! args) -> void +virtual Java.Interop.JniRuntime.JniObjectReferenceManager.WriteLocalReferenceLine(string! format, params object![]! args) -> void +virtual Java.Interop.JniRuntime.JniTypeManager.Dispose(bool disposing) -> void +virtual Java.Interop.JniRuntime.JniTypeManager.GetReplacementMethodInfoCore(string! jniSimpleReference, string! jniMethodName, string! jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? +virtual Java.Interop.JniRuntime.JniTypeManager.GetReplacementTypeCore(string! jniSimpleReference) -> string? +virtual Java.Interop.JniRuntime.JniTypeManager.GetSimpleReference(System.Type! type) -> string? +virtual Java.Interop.JniRuntime.JniTypeManager.GetSimpleReferences(System.Type! type) -> System.Collections.Generic.IEnumerable! +virtual Java.Interop.JniRuntime.JniTypeManager.GetStaticMethodFallbackTypesCore(string! jniSimple) -> System.Collections.Generic.IReadOnlyList? +virtual Java.Interop.JniRuntime.JniTypeManager.GetTypes(Java.Interop.JniTypeSignature typeSignature) -> System.Collections.Generic.IEnumerable! +virtual Java.Interop.JniRuntime.JniTypeManager.GetTypesForSimpleReference(string! jniSimpleReference) -> System.Collections.Generic.IEnumerable! +virtual Java.Interop.JniRuntime.JniTypeManager.OnSetRuntime(Java.Interop.JniRuntime! runtime) -> void +virtual Java.Interop.JniRuntime.JniTypeManager.RegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, string? methods) -> void +virtual Java.Interop.JniRuntime.JniTypeManager.RegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, System.ReadOnlySpan methods) -> void +virtual Java.Interop.JniRuntime.JniValueManager.CreatePeer(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions transfer, System.Type? targetType) -> Java.Interop.IJavaPeerable? +virtual Java.Interop.JniRuntime.JniValueManager.Dispose(bool disposing) -> void +virtual Java.Interop.JniRuntime.JniValueManager.DisposePeer(Java.Interop.IJavaPeerable! value) -> void +virtual Java.Interop.JniRuntime.JniValueManager.DisposePeerUnlessReferenced(Java.Interop.IJavaPeerable! value) -> void +virtual Java.Interop.JniRuntime.JniValueManager.GetValueMarshalerCore(System.Type! type) -> Java.Interop.JniValueMarshaler! +virtual Java.Interop.JniRuntime.JniValueManager.OnSetRuntime(Java.Interop.JniRuntime! runtime) -> void +virtual Java.Interop.JniRuntime.JniValueManager.TryUnboxPeerObject(Java.Interop.IJavaPeerable! value, out object? result) -> bool +virtual Java.Interop.JniRuntime.RaisePendingException(System.Exception! pendingException) -> void +virtual Java.Interop.JniValueMarshaler.CreateArgumentState(object? value, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> Java.Interop.JniValueMarshalerState +virtual Java.Interop.JniValueMarshaler.CreateParameterFromManagedExpression(Java.Interop.Expressions.JniValueMarshalerContext! context, System.Linq.Expressions.ParameterExpression! sourceValue, System.Reflection.ParameterAttributes synchronize) -> System.Linq.Expressions.Expression! +virtual Java.Interop.JniValueMarshaler.CreateParameterToManagedExpression(Java.Interop.Expressions.JniValueMarshalerContext! context, System.Linq.Expressions.ParameterExpression! sourceValue, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None, System.Type? targetType = null) -> System.Linq.Expressions.Expression! +virtual Java.Interop.JniValueMarshaler.CreateReturnValueFromManagedExpression(Java.Interop.Expressions.JniValueMarshalerContext! context, System.Linq.Expressions.ParameterExpression! sourceValue) -> System.Linq.Expressions.Expression! +virtual Java.Interop.JniValueMarshaler.IsJniValueType.get -> bool +virtual Java.Interop.JniValueMarshaler.MarshalType.get -> System.Type! +virtual Java.Interop.JniValueMarshaler.CreateGenericArgumentState(T value, System.Reflection.ParameterAttributes synchronize = System.Reflection.ParameterAttributes.None) -> Java.Interop.JniValueMarshalerState diff --git a/external/Java.Interop/src/Java.Interop/PublicAPI.Unshipped.txt b/external/Java.Interop/src/Java.Interop/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..c4b72718507 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/PublicAPI.Unshipped.txt @@ -0,0 +1,118 @@ +#nullable enable +static Java.Interop.JniEnvironment.BeginMarshalMethod(nint jnienv, out Java.Interop.JniTransition transition, out Java.Interop.JniRuntime? runtime) -> bool +static Java.Interop.JniEnvironment.EndMarshalMethod(ref Java.Interop.JniTransition transition) -> void +virtual Java.Interop.JniRuntime.OnEnterMarshalMethod() -> void +virtual Java.Interop.JniRuntime.OnUserUnhandledException(ref Java.Interop.JniTransition transition, System.Exception! e) -> void +virtual Java.Interop.JniRuntime.JniTypeManager.GetInvokerTypeCore(System.Type! type) -> System.Type? +virtual Java.Interop.JniRuntime.JniTypeManager.GetTypeForSimpleReference(string! jniSimpleReference) -> System.Type? +virtual Java.Interop.JniRuntime.JniTypeManager.GetTypeSignatureCore(System.Type! type) -> Java.Interop.JniTypeSignature +virtual Java.Interop.JniRuntime.JniTypeManager.GetTypeSignaturesCore(System.Type! type) -> System.Collections.Generic.IEnumerable! +abstract Java.Interop.JniRuntime.JniValueManager.CreateLocalObjectReferenceArgumentCore(System.Type! type, object? value) -> Java.Interop.JniObjectReference +Java.Interop.JavaException.JavaException(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions transfer, Java.Interop.JniObjectReference throwableOverride) -> void +Java.Interop.JavaException.SetJavaStackTrace(Java.Interop.JniObjectReference peerReferenceOverride = default(Java.Interop.JniObjectReference)) -> void +Java.Interop.JniRuntime.ReflectionJniTypeManager +Java.Interop.JniRuntime.ReflectionJniTypeManager.ReflectionJniTypeManager() -> void +Java.Interop.JniRuntime.ReflectionJniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, string? methods) -> bool +Java.Interop.JniRuntime.ReflectionJniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, System.ReadOnlySpan methods) -> bool +Java.Interop.JniRuntime.JniTypeManager.GetInvokerType(System.Type! type) -> System.Type? +Java.Interop.JniRuntime.JniValueManager.GetPeer(Java.Interop.JniObjectReference reference, System.Type? targetType = null) -> Java.Interop.IJavaPeerable? +Java.Interop.JniRuntime.JniValueManager.EnsureNotDisposed() -> void +Java.Interop.JniRuntime.ReflectionJniValueManager +Java.Interop.JniRuntime.ReflectionJniValueManager.ReflectionJniValueManager() -> void +Java.Interop.JniTypeSignatureAttribute.InvokerType.get -> System.Type? +Java.Interop.JniTypeSignatureAttribute.InvokerType.set -> void +Java.Interop.IJavaPeerable.JniObjectReferenceControlBlock.get -> nint +Java.Interop.JniNativeMethod +Java.Interop.JniNativeMethod.JniNativeMethod() -> void +Java.Interop.JniNativeMethod.JniNativeMethod(byte* name, byte* signature, nint functionPointer) -> void +static Java.Interop.JniEnvironment.Types.RegisterNatives(Java.Interop.JniObjectReference type, System.ReadOnlySpan methods) -> void +Java.Interop.JniType.JniType(System.ReadOnlySpan classname) -> void +Java.Interop.JniType.GetConstructor(System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetCachedConstructor(ref Java.Interop.JniMethodInfo? cachedMethod, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetInstanceField(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetCachedInstanceField(ref Java.Interop.JniFieldInfo? cachedField, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetStaticField(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetCachedStaticField(ref Java.Interop.JniFieldInfo? cachedField, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetInstanceMethod(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetCachedInstanceMethod(ref Java.Interop.JniMethodInfo? cachedMethod, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetStaticMethod(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetCachedStaticMethod(ref Java.Interop.JniMethodInfo? cachedMethod, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +static Java.Interop.JniType.GetCachedJniType(ref Java.Interop.JniType? cachedType, System.ReadOnlySpan classname) -> Java.Interop.JniType! +static Java.Interop.JniEnvironment.Types.FindClass(System.ReadOnlySpan classname) -> Java.Interop.JniObjectReference +static Java.Interop.JniEnvironment.Types.TryFindClass(System.ReadOnlySpan classname, out Java.Interop.JniObjectReference instance) -> bool +static Java.Interop.JniEnvironment.InstanceFields.GetFieldID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +static Java.Interop.JniEnvironment.InstanceMethods.GetMethodID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +static Java.Interop.JniEnvironment.StaticFields.GetStaticFieldID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +static Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +*REMOVED*abstract Java.Interop.JniRuntime.JniValueManager.ActivatePeer(Java.Interop.IJavaPeerable? self, Java.Interop.JniObjectReference reference, System.Reflection.ConstructorInfo! cinfo, object?[]? argumentValues) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, T15 p15, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, T1 p1, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeAction(nint jnienv, nint self, T0 p0, delegate* action) -> void +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, T15 p15, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, T3 p3, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, T2 p2, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, T1 p1, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, T0 p0, delegate* action) -> TResult +static Java.Interop.JniMarshal.SafeInvokeFunc(nint jnienv, nint self, delegate* action) -> TResult +abstract Java.Interop.JniRuntime.JniValueManager.ActivatePeer(Java.Interop.JniObjectReference reference, System.Type! type, System.Reflection.ConstructorInfo! cinfo, object?[]? argumentValues) -> void +abstract Java.Interop.JniRuntime.JniValueManager.ConstructPeerCore(Java.Interop.IJavaPeerable! peer, ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +abstract Java.Interop.JniRuntime.JniValueManager.CreateValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +abstract Java.Interop.JniRuntime.JniValueManager.CreateValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> T +abstract Java.Interop.JniRuntime.JniValueManager.GetValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +abstract Java.Interop.JniRuntime.JniValueManager.GetValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> T +abstract Java.Interop.JniRuntime.JniValueManager.GetValueMarshalerCore() -> Java.Interop.JniValueMarshaler! +*REMOVED*Java.Interop.JniRuntime.JniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, string? methods) -> bool +*REMOVED*Java.Interop.JniRuntime.JniTypeManager.TryRegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, System.ReadOnlySpan methods) -> bool +*REMOVED*virtual Java.Interop.JniRuntime.JniValueManager.CreatePeer(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions transfer, System.Type? targetType) -> Java.Interop.IJavaPeerable? +abstract Java.Interop.JniRuntime.JniValueManager.CreatePeer(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions transfer, System.Type? targetType) -> Java.Interop.IJavaPeerable? +*REMOVED*virtual Java.Interop.JniRuntime.JniValueManager.GetValueMarshalerCore(System.Type! type) -> Java.Interop.JniValueMarshaler! +abstract Java.Interop.JniRuntime.JniValueManager.GetValueMarshalerCore(System.Type! type) -> Java.Interop.JniValueMarshaler! +override Java.Interop.JniRuntime.ReflectionJniValueManager.ActivatePeer(Java.Interop.JniObjectReference reference, System.Type! type, System.Reflection.ConstructorInfo! cinfo, object?[]? argumentValues) -> void +override Java.Interop.JniRuntime.ReflectionJniValueManager.ConstructPeerCore(Java.Interop.IJavaPeerable! peer, ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options) -> void +override Java.Interop.JniRuntime.ReflectionJniValueManager.CreatePeer(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions transfer, System.Type? targetType) -> Java.Interop.IJavaPeerable? +override Java.Interop.JniRuntime.ReflectionJniValueManager.CreateLocalObjectReferenceArgumentCore(System.Type! type, object? value) -> Java.Interop.JniObjectReference +override Java.Interop.JniRuntime.ReflectionJniValueManager.CreateValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +override Java.Interop.JniRuntime.ReflectionJniValueManager.CreateValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> T +override Java.Interop.JniRuntime.ReflectionJniValueManager.GetValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> object? +override Java.Interop.JniRuntime.ReflectionJniValueManager.GetValueCore(ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type? targetType = null) -> T +override Java.Interop.JniRuntime.ReflectionJniValueManager.GetValueMarshalerCore(System.Type! type) -> Java.Interop.JniValueMarshaler! +override Java.Interop.JniRuntime.ReflectionJniValueManager.GetValueMarshalerCore() -> Java.Interop.JniValueMarshaler! +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetInvokerTypeCore(System.Type! type) -> System.Type? +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetReplacementMethodInfoCore(string! jniSimpleReference, string! jniMethodName, string! jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetReplacementTypeCore(string! jniSimpleReference) -> string? +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetSimpleReference(System.Type! type) -> string? +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetSimpleReferences(System.Type! type) -> System.Collections.Generic.IEnumerable! +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetStaticMethodFallbackTypesCore(string! jniSimple) -> System.Collections.Generic.IReadOnlyList? +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetTypeForSimpleReference(string! jniSimpleReference) -> System.Type? +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetTypeSignatureCore(System.Type! type) -> Java.Interop.JniTypeSignature +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetTypeSignaturesCore(System.Type! type) -> System.Collections.Generic.IEnumerable! +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetTypes(Java.Interop.JniTypeSignature typeSignature) -> System.Collections.Generic.IEnumerable! +override Java.Interop.JniRuntime.ReflectionJniTypeManager.GetTypesForSimpleReference(string! jniSimpleReference) -> System.Collections.Generic.IEnumerable! +override Java.Interop.JniRuntime.ReflectionJniTypeManager.RegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, string? methods) -> void +override Java.Interop.JniRuntime.ReflectionJniTypeManager.RegisterNativeMembers(Java.Interop.JniType! nativeClass, System.Type! type, System.ReadOnlySpan methods) -> void +virtual Java.Interop.JniRuntime.ReflectionJniValueManager.TryConstructPeer(Java.Interop.IJavaPeerable! self, ref Java.Interop.JniObjectReference reference, Java.Interop.JniObjectReferenceOptions options, System.Type! type) -> bool diff --git a/external/Java.Interop/src/Java.Interop/java/net/dot/jni/GCUserPeerable.java b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/GCUserPeerable.java new file mode 100644 index 00000000000..7356f4bbc45 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/GCUserPeerable.java @@ -0,0 +1,8 @@ +package net.dot.jni; + +public interface GCUserPeerable { + + void jiAddManagedReference (java.lang.Object obj); + void jiClearManagedReferences (); +} + diff --git a/external/Java.Interop/src/Java.Interop/java/net/dot/jni/ManagedPeer.java b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/ManagedPeer.java new file mode 100644 index 00000000000..dc66d3122e9 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/ManagedPeer.java @@ -0,0 +1,16 @@ +package net.dot.jni; + +public /* static */ final class ManagedPeer { + private ManagedPeer () { + } + + public static native void registerNativeMembers ( + java.lang.Class nativeClass, + String methods); + + public static native void construct ( + Object self, + String constructorSignature, + Object... arguments + ); +} diff --git a/external/Java.Interop/src/Java.Interop/java/net/dot/jni/internal/JavaProxyObject.java b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/internal/JavaProxyObject.java new file mode 100644 index 00000000000..013cb070876 --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/internal/JavaProxyObject.java @@ -0,0 +1,38 @@ +package net.dot.jni.internal; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +/* package */ final class JavaProxyObject + extends java.lang.Object + implements GCUserPeerable +{ + static { + net.dot.jni.ManagedPeer.registerNativeMembers ( + JavaProxyObject.class, + ""); + } + + ArrayList managedReferences = new ArrayList(); + + @Override + public native boolean equals(Object obj); + + @Override + public native int hashCode(); + + @Override + public native String toString(); + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} + diff --git a/external/Java.Interop/src/Java.Interop/java/net/dot/jni/internal/JavaProxyThrowable.java b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/internal/JavaProxyThrowable.java new file mode 100644 index 00000000000..066025ac58a --- /dev/null +++ b/external/Java.Interop/src/Java.Interop/java/net/dot/jni/internal/JavaProxyThrowable.java @@ -0,0 +1,36 @@ +package net.dot.jni.internal; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +/* package */ final class JavaProxyThrowable + extends java.lang.Error + implements GCUserPeerable +{ + static { + net.dot.jni.ManagedPeer.registerNativeMembers ( + JavaProxyThrowable.class, + ""); + } + + ArrayList managedReferences = new ArrayList(); + + public JavaProxyThrowable () { + } + + public JavaProxyThrowable (String message) { + super (message); + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/CecilExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/CecilExtensions.cs new file mode 100644 index 00000000000..b1bbfcc3464 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/CecilExtensions.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.Cecil; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public static class CecilExtensions + { + public static string GetCorrectName (this TypeReference t) + { + return (t.DeclaringType != null ? t.DeclaringType.GetCorrectName () + "." + t.Name : t.Name).Replace ('/', '.'); + } + + public static string GetCorrectNamespace (this TypeReference t) + { + return t.DeclaringType != null ? t.DeclaringType.GetCorrectNamespace () : t.Namespace; + } + + public static IEnumerable FlattenTypes (this TypeDefinition t) + { + yield return t; + foreach (var x in t.NestedTypes.SelectMany (nt => nt.FlattenTypes ())) + yield return x; + } + + public static IEnumerable GetSelfAndAncestors (this TypeDefinition t) + { + yield return t; + if (t.BaseType != null) + foreach (var a in t.BaseType.Resolve ().GetSelfAndAncestors ()) + yield return t; + } + + public static IEnumerable GetMethods (this TypeDefinition t) + { + foreach (var m in t.Methods) + yield return m; + foreach (var p in t.Properties) { + if (p.GetMethod != null) + yield return p.GetMethod; + if (p.SetMethod != null) + yield return p.SetMethod; + } + if (t.BaseType != null) + foreach (var m in t.BaseType.Resolve ().GetMethods ()) + yield return m; + if (t.IsInterface) + foreach (var it in t.Interfaces) + foreach (var m in it.InterfaceType.Resolve ().GetMethods ()) + yield return m; + } + + public static IEnumerable GetProperties (this TypeDefinition t) + { + return t.BaseType == null ? t.Properties : t.Properties.Concat (t.BaseType.Resolve ().GetProperties ()); + } + + #region conversion between general interfaces + + public static TypeDefinition Value (this ManagedTypeFinder.IType t) + { + return ((ManagedTypeFinderCecil.TType) t).Value; + } + public static PropertyDefinition Value (this ManagedTypeFinder.IProperty p) + { + return ((ManagedTypeFinderCecil.TProperty) p).Value; + } + public static FieldDefinition Value (this ManagedTypeFinder.IDefinition t) + { + return ((ManagedTypeFinderCecil.TDefinition) t).Value; + } + public static MethodDefinition Value (this ManagedTypeFinder.IMethodBase t) + { + return ((ManagedTypeFinderCecil.TMethodBase) t).Value; + } + + public static ManagedTypeFinder.IType Wrap (this TypeDefinition t) + { + return t == null ? null : new ManagedTypeFinderCecil.TType () { Value = t }; + } + public static ManagedTypeFinder.IProperty WrapAsProperty (this PropertyDefinition t) + { + return t == null ? null : new ManagedTypeFinderCecil.TProperty () { Value = t }; + } + public static ManagedTypeFinder.IDefinition WrapAsDefinition (this FieldDefinition t) + { + return t == null ? null : new ManagedTypeFinderCecil.TDefinition () { Value = t }; + } + public static ManagedTypeFinder.IMethodBase Wrap (this MethodDefinition t) + { + return t == null ? null : new ManagedTypeFinderCecil.TMethodBase () { Value = t }; + } + + #endregion + + #region Utility methods for public + + public static ManagedApiQuery AsQuery (this IMemberDefinition member, int parameterIndex = -1) + { + if (member is TypeDefinition) + return new ManagedApiQuery { TypeName = GetCorrectName ((TypeDefinition) member) }; + var type = member.DeclaringType; + var typeName = GetCorrectName (type); + if (member is FieldDefinition || member is PropertyDefinition) + return new ManagedApiQuery { TypeName = typeName, MemberName = member.Name }; + var method = (MethodDefinition) member; + return new ManagedApiQuery { + TypeName = typeName, + MemberName = member.Name, + Arguments = method.Parameters.Select (p => GetCorrectName (p.ParameterType)).ToArray (), + ParameterIndex = parameterIndex + }; + } + + #endregion + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/ManagedTypeFinderCecil.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/ManagedTypeFinderCecil.cs new file mode 100644 index 00000000000..1181081e247 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/ManagedTypeFinderCecil.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.Cecil; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + // It is not for use within generator; it is an isolated implementation model for + // Java annotation - managed type binder. + public class ManagedTypeFinderCecil : ManagedTypeFinderDefault + { + public ManagedTypeFinderCecil (string assemblyFileName) + { + assembly = assemblyFileName; + } + + string assembly; + + #region AnnotationParserExtension + + protected override void OnAnnotationsParsed (IEnumerable itemsToBeBound) + { + var allTypes = AssemblyDefinition.ReadAssembly (assembly).Modules + .SelectMany (m => m.Types) + .SelectMany (t => t.FlattenTypes ()) + .ToArray (); + var types = allTypes.Where (t => !t.FullName.StartsWith ("Android.Runtime.", StringComparison.Ordinal)) + // This condition is added for kind of hacky reason: interface consts are + // saved in a static class (because C# interface cannot have consts) and + // they have identical [Register]-ed Java names as that of the corresponding interface types. + // In this java-C# matcher we don't need those consts-only classes, so filter them out. + .Where (t => (t.IsInterface || t.BaseType == null || t.BaseType.FullName != "System.Object") && (t.Methods.Where (m => !m.IsConstructor).Any () || t.Properties.Any ())) + // This condition would also look weird, but some managed types have manual binding with + // [Register] attribute, namely ArrayAdapter. They don't come up with + // JavaTypeParametersAttribute, so we have to exclude them. + .Where (t => !t.GenericParameters.Any ()) + .Select (t => t.Wrap ()) + .ToArray (); + + LoadManagedMappings (itemsToBeBound, types); + } + + #endregion + + #region ManagedTypeFinder implementation + public abstract class Wrapper + { + public T Value { get; set; } + } + + public class TType : Wrapper, IType { } + public class TDefinition : Wrapper, IDefinition { } + public class TProperty : Wrapper, IProperty { } + public class TMethodBase : Wrapper, IMethodBase { } + + internal Func getRegisterAtt = t => t.CustomAttributes.FirstOrDefault (a => a.AttributeType.FullName == "Android.Runtime.RegisterAttribute"); + internal Func getJavaTypesAtt = t => t.CustomAttributes.FirstOrDefault (a => a.AttributeType.FullName == "Java.Interop.JavaTypeParametersAttribute"); + + public override string GetManagedName (ManagedTypeFinder.IType t) + { + return t.Value ().GetCorrectName (); + } + + public override string GetJavaName (IType t) + { + return GetJavaNameFromCustomAttribute (t.Value ()); + } + + public override string GetJavaName (IDefinition f) + { + return GetJavaNameFromCustomAttribute (f.Value ()); + } + + public override IProperty GetAnnotatedField (IType t, string fieldName) + { + return t.Value ().GetProperties () + .Select (f => new { Property = f, Value = GetJavaNameFromCustomAttribute (f) }) + .FirstOrDefault (p => p.Value == fieldName) + ?.Property.WrapAsProperty (); + } + + public override IDefinition GetDefinitionField (IType iType, string fieldName) + { + // Since a managed interface cannot have fields, we put them into a class. + // Retrieve the field from the class, if applicable. + var t = iType.Value (); + t = t.IsInterface ? t.Module.Types.FirstOrDefault (_ => _.GetCorrectNamespace () == t.GetCorrectNamespace () && _.GetCorrectName () == t.GetCorrectName ().Substring (1)) ?? t : t; + return t.Fields.FirstOrDefault (f => GetJavaNameFromCustomAttribute (f) == fieldName).WrapAsDefinition (); + } + + string GetJavaNameFromCustomAttribute (ICustomAttributeProvider t) + { + var ca = getRegisterAtt (t); + return ca == null ? null : ca.ConstructorArguments.First ().Value as string; + } + + public override TypeName [] GetParameterTypes (IMethodBase method) + { + return method.Value ().Parameters.Select (p => new TypeName () { Namespace = p.ParameterType.GetCorrectNamespace (), Name = p.ParameterType.GetCorrectName () }).ToArray (); + } + + public override void SetName (ManagedMemberInfo destination, IType iType) + { + var type = iType.Value (); + destination.Type.Namespace = type.GetCorrectNamespace (); + destination.Type.Name = type.GetCorrectName (); + } + + public override string GetPropertyName (IProperty m) + { + return m.Value ().Name; + } + + public override string GetDefinitionName (IDefinition m) + { + return m.Value ().Name; + } + + public override IEnumerable GetFields (IType t) + { + return t.Value ().Fields.Select (f => f.WrapAsDefinition ()); + } + + public override string GetMethodName (IMethodBase m) + { + return m.Value ().Name; + } + + public override string GetFieldManagedTypeName (ManagedTypeFinder.IProperty property) + { + return property.Value ().PropertyType.FullName; + } + + public override string GetMethodReturnManagedTypeName (IMethodBase method) + { + var m = method.Value (); + return m.IsConstructor ? null : m.ReturnType.FullName; + } + + public override string GetParameterManagedTypeName (IMethodBase m, int index) + { + return m.Value ().Parameters [index].ParameterType.FullName; + } + + public override IMethodBase GetMethod (IType iType, AnnotatedItem item) + { + var t = iType.Value (); + Func getRegisterAttName = type => { + var ca = getRegisterAtt (type); + return ca == null ? null : ca.ConstructorArguments [0].Value as string; + }; + Func getRegisterAttJni = type => { + var ca = getRegisterAtt (type); + return ca == null ? null : ca.ConstructorArguments [1].Value as string; + }; + + var methods = t.GetMethods () + .Where (m => (item.MemberName == "#ctor" && m.IsConstructor || getRegisterAttName (m) == item.MemberName) && m.Parameters.Count == item.Arguments.Length) + .ToArray (); + + // First, try loose match just by checking argument count. + + MethodDefinition candidate = null; + bool overloaded = false; + foreach (var m in methods) { + if (overloaded) + break; + if (candidate != null) { + overloaded = true; + break; + } else + candidate = m; + } + if (!overloaded) { + if (candidate == null) + Errors.Add ("warning: method with matching argument count not found: " + t + " member: " + item.FormatMember ()); + return candidate.Wrap (); + } + + // Second, try strict match. + + Func getJavaGenTypesValue = td => { + var a = getJavaTypesAtt (td); + var arr = a == null ? new string [0] : ((CustomAttributeArgument []) a.ConstructorArguments [0].Value).Select (ca => ca.Value as string); + return arr.Select (s => s.Contains (' ') ? s.Substring (0, s.IndexOf (' ')) : s).ToArray (); + }; + var typeGenArgs = t.GetSelfAndAncestors ().SelectMany (getJavaGenTypesValue).ToArray (); + + var argTypeLists = methods.Select (m => new { Method = m, Jni = getRegisterAttJni (m)}) + .Select (p => new { Method = p.Method, Arguments = p.Jni == null ? null : ParseJniMethodArgumentsSignature (p.Jni)}) + .ToArray (); + + for (int i = 0; i < argTypeLists.Length; i++) { + var argTypeListPair = argTypeLists [i]; + var argTypeList = argTypeListPair.Arguments; + var methodGenArgs = getJavaGenTypesValue (argTypeListPair.Method); + if (!AreArgumentsEqualLax (argTypeList, item.Arguments, typeGenArgs.Concat (methodGenArgs))) + continue; + return methods [i].Wrap (); + } + Errors.Add ("warning: method overload not found: " + t + " member: " + item.FormatMember ()); + return null; + } + #endregion + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/Xamarin.Android.Tools.AnnotationSupport.Cecil.csproj b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/Xamarin.Android.Tools.AnnotationSupport.Cecil.csproj new file mode 100644 index 00000000000..e670ba91a3a --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport.Cecil/Xamarin.Android.Tools.AnnotationSupport.Cecil.csproj @@ -0,0 +1,24 @@ + + + + $(DotNetTargetFramework) + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AndroidAnnotationsSupport.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AndroidAnnotationsSupport.cs new file mode 100644 index 00000000000..05641e28019 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AndroidAnnotationsSupport.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using System.Xml; +using HtmlAgilityPack; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class AndroidAnnotationsSupport + { + #region static members + + public static IList ParseArchive (string file) + { + using (var zipFile = File.OpenRead (file)) + return new ZipArchive (zipFile).Entries + .Where (e => e.Name.EndsWith ("annotations.xml", StringComparison.Ordinal)) + .SelectMany (e => ParseArchiveEntry (e)) + .OrderBy (k => k.Name) + .ToArray (); + } + + static IEnumerable ParseArchiveEntry (ZipArchiveEntry entry) + { + using (var s = entry.Open ()) + return SafeXmlLoad (s, entry.FullName).Root.Elements ("item").Select (e => new AnnotatedItem (e)); + } + + static XDocument SafeXmlLoad (Stream s, string fileName) + { + // We must save to a temporary stream because the stream doesn't support seeking and should the + // parsing fail we won't be able to go back to its beginnig to reparse it. + using (var ms = new MemoryStream ()) { + s.CopyTo (ms); + ms.Seek (0, SeekOrigin.Begin); + + try { + return XDocument.Load (ms); + } catch (XmlException ex) { + Console.Error.WriteLine ($"Warning: failed to load annotation document '{fileName}' directly from the annotations archive. {ex.Message}"); + Console.Error.WriteLine ("Attempting to fix up and reload"); + } + + try { + using (var ns = FixAnnotationXML (ms)) { + return XDocument.Load (ns); + } + } catch (Exception ex) { + throw new InvalidOperationException ($"Failed to fix up invalid XML in annotation document '{fileName}'. {ex.Message}", ex); + } + } + } + + static Stream FixAnnotationXML (Stream s) + { + s.Seek (0, SeekOrigin.Begin); + + // + // Context: https://issuetracker.google.com/issues/116182838 + // + // Google ships not well-formed XML files in the platform-tools 28.0.1 package (in the + // annotations.zip file), so we need to load the files with a forgiving parser in order to fix + // them up before loading with a validating XML parser. + var doc = new HtmlDocument (); + doc.Load (s); + if (doc.DocumentNode.FirstChild.InnerHtml.StartsWith (" l; + if (!data.TryGetValue (key, out l)) + data [key] = l = new List (); + l.Add (a); + } + } + + List extensions = new List (); + + public IList Extensions { + get { return extensions; } + } + + Dictionary> data = new Dictionary> (); + + public IDictionary> Data { + get { return data; } + } + + #endregion + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AnnotationExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AnnotationExtensions.cs new file mode 100644 index 00000000000..a56c05ae611 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AnnotationExtensions.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public static class AnnotationExtensions + { + public static string FormatMember (this AnnotatedItem a) + { + return string.Format (" [{0}] {1} {2} {3}", + a.Arguments == null ? "F" : a.ParameterIndex >= 0 ? ("P" + a.ParameterIndex) : a.MemberName == "#ctor" ? "C" : "M", + a.MemberType, + a.MemberName, + a.Arguments == null ? null : "(" + string.Join (", ", a.Arguments) + ")"); + } + + #region annotated member retrieval + + public static IEnumerable Data (this IEnumerable anns) + { + return anns.SelectMany (a => a.Annotations); + } + + public static IEnumerable GetAnnotations (this AndroidAnnotationsSupport api, ManagedApiQuery query) + { + if (query == null) + throw new ArgumentNullException (nameof (query)); + if (query.TypeName == null) + throw new ArgumentNullException ("TypeName must not be null"); + + IList l; + var qt = api.Data.TryGetValue (query.TypeName, out l) ? l : new AnnotatedItem [0]; + + if (query.MemberName == null) // type + return qt; + + var qmbr = qt.Where (a => a.ManagedInfo.MemberName == query.MemberName); + if (query.Arguments == null) // field, property (from managed signature), or method match without arguments. + return qmbr.Concat (qt.Where (a => IsProperty (a, query.MemberName))); + + var qmth = qmbr.Where (a => AreArgumentsEqual (a.ManagedInfo.Arguments, query.Arguments)); + // method (idx < 0) or parameter (idx >= 0) + return qmth.Where (a => a.ParameterIndex == query.ParameterIndex || a.ParameterIndex < 0 && query.ParameterIndex < 0); + } + + public static IEnumerable GetAnnotations (this AndroidAnnotationsSupport api, string managedTypeName) + { + return api.GetAnnotations (new ManagedApiQuery { TypeName = managedTypeName }); + } + + public static IEnumerable GetAnnotations (this AndroidAnnotationsSupport api, string managedTypeName, string managedMemberName) + { + return api.GetAnnotations (new ManagedApiQuery { TypeName = managedTypeName, MemberName = managedMemberName }); + } + + public static IEnumerable GetAnnotations (this AndroidAnnotationsSupport api, string managedTypeName, string managedMethodName, string [] parameterTypes) + { + return api.GetAnnotations (new ManagedApiQuery { TypeName = managedTypeName, MemberName = managedMethodName, Arguments = parameterTypes }); + } + + public static IEnumerable GetAnnotations (this AndroidAnnotationsSupport api, string managedTypeName, string managedMethodName, string [] parameterTypes, int parameterIndex) + { + return api.GetAnnotations (new ManagedApiQuery { TypeName = managedTypeName, MemberName = managedMethodName, Arguments = parameterTypes, ParameterIndex = parameterIndex }); + } + + static bool IsProperty (AnnotatedItem item, string propertyName) + { + if (item.Arguments == null) + return false; + return item.ManagedInfo.MemberName == "get_" + propertyName && item.Arguments.Length == 0 + || item.ManagedInfo.MemberName == "set_" + propertyName && item.Arguments.Length == 1; + } + + [Obsolete ("Use GetAnnotations() overload.")] + public static IEnumerable GetMethodsAnnotations (this AndroidAnnotationsSupport api, string managedTypeName, string managedMethodName) + { + if (managedMethodName == null) + throw new ArgumentNullException (nameof (managedMethodName)); + return GetAnnotations (api, managedTypeName, managedMethodName); + } + + [Obsolete ("Use GetAnnotations() overload.")] + public static IEnumerable GetFieldAnnotations (this AndroidAnnotationsSupport api, string managedTypeName, string managedPropertyName) + { + if (managedPropertyName == null) + throw new ArgumentNullException (nameof (managedPropertyName)); + return GetAnnotations (api, managedTypeName, managedPropertyName); + } + + [Obsolete ("Use GetAnnotations() overload.")] + public static IEnumerable GetMethodAnnotations (this AndroidAnnotationsSupport api, string managedTypeName, string managedMethodName, string [] managedParameterTypes) + { + if (managedMethodName == null) + throw new ArgumentNullException (nameof (managedMethodName)); + if (managedParameterTypes == null) + throw new ArgumentNullException (nameof (managedParameterTypes)); + return GetAnnotations (api, managedTypeName, managedMethodName, managedParameterTypes); + } + + [Obsolete ("Use GetAnnotations() overload.")] + public static IEnumerable GetParameterAnnotations (this AndroidAnnotationsSupport api, string managedTypeName, string managedMethodName, string [] managedParameterTypes, int parameterIndex) + { + if (managedMethodName == null) + throw new ArgumentNullException (nameof (managedMethodName)); + if (managedParameterTypes == null) + throw new ArgumentNullException (nameof (managedParameterTypes)); + return GetAnnotations (api, managedTypeName, managedMethodName, managedParameterTypes, parameterIndex); + } + + static bool AreArgumentsEqual (TypeName [] definedArguments, IList queriedArguments) + { + if (definedArguments.Length != queriedArguments.Count) + return false; + return definedArguments.Zip (queriedArguments, (t, s) => t.FullName == s).All (b => b); + } + + #endregion + + #region Constant definition analysys + + static Func is_intdef = a => a.Name == "IntDef"; + static Func is_stringdef = a => a.Name == "StringDef"; + + public static AnnotationData GetIntDef (this AndroidAnnotationsSupport api, ManagedApiQuery query) + { + return api.GetAnnotations (query).Data ().FirstOrDefault (is_intdef); + } + + [Obsolete ("Use GetIntDef(ManagedApiQuery)")] + public static AnnotationData GetFieldIntDef (this AndroidAnnotationsSupport api, string managedTypeName, string managedPropertyName) + { + if (managedPropertyName == null) + throw new ArgumentNullException (nameof (managedPropertyName)); + return api.GetAnnotations (managedTypeName, managedPropertyName).Data ().FirstOrDefault (is_intdef); + } + + // This is nothing but shortcut to GetMethodReturnIntDef(..., "get_" + propName ?? "set_" + propName) + // Won't work if the getter and the setter have inconsistent parameter/return types. + [Obsolete ("Use GetIntDef(ManagedApiQuery)")] + public static AnnotationData GetPropertyIntDef (this AndroidAnnotationsSupport api, string managedTypeName, string managedPropertyName) + { + if (managedPropertyName == null) + throw new ArgumentNullException (nameof (managedPropertyName)); + return api.GetAnnotations (managedTypeName, managedPropertyName).Data ().FirstOrDefault (is_intdef); + } + + [Obsolete ("Use GetIntDef(ManagedApiQuery)")] + public static AnnotationData GetMethodReturnIntDef (this AndroidAnnotationsSupport api, string managedTypeName, string managedMethodName, string [] managedParameterTypes) + { + if (managedMethodName == null) + throw new ArgumentNullException (nameof (managedMethodName)); + if (managedParameterTypes == null) + throw new ArgumentNullException (nameof (managedParameterTypes)); + return api.GetAnnotations (managedTypeName, managedMethodName, managedParameterTypes).Data ().FirstOrDefault (is_intdef); + } + + [Obsolete ("Use GetIntDef(ManagedApiQuery)")] + public static AnnotationData GetMethodParameterIntDef (this AndroidAnnotationsSupport api, string managedTypeName, string managedMethodName, string [] managedParameterTypes, int parameterIndex) + { + if (managedMethodName == null) + throw new ArgumentNullException (nameof (managedMethodName)); + if (managedParameterTypes == null) + throw new ArgumentNullException (nameof (managedParameterTypes)); + return api.GetAnnotations (managedTypeName, managedMethodName, managedParameterTypes, parameterIndex).Data ().FirstOrDefault (is_intdef); + } + + public static IList AsCompletionCandidates (this AnnotationData a) + { + return a == null ? null : a.GetExtension ().ManagedConstants; + } + + public static bool IsAlreadyEnumified (this AnnotationData a) + { + var ext = a == null ? null : a.GetExtension (); + return ext != null && ext.IsTargetAlreadyEnumified; + } + + public static AnnotationData IntDef (this IEnumerable anns) + { + return anns.FirstOrDefault (is_intdef); + } + + public static AnnotationData StringDef (this IEnumerable anns) + { + return anns.FirstOrDefault (is_stringdef); + } + + #endregion + + #region permission requirements retrieval + + public static IEnumerable GetRequiredPermissions (this IEnumerable items) + { + return items.Select (item => item.GetExtension ()) + .Where (x => x != null) + .SelectMany (x => x.Values); + } + + #endregion + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AnnotationParserExtension.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AnnotationParserExtension.cs new file mode 100644 index 00000000000..d2a2717f8ac --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/AnnotationParserExtension.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public abstract class AnnotationParserExtension + { + protected internal abstract void OnAnnotationsParsed (IEnumerable anns); + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedApiQuery.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedApiQuery.cs new file mode 100644 index 00000000000..a353a63d337 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedApiQuery.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class ManagedApiQuery + { + public ManagedApiQuery () + { + ParameterIndex = -1; // not a parameter query default + } + + public string TypeName { get; set; } + + public string MemberName { get; set; } + + public IList Arguments { get; set; } + + public int ParameterIndex { get; set; } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ConstantDefinitionExtension.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ConstantDefinitionExtension.cs new file mode 100644 index 00000000000..a7b5c08aad6 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ConstantDefinitionExtension.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public enum ConstantKind + { + IntDef, + StringDef, + Other + } + + public class ConstantDefinitionExtension + { + public bool Flag { get; set; } + public ConstantKind ConstantKind { get; set; } + public IList ManagedConstants { get; set; } + public string TargetManagedTypeName { get; set; } + public bool IsTargetAlreadyEnumified { + get { return ConstantKind == ConstantKind.IntDef && TargetManagedTypeName != "int" && TargetManagedTypeName != "System.Int32"; } + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/DefinitionManagedTypeFinderExtension.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/DefinitionManagedTypeFinderExtension.cs new file mode 100644 index 00000000000..e15fbe595ae --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/DefinitionManagedTypeFinderExtension.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + // Processes *Def (IntDef,StringDef, etc.) and sets ManagedInfo on each AnnotationValue constant values. + public class DefinitionManagedTypeFinderExtension : ManagedTypeFinderExtension + { + public DefinitionManagedTypeFinderExtension (ManagedTypeFinder m) + : base (m) + { + } + + ManagedTypeFinder _ { + get { return ManagedTypeFinder; } + } + + public override void ProcessAnnotation (AnnotatedItem item) + { + if (item.ManagedInfo.Type.Name == null) + return; + + foreach (var a in item.Annotations) { + if (a.Values == null || a.Name.Contains ('.') || !a.Name.EndsWith ("Def", StringComparison.Ordinal)) + continue; + for (int i = 0; i < a.Values.Count; i++) { + var v = a.Values [i]; + if (v.Name != "value") + continue; + ProcessAnnotationValue (item, a, v); + } + } + } + + void ProcessAnnotationValue (AnnotatedItem item, AnnotationData a, AnnotationValue v) + { + var x = new ConstantDefinitionExtension (); + x.ConstantKind = + a.Name == "IntDef" ? ConstantKind.IntDef : + a.Name == "StringDef" ? ConstantKind.StringDef : + ConstantKind.Other; + x.TargetManagedTypeName = GetTargetManagedTypeName (item); + x.Flag = a.Values.Any (_ => _.Name == "flag"); + a.SetExtension (x); + + x.ManagedConstants = v.ValueAsArray.Select (s => new ManagedMemberInfo ()).ToArray (); + + if (v.ArrayItemCommonPrefix != null) { + // Most of the *Def values share the same type as the const fields' declaring type. + var vManagedType = _.GetContextManagedType (v.ArrayItemCommonPrefix); + if (vManagedType == null) { + _.Errors.Add (string.Format ("Managed type for '{0}' specified in the annotation '{1}' on '{2}' was not found", + v.ArrayItemCommonPrefix, a.Name, item.Name)); + } else { + var missingConsts = new List (); + for (int c = 0; c < x.ManagedConstants.Count; c++) { + var m = x.ManagedConstants [c]; + var mf = _.GetDefinitionField (vManagedType, v.ValueAsArray [c]); + if (mf == null) + // it is most likely removed constants due to enumification. + missingConsts.Add (v.ValueAsArray [c]); + else { + _.SetName (m, vManagedType); + m.MemberName = _.GetDefinitionName (mf); + } + } + if (missingConsts.Count != 0 && /*x.ManagedConstants.Count != missingConsts.Count*/!x.IsTargetAlreadyEnumified) + _.Errors.Add (string.Format ("Warning: For '{0}', managed constants are partially missing in {1}: {2}", + item.Name, v.ArrayItemCommonPrefix, string.Join (", ", missingConsts))); + } + } else { + // Sometimes (namely "PendingIntent flags") have different declaring types and + // in that case this lookup is somewhat complicated - we find the "type name . field name" matches. + // As of XA 5.3, nothing should matter - the only pattern that falls here is about + // wherever PendingIntentFlags apply. + for (int c = 0; c < v.ValueAsArray.Count; c++) { + var javaConst = v.ValueAsArray [c]; + var candidate = _.ContextTypes.Keys.Where (j => !string.IsNullOrEmpty (j) && (javaConst.StartsWith (j, StringComparison.Ordinal))) + .Select (j => _.GetContextManagedType (j)) + .Select (mn => new { Type = mn, Field = _.GetFields (mn).FirstOrDefault (f => javaConst.EndsWith ("." + _.GetJavaName (f), StringComparison.Ordinal)) }) + .FirstOrDefault (z => z.Field != null); + if (candidate == null) + continue; + var m = x.ManagedConstants [c]; + _.SetName (m, candidate.Type); + m.MemberName = _.GetDefinitionName (candidate.Field); + break; + } + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinder.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinder.cs new file mode 100644 index 00000000000..3517594a2d8 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinder.cs @@ -0,0 +1,204 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public abstract class ManagedTypeFinder : AnnotationParserExtension + { + #region type system abstraction + + public interface IType { } + public interface IProperty { } + public interface IDefinition { } + public interface IMethodBase { } + + public abstract string GetManagedName (IType t); + + public abstract string GetJavaName (IType t); + + public abstract string GetJavaName (IDefinition f); + + public abstract IProperty GetAnnotatedField (IType t, string fieldName); + + public abstract IDefinition GetDefinitionField (IType t, string fieldName); + + public abstract IMethodBase GetMethod (IType t, AnnotatedItem item); + + public abstract TypeName [] GetParameterTypes (IMethodBase method); + + public abstract void SetName (ManagedMemberInfo destination, IType type); + + public abstract IEnumerable GetFields (IType t); + + public abstract string GetPropertyName (IProperty m); + + public abstract string GetDefinitionName (IDefinition m); + + public abstract string GetMethodName (IMethodBase m); + + public abstract string GetMethodReturnManagedTypeName (IMethodBase m); + + public abstract string GetFieldManagedTypeName (IProperty property); + + public abstract string GetParameterManagedTypeName (IMethodBase m, int index); + + #endregion + + List errors = new List (); + + public IList Errors { + get { return errors; } + } + + public Func FilterAnnotatedItem { get; set; } + + List extensions = new List (); + public IList Extensions { + get { return extensions; } + } + + #region Context-sensitive members, which works only within LoadManagedMappings(). + + public IType GetContextManagedType (string javaTypeName) + { + IType t; + return typemap.TryGetValue (javaTypeName, out t) ? t : null; + } + + public virtual void PrepareContextTypes (IType [] types) + { + var maptmp = types.Select (t => new { Managed = t, JavaName = GetJavaName (t) }) + .Where (p => p.JavaName != null) + .Select (p => new { Managed = p.Managed, JavaName = p.JavaName.Replace ('/', '.').Replace ('$', '.') }); + + foreach (var p in maptmp) + // We don't want *Invoker classes to overwrite this mapping, so check name and skip them. + if (!typemap.ContainsKey (p.JavaName) || GetManagedName (typemap [p.JavaName]) == GetManagedName (p.Managed) + "Invoker") + typemap [p.JavaName] = p.Managed; + } + + Dictionary typemap = new Dictionary (); + + public IDictionary ContextTypes + { + get { return typemap; } + } + + #endregion + + public void LoadManagedMappings (IEnumerable anns, IType [] types) + { + PrepareContextTypes (types); + + foreach (var ann in anns) { + if (FilterAnnotatedItem != null && !FilterAnnotatedItem (ann)) + continue; + + // Find annotated members themselves. + var managedType = GetContextManagedType (ann.TypeName); + if (managedType == null) + Errors.Add ("warning: managed type for " + ann.TypeName + " was not found"); + else { + SetName (ann.ManagedInfo, managedType); + ann.ManagedInfo.TypeObject = managedType; + if (ann.MemberName == null) { + // nothing to do: annotation on type. + } else if (ann.Arguments == null) { + var managedProperty = GetAnnotatedField (managedType, ann.MemberName); + if (managedProperty == null) + Errors.Add ("warning: managed field for " + ann.TypeName + "." + ann.MemberName + " was not found"); + else { + ann.ManagedInfo.MemberName = GetPropertyName (managedProperty); + ann.ManagedInfo.PropertyObject = managedProperty; + } + } else { + // constructor or method. + var m = GetMethod (managedType, ann); + if (m != null) { + ann.ManagedInfo.MemberName = GetMethodName (m); + ann.ManagedInfo.Arguments = GetParameterTypes (m); + ann.ManagedInfo.MethodObject = m; + } + } + } + // Find the managed members that each annotation value mentions. + foreach (var ext in Extensions) + ext.ProcessAnnotation (ann); + } + } + + #region JNI signature parsing + + public static bool AreArgumentsEqualLax (string [] arguments1, string [] arguments2, IEnumerable genericArguments) + { + if (arguments1 == null || arguments2 == null || arguments1.Length != arguments2.Length) + return false; + + // this .Replace() is needed so that T[] can match generic arguments + Func stripParamSuffix = s => s.Replace ("...", "").Replace ("[]", ""); + Func stripGenParams = s => s == null ? s : (s.Contains ('<') ? s.Substring (0, s.IndexOf ('<')) : s).Replace ("...", "[]"); + Func cmp = (v, w) => stripGenParams (v) == stripGenParams (w); + + bool mismatch = false; + for (int a = 0; a < arguments1.Length; a++) { + if (cmp (arguments1 [a], arguments2 [a]) + || genericArguments.Any (ga => cmp (ga, stripParamSuffix (arguments2 [a])))) + continue; + mismatch = true; + break; + } + return !mismatch; + } + + public static string [] ParseJniMethodArgumentsSignature (string jni) + { + int idx = jni.IndexOf (')'); + string parameters = jni.Substring (1, idx - 1); + return FromJniToFullName (parameters).ToArray (); + } + + static IEnumerable FromJniToFullName (string s) + { + var l = new List (); + FromJniToFullName (s, l, 0); + return l; + } + + static void FromJniToFullName (string s, IList l, int idx) + { + if (s.Length == idx) + return; + + int next = idx + 1; + string type = null; + switch (s [idx]) { + case 'Z': type = "boolean"; break; + case 'B': type = "byte"; break; + case 'C': type = "char"; break; + case 'S': type = "short"; break; + case 'I': type = "int"; break; + case 'J': type = "long"; break; + case 'F': type = "float"; break; + case 'D': type = "double"; break; + case '[': + var item = l.Count; + next = idx + 1; + FromJniToFullName (s, l, next); + l [item] += "[]"; + return; + case 'L': + next = s.IndexOf (';', idx) + 1; + type = s.Substring (idx + 1, next - idx - 2).Replace ('/', '.').Replace ('$', '.'); + break; + default: + throw new InvalidOperationException ("Unexpected JNI type signature: " + s + " index " + idx); + } + l.Add (type); + FromJniToFullName (s, l, next); + } + + #endregion + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinderDefault.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinderDefault.cs new file mode 100644 index 00000000000..113b4b79f14 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinderDefault.cs @@ -0,0 +1,14 @@ +using System; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public abstract class ManagedTypeFinderDefault : ManagedTypeFinder + { + public ManagedTypeFinderDefault () + { + Extensions.Add (new DefinitionManagedTypeFinderExtension (this)); + Extensions.Add (new PermissionManagedTypeFinderExtension (this)); + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinderExtension.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinderExtension.cs new file mode 100644 index 00000000000..594522b077c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/ManagedTypeFinderExtension.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public abstract class ManagedTypeFinderExtension + { + protected ManagedTypeFinderExtension (ManagedTypeFinder m) + { + this.ManagedTypeFinder = m; + } + + protected ManagedTypeFinder ManagedTypeFinder { get; private set; } + + ManagedTypeFinder _ { + get { return ManagedTypeFinder; } + } + + public abstract void ProcessAnnotation (AnnotatedItem item); + + protected string GetTargetManagedTypeName (AnnotatedItem item) + { + var contextType = _.GetContextManagedType (item.TypeName); + var contextField = item.Arguments == null ? _.GetAnnotatedField (contextType, item.MemberName) : null; + if (item.Arguments == null) + return contextField == null ? null :_.GetFieldManagedTypeName (contextField); + var contextMethod = item.Arguments == null ? null : _.GetMethod (contextType, item); + if (contextMethod != null) + return item.ParameterIndex < 0 ? + _.GetMethodReturnManagedTypeName (contextMethod) : + _.GetParameterManagedTypeName (contextMethod, item.ParameterIndex); + return null; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/PermissionManagedTypeFinderExtension.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/PermissionManagedTypeFinderExtension.cs new file mode 100644 index 00000000000..d15ed59ebd8 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/PermissionManagedTypeFinderExtension.cs @@ -0,0 +1,38 @@ +using System; +namespace Xamarin.AndroidTools.AnnotationSupport +{ + // Looks for @RequiresPermission, store them and use for auditing user code to find missing permissions. + public class PermissionManagedTypeFinderExtension : ManagedTypeFinderExtension + { + public PermissionManagedTypeFinderExtension (ManagedTypeFinder m) + : base (m) + { + } + + public override void ProcessAnnotation (AnnotatedItem item) + { + if (item.ManagedInfo.Type.Name == null) + return; + + foreach (var a in item.Annotations) { + if (a.Values == null || a.Name != "RequiresPermission") + continue; + for (int i = 0; i < a.Values.Count; i++) { + var v = a.Values [i]; + if (v.Name != "value") + continue; + var ext = item.GetExtension (); + if (ext == null) { + ext = new RequiresPermissionExtension (); + item.SetExtension (ext); + } + // value is quoted by "", so chop them out. + string val = v.Val.Substring (1, v.Val.Length - 2); + if (!ext.Values.Contains (val)) + ext.Values.Add (val); + } + } + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/RequiresPermissionExtension.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/RequiresPermissionExtension.cs new file mode 100644 index 00000000000..6f9e6715175 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/ManagedTypeFinders/RequiresPermissionExtension.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class RequiresPermissionExtension + { + public RequiresPermissionExtension () + { + Values = new List (); + } + + public IList Values { get; private set; } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotatedItem.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotatedItem.cs new file mode 100644 index 00000000000..e2c62bc8e9c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotatedItem.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class AnnotatedItem : AnnotationObject + { + public AnnotatedItem (XElement e) + { + ManagedInfo = new ManagedMemberInfo (); + + var a = e.Attribute ("name"); + Name = a == null ? null : a.Value; + Annotations = e.Elements ("annotation") + .Select (c => new AnnotationData (c)) + .ToArray (); + + if (Name.Contains (' ')) { + string last = Name.Substring (Name.LastIndexOf (' ') + 1); + int p; + ParameterIndex = int.TryParse (last, out p) ? p : -1; + TypeName = Name.Substring (0, Name.IndexOf (' ')); + var member = Name.Substring (TypeName.Length + 1, Name.Length - TypeName.Length - 1 - (ParameterIndex < 0 ? 0 : last.Length + 1)); + int argStart = member.IndexOf ('('); + Arguments = argStart < 0 ? null : ParseArguments (member.Substring (argStart + 1, member.Length - argStart - 2)) + .Select (s => s.Trim ()) + .ToArray (); + var memberNoArgs = argStart < 0 ? member : member.Substring (0, argStart); + int memberNameIdx = memberNoArgs.IndexOf (' '); + if (memberNameIdx < 0 && Arguments != null) + MemberName = "#ctor"; + else { + MemberType = memberNameIdx < 0 ? null : memberNoArgs.Substring (0, memberNameIdx); + MemberName = memberNoArgs.Substring (memberNameIdx < 0 ? 0 : memberNameIdx + 1); + } + if (MemberName == "#ctor" && argStart < 0) throw new Exception (Name + " | " + member); + } else { + TypeName = Name; + } + } + + public string Name { get; set; } + public IList Annotations { get; private set; } + + public int ParameterIndex { get; private set; } + public string TypeName { get; private set; } + public string MemberType { get; private set; } + public string MemberName { get; private set; } + public string [] Arguments { get; private set; } + + public ManagedMemberInfo ManagedInfo { get; set; } + + static readonly char [] sep = new char [] {',', '<', '['}; + + IEnumerable ParseArguments (string args) + { + int idx = args.IndexOfAny (sep); + if (idx < 0) { + if (!string.IsNullOrWhiteSpace (args)) + yield return args; + } else if (args [idx] == ',') { + if (idx > 0) + yield return args.Substring (0, idx); + foreach (var x in ParseArguments (args.Substring (idx + 2))) // 2 = ',' and ' ' + yield return x; + } else if (args [idx] == '[') { + while (idx < args.Length && args [idx] == '[') + idx += 2; // [] + yield return args.Substring (0, idx); + foreach (var x in ParseArguments (args.Substring (idx))) + yield return x; + } else { + int tmp = idx + 1; + int open = 1; + int end = args.IndexOf ('>', tmp); + do { + int midS = args.IndexOf ('<', tmp); + end = args.IndexOf ('>', tmp); + if (midS >= 0 && midS < end) { + open++; + tmp = midS + 1; + } else { + open--; + tmp = end + 1; + } + } while (open > 0); + + + idx = end + 1; + while (idx < args.Length && args [idx] == '[') + idx += 2; // [] + string gen = args.Substring (0, idx); + yield return gen; + if (idx != args.Length) + foreach (var x in ParseArguments (args.Substring (idx + 1))) // skip '.' (hence +1) + yield return x; + } + } + + public override string ToString () + { + var s = new System.Text.StringBuilder (); + foreach (var a in Annotations) { + s.Append ("@").Append (a.Name); + if (a.Values.Count > 0) { + s.Append ("("); + AppendAnnotationValue (a.Values [0]); + for (int i = 1; i < a.Values.Count; ++i) { + s.Append (", "); + AppendAnnotationValue (a.Values [i]); + } + s.Append (")"); + } + s.Append (" "); + } + s.Append (TypeName).Append (".").Append (MemberName); + if (Arguments?.Length > 0) { + s.Append ("(").Append (Arguments [0]); + for (int i = 1; i < Arguments.Length; ++i) { + s.Append (", ").Append (Arguments [i]); + } + s.Append (")"); + } + return s.ToString (); + + void AppendAnnotationValue (AnnotationValue d) + { + s.Append (d.Name).Append("=").Append (d.ValueAsArray); + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationData.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationData.cs new file mode 100644 index 00000000000..539cc5f32d6 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationData.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class AnnotationData : AnnotationObject + { + static readonly string[] Prefixes = new[] { + "android.support.annotation.", + "androidx.annotation.", + }; + + public AnnotationData (XElement e) + { + var a = e.Attribute ("name"); + Name = a == null ? null : a.Value; + foreach (var predef in Prefixes) { + if (!Name.StartsWith (predef, StringComparison.Ordinal)) + continue; + Name = Name.Substring (predef.Length); + break; + } + Values = e.Elements ("val").Select (c => new AnnotationValue (c)).ToArray (); + } + + public string Name { get; set; } + public IList Values { get; private set; } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationObject.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationObject.cs new file mode 100644 index 00000000000..bd9b462895a --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationObject.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class AnnotationObject + { + List extensions = new List (); + + public T GetExtension () + { + foreach (var e in extensions) + if (e is T) + return (T) e; + return default (T); + } + + public void SetExtension (T obj) + { + if (extensions.Any (o => o is T)) + throw new InvalidOperationException ("There is already extension of type " + typeof (T)); + extensions.Add ((object) obj); + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationValue.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationValue.cs new file mode 100644 index 00000000000..901e1c9f986 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/AnnotationValue.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class AnnotationValue : AnnotationObject + { + public AnnotationValue (XElement e) + { + var an = e.Attribute ("name"); + Name = an == null ? null : an.Value; + var av = e.Attribute ("val"); + Val = av == null ? null : av.Value; + if (!string.IsNullOrWhiteSpace (Val) && Val [0] == '{') { + ValueAsArray = Val.Substring (1, Val.Length - 2).Split (',').Select (s => s.Trim ()).ToArray (); + if (ValueAsArray.Count > 0) { + var prefix = ValueAsArray [0]; + int idx = prefix.LastIndexOf ('.'); + if (idx > 0) { + prefix = prefix.Substring (0, idx); + if (ValueAsArray.All (s => s.StartsWith (prefix, StringComparison.Ordinal))) { + ArrayItemCommonPrefix = prefix; + ValueAsArray = ValueAsArray.Select (s => s.Substring (prefix.Length + 1)).ToArray (); + } + } + } + } else + ValueAsArray = new string [] {Val}; + } + + public string Name { get; set; } + public string Val { get; set; } + public IList ValueAsArray { get; private set; } + public string ArrayItemCommonPrefix { get; set; } + + public override string ToString () + { + if (ArrayItemCommonPrefix == null) + return Name + " = " + Val; + return string.Format ("{0} = {1}[{2}]", Name, ArrayItemCommonPrefix, string.Join (",", ValueAsArray)); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/ManagedMemberInfo.cs b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/ManagedMemberInfo.cs new file mode 100644 index 00000000000..255d7d1d4e7 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Objects/ManagedMemberInfo.cs @@ -0,0 +1,30 @@ +using System; +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class ManagedMemberInfo + { + public ManagedMemberInfo () + { + Type = new TypeName (); + } + + public TypeName Type { get; private set; } + public string MemberName { get; set; } + public TypeName [] Arguments { get; set; } + + // These fields are optional, as they are extraneous except for use in generator.exe. + public ManagedTypeFinder.IType TypeObject { get; set; } + public ManagedTypeFinder.IProperty PropertyObject { get; set; } + public ManagedTypeFinder.IMethodBase MethodObject { get; set; } + } + + public class TypeName + { + public string FullName { + get { return string.IsNullOrEmpty (Namespace) ? Name : Namespace + '.' + Name; } + } + public string Namespace { get; set; } + public string Name { get; set; } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Xamarin.Android.Tools.AnnotationSupport.csproj b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Xamarin.Android.Tools.AnnotationSupport.csproj new file mode 100644 index 00000000000..181ed7cffe2 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.AnnotationSupport/Xamarin.Android.Tools.AnnotationSupport.csproj @@ -0,0 +1,18 @@ + + + + $(DotNetTargetFramework) + + + + + + $(TestOutputFullPath) + + + + + + + + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApi.RelationAnalysisModel.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApi.RelationAnalysisModel.cs new file mode 100644 index 00000000000..29cbf651682 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApi.RelationAnalysisModel.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + // TypeResolver extensibility + + public partial class JavaClass + { + public JavaTypeReference? ResolvedExtends { get; set; } + } + + public partial class JavaImplements + { + public JavaTypeReference? ResolvedName { get; set; } + } + + public partial class JavaField + { + public JavaTypeReference? ResolvedType { get; set; } + } + + public partial class JavaMethod + { + public JavaTypeReference? ResolvedReturnType { get; set; } + } + + public partial class JavaParameter + { + public JavaTypeReference? ResolvedType { get; set; } + } + + public partial class JavaGenericConstraint + { + public JavaTypeReference? ResolvedType { get; set; } + } + + // GenericInheritanceMapper extensibility + + public partial class JavaClass + { + public IDictionary? + GenericInheritanceMapping { get; set; } + } + + // OverrideMarker extensibility + + public partial class JavaMethod + { + public JavaMethodReference? BaseMethod { get; set; } + public IList? ImplementedInterfaces { get; set; } + } + + public partial class JavaMethodReference + { + public JavaMethodReference (JavaMethod candidate) + { + this.Method = candidate; + } + + public JavaMethod? Method { get; set; } + } + + public partial class JavaParameter + { + public string? InstantiatedGenericArgumentName { get; set; } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApi.XmlModel.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApi.XmlModel.cs new file mode 100644 index 00000000000..d19d8174e18 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApi.XmlModel.cs @@ -0,0 +1,424 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Xml; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public partial class JavaApi + { + public JavaApi () + { + Packages = new Dictionary (); + } + + public string? ExtendedApiSource { get; set; } + public string? Platform { get; set; } + public IDictionary Packages { get; } + + public ICollection AllPackages => Packages.Values; + } + + public partial class JavaPackage + { + private Dictionary> types = new Dictionary> (); + + public JavaPackage (JavaApi? parent) + { + Parent = parent; + } + + public JavaApi? Parent { get; private set; } + + public string? Name { get; set; } + public string? JniName { get; set; } + + // Yes, there can be multiple types with the same *Java* name. + // For example: + // - MyInterface + // - MyInterfaceConsts + // It's debatable whether we handle this "properly", as most callers just + // do `First ()`, but it's been working for years so I'm not changing it. + // Exposes an IReadOnlyDictionary so caller cannot bypass our AddType/RemoveType code. + public IReadOnlyDictionary> Types => types; + + // Use this for a flat list of *all* types + public IEnumerable AllTypes => Types.Values.SelectMany (v => v); + + public void AddType (JavaType type) + { + // If this is a duplicate key, add it to existing list + if (Types.TryGetValue (type.Name!, out var list)) { + list.Add (type); + return; + } + + // Add to a new list + var new_list = new List (); + new_list.Add (type); + + types.Add (type.Name!, new_list); + } + + public void RemoveType (JavaType type) + { + if (!Types.TryGetValue (type.Name!, out var list)) + return; + + // Remove 1 type from list if it contains multiple types + if (list.Count > 1) { + list.Remove (type); + return; + } + + // Remove the whole dictionary entry + types.Remove (type.Name!); + } + + public void ClearTypes () + { + types.Clear (); + } + + // Content of this value is not stable. + public override string ToString () + { + return string.Format ("[Package] " + Name); + } + } + + public abstract partial class JavaType + { + protected JavaType (JavaPackage? parent) + { + Parent = parent; + + Implements = new List (); + Members = new List (); + } + + public JavaPackage? Parent { get; private set; } + + public bool IsReferenceOnly { get; set; } + + public bool Abstract { get; set; } + public string? Deprecated { get; set; } + public bool Final { get; set; } + public string? Name { get; set; } + public bool Static { get; set; } + public string? Visibility { get; set; } + + public string? ExtendedJniSignature { get; set; } + + public IList Implements { get; set; } + public JavaTypeParameters? TypeParameters { get; set; } + public IList Members { get; set; } + + public string FullName { + get { return Parent?.Name + ((Parent?.Name?.Length ?? 0) > 0 ? "." : string.Empty) + Name; } + } + + // Content of this value is not stable. + public string ToStringHelper () + { + // FIXME: add type attributes. + return (Parent?.Name == null ? "" : Parent.Name + ".") + + (Name ?? ""); + } + } + + public partial class JavaInterface : JavaType + { + public JavaInterface (JavaPackage? parent) + : base (parent) + { + } + + // Content of this value is not stable. + public override string ToString () + { + return "[Interface] " + ToStringHelper (); + } + } + + public partial class JavaClass : JavaType + { + public JavaClass (JavaPackage? parent) + : base (parent) + { + } + + public string? Extends { get; set; } + public string? ExtendsGeneric { get; set; } + public string? ExtendedJniExtends { get; set; } + + // Content of this value is not stable. + public override string ToString () + { + return "[Class] " + ToStringHelper (); + } + } + + + class ManagedType : JavaType + { + static JavaPackage dummy_system_package, dummy_system_io_package, dummy_system_xml_package; + static JavaType system_object, system_exception, system_io_stream, system_xml_xmlreader; + + static ManagedType () + { + dummy_system_package = new JavaPackage (null) { Name = "System" }; + system_object = new ManagedType (dummy_system_package) { Name = "Object" }; + system_exception = new ManagedType (dummy_system_package) { Name = "Exception" }; + dummy_system_package.AddType (system_object); + dummy_system_package.AddType (system_exception); + dummy_system_io_package = new JavaPackage (null) { Name = "System.IO" }; + system_io_stream = new ManagedType (dummy_system_io_package) { Name = "Stream" }; + dummy_system_io_package.AddType (system_io_stream); + dummy_system_xml_package = new JavaPackage (null) { Name = "System.Xml" }; + system_xml_xmlreader = new ManagedType (dummy_system_xml_package) { Name = "XmlReader" }; + dummy_system_io_package.AddType (system_xml_xmlreader); + } + + public static IEnumerable DummyManagedPackages { + get { + yield return dummy_system_package; + yield return dummy_system_io_package; + yield return dummy_system_xml_package; + } + } + + public ManagedType (JavaPackage package) : base (package) + { + } + } + + + public partial class JavaImplements + { + public string? Name { get; set; } + public string? NameGeneric { get; set; } + + public string? ExtendedJniType { get; set; } + } + + public partial class JavaMember + { + protected JavaMember (JavaType? parent) + { + Parent = parent; + } + + public JavaType? Parent { get; private set; } + + public string? Deprecated { get; set; } + public bool Final { get; set; } + public string? Name { get; set; } + public bool Static { get; set; } + public string? Visibility { get; set; } + public string? ExtendedJniSignature { get; set; } + } + + public partial class JavaField : JavaMember + { + public JavaField (JavaType? parent) + : base (parent) + { + } + + public bool NotNull { get; set; } + public bool Transient { get; set; } + public string? Type { get; set; } + public string? TypeGeneric { get; set; } + public string? Value { get; set; } + public bool Volatile { get; set; } + + // Content of this value is not stable. + public override string ToString () + { + return "[Field] " + TypeGeneric + " " + Name; + } + } + + public partial class JavaMethodBase : JavaMember + { + protected JavaMethodBase (JavaType? parent) + : base (parent) + { + Parameters = new List (); + } + + IList? exceptions; + + public IList Parameters { get; set; } + public JavaTypeParameters? TypeParameters { get; set; } + + public bool ExtendedBridge { get; set; } + public string? ExtendedJniReturn { get; set; } + public bool ExtendedSynthetic { get; set; } + + [NotNull] + public IList? Exceptions { + get => exceptions ?? (exceptions = new List()); + set => exceptions = value; + } + + // Content of this value is not stable. + public string ToStringHelper (string? returnType, string? name, JavaTypeParameters? typeParameters) + { + return string.Format ("{0}{1}{2}{3}{4}{5}({6})", + returnType, + returnType == null ? null : " ", + Name, + typeParameters == null ? null : "<", + typeParameters == null ? null : string.Join (", ", typeParameters.TypeParameters), + typeParameters == null ? null : ">", + string.Join (", ", Parameters)); + } + } + + public partial class JavaConstructor : JavaMethodBase + { + public JavaConstructor (JavaType? parent) + : base (parent) + { + } + + // it was required in the original API XML, but removed in class-parsed... + public string? Type { get; set; } + + // Content of this value is not stable. + public override string ToString () + { + return "[Constructor] " + ToStringHelper (null, Parent?.Name, null); + } + } + + public partial class JavaMethod : JavaMethodBase + { + public JavaMethod (JavaType? parent) + : base (parent) + { + } + + public bool Abstract { get; set; } + public bool Native { get; set; } + public string? Return { get; set; } + public bool ReturnNotNull { get; set; } + public bool Synchronized { get; set; } + + // Content of this value is not stable. + public override string ToString () + { + return "[Method] " + ToStringHelper (Return, Name, TypeParameters); + } + } + + public partial class JavaParameter + { + public JavaParameter (JavaMethodBase? parent) + { + Parent = parent; + } + + public JavaMethodBase? Parent { get; private set; } + public string? Name { get; set; } + public string? Type { get; set; } + public string? JniType { get; set; } + public bool NotNull { get; set; } + + // Content of this value is not stable. + public override string ToString () + { + return Type + " " + Name; + } + } + + public partial class JavaException + { + public string? Name { get; set; } + public string? Type { get; set; } + public string? TypeGenericAware { get; set; } + } + + public partial class JavaTypeParameters + { + public JavaTypeParameters (JavaType parent) + { + ParentType = parent; + TypeParameters = new List (); + } + + public JavaTypeParameters (JavaMethodBase? parent) + { + ParentMethod = parent; + TypeParameters = new List (); + } + + public JavaType? ParentType { get; set; } + public JavaMethodBase? ParentMethod { get; set; } + + public IList TypeParameters { get; set; } + } + + public partial class JavaTypeParameter + { + public JavaTypeParameter (JavaTypeParameters? parent) + { + Parent = parent; + } + + public JavaTypeParameters? Parent { get; set; } + + public string? Name { get; set; } + + public string? ExtendedJniClassBound { get; set; } + public string? ExtendedClassBound { get; set; } + public string? ExtendedInterfaceBounds { get; set; } + public string? ExtendedJniInterfaceBounds { get; set; } + + public JavaGenericConstraints? GenericConstraints { get; set; } + + public override string ToString () + { + return Name ?? ""; + } + } + + public partial class JavaGenericConstraints + { + public JavaGenericConstraints () + { + GenericConstraints = new List (); + } + + public string? BoundsType { get; set; } // extends / super + + IList? genericConstraints; + + [NotNull] + public IList? GenericConstraints { + get => genericConstraints ?? (genericConstraints = new List ()); + set => genericConstraints = value; + } + + public override string ToString () + { + string csts = string.Join (" & ", GenericConstraints); + if (csts == "java.lang.Object") + return string.Empty; + return " " + (BoundsType ?? "extends") + " " + csts; + } + } + + public partial class JavaGenericConstraint + { + public string? Type { get; set; } + + public override string ToString () + { + return Type ?? ""; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiDefectFinderExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiDefectFinderExtensions.cs new file mode 100644 index 00000000000..0136d86a43e --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiDefectFinderExtensions.cs @@ -0,0 +1,33 @@ +using System; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiDefectFinderExtensions + { + public static void FindDefects (this JavaApi api) + { + foreach (var type in api.AllPackages.SelectMany (p => p.AllTypes).Where (t => !t.IsReferenceOnly)) + type.FindDefects (); + } + + static void FindDefects (this JavaType type) + { + foreach (var m in type.Members.OfType ()) + m.FindParametersDefects (); + } + + static void FindParametersDefects (this JavaMethodBase methodBase) + { + int dummy; + foreach (var p in methodBase.Parameters) { + if ((p.Name?.StartsWith ("p", StringComparison.Ordinal) ?? false) && + int.TryParse (p.Name.Substring (1), out dummy)) { + Log.LogWarning ("Warning: {0} in {1} has 'unnamed' parameters", methodBase.Parent, methodBase); + break; // reporting once is enough. + } + } + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiFixVisibilityExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiFixVisibilityExtensions.cs new file mode 100644 index 00000000000..d68d83ad28c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiFixVisibilityExtensions.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiFixVisibilityExtensions + { + public static string? GetVisibleTypeName (this JavaParameter parameter) + { + var r = GetVisibleNonSpecialType (parameter); + return r != null ? r.ToString () : parameter.Type; + } + + public static string? GetVisibleReturnTypeName (this JavaMethod method) + { + var r = GetVisibleNonSpecialReturnType (method); + return r != null ? r.ToString () : method.Return; + } + + public static JavaTypeReference? GetVisibleNonSpecialType (this JavaParameter parameter) + { + return GetVisibleNonSpecialType (parameter.Parent, parameter.ResolvedType); + } + + public static JavaTypeReference? GetVisibleNonSpecialReturnType (this JavaMethod method) + { + return GetVisibleNonSpecialType (method, method.ResolvedReturnType); + } + + static JavaTypeReference? GetVisibleNonSpecialType (this JavaMethodBase? method, JavaTypeReference? r) + { + if (r == null || r.SpecialName != null || r.ReferencedTypeParameter != null || r.ArrayPart != null) + return null; + var requiredVisibility = method?.Visibility == "public" && method.Parent?.Visibility == "public" ? "public" : method?.Visibility; + for (var t = r; t != null; t = (t.ReferencedType as JavaClass)?.ResolvedExtends) { + if (t.ReferencedType == null) + break; + if (IsAcceptableVisibility (required: requiredVisibility, actual: t.ReferencedType.Visibility)) + return t; + } + return null; + } + + static bool IsAcceptableVisibility (string? required, string? actual) + { + if (required == "public") + return actual == "public"; + else + return true; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiGeneralExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiGeneralExtensions.cs new file mode 100644 index 00000000000..4db00db164f --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiGeneralExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiGeneralExtensions + { + public static JavaApi GetApi (this JavaType type) + { + return type.Parent?.Parent ?? throw new InvalidOperationException ("`JavaApi` via JavaType.Parent.Parent not set!"); + } + + public static JavaApi GetApi (this JavaMember member) + { + return member.Parent?.Parent?.Parent ?? throw new InvalidOperationException ("`JavaApi` via JavaMethod.Parent.Parent.Parent not set!");; + } + } + +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiGenericInheritanceMapperExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiGenericInheritanceMapperExtensions.cs new file mode 100644 index 00000000000..73b93e16f14 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiGenericInheritanceMapperExtensions.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiGenericInheritanceMapperExtensions + { + public static void CreateGenericInheritanceMapping (this JavaApi api) + { + foreach (var kls in api.AllPackages.SelectMany (p => p.AllTypes).OfType ()) + kls.PrepareGenericInheritanceMapping (); + } + + static void PrepareGenericInheritanceMapping (this JavaClass cls) + { + if (cls.GenericInheritanceMapping != null) + return; // already done. + + var empty = new Dictionary (); + + var bt = cls.ResolvedExtends == null ? null : cls.ResolvedExtends.ReferencedType as JavaClass; + if (bt == null) + cls.GenericInheritanceMapping = new Dictionary (); // empty + else { + // begin processing from the base class. + bt.PrepareGenericInheritanceMapping (); + + if (cls.ResolvedExtends?.TypeParameters == null) + cls.GenericInheritanceMapping = empty; + else if (cls.ResolvedExtends?.ReferencedType?.TypeParameters == null) { + // FIXME: I guess this should not happen. But this still happens. + Log.LogWarning ("Warning: '{0}' is referenced as base type of '{1}' and expected to have generic type parameters, but it does not.", cls.ExtendsGeneric, cls.FullName); + cls.GenericInheritanceMapping = empty; + } else { + if (cls.ResolvedExtends.ReferencedType.TypeParameters.TypeParameters.Count != cls.ResolvedExtends.TypeParameters.Count) + throw new Exception (string.Format ("On {0}.{1}, referenced generic arguments count do not match the base type parameters definition", + cls.Parent?.Name, cls.Name)); + var dic = empty; + foreach (var kvp in cls.ResolvedExtends.ReferencedType.TypeParameters.TypeParameters.Zip ( + cls.ResolvedExtends.TypeParameters, + (def, use) => new KeyValuePair (def, use)) + .Where (p => p.Value.ReferencedTypeParameter == null || p.Key.Name != p.Value.ReferencedTypeParameter.Name)) + dic.Add (new JavaTypeReference (kvp.Key, null), kvp.Value); + if (dic.Any ()) { + cls.GenericInheritanceMapping = dic; + } + else + cls.GenericInheritanceMapping = empty; + } + } + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiNonBindableStripper.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiNonBindableStripper.cs new file mode 100644 index 00000000000..0caf7095311 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiNonBindableStripper.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiNonBindableStripper + { + public static void StripNonBindables (this JavaApi api) + { + var invalids = new List (); + foreach (var member in api.AllPackages.SelectMany (p => p.AllTypes) + .SelectMany (t => t.Members).Where (m => m.Name != null && m.Name.Contains ('$'))) + invalids.Add (member); + foreach (var invalid in invalids) + invalid.Parent?.Members.Remove (invalid); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiOverrideMarkerExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiOverrideMarkerExtensions.cs new file mode 100644 index 00000000000..3e1aa50a16b --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiOverrideMarkerExtensions.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiOverrideMarkerExtensions + { + + public static void MarkOverrides (this JavaApi api) + { + api.MarkOverrides (new HashSet ()); + } + + public static void MarkOverrides (this JavaApi api, HashSet doneList) + { + foreach (var kls in api.AllPackages.SelectMany (p => p.AllTypes).OfType ()) + kls.MarkOverrides (doneList); + } + + static void MarkOverrides (this JavaClass cls, HashSet doneList) + { + if (doneList.Contains (cls)) + return; + doneList.Add (cls); + + var baseClass = cls.ResolvedExtends == null ? null :cls.ResolvedExtends.ReferencedType as JavaClass; + if (baseClass != null) + baseClass.MarkOverrides (doneList); + + foreach (var method in cls.Members.OfType ()) + cls.MarkBaseMethod (method); + } + + static void MarkBaseMethod (this JavaClass cls, JavaMethod method) + { + JavaClass? k = cls; + while (true) { + k = k.ResolvedExtends != null ? k.ResolvedExtends.ReferencedType as JavaClass : null; + if (k == null) + break; + + // first we collect base method candidates by name (which is absolutely required!) + var candidates = k.Members.OfType ().Where (_ => _.Name == method.Name); + // Then we find exact parameter type matches. + // No need to check returns. We only care about Java. + var candidate = candidates.FirstOrDefault (c => method.IsImplementing (c, cls.GenericInheritanceMapping ?? throw new InvalidOperationException ($"missing {nameof(cls.GenericInheritanceMapping)}!"))); + if (candidate != null) { + method.BaseMethod = new JavaMethodReference (candidate); + + for (int i = 0; i < candidate.Parameters.Count; i++) + if (candidate.Parameters [i].ResolvedType?.ReferencedTypeParameter != null && + method.Parameters [i].ResolvedType?.ReferencedTypeParameter == null) + method.Parameters [i].InstantiatedGenericArgumentName = candidate.Parameters [i].ResolvedType?.ReferencedTypeParameter?.Name; + break; + } + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiTypeResolverExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiTypeResolverExtensions.cs new file mode 100644 index 00000000000..36fa3f62466 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiTypeResolverExtensions.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + class JavaTypeResolutionException : Exception + { + public JavaTypeResolutionException (string message) : base (message) + { + } + } + + public static class JavaApiTypeResolverExtensions + { + public static JavaTypeReference Parse (this JavaApi api, string name, params JavaTypeParameters?[] contextTypeParameters) + { + var tn = JavaTypeName.Parse (name); + return JavaTypeNameToReference (api, tn, contextTypeParameters); + } + + static JavaTypeReference JavaTypeNameToReference (this JavaApi api, JavaTypeName tn, params JavaTypeParameters?[] contextTypeParameters) + { + var tp = contextTypeParameters.Where (tps => tps != null) + .SelectMany (tps => tps!.TypeParameters) + .FirstOrDefault (xp => xp.Name == tn.DottedName); + if (tp != null) + return new JavaTypeReference (tp, tn.ArrayPart); + if (tn.DottedName == JavaTypeReference.GenericWildcard.SpecialName) + return new JavaTypeReference (tn.BoundsType, tn.GenericConstraints?.Select (gc => JavaTypeNameToReference (api, gc, contextTypeParameters)), tn.ArrayPart); + var primitive = JavaTypeReference.GetSpecialType (tn.DottedName); + if (primitive != null) + return tn.ArrayPart == null && tn.GenericConstraints == null ? primitive : new JavaTypeReference (primitive, tn.ArrayPart, tn.BoundsType, tn.GenericConstraints?.Select (gc => JavaTypeNameToReference (api, gc, contextTypeParameters))); + var type = api.FindNonGenericType (tn.FullNameNonGeneric); + return new JavaTypeReference (type, + tn.GenericArguments != null ? tn.GenericArguments.Select (_ => api.JavaTypeNameToReference (_, contextTypeParameters)).ToArray () : null, + tn.ArrayPart); + } + + public static JavaType FindNonGenericType (this JavaApi api, string? name) + { + // Given a type name like 'android.graphics.BitmapFactory.Options' + // We're going to search for: + // - Pkg: android.graphics.BitmapFactory Type: Options + // - Pkg: android.graphics Type: BitmapFactory.Options + // - Pkg: android Type: graphics.BitmapFactory.Options + // etc. We will short-circuit as soon as we find a match + var index = name?.LastIndexOf ('.') ?? -1; + + while (index > 0) { + var ns = name!.Substring (0, index); + var type_name = name.Substring (index + 1); + + if (api.Packages.TryGetValue (ns, out var pkg)) { + if (pkg.Types.TryGetValue (type_name, out var type)) + return type.First (); + } + + index = name.LastIndexOf ('.', index - 1); + } + + // See if it's purely a C# type + var ret = ManagedType.DummyManagedPackages + .SelectMany (p => p.AllTypes) + .FirstOrDefault (t => t.FullName == name); + + if (ret == null) { + // We moved this type to "mono.android.app.IntentService" which makes this + // type resolution fail if a user tries to reference it in Java. + if (name == "android.app.IntentService") + return FindNonGenericType (api, "mono.android.app.IntentService"); + + throw new JavaTypeResolutionException (string.Format ("Type '{0}' was not found.", name)); + } + + return ret; + } + + public static void Resolve (this JavaApi api) + { + while (true) { + bool errors = false; + foreach (var t in api.AllPackages.SelectMany (p => p.AllTypes).OfType ().ToArray ()) + try { + t.Resolve (); + } + catch (JavaTypeResolutionException ex) { + Log.LogError ("Error while processing type '{0}': {1}", t, ex.Message); + errors = true; + t.Parent?.RemoveType (t); + } + foreach (var t in api.AllPackages.SelectMany (p => p.AllTypes).OfType ().ToArray ()) + try { + t.Resolve (); + } catch (JavaTypeResolutionException ex) { + Log.LogError ("Error while processing type '{0}': {1}", t, ex.Message); + errors = true; + t.Parent?.RemoveType (t); + } + if (!errors) + break; + } + } + + static void ResolveType (this JavaType type) + { + if (type.TypeParameters != null) + type.TypeParameters.Resolve (type.GetApi (), type.TypeParameters); + foreach (var t in type.Implements) { + if (t.NameGeneric == null) + continue; + t.ResolvedName = type.GetApi ().Parse (t.NameGeneric, type.TypeParameters); + } + + foreach (var m in type.Members.OfType ().ToArray ()) + ResolveWithTryCatch (m.Resolve, m); + foreach (var m in type.Members.OfType ().ToArray ()) + ResolveWithTryCatch (m.Resolve, m); + } + + public static void Resolve (this JavaClass c) + { + if (c.ExtendsGeneric != null) + c.ResolvedExtends = c.GetApi ().Parse (c.ExtendsGeneric, c.TypeParameters); + c.ResolveType (); + foreach (var m in c.Members.OfType ().ToArray ()) + ResolveWithTryCatch (() => m.Resolve (), m); + } + + static void ResolveWithTryCatch (Action resolve, JavaMember m) + { + try { + resolve (); + } catch (JavaTypeResolutionException ex) { + Log.LogError ("Error while processing '{0}' in '{1}': {2}", m, m.Parent, ex.Message); + m.Parent?.Members.Remove (m); + } + } + + public static void Resolve (this JavaInterface i) + { + i.ResolveType (); + } + + public static void Resolve (this JavaField f) + { + if (f.TypeGeneric == null) + return; + f.ResolvedType = f.GetApi ().Parse (f.TypeGeneric, f.Parent?.TypeParameters); + } + + static void ResolveMethodBase (this JavaMethodBase m) + { + if (m.TypeParameters != null) + m.TypeParameters.Resolve (m.GetApi (), m.TypeParameters); + foreach (var p in m.Parameters) { + if (p.Type == null) + continue; + p.ResolvedType = m.GetApi ().Parse (p.Type, m.Parent?.TypeParameters, m.TypeParameters); + } + } + + public static void Resolve (this JavaMethod m) + { + m.ResolveMethodBase (); + if (m.Return == null) + return; + m.ResolvedReturnType = m.GetApi ().Parse (m.Return, m.Parent?.TypeParameters, m.TypeParameters); + } + + public static void Resolve (this JavaConstructor c) + { + c.ResolveMethodBase (); + } + + static void Resolve (this JavaTypeParameters tp, JavaApi api, params JavaTypeParameters?[] additionalTypeParameters) + { + foreach (var t in tp.TypeParameters) { + if (t.GenericConstraints == null || t.GenericConstraints.GenericConstraints == null) + continue; + foreach (var g in t.GenericConstraints.GenericConstraints) { + if (g.Type == null) + continue; + try { + g.ResolvedType = api.Parse (g.Type, additionalTypeParameters); + } + catch (JavaTypeResolutionException ex) { + Log.LogDebug ("Warning: failed to resolve generic constraint: '{0}': {1}", g.Type, ex.Message); + } + } + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiXmlGeneratorExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiXmlGeneratorExtensions.cs new file mode 100644 index 00000000000..53c85325ff9 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiXmlGeneratorExtensions.cs @@ -0,0 +1,322 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiXmlGeneratorExtensions + { + public static void Save (this JavaApi api, string xmlfile) + { + using (var writer = XmlWriter.Create (xmlfile, new XmlWriterSettings () { + Encoding = new UTF8Encoding (false, true), + Indent = true, + OmitXmlDeclaration = true, + })) + api.Save (writer); + } + + public static void Save (this JavaApi api, XmlWriter writer) + { + writer.WriteStartElement ("api"); + if (api.Platform != null) + writer.WriteAttributeString ("platform", api.Platform); + + foreach (var pkg in api.AllPackages) { + if (!pkg.AllTypes.Any (t => !t.IsReferenceOnly)) + continue; + writer.WriteStartElement ("package"); + writer.WriteAttributeString ("name", pkg.Name); + if (!string.IsNullOrEmpty (pkg.JniName)) { + writer.WriteAttributeString ("jni-name", pkg.JniName); + } + foreach (var type in pkg.AllTypes) { + if (type.IsReferenceOnly) + continue; // skip reference only types + if (type is JavaClass) + ((JavaClass) type).Save (writer); + else + ((JavaInterface) type).Save (writer); + } + writer.WriteFullEndElement (); + } + writer.WriteFullEndElement (); + } + + static void Save (this JavaClass cls, XmlWriter writer) + { + SaveTypeCommon (cls, writer, "class", XmlConvert.ToString (cls.Abstract), cls.Extends, cls.ExtendsGeneric, cls.ExtendedJniExtends); + } + + static void Save (this JavaInterface iface, XmlWriter writer) + { + SaveTypeCommon (iface, writer, "interface", "true", null, null, null); + } + + static void SaveTypeCommon (this JavaType cls, XmlWriter writer, string elementName, string abs, string? ext, string? extgen, string? jniExt) + { + writer.WriteStartElement (elementName); + if (abs != null) + writer.WriteAttributeString ("abstract", abs); + writer.WriteAttributeString ("deprecated", cls.Deprecated); + if (ext != null) + writer.WriteAttributeString ("extends", ext); + if (ext != null) + writer.WriteAttributeString ("extends-generic-aware", extgen); + if (jniExt != null) + writer.WriteAttributeString ("jni-extends", jniExt); + writer.WriteAttributeString ("final", XmlConvert.ToString (cls.Final)); + writer.WriteAttributeString ("name", cls.Name); + writer.WriteAttributeString ("static", XmlConvert.ToString (cls.Static)); + writer.WriteAttributeString ("visibility", cls.Visibility); + if (!string.IsNullOrEmpty (cls.ExtendedJniSignature)) { + writer.WriteAttributeString ("jni-signature", cls.ExtendedJniSignature); + } + + foreach (var imp in cls.Implements.OrderBy (i => i.Name, StringComparer.Ordinal)) { + writer.WriteStartElement ("implements"); + writer.WriteAttributeString ("name", imp.Name); + writer.WriteAttributeString ("name-generic-aware", imp.NameGeneric); + if (!string.IsNullOrEmpty (imp.ExtendedJniType)) { + writer.WriteAttributeString ("jni-type", imp.ExtendedJniType); + } + writer.WriteString ("\n "); + writer.WriteFullEndElement (); + } + + if (cls.TypeParameters != null) + cls.TypeParameters.Save (writer, " "); + + foreach (var m in cls.Members.OfType ().OrderBy (m => m.Name, StringComparer.Ordinal).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.ExtendedSynthetic)) + m.Save (writer); + foreach (var m in cls.Members.OfType ().OrderBy (m => m.Name, StringComparer.Ordinal).ThenBy (m => string.Join (", ", m.Parameters.Select (p => p.Type))).ThenBy (m => m.ExtendedSynthetic)) + m.Save (writer); + foreach (var m in cls.Members.OfType ().OrderBy (m => m.Name, StringComparer.Ordinal)) + m.Save (writer); + + writer.WriteFullEndElement (); + } + + static void Save (this JavaTypeParameters typeParameters, XmlWriter writer, string indent) + { + writer.WriteStartElement ("typeParameters"); + foreach (var tp in typeParameters.TypeParameters) { + writer.WriteStartElement ("typeParameter"); + writer.WriteAttributeString ("name", tp.Name); + if (!string.IsNullOrEmpty (tp.ExtendedClassBound)) { + writer.WriteAttributeString ("classBound", tp.ExtendedClassBound); + } + if (!string.IsNullOrEmpty (tp.ExtendedJniClassBound)) { + writer.WriteAttributeString ("jni-classBound", tp.ExtendedJniClassBound); + } + if (!string.IsNullOrEmpty (tp.ExtendedInterfaceBounds)) { + writer.WriteAttributeString ("interfaceBounds", tp.ExtendedInterfaceBounds); + } + if (!string.IsNullOrEmpty (tp.ExtendedJniInterfaceBounds)) { + writer.WriteAttributeString ("jni-interfaceBounds", tp.ExtendedJniInterfaceBounds); + } + + if (tp.GenericConstraints != null) { + // If there is only one generic constraint that specifies java.lang.Object, + // that is not really a constraint, so skip that. + // jar2xml does not emit that either. + var gcs = tp.GenericConstraints.GenericConstraints; + var gctr = gcs.Count == 1 ? gcs [0].ResolvedType : null; + if (gctr?.ReferencedType?.FullName != "java.lang.Object") + { + writer.WriteStartElement ("genericConstraints"); + foreach (var g in tp.GenericConstraints.GenericConstraints) { + writer.WriteStartElement ("genericConstraint"); + writer.WriteAttributeString ("type", g.Type); + writer.WriteString ("\n" + indent + " "); + writer.WriteFullEndElement (); + } + writer.WriteFullEndElement (); + } + } + else + writer.WriteString ("\n" + indent + " "); + writer.WriteFullEndElement (); + } + writer.WriteString ("\n" + indent); + writer.WriteFullEndElement (); + } + + static void Save (this JavaField field, XmlWriter writer) + { + var value = field.Value; + if (value != null && (field.Type == "double" || field.Type == "float")) + value = value.Replace ("E+", "E"); + SaveCommon (field, writer, "field", null, null, null, null, + XmlConvert.ToString (field.Transient), + field.Type, + field.TypeGeneric, + value, + XmlConvert.ToString (field.Volatile), + null, + null, + null, + null, + null, + null, + field.NotNull); + } + + static void Save (this JavaConstructor ctor, XmlWriter writer) + { + SaveCommon (ctor, writer, "constructor", null, null, null, null, null, ctor.Type ?? ctor.Parent?.FullName, null, null, null, ctor.TypeParameters, ctor.Parameters, ctor.Exceptions, ctor.ExtendedBridge, ctor.ExtendedJniReturn, ctor.ExtendedSynthetic, null); + } + + static void Save (this JavaMethod method, XmlWriter writer) + { + Func check = _ => _.BaseMethod?.Method?.Parent?.Visibility == "public" && + !method.Static && + method.Parameters.All (p => p.InstantiatedGenericArgumentName == null); + + // skip synthetic methods, that's what jar2xml does. + // However, jar2xml is based on Java reflection and it generates synthetic methods + // that actually needs to be generated in the output XML (they are not marked as + // "synthetic" either by asm or java reflection), when: + // - the synthetic method is actually from non-public ancestor class + // (e.g. FileBackupHelperBase.writeNewStateDescription()) + // For such case, it does not skip generation. + if (method.ExtendedSynthetic && (method.BaseMethod == null || check (method))) + return; + + // Here we skip most of the overriding methods of a virtual method, unless + // - the method visibility or final-ity has changed: protected Object#clone() is often + // overriden as public. In that case, we need a "new" method. + // - the method is covariant. In that case we need another overload. + // - they differ in "abstract" or "final" method attribute. + // - the derived method is static. + // - the base method is in the NON-public class. + // - none of the arguments are type parameters. + // - finally, it is the synthetic method already checked above. + if (method.BaseMethod != null && method.BaseMethod.Method != null && + !method.BaseMethod.Method.Abstract && + method.BaseMethod.Method.Visibility == method.Visibility && + method.BaseMethod.Method.Abstract == method.Abstract && + method.BaseMethod.Method.Final == method.Final && + !method.ExtendedSynthetic && + check (method)) + return; + + SaveCommon (method, writer, "method", + XmlConvert.ToString (method.Abstract), + XmlConvert.ToString (method.Native), + method.GetVisibleReturnTypeName (), + XmlConvert.ToString (method.Synchronized), + null, + null, + null, + null, + null, + method.TypeParameters, + method.Parameters, + method.Exceptions, + method.ExtendedBridge, + method.ExtendedJniReturn, + method.ExtendedSynthetic, + method.ReturnNotNull); + } + + static void SaveCommon (this JavaMember m, XmlWriter writer, string elementName, + string? abs, string? native, string? ret, string? sync, + string? transient, string? type, string? typeGeneric, + string? value, string? volat, + JavaTypeParameters? typeParameters, + IEnumerable? parameters, + IEnumerable? exceptions, + bool? extBridge, string? jniReturn, bool? extSynthetic, bool? notNull) + { + // If any of the parameters contain reference to non-public type, it cannot be generated. + if (parameters != null && parameters.Any (p => p.ResolvedType?.ReferencedType != null && string.IsNullOrEmpty (p.ResolvedType.ReferencedType.Visibility))) + return; + + writer.WriteStartElement (elementName); + if (abs != null) + writer.WriteAttributeString ("abstract", abs); + writer.WriteAttributeString ("deprecated", m.Deprecated); + writer.WriteAttributeString ("final", XmlConvert.ToString (m.Final)); + writer.WriteAttributeString ("name", m.Name); + writer.WriteAttributeString ("jni-signature", m.ExtendedJniSignature); + if (extBridge.HasValue) + writer.WriteAttributeString ("bridge", extBridge.Value ? "true" : "false"); + if (native != null) + writer.WriteAttributeString ("native", native); + if (ret != null) + writer.WriteAttributeString ("return", ret); + if (jniReturn != null) + writer.WriteAttributeString ("jni-return", jniReturn); + if (notNull.GetValueOrDefault ()) + writer.WriteAttributeString (m is JavaField ? "not-null" : "return-not-null", "true"); + writer.WriteAttributeString ("static", XmlConvert.ToString (m.Static)); + if (sync != null) + writer.WriteAttributeString ("synchronized", sync); + if (transient != null) + writer.WriteAttributeString ("transient", transient); + if (type != null) + writer.WriteAttributeString ("type", type); + if (typeGeneric != null) + writer.WriteAttributeString ("type-generic-aware", typeGeneric); + if (value != null) + writer.WriteAttributeString ("value", value); + if (extSynthetic.HasValue) + writer.WriteAttributeString ("synthetic", extSynthetic.Value ? "true" : "false"); + writer.WriteAttributeString ("visibility", m.Visibility); + if (volat != null) + writer.WriteAttributeString ("volatile", volat); + + if (typeParameters != null) + typeParameters.Save (writer, " "); + + if (parameters != null) { + foreach (var p in parameters) { + writer.WriteStartElement ("parameter"); + writer.WriteAttributeString ("name", p.Name); + writer.WriteAttributeString ("type", p.GetVisibleTypeName ()); + if (!string.IsNullOrEmpty (p.JniType)) { + writer.WriteAttributeString ("jni-type", p.JniType); + } + if (p.NotNull == true) { + writer.WriteAttributeString ("not-null", "true"); + } + writer.WriteString ("\n "); + writer.WriteFullEndElement (); + } + } + + if (exceptions != null) { + foreach (var e in exceptions.OrderBy (e => GetName (e.Name), StringComparer.Ordinal)) { + writer.WriteStartElement ("exception"); + writer.WriteAttributeString ("name", GetName (e.Name)); + writer.WriteAttributeString ("type", e.Type); + if (!string.IsNullOrEmpty (e.TypeGenericAware)) { + writer.WriteAttributeString ("type-generic-aware", e.TypeGenericAware); + } + writer.WriteString ("\n "); + writer.WriteFullEndElement (); + } + } + + writer.WriteString ("\n "); + writer.WriteFullEndElement (); + } + + static string? GetName (string? jniName) + { + if (jniName == null) + return null; + + int slash = jniName.LastIndexOf ('/'); + var name = slash >= 0 + ? jniName.Substring (slash + 1) + : jniName; + return name; + } + + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiXmlLoaderExtensions.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiXmlLoaderExtensions.cs new file mode 100644 index 00000000000..ff4a4b40d30 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApiXmlLoaderExtensions.cs @@ -0,0 +1,407 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiLoaderExtensions + { + public static void Load (this JavaApi api, string xmlfile) + { + using (var reader = XmlReader.Create (xmlfile)) + api.Load (reader, false); + } + + public static void Load (this JavaApi api, XmlReader reader, bool isReferenceOnly) + { + reader.MoveToContent (); + if (reader.LocalName != "api") + throw XmlUtil.UnexpectedElementOrContent (null, reader, "api"); + api.ExtendedApiSource = reader.GetAttribute ("api-source"); + api.Platform = reader.GetAttribute ("platform"); + XmlUtil.CheckExtraneousAttributes ("api", reader, "api-source", "platform"); + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; // + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "package") + throw XmlUtil.UnexpectedElementOrContent ("api", reader, "package"); + + var name = reader.GetAttribute ("name") ?? throw new InvalidOperationException (" element must contain a 'name' attribute"); + + if (!api.Packages.TryGetValue (name, out var pkg)) { + pkg = new JavaPackage (api); + api.Packages.Add (name, pkg); + } + + pkg.Load (reader, isReferenceOnly); + } while (true); + + XmlUtil.VerifyEndElement (reader, "api"); + reader.Read (); + } + } + + public static void Load (this JavaPackage package, XmlReader reader, bool isReferenceOnly) + { + reader.MoveToContent (); + package.Name = XmlUtil.GetRequiredAttribute (reader, "name"); + package.JniName = reader.GetAttribute ("jni-name"); + if (reader.MoveToFirstAttribute ()) + if (reader.LocalName != "name") + throw XmlUtil.UnexpectedAttribute (reader, "package"); + reader.MoveToElement (); + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; // + if (reader.NodeType != XmlNodeType.Element) + throw XmlUtil.UnexpectedElementOrContent ("package", reader, "class", "interface"); + if (reader.LocalName == "class") { + var kls = new JavaClass (package) { IsReferenceOnly = isReferenceOnly }; + kls.Load (reader); + package.AddType (kls); + } else if (reader.LocalName == "interface") { + var iface = new JavaInterface (package) { IsReferenceOnly = isReferenceOnly }; + iface.Load (reader); + package.AddType (iface); + } else + throw XmlUtil.UnexpectedElementOrContent ("package", reader, "class", "interface"); + } while (true); + + XmlUtil.VerifyEndElement (reader, "package"); + reader.Read (); + } + } + + static readonly string [] expected_type_attributes = new String [] { + "abstract", + "deprecated", + "enclosing-method-jni-type", + "enclosing-method-name", + "enclosing-method-signature", + "final", + "jni-signature", + "name", + "source-file-name", + "static", + "visibility", + }; + + internal static void LoadTypeAttributes (this JavaType type, XmlReader reader, params string [] otherAllowedAttributes) + { + type.Abstract = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "abstract")); + type.Deprecated = XmlUtil.GetRequiredAttribute (reader, "deprecated"); + type.Final = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "final")); + type.Name = XmlUtil.GetRequiredAttribute (reader, "name"); + type.Static = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "static")); + type.Visibility = XmlUtil.GetRequiredAttribute (reader, "visibility"); + type.ExtendedJniSignature = reader.GetAttribute ("jni-signature"); + XmlUtil.CheckExtraneousAttributes (reader.LocalName, reader, expected_type_attributes.Concat (otherAllowedAttributes).ToArray ()); + } + + internal static bool TryLoadCommonElement (this JavaType type, XmlReader reader) + { + if (reader.LocalName == "implements") { + var implements = new JavaImplements (); + implements.Load (reader); + type.Implements.Add (implements); + } else if (reader.LocalName == "typeParameters") { + var tp = new JavaTypeParameters (type); + tp.Load (reader); + type.TypeParameters = tp; + } else if (reader.LocalName == "field") { + var field = new JavaField (type); + field.Load (reader); + type.Members.Add (field); + } else if (reader.LocalName == "method") { + var method = new JavaMethod (type); + method.Load (reader); + type.Members.Add (method); + } else + return false; + return true; + } + + public static void Load (this JavaInterface iface, XmlReader reader) + { + reader.MoveToContent (); + iface.LoadTypeAttributes (reader); + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; // + if (reader.NodeType != XmlNodeType.Element) + throw XmlUtil.UnexpectedElementOrContent ("interface", reader, "implements", "typeParameters", "field", "method"); + if (!iface.TryLoadCommonElement (reader)) + throw XmlUtil.UnexpectedElementOrContent ("interface", reader, "implements", "typeParameters", "field", "method"); + } while (true); + + XmlUtil.VerifyEndElement (reader, "interface"); + reader.Read (); + } + } + + public static void Load (this JavaClass kls, XmlReader reader) + { + reader.MoveToContent (); + kls.LoadTypeAttributes (reader, "extends", "extends-generic-aware", "jni-extends"); + // they are not mandatory; Java.Lang.Object doesn't have them. + kls.Extends = reader.GetAttribute ("extends"); + kls.ExtendsGeneric = reader.GetAttribute ("extends-generic-aware"); + kls.ExtendedJniExtends = reader.GetAttribute ("jni-extends"); + + reader.MoveToElement (); + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; // + if (reader.NodeType != XmlNodeType.Element) + throw XmlUtil.UnexpectedElementOrContent ("class", reader, "implements", "typeParameters", "field", "constructor", "method"); + if (!kls.TryLoadCommonElement (reader)) { + if (reader.LocalName == "constructor") { + var constructor = new JavaConstructor (kls); + constructor.Load (reader); + kls.Members.Add (constructor); + } else + throw XmlUtil.UnexpectedElementOrContent ("class", reader, "implements", "typeParameters", "field", "constructor", "method"); + } + } while (true); + XmlUtil.VerifyEndElement (reader, "class"); + reader.Read (); + } + } + + public static void Load (this JavaImplements implements, XmlReader reader) + { + implements.Name = XmlUtil.GetRequiredAttribute (reader, "name"); + implements.NameGeneric = XmlUtil.GetRequiredAttribute (reader, "name-generic-aware"); + implements.ExtendedJniType = reader.GetAttribute ("jni-type"); + XmlUtil.CheckExtraneousAttributes (reader.LocalName, reader, "name", "name-generic-aware", "jni-type"); + if (!reader.IsEmptyElement) { + reader.Read (); + reader.MoveToContent (); + XmlUtil.VerifyEndElement (reader, "implements"); + } + reader.Read (); + } + + public static void LoadMemberAttributes (this JavaMember member, XmlReader reader) + { + member.Deprecated = XmlUtil.GetRequiredAttribute (reader, "deprecated"); + member.Final = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "final")); + member.Name = XmlUtil.GetRequiredAttribute (reader, "name"); + member.Static = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "static")); + member.Visibility = XmlUtil.GetRequiredAttribute (reader, "visibility"); + member.ExtendedJniSignature = reader.GetAttribute ("jni-signature"); + } + + public static void Load (this JavaField field, XmlReader reader) + { + field.LoadMemberAttributes (reader); + field.Transient = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "transient")); + field.Volatile = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "volatile")); + field.Type = XmlUtil.GetRequiredAttribute (reader, "type"); + field.TypeGeneric = XmlUtil.GetRequiredAttribute (reader, "type-generic-aware"); + field.Value = reader.GetAttribute ("value"); + field.NotNull = reader.GetAttribute ("not-null") == "true"; + + reader.Skip (); + } + + static void LoadMethodBase (this JavaMethodBase methodBase, string elementName, XmlReader reader) + { + var method = methodBase as JavaMethod; // kind of ugly hack yeah... + + methodBase.LoadMemberAttributes (reader); + methodBase.ExtendedJniReturn = reader.GetAttribute ("jni-return"); + methodBase.ExtendedSynthetic = XmlConvert.ToBoolean (reader.GetAttribute ("synthetic") ?? "false"); + methodBase.ExtendedBridge = XmlConvert.ToBoolean (reader.GetAttribute ("bridge") ?? "false"); + + reader.MoveToElement (); + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; + if (reader.NodeType != XmlNodeType.Element) + throw XmlUtil.UnexpectedElementOrContent (elementName, reader, "parameter"); + if (reader.LocalName == "typeParameters") { + var tp = new JavaTypeParameters (methodBase); + tp.Load (reader); + methodBase.TypeParameters = tp; + } else if (reader.LocalName == "parameter") { + var p = new JavaParameter (methodBase); + p.Load (reader); + methodBase.Parameters.Add (p); + } else if (reader.LocalName == "exception") { + var p = new JavaException (); + p.Load (reader); + methodBase.Exceptions.Add (p); + } else + throw XmlUtil.UnexpectedElementOrContent (elementName, reader, "parameter"); + } while (true); + XmlUtil.VerifyEndElement (reader, elementName); + reader.Read (); + } + } + + public static void Load (this JavaConstructor constructor, XmlReader reader) + { + // it was required in the original API XML, but removed in class-parsed... + constructor.Type = reader.GetAttribute ("type"); + XmlUtil.CheckExtraneousAttributes ("constructor", reader, "deprecated", "final", "name", "static", "visibility", "jni-signature", "jni-return", "synthetic", "bridge", + "type"); + constructor.LoadMethodBase ("constructor", reader); + } + + public static void Load (this JavaMethod method, XmlReader reader) + { + method.Abstract = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "abstract")); + method.Native = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "native")); + method.Return = XmlUtil.GetRequiredAttribute (reader, "return"); + method.ReturnNotNull = reader.GetAttribute ("return-not-null") == "true"; + method.Synchronized = XmlConvert.ToBoolean (XmlUtil.GetRequiredAttribute (reader, "synchronized")); + XmlUtil.CheckExtraneousAttributes ("method", reader, "deprecated", "final", "name", "static", "visibility", "jni-signature", "jni-return", "synthetic", "bridge", + "abstract", "native", "return", "synchronized", "return-not-null"); + method.LoadMethodBase ("method", reader); + } + + internal static void Load (this JavaParameter p, XmlReader reader) + { + p.Name = XmlUtil.GetRequiredAttribute (reader, "name"); + p.Type = XmlUtil.GetRequiredAttribute (reader, "type"); + p.JniType = reader.GetAttribute ("jni-type"); + p.NotNull = reader.GetAttribute ("not-null") == "true"; + reader.Skip (); + } + + internal static void Load (this JavaException e, XmlReader reader) + { + e.Name = XmlUtil.GetRequiredAttribute (reader, "name"); + e.Type = XmlUtil.GetRequiredAttribute (reader, "type"); + e.Type = reader.GetAttribute ("type-generic-aware"); + reader.Skip (); + } + + internal static void Load (this JavaTypeParameters tps, XmlReader reader) + { + reader.MoveToContent (); + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; // + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "typeParameter") + throw XmlUtil.UnexpectedElementOrContent ("typeParameters", reader, "typeParameter"); + var tp = new JavaTypeParameter (tps); + tp.Load (reader); + tps.TypeParameters.Add (tp); + } while (true); + + XmlUtil.VerifyEndElement (reader, "typeParameters"); + reader.Read (); + } + } + + public static void Load (this JavaTypeParameter tp, XmlReader reader) + { + tp.Name = XmlUtil.GetRequiredAttribute (reader, "name"); + tp.ExtendedJniClassBound = reader.GetAttribute ("jni-classBound"); + // such an ill-named attribute... + tp.ExtendedClassBound = reader.GetAttribute ("classBound"); + // and un-structuring attribute... + tp.ExtendedInterfaceBounds = reader.GetAttribute ("interfaceBounds"); + tp.ExtendedJniInterfaceBounds = reader.GetAttribute ("jni-interfaceBounds"); + XmlUtil.CheckExtraneousAttributes ("typeParameter", reader, "name", "jni-classBound", "jni-interfaceBounds", "classBound", "interfaceBounds"); + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; // + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "genericConstraints") + throw XmlUtil.UnexpectedElementOrContent ("typeParameter", reader, "genericConstraints"); + + var gc = new JavaGenericConstraints (); + gc.Load (reader); + tp.GenericConstraints = gc; + } while (true); + + XmlUtil.VerifyEndElement (reader, "typeParameter"); + reader.Read (); + } + // Now we have to deal with the format difference... + // Some versions of class-parse stopped generating but started + // generating "classBound" and "interfaceBounds" attributes instead. + // They don't make sense and blocking this effort, but we have to deal with that... + if (!string.IsNullOrEmpty (tp.ExtendedClassBound) || !string.IsNullOrEmpty (tp.ExtendedInterfaceBounds)) { + var gcs = new JavaGenericConstraints (); + if (!string.IsNullOrEmpty (tp.ExtendedClassBound)) + gcs.GenericConstraints.Add (new JavaGenericConstraint () { Type = tp.ExtendedClassBound }); + if (!string.IsNullOrEmpty (tp.ExtendedInterfaceBounds)) + foreach (var ic in tp.ExtendedInterfaceBounds.Split (':')) + gcs.GenericConstraints.Add (new JavaGenericConstraint () { Type = ic }); + tp.GenericConstraints = gcs; + } + } + + public static void Load (this JavaGenericConstraints gcs, XmlReader reader) + { + reader.MoveToContent (); + + if (reader.IsEmptyElement) + reader.Read (); + else { + reader.Read (); + + do { + reader.MoveToContent (); + if (reader.NodeType == XmlNodeType.EndElement) + break; // + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "genericConstraint") + throw XmlUtil.UnexpectedElementOrContent ("genericConstraints", reader, "genericConstraint"); + var gc = new JavaGenericConstraint (); + gc.Load (reader); + gcs.GenericConstraints.Add (gc); + } while (true); + + XmlUtil.VerifyEndElement (reader, "genericConstraints"); + reader.Read (); + } + } + + public static void Load (this JavaGenericConstraint gc, XmlReader reader) + { + gc.Type = XmlUtil.GetRequiredAttribute (reader, "type"); + XmlUtil.CheckExtraneousAttributes ("genericConstraint", reader, "type"); + reader.Skip (); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeName.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeName.cs new file mode 100644 index 00000000000..99b7d99424c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeName.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + // An internal Type that represents a parsed Java type name structure. + // A type name string is passed to Parse() method to create this instance + // (the only place you can create an instance of this type), then it is + // used to create JavaTypeReference instance. + // + // The structure does not depend on any context type information. + // + // It is constructed from a "dotted" name. + // Unlike JNI-based names, there is no way to determine that a dot is within + // package name, between package and class, or for nested class. + // Hence it is impossible to get a package and a local names without + // context type information. Such analyses should be done at JavaTypeReference. + // + // A generic type parameter, or a primitive type, is also represented by this too. + // + public class JavaTypeName + { + const string extendsLabel = " extends "; + const string superLabel = " super "; + + static readonly string [] genericConstraintsLabels = { extendsLabel, superLabel }; + + JavaTypeName () + { + } + + public static JavaTypeName Parse (string dottedFullName) + { + var ret = new JavaTypeName (); + + foreach (var label in genericConstraintsLabels) { + int gcidx = dottedFullName.IndexOf (label, StringComparison.Ordinal); + int gcgidx = gcidx < 0 ? -1 : dottedFullName.IndexOf ('<', 0, gcidx); + int gccidx = gcidx < 0 ? -1 : dottedFullName.IndexOf (',', 0, gcidx); + if (gcidx > 0 && gcgidx < 0 && gccidx < 0) { + string args = dottedFullName.Substring (gcidx + label.Length).Trim (); + ret.BoundsType = label; + ret.GenericConstraints = ParseCommaSeparatedTypeNames (args).Select (s => Parse (s)).ToArray (); + dottedFullName = dottedFullName.Substring (0, gcidx).Trim (); + } + } + + if (dottedFullName.EndsWith ("...", StringComparison.Ordinal)) { + ret.ArrayPart = "..."; + dottedFullName = dottedFullName.Substring (0, dottedFullName.Length - 3); + } + while (dottedFullName.LastOrDefault () == ']') { + int aidx = dottedFullName.LastIndexOf ('['); + ret.ArrayPart += dottedFullName.Substring (aidx); + dottedFullName = dottedFullName.Substring (0, aidx); + } + + int idx = dottedFullName.IndexOf ('<'); + int nextIndex = dottedFullName.Length; + if (idx > 0) { + int last = GetMatchingGenericCloser (dottedFullName, idx + 1); + ret.GenericArguments = ParseCommaSeparatedTypeNames (dottedFullName.Substring (idx + 1, last - idx - 1)) + .Select (s => JavaTypeName.Parse (s.Trim ())) + .ToArray (); + nextIndex = last + 1; + } + // at this state, there is no way to distinguish package name from this name specification. + ret.DottedName = idx < 0 ? dottedFullName : dottedFullName.Substring (0, idx); + + if (nextIndex < dottedFullName.Length) { + if (dottedFullName [nextIndex] != '.') + throw new ArgumentException (nameof (dottedFullName)); + // the generic parent is parsed, but the rest is still there. + var parent = ret; + ret = Parse (dottedFullName.Substring (nextIndex + 1)); + ret.GenericParent = parent; + } + + return ret; + } + + static int GetMatchingGenericCloser (string str, int start) + { + int count = 0; + for (int i = start; i < str.Length; i++) { + switch (str [i]) { + case '<': + count++; + break; + case '>': + if (count-- == 0) + return i; + break; + } + } + return -1; + } + + static IEnumerable ParseCommaSeparatedTypeNames (string args) + { + int comma = args.IndexOf (','); + if (comma < 0) + yield return args; + else { + int open = args.IndexOf ('<', 0, comma); + if (open > 0) { + int openCount = 1; + int i = open + 1; + while (i < args.Length) { + if (args [i] == '<') + openCount++; + else if (args [i] == '>') + openCount--; + i++; + if (openCount == 0) + break; + } + yield return args.Substring (0, i); + if (i < args.Length) { + comma = args.IndexOf (',', i); + if (comma > 0) + foreach (var s in ParseCommaSeparatedTypeNames (args.Substring (comma + 1))) + yield return s; + } + } else { + yield return args.Substring (0, comma); + foreach (var s in ParseCommaSeparatedTypeNames (args.Substring (comma + 1).Trim ())) + yield return s; + } + } + } + + public JavaTypeName? GenericParent { get; set; } + public string? DottedName { get; set; } + public string? BoundsType { get; set; } // " extends " / " super " + public IList? GenericConstraints { get; private set; } + public IList? GenericArguments { get; private set; } + public string? ArrayPart { get; set; } + + public string? FullNameNonGeneric { + get { + if (GenericParent != null) + return GenericParent.FullNameNonGeneric + "." + DottedName; + else + return DottedName; + } + } + + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeReference.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeReference.cs new file mode 100644 index 00000000000..8ca86ff2db8 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeReference.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public class JavaTypeReference + { + public static readonly JavaTypeReference Void; + public static readonly JavaTypeReference Boolean; + public static readonly JavaTypeReference Char; + public static readonly JavaTypeReference Byte; + public static readonly JavaTypeReference Short; + public static readonly JavaTypeReference Int; + public static readonly JavaTypeReference Long; + public static readonly JavaTypeReference Float; + public static readonly JavaTypeReference Double; + public static readonly JavaTypeReference GenericWildcard; + public static readonly JavaTypeReference UInt; + public static readonly JavaTypeReference UShort; + public static readonly JavaTypeReference ULong; + public static readonly JavaTypeReference UByte; + + internal static JavaTypeReference? GetSpecialType (string? name) + { + switch (name) { + case "void": return Void; + case "boolean": return Boolean; + case "char": return Char; + case "byte": return Byte; + case "short": return Short; + case "int": return Int; + case "long": return Long; + case "float": return Float; + case "double": return Double; + case "uint": return UInt; + case "ushort": return UShort; + case "ulong": return ULong; + case "ubyte": return UByte; + case "?": return GenericWildcard; + } + return null; + } + + static JavaTypeReference () + { + Void = new JavaTypeReference ("void"); + Boolean = new JavaTypeReference ("boolean"); + Char = new JavaTypeReference ("char"); + Byte = new JavaTypeReference ("byte"); + Short = new JavaTypeReference ("short"); + Int = new JavaTypeReference ("int"); + Long = new JavaTypeReference ("long"); + Float = new JavaTypeReference ("float"); + Double = new JavaTypeReference ("double"); + GenericWildcard = new JavaTypeReference ("?"); + UInt = new JavaTypeReference ("uint"); + UShort = new JavaTypeReference ("ushort"); + ULong = new JavaTypeReference ("ulong"); + UByte = new JavaTypeReference ("ubyte"); + } + + JavaTypeReference (string? specialName) + { + SpecialName = specialName; + } + + public JavaTypeReference (string? constraintLabel, IEnumerable? wildcardConstraints, string? arrayPart) + { + SpecialName = GenericWildcard.SpecialName; + ArrayPart = arrayPart; + WildcardBoundsType = constraintLabel; + WildcardConstraints = wildcardConstraints != null && wildcardConstraints.Any () ? wildcardConstraints.ToList () : null; + } + + public JavaTypeReference (JavaTypeReference referencedType, string? arrayPart, string? wildcardBoundsType, IEnumerable? wildcardConstraints) + { + if (referencedType == null) + throw new ArgumentNullException ("referencedType"); + SpecialName = referencedType.SpecialName; + WildcardBoundsType = wildcardBoundsType; + WildcardConstraints = wildcardConstraints?.ToList (); + ReferencedType = referencedType.ReferencedType; + ReferencedTypeParameter = referencedType.ReferencedTypeParameter; + TypeParameters = referencedType.TypeParameters; + ArrayPart = arrayPart; + } + + public JavaTypeReference (JavaTypeParameter referencedTypeParameter, string? arrayPart) + { + if (referencedTypeParameter == null) + throw new ArgumentNullException ("referencedTypeParameter"); + ReferencedTypeParameter = referencedTypeParameter; + ArrayPart = arrayPart; + } + + public JavaTypeReference (JavaType referencedType, IList? typeParameters, string? arrayPart) + { + if (referencedType == null) + throw new ArgumentNullException ("referencedType"); + ReferencedType = referencedType; + TypeParameters = typeParameters; + ArrayPart = arrayPart; + } + + public string? SpecialName { get; private set; } + + public string? WildcardBoundsType { get; private set; } + public IList? WildcardConstraints { get; private set; } + + public JavaType? ReferencedType { get; private set; } + public JavaTypeParameter? ReferencedTypeParameter { get; private set; } + public IList? TypeParameters { get; private set; } + public string? ArrayPart { get; private set; } + + public override string ToString () + { + if (SpecialName == GenericWildcard.SpecialName && WildcardConstraints != null) + return SpecialName + WildcardBoundsType + string.Join (" & ", WildcardConstraints); + else if (SpecialName != null) + return SpecialName + ArrayPart; + else if (ReferencedTypeParameter != null) + return ReferencedTypeParameter.ToString () + ArrayPart; + else + return string.Format ("{0}{1}{2}{3}{4}", + ReferencedType?.Parent?.Name, + string.IsNullOrEmpty (ReferencedType?.Parent?.Name) ? string.Empty : ".", + ReferencedType?.Name, + TypeParameters == null ? null : '<' + string.Join (", ", TypeParameters.Select (_ => _.ToString ())) + '>', + ArrayPart); + } + + public override int GetHashCode () + { + // it's skipping TypeParameters because it's too annoying... + if (SpecialName != null) + return SpecialName.GetHashCode (); + return (ReferencedType != null ? ReferencedType.Name?.GetHashCode () ?? 0 : 0) << 15 + + (ReferencedTypeParameter != null ? ReferencedTypeParameter.Name?.GetHashCode () ?? 0 : 0) << 7 + + (ArrayPart != null ? ArrayPart.GetHashCode () : 0); + } + + public override bool Equals (object? obj) + { + return AreEqual (this, obj as JavaTypeReference); + } + + // It compares two JavaTypeReferences. + // Note that it is to compare them as a type reference, not as its object entity. + // So, for example, if one has a TypeParameter with T with some contraint and + // the other has a TypeParameter with T somehow without it, they are still "same". + public static bool AreEqual (JavaTypeReference tr1, JavaTypeReference? tr2) + { + if (tr1 == null) + return tr2 == null; + else if (tr2 == null) + return false; + + if (tr1.ArrayPart != tr2.ArrayPart) + return false; + + if (tr1.SpecialName != null) + return tr1.SpecialName == tr2.SpecialName; + + if (tr1.ReferencedTypeParameter != null) { + if (tr2.ReferencedTypeParameter == null || tr1.ReferencedTypeParameter.Name != tr2.ReferencedTypeParameter.Name) + return false; + + return true; + } + else if (tr2.ReferencedTypeParameter != null) + return false; + + if (tr1.ReferencedType == null || tr2.ReferencedType == null) + return false; + if (tr1.ReferencedType.Parent != tr2.ReferencedType.Parent) + return false; + if (tr1.ReferencedType.Name != tr2.ReferencedType.Name) + return false; + return true; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeResolutionUtil.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeResolutionUtil.cs new file mode 100644 index 00000000000..aa50be957f2 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeResolutionUtil.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaTypeResolutionUtil + { + + [return: MaybeNull] + static V Get (this IDictionary dic, K key) + { + V? v; + return dic.TryGetValue (key, out v) ? v : default (V); + } + + // It should detect implementation method for: + // - equivalent implementation + // - generic instantiation + // - TODO: variance + // - TODO?: array indicator fixup ("T..." should match "T[]") + public static bool IsImplementing (this JavaMethod derived, JavaMethod basis, IDictionary genericInstantiation) + { + if (genericInstantiation == null) + throw new ArgumentNullException ("genericInstantiation"); + + if (basis.Name != derived.Name) + return false; + + if (basis.Parameters.Count != derived.Parameters.Count) + return false; + + if (basis.Parameters.Zip (derived.Parameters, (bp, dp) => dp.IsParameterAssignableTo (bp, derived, basis, genericInstantiation)).All (v => v)) + return true; + return false; + } + + static bool IsParameterAssignableTo (this JavaParameter dp, JavaParameter bp, JavaMethod derived, JavaMethod basis, IDictionary genericInstantiation) + { + // If type names are equivalent, they simply match... except that the generic type parameter names match. + // Generic type arguments need more check, so do not examine them just by name. + // + // FIXME: It is likely that this check should NOT result in "this method is not an override", + // but rather like "this method is an override, but it should be still generated in the resulting XML". + // For example, this results in that java.util.EnumMap#put() is NOT an override of + // java.util.AbstractMap#put(), it is an override, not just that it is still generated in the XML. + if (bp.ResolvedType?.ReferencedTypeParameter != null && dp.ResolvedType?.ReferencedTypeParameter != null && + bp.ResolvedType.ReferencedTypeParameter.ToString () != dp.ResolvedType.ReferencedTypeParameter.ToString ()) + return false; + if (bp.Type == dp.Type) + return true; + + if (bp.ResolvedType?.ArrayPart != bp.ResolvedType?.ArrayPart) + return false; + + // if base is type with generic type parameters and derived is without any generic args, that's OK. + // java.lang.Class should match java.lang.Class. + if (bp.ResolvedType?.ReferencedType != null && dp.ResolvedType?.ReferencedType != null && + bp.ResolvedType?.ReferencedType.FullName == dp.ResolvedType?.ReferencedType.FullName && + dp.ResolvedType?.TypeParameters == null) + return true; + + // generic instantiation check. + var baseGTP = bp.ResolvedType?.ReferencedTypeParameter; + if (baseGTP != null) { + if (baseGTP.Parent?.ParentMethod != null && baseGTP.IsConformantType (dp.ResolvedType)) + return true; + var k = genericInstantiation.Keys.FirstOrDefault (tr => bp.ResolvedType?.Equals (tr) ?? false); + if (k == null) + // the specified generic type parameter is not part of + // the mappings e.g. non-instantiated ones. + return false; + if (genericInstantiation [k].Equals (dp.ResolvedType)) + // the specified generic type parameter exactly matches + // whatever specified at the derived method. + return true; + } + + // FIXME: implement variance check. + + return false; + } + + static bool IsConformantType (this JavaTypeParameter typeParameter, JavaTypeReference? examinedType) + { + if (typeParameter.GenericConstraints == null) + return true; + // FIXME: implement correct generic constraint conformance check. + Log.LogDebug ("NOTICE: generic constraint conformance check is not implemented, so the type might be actually compatible. Type parameter: {0}{1}, examined type: {2}", + typeParameter.Name, typeParameter.Parent?.ParentMethod?.Name ?? typeParameter.Parent?.ParentType?.Name, examinedType); + return false; + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/Log.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/Log.cs new file mode 100644 index 00000000000..00f74968a24 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/Log.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class Log + { + public enum LoggingLevel + { + None = 0, + Error = 1, + Warning = 2, + Debug = 3, + } + + static Action write_default = s => (DefaultWriter ?? Console.Out).WriteLine (s); + + static Action? e, w, d; + + public static TextWriter? DefaultWriter { get; set; } + + public static LoggingLevel Verbosity { get; set; } = LoggingLevel.Error; + + public static Action LogErrorAction { + get { return e ?? write_default; } + set { e = value; } + } + public static Action LogWarningAction { + get { return w ?? write_default; } + set { w = value; } + } + public static Action LogDebugAction { + get { return d ?? write_default; } + set { d = value; } + } + + public static void LogError (string format, params object?[] args) + { + if ((int) Verbosity >= (int) LoggingLevel.Error) + LogErrorAction (args.Length > 0 ? string.Format (format, args) : format); + } + + public static void LogWarning (string format, params object?[] args) + { + if ((int)Verbosity >= (int)LoggingLevel.Warning) + LogWarningAction (args.Length > 0 ? string.Format (format, args) : format); + } + + public static void LogDebug (string format, params object?[] args) + { + if ((int)Verbosity >= (int)LoggingLevel.Debug) + LogDebugAction (args.Length > 0 ? string.Format (format, args) : format); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/Xamarin.Android.Tools.ApiXmlAdjuster.csproj b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/Xamarin.Android.Tools.ApiXmlAdjuster.csproj new file mode 100644 index 00000000000..caa1c2cfcec --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/Xamarin.Android.Tools.ApiXmlAdjuster.csproj @@ -0,0 +1,18 @@ + + + + $(DotNetTargetFramework) + enable + + + + + + $(TestOutputFullPath) + + + + + + + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/XmlUtil.cs b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/XmlUtil.cs new file mode 100644 index 00000000000..6e92c7274f1 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.ApiXmlAdjuster/XmlUtil.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + class XmlUtil + { + static string GetLocation (XmlReader reader) + { + var li = reader as IXmlLineInfo; + return string.Format ("{0} ({1},{2})", string.IsNullOrEmpty (reader.BaseURI) ? null : new Uri (reader.BaseURI).LocalPath, li?.LineNumber ?? 0, li?.LinePosition ?? 0); + } + + public static Exception UnexpectedElementOrContent (string? elementName, XmlReader reader, params string?[] expected) + { + return new Exception (string.Format ("{0}: Unexpected element or content in '{1}': node is {2}, name is '{3}'. Expected elements are: {4}", + GetLocation (reader), elementName ?? "(top level)", reader.NodeType, reader.LocalName, string.Join (", ", expected))); + } + + public static Exception UnexpectedAttribute (XmlReader reader, string elementName, params string [] expected) + { + if (reader.NodeType != XmlNodeType.Attribute) + throw new ArgumentException (string.Format ("Internal error: XmlReader should be positioned on attribute, but it is on {0}", reader.NodeType)); + return new Exception (string.Format ("{0}: Element '{1}' has an unexpected attribute: '{2}'. Expected attributes are: {3}", + GetLocation (reader), elementName, reader.LocalName, string.Join (", ", expected))); + } + + internal static string GetRequiredAttribute (XmlReader reader, string name) + { + var value = reader.GetAttribute (name); + if (value == null) + throw new Exception (string.Format ("{0}: Element '{1}' requires attribute '{2}'", GetLocation (reader), reader.LocalName, name)); + return value; + } + + internal static void VerifyEndElement (XmlReader reader, string elementName) + { + if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != elementName) + throw new Exception (string.Format ("{0}: EndElement of '{1}' was expected, but got {2} with name '{3}' instead.", + GetLocation (reader), elementName, reader.NodeType, reader.LocalName)); + } + + internal static void CheckExtraneousAttributes (string elementName, XmlReader reader, params string [] expected) + { + if (reader.MoveToFirstAttribute ()) { + do { + if (!expected.Contains (reader.LocalName)) + throw XmlUtil.UnexpectedAttribute (reader, elementName, expected); + } while (reader.MoveToNextAttribute ()); + } + reader.MoveToElement (); + } + } + +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Annotation.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Annotation.cs new file mode 100644 index 00000000000..fcde061a514 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Annotation.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode +{ + public sealed class Annotation + { + public ConstantPool ConstantPool { get; } + + ushort typeIndex; + public string Type => ((ConstantPoolUtf8Item) ConstantPool [typeIndex]).Value; + + public IList> + Values { get; } = new List> (); + + public Annotation (ConstantPool constantPool, Stream stream) + { + ConstantPool = constantPool; + typeIndex = stream.ReadNetworkUInt16 (); + + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + var elementNameIndex = stream.ReadNetworkUInt16 (); + var elementName = ((ConstantPoolUtf8Item) ConstantPool [elementNameIndex]).Value; + var elementValue = AnnotationElementValue.Create (constantPool, stream); + Values.Add (new KeyValuePair (elementName, elementValue)); + } + } + + public override string ToString () + { + var values = new StringBuilder ("{"); + if (Values.Count > 0) { + Append (Values [0]); + } + for (int i = 1; i < Values.Count; ++i) { + values.Append (", "); + Append (Values [i]); + } + values.Append ("}"); + return $"Annotation('{Type}', {values})"; + + void Append (KeyValuePair value) + { + values.Append (value.Key).Append (": "); + values.Append (value.Value); + } + } + } + + public sealed class ParameterAnnotation + { + public int ParameterIndex { get; } + public IList Annotations { get; } = new List (); + public ConstantPool ConstantPool { get; } + + public ParameterAnnotation (ConstantPool constantPool, Stream stream, int index) + { + ConstantPool = constantPool; + + ParameterIndex = index; + + var ann_count = stream.ReadNetworkUInt16 (); + + for (var i = 0; i < ann_count; ++i) { + var a = new Annotation (constantPool, stream); + Annotations.Add (a); + } + } + + public override string ToString () + { + var annotations = string.Join (", ", Annotations.Select (v => v.ToString ())); + return $"Parameter{ParameterIndex}({annotations})"; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/AnnotationElementValue.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/AnnotationElementValue.cs new file mode 100644 index 00000000000..919b19813c3 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/AnnotationElementValue.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode +{ + // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.16.1 + public abstract class AnnotationElementValue + { + public virtual string? ToEncodedString () => ToString (); + + public static AnnotationElementValue? Create (ConstantPool constantPool, Stream stream) + { + var tag = stream.ReadNetworkByte (); + + switch (tag) { + case (byte) 'e': { + var typeNameIndex = stream.ReadNetworkUInt16 (); + var constNameIndex = stream.ReadNetworkUInt16 (); + + var typeName = ((ConstantPoolUtf8Item) constantPool [typeNameIndex]).Value; + var constName = ((ConstantPoolUtf8Item) constantPool [constNameIndex]).Value; + + return new AnnotationElementEnum { TypeName = typeName, ConstantName = constName }; + } + case (byte) 'c': { + var classInfoIndex = stream.ReadNetworkUInt16 (); + + return new AnnotationElementClassInfo { ClassInfo = ((ConstantPoolUtf8Item) constantPool [classInfoIndex]).Value }; + } + case (byte) '@': { + return new AnnotationElementAnnotation { Annotation = new Annotation (constantPool, stream) }; + } + case (byte) '[': { + var numValues = stream.ReadNetworkUInt16 (); + + var values = new List (); + + for (var i = 0; i < numValues; i++) { + var v = Create (constantPool, stream); + if (v == null) + continue; + values.Add (v); + } + + return new AnnotationElementArray { Values = values.ToArray () }; + } + case (byte) 'B': + case (byte) 'C': + case (byte) 'D': + case (byte) 'F': + case (byte) 'I': + case (byte) 'J': + case (byte) 'S': + case (byte) 's': + case (byte) 'Z': { + var constValueIndex = stream.ReadNetworkUInt16 (); + var poolItem = constantPool [constValueIndex]; + var value = poolItem.ToString (); + + if (poolItem is ConstantPoolDoubleItem d) + value = d.Value.ToString (); + else if (poolItem is ConstantPoolFloatItem f) + value = f.Value.ToString (); + else if (poolItem is ConstantPoolIntegerItem i) + value = i.Value.ToString (); + else if (poolItem is ConstantPoolLongItem l) + value = l.Value.ToString (); + else if (poolItem is ConstantPoolStringItem s) + return new AnnotationStringElementConstant { Value = s.StringData.Value.ToString () }; + else if (poolItem is ConstantPoolUtf8Item u) + return new AnnotationStringElementConstant { Value = u.Value.ToString () }; + + return new AnnotationElementConstant { Value = value }; + } + } + + return null; + } + } + + public class AnnotationElementEnum : AnnotationElementValue + { + public string? TypeName { get; set; } + public string? ConstantName { get; set; } + + public override string ToString () => $"Enum({TypeName}.{ConstantName})"; + } + + public class AnnotationElementClassInfo : AnnotationElementValue + { + public string? ClassInfo { get; set; } + + public override string? ToString () => ClassInfo; + } + + public class AnnotationElementAnnotation : AnnotationElementValue + { + public Annotation? Annotation { get; set; } + + public override string? ToString () => Annotation?.ToString (); + } + + public class AnnotationElementArray : AnnotationElementValue + { + public AnnotationElementValue[]? Values { get; set; } + + public override string ToString () => Values == null + ? "[]" + : $"[{string.Join (", ", Values.Select (v => v.ToString ()))}]"; + + public override string? ToEncodedString () => Values == null + ? "[]" + : $"[{string.Join (", ", Values.Select (v => v.ToEncodedString ()))}]"; + } + + public class AnnotationElementConstant : AnnotationElementValue + { + public string? Value { get; set; } + + public override string? ToString () => Value; + } + + public class AnnotationStringElementConstant : AnnotationElementConstant + { + public override string ToString () => $"\"{Value}\""; + + public override string? ToEncodedString () + { + return $"\"{Convert.ToBase64String (Encoding.UTF8.GetBytes (Value ?? ""))}\""; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/AttributeInfo.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/AttributeInfo.cs new file mode 100644 index 00000000000..a1a819b6588 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/AttributeInfo.cs @@ -0,0 +1,860 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode { + + public sealed class AttributeCollection : Collection { + + public ConstantPool ConstantPool {get; private set;} + + public AttributeCollection (ConstantPool constantPool, Stream stream) + { + ConstantPool = constantPool; + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + Add (AttributeInfo.CreateFromStream (constantPool, stream)); + } + } + + public IEnumerable GetInfos (string name) + { + return this.Where (a => a.Name == name); + } + + public T? Get () + where T : AttributeInfo + { + return (T?) GetInfos (AttributeInfo.GetAttributeName()).SingleOrDefault (); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7 + public class AttributeInfo { + + public const string Code = "Code"; + public const string ConstantValue = "ConstantValue"; + public const string Deprecated = "Deprecated"; + public const string Exceptions = "Exceptions"; + public const string EnclosingMethod = "EnclosingMethod"; + public const string InnerClasses = "InnerClasses"; + public const string LocalVariableTable = "LocalVariableTable"; + public const string MethodParameters = "MethodParameters"; + public const string Module = "Module"; + public const string ModulePackages = "ModulePackages"; + public const string Signature = "Signature"; + public const string SourceFile = "SourceFile"; + public const string StackMapTable = "StackMapTable"; + public const string RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations"; + public const string RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations"; + public const string RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations"; + public const string RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations"; + public const string RuntimeVisibleTypeAnnotations = "RuntimeVisibleTypeAnnotations"; + public const string RuntimeInvisibleTypeAnnotations = "RuntimeInvisibleTypeAnnotations"; + + ushort nameIndex; + + public ConstantPool ConstantPool {get; private set;} + + protected AttributeInfo (ConstantPool constantPool, ushort nameIndex, Stream stream) + { + if (constantPool == null) + throw new ArgumentNullException ("constantPool"); + if (stream == null) + throw new ArgumentNullException ("stream"); + + ConstantPool = constantPool; + this.nameIndex = nameIndex; + } + + public string Name { + get {return ((ConstantPoolUtf8Item) ConstantPool [nameIndex]).Value;} + } + + static Dictionary AttributeNames = new Dictionary { + { typeof (CodeAttribute), Code }, + { typeof (ConstantValueAttribute), ConstantValue }, + { typeof (DeprecatedAttribute), Deprecated }, + { typeof (EnclosingMethodAttribute), EnclosingMethod }, + { typeof (ExceptionsAttribute), Exceptions }, + { typeof (InnerClassesAttribute), InnerClasses }, + { typeof (LocalVariableTableAttribute), LocalVariableTable }, + { typeof (MethodParametersAttribute), MethodParameters }, + { typeof (ModuleAttribute), Module }, + { typeof (ModulePackagesAttribute), ModulePackages }, + { typeof (RuntimeVisibleAnnotationsAttribute), RuntimeVisibleAnnotations }, + { typeof (RuntimeInvisibleAnnotationsAttribute), RuntimeInvisibleAnnotations }, + { typeof (RuntimeVisibleParameterAnnotationsAttribute), RuntimeVisibleParameterAnnotations }, + { typeof (RuntimeInvisibleParameterAnnotationsAttribute), RuntimeInvisibleParameterAnnotations }, + { typeof (RuntimeVisibleTypeAnnotationsAttribute), RuntimeVisibleTypeAnnotations }, + { typeof (RuntimeInvisibleTypeAnnotationsAttribute), RuntimeInvisibleTypeAnnotations }, + { typeof (SignatureAttribute), Signature }, + { typeof (SourceFileAttribute), SourceFile }, + { typeof (StackMapTableAttribute), StackMapTable }, + }; + + internal static string GetAttributeName() + { + string? value; + if (AttributeNames.TryGetValue (typeof(T), out value)) { + return value; + } + throw new InvalidOperationException ("No known name for type: " + typeof(T).Name); + } + + public static AttributeInfo CreateFromStream (ConstantPool constantPool, Stream stream) + { + var nameIndex = stream.ReadNetworkUInt16 (); + var constant = constantPool [nameIndex]; + var name = ((ConstantPoolUtf8Item) constantPool [nameIndex]).Value; + var attr = CreateAttribute (name, constantPool, nameIndex, stream); + return attr; + } + + static AttributeInfo CreateAttribute (string name, ConstantPool constantPool, ushort nameIndex, Stream stream) + { + switch (name) { + case Code: return new CodeAttribute (constantPool, nameIndex, stream); + case ConstantValue: return new ConstantValueAttribute (constantPool, nameIndex, stream); + case Deprecated: return new DeprecatedAttribute (constantPool, nameIndex, stream); + case EnclosingMethod: return new EnclosingMethodAttribute (constantPool, nameIndex, stream); + case Exceptions: return new ExceptionsAttribute (constantPool, nameIndex, stream); + case InnerClasses: return new InnerClassesAttribute (constantPool, nameIndex, stream); + case LocalVariableTable: return new LocalVariableTableAttribute (constantPool, nameIndex, stream); + case MethodParameters: return new MethodParametersAttribute (constantPool, nameIndex, stream); + case Module: return new ModuleAttribute (constantPool, nameIndex, stream); + case ModulePackages: return new ModulePackagesAttribute (constantPool, nameIndex, stream); + case RuntimeVisibleAnnotations: return new RuntimeVisibleAnnotationsAttribute (constantPool, nameIndex, stream); + case RuntimeInvisibleAnnotations: return new RuntimeInvisibleAnnotationsAttribute (constantPool, nameIndex, stream); + case RuntimeVisibleParameterAnnotations: return new RuntimeVisibleParameterAnnotationsAttribute (constantPool, nameIndex, stream); + case RuntimeInvisibleParameterAnnotations: return new RuntimeInvisibleParameterAnnotationsAttribute (constantPool, nameIndex, stream); + case RuntimeVisibleTypeAnnotations: return new RuntimeVisibleTypeAnnotationsAttribute (constantPool, nameIndex, stream); + case RuntimeInvisibleTypeAnnotations: return new RuntimeInvisibleTypeAnnotationsAttribute (constantPool, nameIndex, stream); + case Signature: return new SignatureAttribute (constantPool, nameIndex, stream); + case SourceFile: return new SourceFileAttribute (constantPool, nameIndex, stream); + case StackMapTable: return new StackMapTableAttribute (constantPool, nameIndex, stream); + default: return new UnknownAttribute (constantPool, nameIndex, stream); + } + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.3 + public sealed class CodeAttribute : AttributeInfo { + + public byte[] ByteCode; + public ushort MaxStack; + public ushort MaxLocals; + + public AttributeCollection Attributes {get; private set;} + + public Collection ExceptionTable = new Collection (); + + public CodeAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + MaxStack = stream.ReadNetworkUInt16 (); + MaxLocals = stream.ReadNetworkUInt16 (); + + var code_length = stream.ReadNetworkUInt32 (); + var code = new byte[code_length]; + for (int i = 0; i < code.Length; ++i) + code [i] = stream.ReadNetworkByte (); + ByteCode = code; + + var exception_table_length = stream.ReadNetworkUInt16 (); + for (int i = 0; i < exception_table_length; ++i) { + var ex = new CodeExceptionTableEntry (constantPool) { + StartPC = stream.ReadNetworkUInt16 (), + EndPC = stream.ReadNetworkUInt16 (), + HandlerPC = stream.ReadNetworkUInt16 (), + catchType = stream.ReadNetworkUInt16 (), + }; + ExceptionTable.Add (ex); + } + + Attributes = new AttributeCollection (constantPool, stream); + } + + public override string ToString () + { + var sb = new StringBuilder ("Code(") + .Append (ByteCode.Length); + foreach (var attr in Attributes) { + sb.Append (", ").Append (attr); + } + sb.Append (")"); + return sb.ToString (); + } + } + + public sealed class CodeExceptionTableEntry { + public ushort StartPC; + public ushort EndPC; + public ushort HandlerPC; + internal ushort catchType; + + public ConstantPool ConstantPool {get; private set;} + + public CodeExceptionTableEntry (ConstantPool constantPool) + { + if (constantPool == null) + throw new ArgumentNullException ("constantPool"); + + ConstantPool = constantPool; + } + + public ConstantPoolClassItem CatchType { + get {return (ConstantPoolClassItem) ConstantPool [catchType];} + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.2 + public sealed class ConstantValueAttribute : AttributeInfo { + + ushort constantValueIndex; + + public ConstantValueAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + Debug.Assert (length == 2); + constantValueIndex = stream.ReadNetworkUInt16 (); + } + + public ConstantPoolItem Constant { + get {return ConstantPool [constantValueIndex];} + } + + public override string ToString () + { + return string.Format ("ConstantValue({0})", Constant); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.15 + public sealed class DeprecatedAttribute : AttributeInfo { + + public DeprecatedAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + Debug.Assert (length == 0); + } + + public override string ToString () + { + return "Deprecated"; + } + } + + // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.7 + public sealed class EnclosingMethodAttribute : AttributeInfo { + + ushort classIndex, methodIndex; + + public ConstantPoolClassItem Class { + get {return (ConstantPoolClassItem) ConstantPool [classIndex];} + } + + public ConstantPoolNameAndTypeItem? Method { + get {return methodIndex == 0 ? null : (ConstantPoolNameAndTypeItem) ConstantPool [methodIndex];} + } + + public EnclosingMethodAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + classIndex = stream.ReadNetworkUInt16 (); + methodIndex = stream.ReadNetworkUInt16 (); + } + + public override string ToString () + { + return $"EnclosingMethod({Class}, {Method})"; + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.5 + public sealed class ExceptionsAttribute : AttributeInfo { + + List exceptions = new List (); + + public ExceptionsAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var number_of_exceptions = stream.ReadNetworkUInt16 (); + for (int i = 0; i < number_of_exceptions; ++i) { + exceptions.Add (stream.ReadNetworkUInt16 ()); + } + } + + public IEnumerable CheckedExceptions { + get {return exceptions.Select (c => (ConstantPoolClassItem) ConstantPool [c]);} + } + + public override string ToString () + { + var sb = new StringBuilder ("Exceptions("); + bool first = true; + foreach (var e in CheckedExceptions) { + if (!first) + sb.Append (", "); + first = false; + sb.Append (e.Name.Value); + } + sb.Append (")"); + return sb.ToString (); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.6 + public sealed class InnerClassesAttribute : AttributeInfo { + + public Collection Classes = new Collection (); + + public InnerClassesAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var number_of_classes = stream.ReadNetworkUInt16 (); + for (int i = 0; i < number_of_classes; ++i) { + var info = new InnerClassInfo (ConstantPool) { + innerClassInfoIndex = stream.ReadNetworkUInt16 (), + outerClassInfoIndex = stream.ReadNetworkUInt16 (), + innerNameIndex = stream.ReadNetworkUInt16 (), + InnerClassAccessFlags = (ClassAccessFlags) stream.ReadNetworkUInt16 (), + }; + Classes.Add (info); + } + } + + public override string ToString () + { + return string.Format ("InnerClasses(Count={0}{1}{2})", + Classes.Count, + Classes.Count == 0 ? "" : ", ", + string.Join (", ", Classes)); + } + } + + public sealed class InnerClassInfo { + + internal ushort innerClassInfoIndex; + internal ushort outerClassInfoIndex; + internal ushort innerNameIndex; + public ClassAccessFlags InnerClassAccessFlags; + + public ConstantPool ConstantPool {get; private set;} + + public InnerClassInfo (ConstantPool constantPool) + { + if (constantPool == null) + throw new ArgumentNullException ("constantPool"); + + ConstantPool = constantPool; + } + + public ConstantPoolClassItem InnerClass { + get {return (ConstantPoolClassItem) ConstantPool [innerClassInfoIndex];} + } + + public ConstantPoolClassItem OuterClass { + get {return (ConstantPoolClassItem) ConstantPool [outerClassInfoIndex];} + } + + public string? InnerName { + get { + if (innerNameIndex == 0) + // anonymous class + return null; + return ((ConstantPoolUtf8Item) ConstantPool [innerNameIndex]).Value; + } + } + + public string? OuterClassName => OuterClass?.Name?.Value; + + public override string ToString () + { + return string.Format ("InnerClass(InnerClass='{0}', OuterClass='{1}', InnerName='{2}', InnerClassAccessFlags={3})", + InnerClass?.Name?.Value, OuterClass?.Name?.Value, InnerName, InnerClassAccessFlags); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.13 + public sealed class LocalVariableTableAttribute : AttributeInfo { + + public Collection LocalVariables = new Collection (); + + public LocalVariableTableAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var local_variable_table_length = stream.ReadNetworkUInt16 (); + for (int i = 0; i < local_variable_table_length; ++i) { + var entry = new LocalVariableTableEntry (constantPool) { + StartPC = stream.ReadNetworkUInt16 (), + Length = stream.ReadNetworkUInt16 (), + nameIndex = stream.ReadNetworkUInt16 (), + descriptorIndex = stream.ReadNetworkUInt16 (), + Index = stream.ReadNetworkUInt16 (), + }; + LocalVariables.Add (entry); + } + } + + public override string ToString () + { + if (LocalVariables.Count == 0) + return "LocalVariableTableAttribute()"; + var sb = new StringBuilder ("LocalVariableTableAttribute("); + sb.Append (LocalVariables [0]); + for (int i = 1; i < LocalVariables.Count; ++i) + sb.Append (", ").Append (LocalVariables [i]); + sb.Append (")"); + return sb.ToString (); + } + } + + public sealed class LocalVariableTableEntry { + public ushort StartPC; + public ushort Length; + internal ushort nameIndex; + internal ushort descriptorIndex; + public ushort Index; + + public ConstantPool ConstantPool {get; private set;} + + public LocalVariableTableEntry (ConstantPool constantPool) + { + if (constantPool == null) + throw new ArgumentNullException ("constantPool"); + + ConstantPool = constantPool; + } + + public string Name { + get {return ((ConstantPoolUtf8Item) ConstantPool [nameIndex]).Value;} + } + + public string Descriptor { + get {return ((ConstantPoolUtf8Item) ConstantPool [descriptorIndex]).Value;} + } + + public override string ToString () + { + return $"LocalVariableTableEntry(Name='{Name}', Descriptor='{Descriptor}', StartPC={StartPC}, Index={Index})"; + } + } + + public sealed class MethodParameterInfo { + + internal ushort nameIndex; + public MethodParameterAccessFlags AccessFlags; + + public ConstantPool ConstantPool {get; private set;} + + public MethodParameterInfo (ConstantPool constantPool) + { + ConstantPool = constantPool; + } + + public string? Name { + get { + if (nameIndex == 0) + return null; + return ((ConstantPoolUtf8Item) ConstantPool [nameIndex]).Value; + } + } + + public override string ToString () + { + return string.Format ("MethodParameterInfo(Name='{0}', AccessFlags={1})", Name, AccessFlags); + } + } + + // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24 + public sealed class MethodParametersAttribute : AttributeInfo { + + List parameters; + + public IList ParameterInfo { + get {return parameters;} + } + + public MethodParametersAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var count = stream.ReadNetworkByte (); + Debug.Assert ( + length == (checked ((count * 4) + 1)), + $"Unexpected `MethodParameters` length; expected {(count*4)+1}, got {length}!"); + parameters = new List (count); + for (int i = 0; i < count; ++i) { + var pNameIndex = stream.ReadNetworkUInt16 (); + var accessFlags = stream.ReadNetworkUInt16 (); + var p = new MethodParameterInfo (constantPool) { + nameIndex = pNameIndex, + AccessFlags = (MethodParameterAccessFlags) accessFlags, + }; + parameters.Add (p); + } + } + + public override string ToString () + { + if (parameters.Count == 0) + return "MethodParametersAttribute()"; + var sb = new StringBuilder ("MethodParametersAttribute("); + sb.Append (parameters [0]); + for (int i = 1; i < parameters.Count; ++i) + sb.Append (", ").Append (parameters [i]); + sb.Append (")"); + return sb.ToString (); + } + } + + // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.25 + public sealed class ModuleAttribute : AttributeInfo + { + ushort moduleNameIndex; + public string ModuleName { + get {return ((ConstantPoolModuleItem) ConstantPool [moduleNameIndex]).Name.Value;} + } + + public ModuleFlags ModuleFlags { get; private set; } + + ushort moduleVersionIndex; + public string? ModuleVersion { + get {return ((ConstantPoolUtf8Item) ConstantPool [moduleVersionIndex])?.Value;} + } + + public Collection Requires {get;} = new (); + public Collection Exports {get;} = new (); + public Collection Opens {get;} = new (); + public Collection Uses {get;} = new (); + public Collection Provides {get;} = new (); + + public ModuleAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var attribute_length = stream.ReadNetworkUInt32 (); + + moduleNameIndex = stream.ReadNetworkUInt16 (); + ModuleFlags = (ModuleFlags) stream.ReadNetworkUInt16 (); + moduleVersionIndex = stream.ReadNetworkUInt16 (); + + var requires_count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < requires_count; ++i) { + Requires.Add (new ModuleRequiresInfo (constantPool, stream)); + } + + var exports_count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < exports_count; ++i) { + Exports.Add (new ModuleExportsPackageInfo (constantPool, stream)); + } + + var opens_count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < opens_count; ++i) { + Opens.Add (new ModuleOpensPackageInfo (constantPool, stream)); + } + + var uses_count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < uses_count; ++i) { + var uses_index = stream.ReadNetworkUInt16 (); + Uses.Add ((ConstantPoolClassItem) constantPool [uses_index]); + } + + var provides_count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < provides_count; ++i) { + Provides.Add (new ModuleProvidesInfo (constantPool, stream)); + } + } + + public override string ToString () + { + var s = new StringBuilder () + .Append ("Module(").AppendLine () + .Append (" ").Append (nameof (ModuleName)).Append ("='").Append (ModuleName).AppendLine ("', ") + .Append (" ").Append (nameof (ModuleVersion)).Append ("='").Append (ModuleVersion).Append ("'"); + AppendString (s, nameof (Requires), Requires); + AppendString (s, nameof (Exports), Exports); + AppendString (s, nameof (Opens), Opens); + AppendString (s, nameof (Uses), Uses.Select (u => $"UsesService({u.Name})").ToList ()); + AppendString (s, nameof (Provides), Provides); + s.Append (")"); + + return s.ToString (); + } + + static StringBuilder AppendString (StringBuilder s, string collectionName, IList items) + { + if (items.Count == 0) { + return s; + } + s.AppendLine (","); + s.Append (" ").Append (collectionName).AppendLine ("={"); + s.Append (" ").Append (items [0]); + for (int i = 1; i < items.Count; ++i) { + s.AppendLine (","); + s.Append (" "); + s.Append (items [i]); + } + return s.Append ("}"); + } + } + + // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.26 + public sealed class ModulePackagesAttribute : AttributeInfo { + public Collection Packages {get;} = new (); + + public ModulePackagesAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var attribute_length = stream.ReadNetworkUInt32 (); + + var package_count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < package_count; ++i) { + var package_index = stream.ReadNetworkUInt16 (); + Packages.Add ((ConstantPoolPackageItem) constantPool [package_index]); + } + } + + public override string ToString () + { + return $"ModulePackages({{{string.Join (", ", Packages.Select (p => p.Name.Value))}}})"; + } + } + + // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.16 + public sealed class RuntimeVisibleAnnotationsAttribute : AttributeInfo + { + + public IList Annotations { get; } = new List (); + + public RuntimeVisibleAnnotationsAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var count = stream.ReadNetworkUInt16 (); + + for (int i = 0; i < count; ++i) { + Annotations.Add (new Annotation (constantPool, stream)); + } + } + + public override string ToString () + { + var annotations = string.Join (", ", Annotations.Select (v => v.ToString ())); + return $"RuntimeVisibleAnnotations({annotations})"; + } + } + + // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.17 + public sealed class RuntimeInvisibleAnnotationsAttribute : AttributeInfo + { + public IList Annotations { get; } = new List (); + + public RuntimeInvisibleAnnotationsAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var count = stream.ReadNetworkUInt16 (); + + for (int i = 0; i < count; ++i) { + var a = new Annotation (constantPool, stream); + Annotations.Add (a); + } + } + + public override string ToString () + { + var annotations = string.Join (", ", Annotations.Select (v => v.ToString ())); + return $"RuntimeInvisibleAnnotations({annotations})"; + } + } + + + // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.18 + public sealed class RuntimeVisibleParameterAnnotationsAttribute : AttributeInfo + { + public IList Annotations { get; } = new List (); + + public RuntimeVisibleParameterAnnotationsAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var param_count = stream.ReadNetworkByte (); + + for (var i = 0; i < param_count; ++i) { + var a = new ParameterAnnotation (constantPool, stream, i); + Annotations.Add (a); + } + } + + public override string ToString () + { + var annotations = string.Join (", ", Annotations.Select (v => v.ToString ())); + return $"RuntimeVisibleParameterAnnotationsAttribute({annotations})"; + } + } + + + // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.19 + public sealed class RuntimeInvisibleParameterAnnotationsAttribute : AttributeInfo + { + public IList Annotations { get; } = new List (); + + public RuntimeInvisibleParameterAnnotationsAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var param_count = stream.ReadNetworkByte (); + + for (var i = 0; i < param_count; ++i) { + var a = new ParameterAnnotation (constantPool, stream, i); + Annotations.Add (a); + } + } + + public override string ToString () + { + var annotations = string.Join (", ", Annotations.Select (v => v.ToString ())); + return $"RuntimeInvisibleParameterAnnotationsAttribute({annotations})"; + } + } + + // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20 + public sealed class RuntimeVisibleTypeAnnotationsAttribute : AttributeInfo + { + public IList Annotations { get; } = new List (); + + public RuntimeVisibleTypeAnnotationsAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var count = stream.ReadNetworkUInt16 (); + + for (int i = 0; i < count; ++i) { + Annotations.Add (new TypeAnnotation (constantPool, stream)); + } + } + + public override string ToString () + { + var annotations = string.Join (", ", Annotations.Select (v => v.ToString ())); + return $"RuntimeVisibleTypeAnnotations({annotations})"; + } + } + + // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.21 + public sealed class RuntimeInvisibleTypeAnnotationsAttribute : AttributeInfo + { + public IList Annotations { get; } = new List (); + + public RuntimeInvisibleTypeAnnotationsAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var count = stream.ReadNetworkUInt16 (); + + for (int i = 0; i < count; ++i) { + Annotations.Add (new TypeAnnotation (constantPool, stream)); + } + } + + public override string ToString () + { + var annotations = string.Join (", ", Annotations.Select (v => v.ToString ())); + return $"RuntimeInvisibleTypeAnnotations({annotations})"; + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.9 + public sealed class SignatureAttribute : AttributeInfo { + + ushort signatureIndex; + + public SignatureAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + Debug.Assert (length == 2); + signatureIndex = stream.ReadNetworkUInt16 (); + } + + public string Value { + get {return ((ConstantPoolUtf8Item) ConstantPool [signatureIndex]).Value;} + } + + public override string ToString () + { + return string.Format ("Signature({0})", Value); + } + } + + // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.10 + public sealed class SourceFileAttribute : AttributeInfo { + + ushort sourceFileIndex; + + public string FileName { + get {return ((ConstantPoolUtf8Item) ConstantPool [sourceFileIndex]).Value;} + } + + public SourceFileAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + sourceFileIndex = stream.ReadNetworkUInt16 (); + } + + public override string ToString () + { + return $"SourceFile('{FileName}')"; + } + } + + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4 + public sealed class StackMapTableAttribute : AttributeInfo { + + public byte[] Data; + + public StackMapTableAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var data = new byte[length]; + for (int i = 0; i < data.Length; ++i) + data [i] = stream.ReadNetworkByte (); + Data = data; + } + } + + public sealed class UnknownAttribute : AttributeInfo { + + public UnknownAttribute (ConstantPool constantPool, ushort nameIndex, Stream stream) + : base (constantPool, nameIndex, stream) + { + var length = stream.ReadNetworkUInt32 (); + var data = new byte[length]; + for (int i = 0; i < data.Length; ++i) + data [i] = stream.ReadNetworkByte (); + Data = data; + } + + public readonly byte[] Data; + + public override string ToString () + { + return string.Format ("Unknown[{0}]({1})", Name, Data.Length); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ClassFile.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ClassFile.cs new file mode 100644 index 00000000000..28e3bdfb15f --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ClassFile.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; + +namespace Xamarin.Android.Tools.Bytecode { + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1 + public sealed class ClassFile { + + public ushort MinorVersion; + public ushort MajorVersion; + public ConstantPool ConstantPool; + public ClassAccessFlags AccessFlags; + + ushort thisClass; + ushort superClass; + + public Interfaces Interfaces; + public Fields Fields; + public Methods Methods; + public AttributeCollection Attributes; + + // Set by KotlinFixups when this class is a Kotlin `@JvmInline value class`. + // The value is the JNI type descriptor of the single backing field + // (e.g. "J", "F", "I", "Ljava/lang/String;"). null otherwise. + // See dotnet/java-interop#1431 (Phase 2). + public string? KotlinInlineClassUnderlyingJniType { get; set; } + + ClassSignature? signature; + + + public ClassFile (Stream stream) + { + if (stream == null) + throw new ArgumentNullException ("stream"); + + uint magic; + if (!IsClassFile (stream, out magic)) + throw new BadImageFormatException ("Stream doesn't start with valid 0xCAFEBABE header! Found: 0x" + magic.ToString ("x")); + + MinorVersion = stream.ReadNetworkUInt16 (); + MajorVersion = stream.ReadNetworkUInt16 (); + ConstantPool = new ConstantPool (stream); + AccessFlags = (ClassAccessFlags)stream.ReadNetworkUInt16 (); + thisClass = stream.ReadNetworkUInt16 (); + superClass = stream.ReadNetworkUInt16 (); + Interfaces = new Interfaces (ConstantPool, stream); + Fields = new Fields (ConstantPool, this, stream); + Methods = new Methods (ConstantPool, this, stream); + Attributes = new AttributeCollection (ConstantPool, stream); + + int e = stream.ReadByte (); + if (e >= 0) { + var trailing = new System.Text.StringBuilder (); + trailing.AppendFormat ("{0:x2}", (byte) e); + while ((e = stream.ReadByte ()) >= 0) { + trailing.Append (" "); + trailing.AppendFormat ("{0:x2}", (byte) e); + } + throw new BadImageFormatException ($"Stream has trailing data?! {{{trailing}}}"); + } + } + + public static bool IsClassFile (Stream stream) + { + if (stream == null) + throw new ArgumentNullException ("stream"); + try { + var magic = stream.ReadNetworkUInt32 (); + if (magic != unchecked ((uint) 0xcafebabe)) + return false; + return true; + } catch (BadImageFormatException) { + return false; + } + } + + static bool IsClassFile (Stream stream, out uint magic) + { + if (stream == null) + throw new ArgumentNullException ("stream"); + try { + magic = stream.ReadNetworkUInt32 (); + if (magic != unchecked ((uint) 0xcafebabe)) + return false; + return true; + } catch (BadImageFormatException) { + magic = 0; + return false; + } + } + + public ConstantPoolClassItem ThisClass { + get {return (ConstantPoolClassItem) ConstantPool [thisClass];} + } + + public ConstantPoolClassItem SuperClass { + get {return (ConstantPoolClassItem) ConstantPool [superClass];} + } + + public string PackageName { + get { + var name = ThisClass.Name.Value; + var slash = name.LastIndexOf ('/'); + if (slash < 0) + return ""; + return name.Substring (0, slash).Replace ('/', '.'); + } + } + + public string FullJniName => "L" + ThisClass.Name.Value + ";"; + + // `package-info.class` is a synthetic class that carries + // package-level annotations (e.g. JSpecify's `@NullMarked`). + // Its simple name is `package-info`. + public bool IsPackageInfo { + get { + var name = ThisClass.Name.Value; + var slash = name.LastIndexOf ('/'); + var simple = slash < 0 ? name : name.Substring (slash + 1); + return simple == "package-info"; + } + } + + public string? SourceFileName { + get { + var sourceFile = Attributes.Get (); + return sourceFile == null ? null : sourceFile.FileName; + } + } + + public bool TryGetEnclosingMethodInfo ( + [NotNullWhen (true)] out string? declaringClass, + out string? declaringMethod, + out string? declaringDescriptor) + { + declaringClass = declaringMethod = declaringDescriptor = null; + + var enclosingMethod = Attributes.Get (); + if (enclosingMethod == null) { + return false; + } + + declaringClass = enclosingMethod.Class.Name.Value; + declaringMethod = enclosingMethod.Method?.Name.Value; + declaringDescriptor = enclosingMethod.Method?.Descriptor.Value; + return true; + } + + public ClassSignature? GetSignature () + { + if (this.signature != null) + return this.signature; + var sig = Attributes.Get (); + return sig != null + ? (this.signature = new ClassSignature (sig.Value)) + : null; + } + + public List GetInterfaces () + { + var interfaces = new List (Interfaces.Count); + for (int i = 0; i < Interfaces.Count; ++i) + interfaces.Add (new TypeInfo (Interfaces [i].Name.Value)); + + var sig = GetSignature (); + if (sig == null) + return interfaces; + + if (interfaces.Count != sig.SuperinterfaceSignatures.Count) + Console.Error.WriteLine ("class-parse: warning: Interfaces count ({0}) differs from Signature's Superinterfaces count ({1})!", + Interfaces.Count, sig.SuperinterfaceSignatures.Count); + int c = Math.Min (interfaces.Count, sig.SuperinterfaceSignatures.Count); + for (int i = 0; i < c; ++i) + interfaces [i].TypeSignature = sig.SuperinterfaceSignatures [i]; + + return interfaces; + } + + public IList InnerClasses { + get { + var inner = Attributes.Get (); + if (inner == null) + return new InnerClassInfo [0]; + return inner.Classes; + } + } + + public InnerClassInfo? InnerClass { + get { + return InnerClasses.SingleOrDefault (c => c.InnerClass == ThisClass); + } + } + + public ClassAccessFlags Visibility { + get { + var inner = InnerClass; + if (inner == null) + return AccessFlags; + return inner.InnerClassAccessFlags; + } + } + + public bool IsStatic { + get { + var inner = InnerClass; + if (inner == null) + return false; + return (inner.InnerClassAccessFlags & ClassAccessFlags.Static) != 0; + } + } + + public bool IsEnum { + get {return (AccessFlags & ClassAccessFlags.Enum) != 0;} + } + + public override string? ToString () => ThisClass?.Name.Value; + } + + [Flags] + public enum ClassAccessFlags { + Public = 0x0001, + + // Begin --only valid on inner types + Private = 0x0002, + Protected = 0x0004, + Static = 0x0008, + // End --only valid on inner types + + Final = 0x0010, + Super = 0x0020, + Interface = 0x0200, + Abstract = 0x0400, + Synthetic = 0x1000, + Annotation = 0x2000, + Enum = 0x4000, + Module = 0x8000, + + // This is not a real Java ClassAccessFlags, it is used to denote non-exported public types + Internal = 0x10000000, + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ClassPath.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ClassPath.cs new file mode 100644 index 00000000000..dda7ccb5f90 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ClassPath.cs @@ -0,0 +1,457 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode { + + public enum JavaDocletType { + DroidDoc, + DroidDoc2, + Java6, + Java7, + Java8, + _ApiXml, + JavaApiParameterNamesXml, + } + + public class ClassPath { + + IList classFiles = new List (); + + public string? ApiSource { get; set; } + + public IEnumerable? DocumentationPaths { get; set; } + + public string? AndroidFrameworkPlatform { get; set; } + + public bool AutoRename { get; set; } + + public ClassPath (string? path = null) + { + if (path == null || string.IsNullOrEmpty (path)) + return; + + Load (path); + } + + public void Load (string filePath) + { + if (IsJmodFile (filePath)) { + using (var source = File.OpenRead (filePath)) { + var slice = new PartialStream (source, 4); + Load (slice); + } + return; + } + if (IsJarFile (filePath)) { + using (var jarStream = File.OpenRead (filePath)) { + Load (jarStream); + } + return; + } + throw new ArgumentException ($"`{filePath}` is not a supported file format.", nameof (filePath)); + } + + public void Load (Stream jarStream, bool leaveOpen = false) + { + if (jarStream == null) + throw new ArgumentNullException (nameof (jarStream)); + + using (var jar = CreateZipArchive (jarStream, leaveOpen)) { + foreach (var entry in jar.Entries) { + if (!ShouldLoadEntry (entry)) + continue; + + using (var entry_stream = entry.Open ()) + using (var s = new BufferedStream (entry_stream)) { + try { + var c = new ClassFile (s); + Add (c); + } catch (Exception e) { + Log.Warning (0, "class-parse: warning: Could not load .jar entry '{0}': {1}", + entry.Name, e); + } + } + } + } + } + + static bool ShouldLoadEntry (ZipArchiveEntry entry) + { + if (entry.Length == 0) + return false; + + if (entry.Name.EndsWith (".jnilib", StringComparison.OrdinalIgnoreCase)) + return false; + + using var s = entry.Open (); + + return ClassFile.IsClassFile (s); + } + + static ZipArchive CreateZipArchive (Stream jarStream, bool leaveOpen) + { + var encoding = new UTF8Encoding (encoderShouldEmitUTF8Identifier: false); + + return new ZipArchive (jarStream, ZipArchiveMode.Read, leaveOpen: leaveOpen, entryNameEncoding: encoding); + } + + public void Add (ClassFile classFile) + { + classFiles.Add (classFile); + } + + public void Add (ClassPath classPath, bool removeModules = true) + { + classPath.FixupModuleVisibility (removeModules); + foreach (var c in classPath.classFiles) { + Add (c); + } + } + + public ReadOnlyDictionary> GetPackages () + { + return new ReadOnlyDictionary> (classFiles + .Select (x => x.PackageName) + .Distinct () + .ToDictionary (x => x, + x => classFiles.Where (p => p.PackageName == x).ToList ())); + } + + // Returns the `package-info.class` for the given package, if any. + public ClassFile? GetPackageInfo (string packageName) + { + foreach (var c in classFiles) { + if (c.IsPackageInfo && c.PackageName == packageName) + return c; + } + return null; + } + + public static bool IsJarFile (string jarFile) + { + if (jarFile == null) + throw new ArgumentNullException ("jarFile"); + try { + using (var f = File.OpenRead (jarFile)) + using (new ZipArchive (f)) { + return true; + } + } + catch (Exception) { + return false; + } + } + + public static bool IsJmodFile (string jmodFile) + { + if (jmodFile == null) + throw new ArgumentNullException (nameof (jmodFile)); + try { + using var f = File.OpenRead (jmodFile); + var h = new byte[4]; + if (f.Read (h, 0, h.Length) != 4) { + return false; + } + return h[0] == 0x4a && h[1] == 0x4d && h[2] == 0x01 && h[3] == 0x00; + } + catch (Exception) { + return false; + } + } + + XAttribute? GetApiSource () + { + if (string.IsNullOrEmpty (ApiSource)) + return null; + return new XAttribute ("api-source", ApiSource); + } + + XAttribute? GetPlatform () + { + if (string.IsNullOrEmpty (AndroidFrameworkPlatform)) + return null; + return new XAttribute ("platform", AndroidFrameworkPlatform); + } + + bool IsGeneratedName (string parameterName) + { + return parameterName.StartsWith ("p", StringComparison.Ordinal) && parameterName.Length > 1 && Char.IsDigit (parameterName [1]); + } + + IEnumerable GetDescendants (ClassFile theClass, IList classFiles) + { + for (var c = classFiles.FirstOrDefault(x => IsDescendedFrom (x, theClass.ThisClass)); + c != null; + c = classFiles.FirstOrDefault(x => IsDescendedFrom (x, c.ThisClass))) + yield return c; + } + + IEnumerable GetInterfaceImplemetations (ClassFile iface, IList classFiles) + { + return classFiles.Where (x => ImplementsInterface(x, iface)); + } + + public bool IsDescendedFrom (ClassFile classToCheck, ConstantPoolClassItem baseClass) + { + if (classToCheck.SuperClass == null && baseClass == null) + return true; + if (classToCheck.SuperClass == null || baseClass == null) + return false; + return classToCheck.SuperClass.Name.Value == baseClass.Name.Value; + } + + public bool ImplementsInterface (ClassFile classToCheck, ClassFile targetInteface) + { + return classToCheck.GetInterfaces ().Any (iface => targetInteface.ThisClass.Name.Value == iface.BinaryName); + } + + void FixUpParameters (ClassFile toUpdate, List implementations) + { + foreach (var method in toUpdate.Methods) { + var targetParams = method.GetParameters (); + if (targetParams.All (p => !IsGeneratedName (p.Name))) + continue; + var candidates = + (from candidateMethod in implementations.SelectMany (x => x.Methods) + where candidateMethod.Name == method.Name + where candidateMethod.Descriptor == method.Descriptor + let candidateParams = candidateMethod.GetParameters () + where candidateParams.Length == targetParams.Length + where candidateParams.All (p => !IsGeneratedName (p.Name)) + select candidateParams); + if (!candidates.Any ()) + continue; + + var parameters = new List [targetParams.Length]; + foreach (var candidate in candidates) { + for (int i = 0; i < candidate.Length; i++) { + if (parameters [i] == null) + parameters [i] = new List (); + parameters [i].Add (candidate [i]); + } + } + + for (int i = 0; i < parameters.Length; i++) { + var r = parameters [i].GroupBy (x => x.Name) + .Select (group => new { + Name = group.Key, + Count = group.Count () + }) + .OrderByDescending (x => x.Count) + .FirstOrDefault (); + if (r != null) + targetParams [i].Name = r.Name; + } + } + } + + void FixUpParametersFromClasses () + { + // Fix up the Parameters on all the abstract classes + // and interfaces. We do the abstact classes first because + // many interfaces are implemented in abstract classes. This + // is the easiest way to ensure that the parameter name changes + // percolate up. + foreach (var abstractClass in classFiles.Where(c => + (c.AccessFlags & ClassAccessFlags.Abstract) != 0 && + (c.AccessFlags & ClassAccessFlags.Interface) == 0)) { + + List implementations = GetDescendants (abstractClass, classFiles) + .ToList(); + if (!implementations.Any ()) + continue; + FixUpParameters (abstractClass, implementations); + } + foreach (var iface in classFiles.Where(c => + (c.AccessFlags & ClassAccessFlags.Abstract) != 0 && + (c.AccessFlags & ClassAccessFlags.Interface) != 0)) { + List implementations = GetInterfaceImplemetations (iface, classFiles) + .ToList(); + if (!implementations.Any ()) + continue; + for (int i=0; i < implementations.Count; i++) { + implementations.AddRange ( GetDescendants (implementations [i], classFiles) + .Where (x => !implementations.Contains(x))); + } + FixUpParameters (iface, implementations); + } + } + + void FixupParametersFromDocs (XElement api) + { + if (DocumentationPaths == null) + return; + foreach (var path in DocumentationPaths) { + if (!Directory.Exists (path) && !File.Exists (path)) + continue; + FixupParametersFromDocs (api, path); + } + } + + IJavaMethodParameterNameProvider CreateDocScraper (string src) + { + switch (JavaMethodParameterNameProvider.GetDocletType (src)) { + default: return new DroidDoc2Scraper (src); + case JavaDocletType.DroidDoc: return new DroidDocScraper (src); + case JavaDocletType.Java6: return new JavaDocScraper (src); + case JavaDocletType.Java7: return new Java7DocScraper (src); + case JavaDocletType.Java8: return new Java8DocScraper (src); + case JavaDocletType._ApiXml: return new ApiXmlDocScraper (src); + case JavaDocletType.JavaApiParameterNamesXml: return new JavaParameterNamesLoader (src); + } + } + + void FixupParametersFromDocs (XElement api, string path) + { + var jdoc = CreateDocScraper (path); + var elements = api.XPathSelectElements ("./package/class[@visibility = 'public' or @visibility = 'protected']").ToList (); + elements.AddRange (api.XPathSelectElements ("./package/interface[@visibility = 'public' or @visibility = 'protected']")); + foreach (var elem in elements) { + var currentpackage = elem.Parent?.Attribute ("name")?.Value ?? ""; + var className = elem.Attribute ("name")?.Value; + + if (className == null) + continue; + + var methodsAndConstructors = elem.XPathSelectElements ("./method[@visibility = 'public' or @visibility = 'protected']").ToList (); + methodsAndConstructors.AddRange (elem.XPathSelectElements ("./constructor[@visibility = 'public' or @visibility = 'protected']")); + + foreach (var method in methodsAndConstructors) { + var currentMethod = method.Attribute ("name")?.Value; + if (currentMethod == null) + continue; + + var parameterElements = method.Elements ("parameter").ToList (); + if (!parameterElements.Select (x => x.Attribute ("name")?.Value).Any (p => p != null && IsGeneratedName (p))) + continue; + + var parameterTypes = parameterElements + .Select (p => new JavaMethodParameterTypeInfo ( + jniType: (string?) p.Attribute ("jni-type") ?? "", + javaType: (string?) p.Attribute ("type") ?? "")) + .ToArray (); + + if (!parameterTypes.Any ()) + continue; + + var nameInfo = new JavaMethodParameterNameInfo ( + currentpackage, + className, + currentMethod, + (string?) method.Attribute ("jni-signature"), + parameterTypes, + isVarArgs: false + ); + + var pnames = jdoc.GetParameterNames (nameInfo); + if (pnames == null || pnames.Length != parameterElements.Count) + continue; + for (int i = 0; i < parameterElements.Count; i++) { + var a = parameterElements [i].Attribute ("name"); + if (a == null) + continue; + a.Value = pnames [i]; + } + } + } + } + + public XElement ToXElement () + { + // In general, don't do this. It brings metadata fixup incompatibility. + // API XML incompatibility makes adoption of class-parse impossible and + // goes against the entire purpose of class-parse existence. + // Bringing metadata fixup incompatibility means more API difference bugs. + // This optional behavior is to bring compatibility with old behavior. + if (AutoRename) + FixUpParametersFromClasses (); + + KotlinFixups.Fixup (classFiles); + FixupModuleVisibility (removeModules: true); + + var packagesDictionary = GetPackages (); + var packageInfos = packagesDictionary.ToDictionary ( + kv => kv.Key, + kv => kv.Value.FirstOrDefault (c => c.IsPackageInfo)); + var api = new XElement ("api", + GetApiSource (), + GetPlatform (), + packagesDictionary.Keys.OrderBy (p => p, StringComparer.OrdinalIgnoreCase) + .Select (p => new XElement ("package", + new XAttribute ("name", p), + new XAttribute ("jni-name", p.Replace ('.', '/')), + packagesDictionary [p].Where (c => !c.IsPackageInfo) + .OrderBy (c => c.ThisClass.Name.Value, StringComparer.OrdinalIgnoreCase) + .Select (c => new XmlClassDeclarationBuilder (c, packageInfos [p]).ToXElement ())))); + FixupParametersFromDocs (api); + return api; + } + + public void FixupModuleVisibility (bool removeModules) + { + var publicPackages = new HashSet (); + + var moduleFiles = classFiles.Where (c => c.AccessFlags == ClassAccessFlags.Module) + .ToList (); + if (moduleFiles.Count == 0) { + return; + } + foreach (var moduleFile in moduleFiles) { + if (removeModules) { + classFiles.Remove (moduleFile); + } + foreach (var moduleAttr in moduleFile.Attributes.OfType ()) { + foreach (var export in moduleAttr.Exports) { + publicPackages.Add (export.Exports); + } + } + } + + foreach (var c in classFiles) { + if (!c.AccessFlags.HasFlag (ClassAccessFlags.Public)) { + continue; + } + var jniName = c.ThisClass.Name.Value; + var packageEnd = jniName.LastIndexOf ('/'); + if (packageEnd < 0) { + continue; + } + var package = jniName.Substring (0, packageEnd); + if (!publicPackages.Contains (package)) { + c.AccessFlags = KotlinFixups.SetVisibility (c.AccessFlags, ClassAccessFlags.Internal); + } + } + } + + public void SaveXmlDescription (string fileName) + { + var encoding = new UTF8Encoding (encoderShouldEmitUTF8Identifier: false); + using (var output = new StreamWriter (fileName, append:false, encoding:encoding)) { + SaveXmlDescription (output); + } + } + + public void SaveXmlDescription (TextWriter textWriter) + { + var settings = new XmlWriterSettings () { + Indent = true, + OmitXmlDeclaration = true, + NewLineOnAttributes = true, + }; + var contents = ToXElement (); + using (var writer = XmlWriter.Create (textWriter, settings)) + contents.Save (writer); + textWriter.WriteLine (); + } + + public IEnumerable GetClassFiles () => classFiles; + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ConstantPool.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ConstantPool.cs new file mode 100644 index 00000000000..946898ec752 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/ConstantPool.cs @@ -0,0 +1,559 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode { + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 + public class ConstantPool : Collection { + + public ConstantPool (Stream stream) + { + if (stream == null) + throw new ArgumentNullException ("stream"); + + // indexes are one-based; + // "The constant_pool table is indexed from 1 to constant_pool_count-1." + Add (null!); + int constant_pool_count = stream.ReadNetworkUInt16 (); + for (int i = 1; i < constant_pool_count; ++i) { + var entry = ConstantPoolItem.CreateFromStream (this, stream); + Add (entry); + if (entry.EntryRequiresTwoSlots) { + ++i; + Add (entry); + } + } + } + } + + public enum ConstantPoolItemType { + Utf8 = 1, + Integer = 3, + Float = 4, + Long = 5, + Double = 6, + Class = 7, + String = 8, + Fieldref = 9, + Methodref = 10, + InterfaceMethodref = 11, + NameAndType = 12, + MethodHandle = 15, + MethodType = 16, + Dynamic = 17, + InvokeDynamic = 18, + Module = 19, + Package = 20, + } + + public abstract class ConstantPoolItem { + + public abstract ConstantPoolItemType Type {get;} + + internal virtual bool EntryRequiresTwoSlots { + get {return false;} + } + + public ConstantPool ConstantPool {get; private set;} + + public ConstantPoolItem (ConstantPool constantPool, Stream stream) + { + if (constantPool == null) + throw new ArgumentNullException ("constantPool"); + if (stream == null) + throw new ArgumentNullException ("stream"); + + ConstantPool = constantPool; + } + + public static ConstantPoolItem CreateFromStream (ConstantPool constantPool, Stream stream) + { + var type = (ConstantPoolItemType) stream.ReadNetworkByte (); + switch (type) { + case ConstantPoolItemType.Utf8: return new ConstantPoolUtf8Item (constantPool, stream); + case ConstantPoolItemType.Integer: return new ConstantPoolIntegerItem (constantPool, stream); + case ConstantPoolItemType.Float: return new ConstantPoolFloatItem (constantPool, stream); + case ConstantPoolItemType.Long: return new ConstantPoolLongItem (constantPool, stream); + case ConstantPoolItemType.Double: return new ConstantPoolDoubleItem (constantPool, stream); + case ConstantPoolItemType.Class: return new ConstantPoolClassItem (constantPool, stream); + case ConstantPoolItemType.String: return new ConstantPoolStringItem (constantPool, stream); + case ConstantPoolItemType.Fieldref: return new ConstantPoolFieldrefItem (constantPool, stream); + case ConstantPoolItemType.Methodref: return new ConstantPoolMethodrefItem (constantPool, stream); + case ConstantPoolItemType.InterfaceMethodref: return new ConstantPoolInterfaceMethodrefItem (constantPool, stream); + case ConstantPoolItemType.NameAndType: return new ConstantPoolNameAndTypeItem (constantPool, stream); + case ConstantPoolItemType.MethodHandle: return new ConstantPoolMethodHandleItem (constantPool, stream); + case ConstantPoolItemType.MethodType: return new ConstantPoolMethodTypeItem (constantPool, stream); + case ConstantPoolItemType.Dynamic: return new ConstantPoolDynamicItem (constantPool, stream); + case ConstantPoolItemType.InvokeDynamic: return new ConstantPoolInvokeDynamicItem (constantPool, stream); + case ConstantPoolItemType.Module: return new ConstantPoolModuleItem (constantPool, stream); + case ConstantPoolItemType.Package: return new ConstantPoolPackageItem (constantPool, stream); + default: + throw new NotSupportedException (string.Format ("Unknown constant type 0x{0}.", type.ToString ("x"))); + } + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.1 + public sealed class ConstantPoolClassItem : ConstantPoolItem { + + ushort nameIndex; + + public ConstantPoolClassItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + nameIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Class;} + } + + public ConstantPoolUtf8Item Name { + get {return ((ConstantPoolUtf8Item) ConstantPool [nameIndex]);} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Class(nameIndex={0} Name=\"{1}\")", nameIndex, Name.Value); + } + } + + public abstract class ConstantPoolMemberrefItem : ConstantPoolItem { + + internal ushort classIndex; + internal ushort nameAndTypeIndex; + + public ConstantPoolMemberrefItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + classIndex = stream.ReadNetworkUInt16 (); + nameAndTypeIndex = stream.ReadNetworkUInt16 (); + } + + public ConstantPoolClassItem Class { + get {return (ConstantPoolClassItem) ConstantPool [classIndex];} + } + + public ConstantPoolNameAndTypeItem NameAndType { + get {return (ConstantPoolNameAndTypeItem) ConstantPool [nameAndTypeIndex];} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "{0}(classIndex={1} nameAndTypeIndex={2} Class='{3}' Name='{4}' Descriptor='{5}')", + Type, classIndex, nameAndTypeIndex, Class.Name, NameAndType.Name.Value, NameAndType.Descriptor.Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.2 + public sealed class ConstantPoolFieldrefItem : ConstantPoolMemberrefItem { + + public ConstantPoolFieldrefItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Fieldref;} + } + } + + public sealed class ConstantPoolMethodrefItem : ConstantPoolMemberrefItem { + + public ConstantPoolMethodrefItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Methodref;} + } + } + + public sealed class ConstantPoolInterfaceMethodrefItem : ConstantPoolMemberrefItem { + + public ConstantPoolInterfaceMethodrefItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.InterfaceMethodref;} + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.3 + public sealed class ConstantPoolStringItem : ConstantPoolItem { + + ushort stringIndex; + + public ConstantPoolStringItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + stringIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.String;} + } + + public ConstantPoolUtf8Item StringData { + get {return (ConstantPoolUtf8Item) ConstantPool [stringIndex];} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "String(stringIndex={0} Utf8=\"{1}\")", + stringIndex, StringData.Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.4 + public sealed class ConstantPoolIntegerItem : ConstantPoolItem { + + int value; + + public ConstantPoolIntegerItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + value = (int) stream.ReadNetworkUInt32 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Integer;} + } + + public int Value { + get {return value;} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Integer({0})", Value); + } + } + + public sealed class ConstantPoolFloatItem : ConstantPoolItem { + + float value; + + public ConstantPoolFloatItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + var data = new byte[]{ + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + }; + if (BitConverter.IsLittleEndian) + Array.Reverse (data); + value = BitConverter.ToSingle (data, 0); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Float;} + } + + public float Value { + get {return value;} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Float({0:G9})", Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.5 + public sealed class ConstantPoolLongItem : ConstantPoolItem { + + long value; + + public ConstantPoolLongItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + value = stream.ReadNetworkInt64 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Long;} + } + + internal override bool EntryRequiresTwoSlots { + get {return true;} + } + + public long Value { + get {return value;} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Long({0})", Value); + } + } + + public sealed class ConstantPoolDoubleItem : ConstantPoolItem { + + double value; + + public ConstantPoolDoubleItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + var data = new byte[]{ + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + stream.ReadNetworkByte (), + }; + if (BitConverter.IsLittleEndian) + Array.Reverse (data); + value = BitConverter.ToDouble (data, 0); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Double;} + } + + internal override bool EntryRequiresTwoSlots { + get {return true;} + } + + public double Value { + get {return value;} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Double({0:G17})", Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.6 + public sealed class ConstantPoolNameAndTypeItem : ConstantPoolItem { + + ushort nameIndex; + ushort descriptorIndex; + + public ConstantPoolNameAndTypeItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + nameIndex = stream.ReadNetworkUInt16 (); + descriptorIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.NameAndType;} + } + + public ConstantPoolUtf8Item Name { + get {return (ConstantPoolUtf8Item) ConstantPool [nameIndex];} + } + + public ConstantPoolUtf8Item Descriptor { + get {return (ConstantPoolUtf8Item) ConstantPool [descriptorIndex];} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "NameAndType(nameIndex={0} descriptorIndex={1} Name=\"{2}\" Descriptor=\"{3}\")", + nameIndex, descriptorIndex, Name.Value, Descriptor.Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.7 + public sealed class ConstantPoolUtf8Item : ConstantPoolItem { + + string value; + + public ConstantPoolUtf8Item (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + var length = stream.ReadNetworkUInt16 (); + var data = new byte [length]; + for (int i = 0; i < data.Length; ++i) + data [i] = stream.ReadNetworkByte (); + + // The .class file specially encodes NUL so that it takes 2 bytes, not 1. + // http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 + var fixup = new List (data.Length); + for (int i = 0; i < data.Length; ++i) { + if (data [i] == 0xc0 && (i + 1) < data.Length && data [i + 1] == 0x80) { + fixup.Add (0x00); + i++; + continue; + } + // ...and they couldn't be bothered with supporting 4-byte UTF-8 sequences, + // needed for Emoji and chars off the Basic Multilingual Plane; instead, they're + // encoded as a surrogate pair. (What is this I don't even...) + if (data [i] == 0xed && i+6 < data.Length && data [i+3] == 0xed) { + var surrogatePair = new char [] { + (char) (0xD800 + (((data [i+1] & 0x0F) << 6) | (data [i+2] & 0x3F))), + (char) (0xDC00 + (((data [i+4] & 0x0F) << 6) | (data [i+5] & 0x3F))), + }; + fixup.AddRange (Encoding.UTF8.GetBytes (surrogatePair)); + i += 5; + continue; + + } + fixup.Add (data [i]); + } + value = Encoding.UTF8.GetString (fixup.Count == data.Length ? data : fixup.ToArray ()); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.Utf8;} + } + + public string Value { + get {return value;} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Utf8(\"{0}\")", Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.8 + public sealed class ConstantPoolMethodHandleItem : ConstantPoolItem { + + byte referenceKind; + ushort referenceIndex; + + public ConstantPoolMethodHandleItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + referenceKind = stream.ReadNetworkByte (); + referenceIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.MethodHandle;} + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.9 + public sealed class ConstantPoolMethodTypeItem : ConstantPoolItem { + + ushort descriptorIndex; + + public ConstantPoolMethodTypeItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + descriptorIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.MethodType;} + } + + public ConstantPoolUtf8Item Descriptor { + get {return (ConstantPoolUtf8Item) ConstantPool [descriptorIndex];} + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "MethodType(descriptorIndex={0} Descriptor=\"{1}\")", + descriptorIndex, Descriptor.Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.4.9 + public sealed class ConstantPoolDynamicItem : ConstantPoolItem + { + ushort boostrapMethodAttrIndex; + ushort nameAndTypeIndex; + + public ConstantPoolDynamicItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + boostrapMethodAttrIndex = stream.ReadNetworkUInt16 (); + nameAndTypeIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get { return ConstantPoolItemType.InvokeDynamic; } + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.10 + public sealed class ConstantPoolInvokeDynamicItem : ConstantPoolItem { + + ushort boostrapMethodAttrIndex; + ushort nameAndTypeIndex; + + public ConstantPoolInvokeDynamicItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + boostrapMethodAttrIndex = stream.ReadNetworkUInt16 (); + nameAndTypeIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get {return ConstantPoolItemType.InvokeDynamic;} + } + } + + // http://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.4.11 + public sealed class ConstantPoolModuleItem : ConstantPoolItem + { + ushort nameIndex; + + public ConstantPoolModuleItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + nameIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get { return ConstantPoolItemType.Module; } + } + + public ConstantPoolUtf8Item Name { + get { return (ConstantPoolUtf8Item) ConstantPool [nameIndex]; } + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Module(nameIndex={0} Name=\"{1}\")", + nameIndex, Name.Value); + } + } + + // http://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.4.12 + public sealed class ConstantPoolPackageItem : ConstantPoolItem + { + ushort nameIndex; + + public ConstantPoolPackageItem (ConstantPool constantPool, Stream stream) + : base (constantPool, stream) + { + nameIndex = stream.ReadNetworkUInt16 (); + } + + public override ConstantPoolItemType Type { + get { return ConstantPoolItemType.Module; } + } + + public ConstantPoolUtf8Item Name { + get { return (ConstantPoolUtf8Item) ConstantPool [nameIndex]; } + } + + public override string ToString () + { + return string.Format (CultureInfo.InvariantCulture, "Package(nameIndex={0} Name=\"{1}\")", + nameIndex, Name.Value); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Fields.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Fields.cs new file mode 100644 index 00000000000..0a0ddfd27b1 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Fields.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; + +namespace Xamarin.Android.Tools.Bytecode { + + public sealed class Fields : Collection { + + public ConstantPool ConstantPool {get; private set;} + + public Fields (ConstantPool constantPool, ClassFile declaringClass, Stream stream) + { + if (constantPool == null) + throw new ArgumentNullException ("constantPool"); + if (stream == null) + throw new ArgumentNullException ("stream"); + + ConstantPool = constantPool; + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + Add (new FieldInfo (constantPool, declaringClass, stream)); + } + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.5 + public sealed class FieldInfo { + ushort nameIndex; + ushort descriptorIndex; + + public ConstantPool ConstantPool {get; private set;} + public ClassFile DeclaringType {get; private set;} + public FieldAccessFlags AccessFlags {get; set;} + public AttributeCollection Attributes {get; private set;} + public string? KotlinType {get; set;} + + public FieldInfo (ConstantPool constantPool, ClassFile declaringType, Stream stream) + { + ConstantPool = constantPool; + DeclaringType = declaringType; + AccessFlags = (FieldAccessFlags) stream.ReadNetworkUInt16 (); + nameIndex = stream.ReadNetworkUInt16 (); + descriptorIndex = stream.ReadNetworkUInt16 (); + Attributes = new AttributeCollection (constantPool, stream); + } + + public string Name { + get { + return ((ConstantPoolUtf8Item) ConstantPool [nameIndex]).Value; + } + } + + public string Descriptor { + get { + return ((ConstantPoolUtf8Item) ConstantPool [descriptorIndex]).Value; + } + } + + public string? GetSignature () + { + var signature = Attributes.Get (); + return signature != null ? signature.Value : null; + } + + public bool IsPubliclyVisible => AccessFlags.HasFlag (FieldAccessFlags.Public) || AccessFlags.HasFlag (FieldAccessFlags.Protected); + } + + [Flags] + public enum FieldAccessFlags { + Public = 0x0001, + Private = 0x0002, + Protected = 0x0004, + Static = 0x0008, + Final = 0x0010, + Volatile = 0x0040, + Transient = 0x0080, + Synthetic = 0x1000, + Enum = 0x4000, + + // This is not a real Java FieldAccessFlags, it is used to denote Kotlin "internal" access. + Internal = 0x10000000, + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Interfaces.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Interfaces.cs new file mode 100644 index 00000000000..45eb30e9f93 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Interfaces.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; + +namespace Xamarin.Android.Tools.Bytecode { + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1 + public sealed class Interfaces : Collection { + + public ConstantPool ConstantPool {get; private set;} + + public Interfaces (ConstantPool constantPool, Stream stream) + { + if (constantPool == null) + throw new ArgumentNullException ("constantPool"); + if (stream == null) + throw new ArgumentNullException ("stream"); + + ConstantPool = constantPool; + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + var iface = stream.ReadNetworkUInt16 (); + Add ((ConstantPoolClassItem) constantPool [iface]); + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs new file mode 100644 index 00000000000..2ac11584e8b --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2011 Xamarin Inc. + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using System.Xml.XPath; +using System.Text.RegularExpressions; + +namespace Xamarin.Android.Tools.Bytecode +{ + class DroidDocScraper : AndroidDocScraper + { + const String pattern_head_droiddoc = ".*.*") + { + ShouldEscapeBrackets = true; + } + + string? prev_path; + string[]? prev_contents; + + protected override IEnumerable GetContentLines (string path) + { + if (prev_path == path) + return prev_contents!; + else { + prev_path = path; + string all = File.ReadAllText (path).Replace ('\r', ' ').Replace ('\n', ' '); + int start = all.IndexOf ("", StringComparison.Ordinal); + all = start < 0 ? all : all.Substring (start); + int end = all.IndexOf ("", StringComparison.Ordinal); + all = end < 0 ? all : all.Substring (0, end); + // ... is the basic structure so is used as the end of member, but we also use

here. + // Sometimes another can appear after "" (for the end of context member) and that messes regex match. + // So, with any

, we interrupt consecutive matches. + prev_contents = all.Split (new string [] { "

", "" }, StringSplitOptions.RemoveEmptyEntries); + return prev_contents; + } + } + + protected override bool ShouldResetMatchBuffer (string text) + { + return true; + } + } + + class JavaDocScraper : AndroidDocScraper + { + const String pattern_head_javadoc = " tags, so remove all of them. + while (value.IndexOf ("<", StringComparison.Ordinal) >= 0 && + value.IndexOf (">", StringComparison.Ordinal) > value.IndexOf ("<", StringComparison.Ordinal)) + value = value.Substring (0, value.IndexOf ("<", StringComparison.Ordinal)) + + value.Substring (value.IndexOf (">", StringComparison.Ordinal) + 1); + return value; + } + } + + public abstract class AndroidDocScraper : IJavaMethodParameterNameProvider + { + readonly String pattern_head; + readonly String? reset_pattern_head; + readonly string [] parameter_pair_splitter; + readonly bool continuous_param_lines; + readonly String open_method; + readonly String param_sep; + readonly String close_method; + readonly String? post_close_method_parens; + string root; + + protected AndroidDocScraper (string dir, String patternHead, String? resetPatternHead, String parameterPairSplitter, bool continuousParamLines) + : this (dir, patternHead, resetPatternHead, parameterPairSplitter, continuousParamLines, "\\(", ", ", "\\)", null) + { + } + + protected AndroidDocScraper (string dir, String patternHead, String? resetPatternHead, String parameterPairSplitter, bool continuousParamLines, string openMethod, string paramSep, string closeMethod, string? postCloseMethodParens) + { + if (dir == null) + throw new ArgumentNullException ("dir"); + + pattern_head = patternHead; + reset_pattern_head = resetPatternHead; + parameter_pair_splitter = new string [] { (parameterPairSplitter != null ? parameterPairSplitter : "\\s+") }; + continuous_param_lines = continuousParamLines; + open_method = openMethod; + param_sep = paramSep; + close_method = closeMethod; + post_close_method_parens = postCloseMethodParens ?? string.Empty; + if (!Directory.Exists (dir)) + throw new Exception ("Directory '" + dir + "' does not exist"); + + root = dir; + + if (!File.Exists (Path.Combine (dir, "package-list")) && !File.Exists (Path.Combine (dir, "packages.html"))) + throw new ArgumentException ("Directory '" + dir + "' does not appear to be an android doc reference directory."); + + //foreach (var f in Directory.GetFiles (dir, "*.html", SearchOption.AllDirectories)) + // LoadDocument (f.Substring (dir.Length + 1), f); + } + + protected bool ShouldEscapeBrackets { get; set; } + protected bool ShouldAlterArraySpec { get; set; } + protected bool ShouldEliminateGenericArguments { get; set; } + + protected virtual IEnumerable GetContentLines (string path) + { + return File.ReadAllText (path).Split ('\n'); + } + + protected virtual bool ShouldResetMatchBuffer (string text) + { + // sometimes we get incomplete tag, so cache it until it gets complete or matched. + // I *know* this is a hack. + return reset_pattern_head == null || text.EndsWith (">", StringComparison.Ordinal) || !continuous_param_lines && !text.StartsWith (reset_pattern_head, StringComparison.Ordinal); + } + + protected virtual string StripTagsFromParameters (string value) + { + return value; + } + + public virtual string[]? GetParameterNames (JavaMethodParameterNameInfo info) + { + var package = info.PackageName; + var type = info.TypeName; + var method = info.MethodName; + var ptypes = info.ParameterTypes.Select (p => p.JavaType).ToArray (); + + string path = package.Replace ('.', '/') + '/' + type.Replace ('$', '.') + ".html"; + string file = Path.Combine (root, path); + if (!File.Exists (file)) { + Log.Warning (1,"Warning: no document found : " + file); + return null; + } + + var buffer = new StringBuilder (); + buffer.Append (pattern_head); + buffer.Append (path); + buffer.Append ("#"); + buffer.Append (method); + buffer.Append (open_method); + for (int i = 0; i < ptypes.Length; i++) { + if (i != 0) + buffer.Append (param_sep); + var ptype = ptypes [i]; + if (ShouldEliminateGenericArguments) + while (ptype.IndexOf ("<", StringComparison.Ordinal) > 0 && + ptype.IndexOf (">", StringComparison.Ordinal) > ptype.IndexOf ("<", StringComparison.Ordinal)) + ptype = ptype.Substring (0, ptype.IndexOf ("<", StringComparison.Ordinal)) + + ptype.Substring (ptype.IndexOf (">", StringComparison.Ordinal) + 1); + buffer.Append (ptype.Replace ('$', '.')); + } + if (ShouldEscapeBrackets) + buffer.Replace ("[", "\\[").Replace ("]", "\\]"); + if (ShouldAlterArraySpec) + buffer.Replace ("[]", ":A"); + buffer.Append (close_method); + buffer.Append ("\".*\\(([^\\(\\)]*)\\)"); + buffer.Append (post_close_method_parens); + buffer.Replace ("?", "\\?"); + Regex pattern = new Regex (buffer.ToString (), RegexOptions.Multiline); + + try { + String text = ""; + String? prev = null; + foreach (var _text in GetContentLines (file)) { + text = _text.TrimEnd ('\r'); + if (prev != null) + prev = text = prev + text; + var matcher = pattern.Match (text); + if (matcher.Success) { + var plist = matcher.Groups [1]; + String[] parms = StripTagsFromParameters (plist.Value).Split (new string [] { ", " }, StringSplitOptions.RemoveEmptyEntries); + if (parms.Length != ptypes.Length) { + Log.Warning (1, "failed matching {0} (expected {1} params, got {2} params)", buffer, ptypes.Length, parms.Length); + return null; + } + String[] result = new String [ptypes.Length]; + for (int i = 0; i < ptypes.Length; i++) { + String[] toks = parms [i].Split (parameter_pair_splitter, StringSplitOptions.RemoveEmptyEntries); + result [i] = toks [toks.Length - 1]; + } + return result; + } + if (ShouldResetMatchBuffer (text)) + prev = null; + else + prev = text; + } + } catch (Exception e) { + Log.Error ("ERROR in {0}.{1}: {2}", type, method, e); + return null; + } + + Log.Warning (1, "Warning : no match for {0}.{1} (rex: {2})", type, method, buffer); + return null; + } + + static Dictionary>? deprecatedFields; + static Dictionary>? deprecatedMethods; + + public static void LoadXml (String filename) + { + try { + var doc = XDocument.Load (filename); + if (doc.Root == null) + return; + deprecatedFields = new Dictionary> (); + deprecatedMethods = new Dictionary> (); + var files = doc.Root.Descendants ("file"); + foreach (var file in files) { + var f = new List (); + var k = file.Attribute ("name")?.Value; + if (k == null) + continue; + deprecatedFields [k] = f; + var fields = file.Descendants ("field"); + foreach (var fld in fields) + f.Add (fld.Value); + + var m = new List (); + deprecatedMethods [k] = m; + var methods = file.Descendants ("method"); + foreach (var meh in methods) + m.Add (meh.Value); + } + + } catch (Exception ex) { + Log.Error ("Annotations parser error: " + ex); + } + } + } + + public readonly struct JavaMethodParameterTypeInfo { + public string JniType {get;} + public string JavaType {get;} + + public JavaMethodParameterTypeInfo (string jniType, string javaType) + { + JniType = jniType; + JavaType = javaType; + } + } + + public readonly struct JavaMethodParameterNameInfo { + public string PackageName {get;} + public string TypeName {get;} + public string MethodName {get;} + public string? MethodSignature {get;} + public bool IsVarArgs {get;} + public JavaMethodParameterTypeInfo[] ParameterTypes {get;} + + public JavaMethodParameterNameInfo (string packageName, string typeName, string methodName, string? methodSignature, JavaMethodParameterTypeInfo[] parameterTypes, bool isVarArgs) + { + PackageName = packageName; + TypeName = typeName; + MethodName = methodName; + MethodSignature = methodSignature; + ParameterTypes = parameterTypes; + IsVarArgs = isVarArgs; + } + } + + public interface IJavaMethodParameterNameProvider + { + string[]? GetParameterNames (JavaMethodParameterNameInfo info); + } + + public static class JavaMethodParameterNameProvider { + + public static JavaDocletType GetDocletType (string path) + { + var kind = JavaDocletType.DroidDoc; + char[] buf = new char[500]; + + string packagesHtml = Path.Combine (path, "packages.html"); + if (File.Exists (packagesHtml) && + File.ReadAllText (packagesHtml).IndexOf ("= 0) + kind = JavaDocletType.DroidDoc2; + + string indexHtml = Path.Combine (path, "index.html"); + if (File.Exists (indexHtml)) { + using (var reader = File.OpenText (indexHtml)) + reader.ReadBlock (buf, 0, buf.Length); + string rawHTML = new string (buf); + if (rawHTML.IndexOf ("Generated by javadoc (build 1.6", StringComparison.Ordinal) >= 0) + kind = JavaDocletType.Java6; + else if (rawHTML.IndexOf ("Generated by javadoc (version 1.7", StringComparison.Ordinal) >= 0) + kind = JavaDocletType.Java7; + else if (rawHTML.IndexOf ("Generated by javadoc (1.8", StringComparison.Ordinal) >= 0) + kind = JavaDocletType.Java8; + } + + // Check to see if it's an api.xml formatted doc + if (File.Exists (path)) { + string rawXML; + using (var reader = File.OpenText (path)) { + int len = reader.ReadBlock (buf, 0, buf.Length); + rawXML = new string (buf, 0, len).Trim (); + } + if (rawXML.IndexOf ("= 0 && + (rawXML.IndexOf ("= 0 || + rawXML.IndexOf ("= 0)) + kind = JavaDocletType._ApiXml; + else if (rawXML.StartsWith ("package", StringComparison.Ordinal) || + rawXML.StartsWith (";", StringComparison.Ordinal)) { + kind = JavaDocletType.JavaApiParameterNamesXml; + } + } + + return kind; + } + } + + public class ApiXmlDocScraper : IJavaMethodParameterNameProvider + { + public ApiXmlDocScraper (string apiXmlFile) + { + xdoc = XDocument.Load (apiXmlFile); + } + + XDocument xdoc; + + public string[]? GetParameterNames (JavaMethodParameterNameInfo info) + { + var xtype = xdoc + .Elements ("api") + .Elements ("package") + .Where (p => ((string?) p.Attribute ("name")) == info.PackageName) + .Elements () + .Where (t => ((string?) t.Attribute ("name")) == info.TypeName) + .FirstOrDefault (); + if (xtype == null) { + return null; + } + + var members = info.MethodName == "constructor" + ? xtype.Elements ("constructor") + : xtype.Elements ("method").Where (m => ((string?) m.Attribute ("name")) == info.MethodName); + var pcount = info.ParameterTypes.Length; + members = members + .Where (m => m.Elements ("parameter").Count () == pcount); + + XElement? member = + members.FirstOrDefault (m => info.MethodSignature == (string?) m.Attribute ("jni-signature")); + if (member == null) { + foreach (var m in members) { + var found = true; + int i = 0; + foreach (var p in m.Elements ("parameter")) { + if (!ParameterTypesMatch (p, info.ParameterTypes [i++].JavaType)) { + found = false; + break; + } + } + if (found) { + member = m; + break; + } + } + } + if (member == null) + return null; + return member.Elements ("parameter") + .Select (p => ((string?) p.Attribute ("name")) ?? "") + .ToArray (); + + bool ParameterTypesMatch (XElement parameter, string ptype) + { + var jtype = (string?) parameter.Attribute ("type"); + if (jtype == null) { + return false; + } + if (!jtype.StartsWith (".*", StringComparison.Ordinal)) { + return jtype == ptype; + } + jtype = "." + jtype.Substring (".*".Length); + return ptype.EndsWith (jtype, StringComparison.Ordinal); + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/JavaParameterNamesLoader.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/JavaParameterNamesLoader.cs new file mode 100644 index 00000000000..63136d1fe9c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/JavaParameterNamesLoader.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; + +namespace Xamarin.Android.Tools.Bytecode +{ + public class JavaParameterNamesLoader : IJavaMethodParameterNameProvider + { + List packages; + + public JavaParameterNamesLoader(string path) + { + packages = this.LoadParameterFixupDescription(path); + } + + class Parameter + { + public string? Type { get; set; } + public string? Name { get; set; } + } + + class Method + { + public string? Name { get; set; } + public List? Parameters { get; set; } + } + + class Type + { + public string? Name { get; set; } + public List? Methods { get; set; } + } + + class Package + { + public string? Name { get; set; } + public List? Types { get; set; } + } + + // from https://github.com/atsushieno/xamarin-android-docimporter-ng/blob/master/Xamarin.Android.Tools.JavaStubImporter/JavaApiParameterNamesXmlExporter.cs#L78 + /* + * The Text Format is: + * + * package {packagename} + * ;--------------------------------------- + * interface {interfacename}{optional_type_parameters} -or- + * class {classname}{optional_type_parameters} + * {optional_type_parameters}{methodname}({parameters}) + * + * Anything after ; is treated as comment. + * + * optional_type_parameters: "" -or- "" (no constraints allowed) + * parameters: type1 p0, type2 p1 (pairs of {type} {name}, joined by ", ") + * + * It is with strict indentations. two spaces for types, four spaces for methods. + * + * Constructors are named as "#ctor". + * + * Commas are used by both parameter types and parameter separators, + * but only parameter separators can be followed by a whitespace. + * It is useful when writing text parsers for this format. + * + * Type names may contain whitespaces in case it is with generic constraints (e.g. "? extends FooBar"), + * so when parsing a parameter type-name pair, the only trustworthy whitespace for tokenizing name is the *last* one. + * + */ + List LoadParameterFixupDescription (string path) + { + var fixup = new List (); + string? package = null; + var types = new List (); + string? type = null; + var methods = new List (); + int currentLine = 0; + foreach (var l in File.ReadAllLines (path)) { + currentLine++; + var line = l.IndexOf (";", StringComparison.Ordinal) >= 0 + ? l.Substring (0, l.IndexOf (";", StringComparison.Ordinal)).TrimEnd (' ', '\t') + : l; + if (line.Trim ().Length == 0) + continue; + if (line.StartsWith ("package ", StringComparison.Ordinal)) { + package = line.Substring ("package ".Length); + types = new List (); + fixup.Add (new Package { Name = package, Types = types }); + continue; + } else if (line.StartsWith (" ", StringComparison.Ordinal)) { + int open = line.IndexOf ("(", StringComparison.Ordinal); + if (open < 0) + throw new ArgumentException ($"Unexpected line in {path} line {currentLine}: {line}"); + string parameters = line.Substring (open + 1).TrimEnd (')'); + string name = line.Substring (4, open - 4); + if (name.FirstOrDefault () == '<') // generic method can begin with type parameters. + name = name.Substring (name.IndexOf (" ", StringComparison.Ordinal) + 1); + methods.Add (new Method { + Name = name, + Parameters = parameters.Replace (", ", "\0").Split ('\0') + .Select (s => s.Split (' ')) + .Select (a => new Parameter { Type = string.Join (" ", a.Take (a.Length - 1)).Replace (",", ", "), Name = a.Last () }).ToList () + }); + } else { + type = line.Substring (line.IndexOf (" ", 2, StringComparison.Ordinal) + 1); + // To match type name from class-parse, we need to strip off generic arguments here (generics are erased). + if (type.IndexOf ("<", StringComparison.Ordinal) > 0) + type = type.Substring (0, type.IndexOf ("<", StringComparison.Ordinal)); + methods = new List (); + types.Add (new Type { Name = type, Methods = methods }); + } + } + return fixup; + } + + public string[]? GetParameterNames (JavaMethodParameterNameInfo info) + { + var package = info.PackageName; + var type = info.TypeName; + var method = info.MethodName; + var ptypes = info.ParameterTypes.Select (p => p.JavaType).ToArray (); + + var methods = this.packages + .Where(p => p.Name == package && p.Types != null) + .SelectMany(p => p.Types!) + .Where(t => t.Name == type && t.Methods != null) + .SelectMany(t => t.Methods!) + .Where(m => m.Name == method); + var namedMethod = methods.FirstOrDefault (m => ParametersEqual (m.Parameters, ptypes)); + if (namedMethod == null) + return null; + return namedMethod.Parameters?.Select (p => p.Name!).ToArray (); + } + + static bool ParametersEqual (List? methodParameters, string[]? ptypes) + { + if (methodParameters?.Count != ptypes?.Length) + return false; + if (methodParameters == null || ptypes == null) + return false; + for (int i = 0; i < ptypes.Length; ++i) { + if (methodParameters[i].Type != ptypes [i]) + return false; + } + return true; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/JvmNameResolver.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/JvmNameResolver.cs new file mode 100644 index 00000000000..a61ae4fb1e3 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/JvmNameResolver.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using org.jetbrains.kotlin.metadata.jvm; + +namespace Xamarin.Android.Tools.Bytecode +{ + // https://github.com/JetBrains/kotlin/blob/master/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolver.kt + class JvmNameResolver + { + readonly List records = new List (); + readonly List strings; + + public JvmNameResolver (StringTableTypes table, List strings) + { + foreach (var t in table.Records) + for (var i = 0; i < t.Range; i++) + records.Add (t); + + this.strings = strings; + } + + public string GetString (int index) + { + var record = records [index]; + + string val; + + // Get string from: + // - Embedded in string record table + // - Predefined string + // - Constant pool + if (!string.IsNullOrEmpty (record.String)) + val = record.String; + else if (record.PredefinedIndex > 0) + val = predefined_strings [record.PredefinedIndex]; + else + val = strings [index]; + + if (record.SubstringIndexs?.Length >= 2) { + var begin = record.SubstringIndexs [0]; + var end = record.SubstringIndexs [1]; + + if (begin > 0 && begin <= end && end <= val.Length) + val = val.Substring (begin, end); + } + + if (record.ReplaceChars?.Length >= 2) { + var from = (char) record.ReplaceChars [0]; + var to = (char) record.ReplaceChars [1]; + + val = val.Replace (from, to); + } + + if (record.operation == StringTableTypes.Record.Operation.InternalToClassId) + val = val.Replace ('$', '.'); + else if (record.operation == StringTableTypes.Record.Operation.DescToClassId) { + if (val.Length >= 2) + val = val.Substring (1, val.Length - 1); + + val = val.Replace ('$', '.'); + } + + return val; + } + + static readonly string [] predefined_strings = new string [] { + "kotlin/Any", + "kotlin/Nothing", + "kotlin/Unit", + "kotlin/Throwable", + "kotlin/Number", + + "kotlin/Byte", "kotlin/Double", "kotlin/Float", "kotlin/Int", + "kotlin/Long", "kotlin/Short", "kotlin/Boolean", "kotlin/Char", + + "kotlin/CharSequence", + "kotlin/String", + "kotlin/Comparable", + "kotlin/Enum", + + "kotlin/Array", + "kotlin/ByteArray", "kotlin/DoubleArray", "kotlin/FloatArray", "kotlin/IntArray", + "kotlin/LongArray", "kotlin/ShortArray", "kotlin/BooleanArray", "kotlin/CharArray", + + "kotlin/Cloneable", + "kotlin/Annotation", + + "kotlin/collections/Iterable", "kotlin/collections/MutableIterable", + "kotlin/collections/Collection", "kotlin/collections/MutableCollection", + "kotlin/collections/List", "kotlin/collections/MutableList", + "kotlin/collections/Set", "kotlin/collections/MutableSet", + "kotlin/collections/Map", "kotlin/collections/MutableMap", + "kotlin/collections/Map.Entry", "kotlin/collections/MutableMap.MutableEntry", + + "kotlin/collections/Iterator", "kotlin/collections/MutableIterator", + "kotlin/collections/ListIterator", "kotlin/collections/MutableListIterator" + }; + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinBitEncoding.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinBitEncoding.cs new file mode 100644 index 00000000000..06edf06f52e --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinBitEncoding.cs @@ -0,0 +1,157 @@ +using System; +using System.IO; +using System.Linq; + +namespace Xamarin.Android.Tools.Bytecode +{ + // https://github.com/JetBrains/kotlin/blob/master/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/BitEncoding.java + public static class KotlinBitEncoding + { + const char UTF8_MODE_MARKER = (char) 0; + const char _8TO7_MODE_MARKER = unchecked((char) -1); + + public static byte [] DecodeBytes (string [] data) + { + if (data.Length > 0 && !string.IsNullOrEmpty (data [0])) { + var possibleMarker = data [0] [0]; + + if (possibleMarker == UTF8_MODE_MARKER) + return StringsToBytes (DropMarker (data)); + + if (possibleMarker == _8TO7_MODE_MARKER) + data = DropMarker (data); + } + + var bytes = CombineStringArrayIntoBytes (data); + + // Adding 0x7f modulo max byte value is equivalent to subtracting 1 the same modulo, which is inverse to what happens in encodeBytes + AddModuloByte (bytes, 0x7f); + + return Decode7to8 (bytes); + } + + public static int ReadRawVarint32 (Stream input) + { + var firstByte = input.ReadByte (); + + if ((firstByte & 128) == 0) + return firstByte; + + var result = firstByte & 127; + + int offset; + int b; + + for (offset = 7; offset < 32; offset += 7) { + + b = input.ReadByte (); + + if (b == -1) + throw new InvalidDataException ("Unable to read varint32 from stream"); + + result |= (b & 127) << offset; + + if ((b & 128) == 0) + return result; + } + + while (offset < 64) { + + b = input.ReadByte (); + + if (b == -1) + throw new InvalidDataException ("Unable to read varint32 from stream"); + + if ((b & 128) == 0) + return result; + + offset += 7; + } + + throw new InvalidDataException ("Unable to read varint32 from stream"); + } + + static string [] DropMarker (string [] data) + { + // Clone because the clients should be able to use the passed array for their own purposes. + // This is cheap because the size of the array is 1 or 2 almost always. + var result = (string []) data.Clone (); + result [0] = result [0].Substring (1); + + return result; + } + + static byte [] StringsToBytes (string [] strings) + { + var length = strings.Sum (s => s.Length); + var result = new byte [length]; + + var i = 0; + + foreach (var s in strings) + foreach (var c in s) + result [i++] = (byte) c; + + return result; + } + + static byte [] CombineStringArrayIntoBytes (string [] data) + { + var resultLength = 0; + + foreach (var s in data) + resultLength += s.Length; + + var result = new byte [resultLength]; + var p = 0; + + foreach (var s in data) + for (int i = 0, n = s.Length; i < n; i++) + result [p++] = (byte) s [i]; + + return result; + } + + static void AddModuloByte (byte [] data, int increment) + { + for (int i = 0, n = data.Length; i < n; i++) { + data [i] = (byte) ((data [i] + increment) & 0x7f); + } + } + + static byte [] Decode7to8 (byte [] data) + { + // floor(7 * data.length / 8) + var resultLength = 7 * data.Length / 8; + + var result = new byte [resultLength]; + + // We maintain a pointer to an input bit in the same fashion as in encode8to7(): it's represented as two numbers: index of the + // current byte in the input and index of the bit in the byte + var byteIndex = 0; + var bit = 0; + + // A resulting byte is comprised of 8 bits, starting from the current bit. Since each input byte only "contains 7 bytes", a + // resulting byte always consists of two parts: several most significant bits of the current byte and several least significant bits + // of the next byte + for (var i = 0; i < resultLength; i++) { + var firstPart = (int) (((uint) (data [byteIndex] & 0xff)) >> bit); + + byteIndex++; + + var secondPart = (data [byteIndex] & ((1 << (bit + 1)) - 1)) << 7 - bit; + + result [i] = (byte) (firstPart + secondPart); + + if (bit == 6) { + byteIndex++; + bit = 0; + } else { + bit++; + } + } + + return result; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs new file mode 100644 index 00000000000..de5a5513ed9 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs @@ -0,0 +1,768 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using org.jetbrains.kotlin.metadata.jvm; +using ProtoBuf; +using Type = org.jetbrains.kotlin.metadata.jvm.Type; + +namespace Xamarin.Android.Tools.Bytecode +{ + // https://github.com/JetBrains/kotlin/blob/master/core/metadata.jvm/src/jvm_metadata.proto + public class KotlinFile + { + public List? Functions { get; set; } + public List? Properties { get; set; } + public List? TypeAliases { get; set; } + public KotlinTypeTable? TypeTable { get; set; } + public KotlinVersionRequirementTable? VersionRequirementTable { get; set; } + + internal static KotlinFile FromProtobuf (Package c, JvmNameResolver resolver) + { + return new KotlinFile { + Functions = c.Functions.ToList (resolver, KotlinFunction.FromProtobuf), + Properties = c.Properties.ToList (resolver, KotlinProperty.FromProtobuf), + TypeAliases = c.TypeAlias.ToList (resolver, KotlinTypeAlias.FromProtobuf), + TypeTable = KotlinTypeTable.FromProtobuf (c.TypeTable, resolver), + VersionRequirementTable = KotlinVersionRequirementTable.FromProtobuf (c.VersionRequirementTable, resolver) + }; + } + } + + public class KotlinClass : KotlinFile + { + public string? CompanionObjectName { get; set; } + public List? Constructors { get; set; } + public List? EnumEntries { get; set; } + public KotlinClassFlags Flags { get; set; } + public string? FullyQualifiedName { get; set; } + public KotlinClassInheritability Inheritability { get; set; } + public List NestedClassNames { get; set; } = new List (); + public KotlinClassType ObjectType { get; set; } + public List? SealedSubclassFullyQualifiedNames { get; set; } + public List? SuperTypeIds { get; set; } + public List? SuperTypes { get; set; } + public List? TypeParameters { get; set; } + public int []? VersionRequirements { get; set; } + public KotlinClassVisibility Visibility { get; set; } + + internal static KotlinClass FromProtobuf (Class c, JvmNameResolver resolver) + { + return new KotlinClass { + CompanionObjectName = c.CompanionObjectName > 0 ? resolver.GetString (c.CompanionObjectName) : null, + Constructors = c.Constructors.ToList (resolver, KotlinConstructor.FromProtobuf), + EnumEntries = c.EnumEntries?.Select (e => resolver.GetString (e.Name)).ToList (), + Flags = (KotlinClassFlags)c.Flags, + FullyQualifiedName = c.FqName > 0 ? resolver.GetString (c.FqName) : null, + Functions = c.Functions.ToList (resolver, KotlinFunction.FromProtobuf), + Inheritability = (KotlinClassInheritability)((c.Flags & 0b110000) >> 4), + NestedClassNames = c.NestedClassNames?.Select (n => resolver.GetString (n)).ToList () ?? new List (), + ObjectType = (KotlinClassType) ((c.Flags & 0b111000000) >> 6), + Properties = c.Properties.ToList (resolver, KotlinProperty.FromProtobuf), + SealedSubclassFullyQualifiedNames = c.SealedSubclassFqNames?.Select (n => resolver.GetString (n)).ToList (), + SuperTypeIds = c.SupertypeIds?.Select (n => resolver.GetString (n)).ToList (), + SuperTypes = c.Supertypes.ToList (resolver, KotlinType.FromProtobuf), + TypeAliases = c.TypeAlias.ToList (resolver, KotlinTypeAlias.FromProtobuf), + TypeParameters = c.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), + VersionRequirements = c.VersionRequirements, + TypeTable = KotlinTypeTable.FromProtobuf (c.TypeTable, resolver), + VersionRequirementTable = KotlinVersionRequirementTable.FromProtobuf (c.VersionRequirementTable, resolver), + Visibility = (KotlinClassVisibility)((c.Flags & 0b1110) >> 1) + }; + } + } + + public class KotlinMethodBase + { + public int []? VersionRequirements { get; set; } + + public virtual string GetSignature () => string.Empty; + } + + public class KotlinConstructor : KotlinMethodBase + { + public KotlinConstructorFlags Flags { get; set; } + public List? ValueParameters { get; set; } + + internal static KotlinConstructor? FromProtobuf (Constructor c, JvmNameResolver resolver) + { + if (c is null) + return null; + + return new KotlinConstructor { + Flags = (KotlinConstructorFlags)c.Flags, + ValueParameters = c.ValueParameters.ToList (resolver, KotlinValueParameter.FromProtobuf), + VersionRequirements = c.VersionRequirements + }; + } + + public override string GetSignature () + { + return $"({ValueParameters?.GetSignature ()})V"; + } + } + + public class KotlinAnnotation + { + public int Id { get; set; } + public List? Arguments { get; set; } + + internal static KotlinAnnotation? FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation a, JvmNameResolver resolver) + { + if (a is null) + return null; + + return new KotlinAnnotation { + Id = a.Id, + Arguments = a.Arguments.ToList (resolver, KotlinAnnotationArgument.FromProtobuf), + }; + } + } + + public class KotlinAnnotationArgument + { + public int NameId { get; set; } + public KotlinAnnotationArgumentValue? Value { get; set; } + + internal static KotlinAnnotationArgument? FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation.Argument a, JvmNameResolver resolver) + { + if (a is null) + return null; + + return new KotlinAnnotationArgument { + NameId = a.NameId, + Value = KotlinAnnotationArgumentValue.FromProtobuf (a.value, resolver) + }; + } + } + + public class KotlinAnnotationArgumentValue + { + public KotlinAnnotationArgumentType Type { get; set; } + public long IntValue { get; set; } + public float FloatValue { get; set; } + public double DoubleValue { get; set; } + public string? StringValue { get; set; } + public int ClassId { get; set; } + public int EnumValueId { get; set; } + public KotlinAnnotation? Annotation { get; set; } + public List? ArrayElements { get; set; } + public int ArrayDimensionCount { get; set; } + public KotlinAnnotationFlags Flags { get; set; } + + internal static KotlinAnnotationArgumentValue? FromProtobuf (org.jetbrains.kotlin.metadata.jvm.Annotation.Argument.Value value, JvmNameResolver resolver) + { + if (value is null) + return null; + + return new KotlinAnnotationArgumentValue { + Type = (KotlinAnnotationArgumentType) value.type, + IntValue = value.IntValue, + FloatValue = value.FloatValue, + DoubleValue = value.DoubleValue, + StringValue = resolver.GetString (value.StringValue), + ClassId = value.ClassId, + EnumValueId = value.EnumValueId, + Annotation = KotlinAnnotation.FromProtobuf (value.Annotation, resolver), + ArrayDimensionCount = value.ArrayDimensionCount, + ArrayElements = value.ArrayElements.ToList (resolver,KotlinAnnotationArgumentValue.FromProtobuf), + Flags = (KotlinAnnotationFlags)value.Flags + }; + } + } + + public class KotlinEffect + { + public KotlinEffectType EffectType { get; set; } + public List? EffectConstructorArguments { get; set; } + public KotlinExpression? ConclusionOfConditionalEffect { get; set; } + public KotlinInvocationKind Kind { get; set; } + + internal static KotlinEffect? FromProtobuf (Effect ef, JvmNameResolver resolver) + { + if (ef is null) + return null; + + return new KotlinEffect { + EffectType = (KotlinEffectType) ef.effect_type, + EffectConstructorArguments = ef.EffectConstructorArguments.ToList (resolver, KotlinExpression.FromProtobuf), + ConclusionOfConditionalEffect = KotlinExpression.FromProtobuf (ef.ConclusionOfConditionalEffect, resolver), + Kind = (KotlinInvocationKind) ef.Kind + }; + } + } + + public class KotlinExpression + { + public KotlinExpressionFlags Flags { get; set; } + public int ValueParameterReference { get; set; } + public KotlinConstantValue ConstantValue { get; set; } + public KotlinType? IsInstanceType { get; set; } + public int IsInstanceTypeId { get; set; } + public List? AndArguments { get; set; } + public List? OrArguments { get; set; } + + internal static KotlinExpression? FromProtobuf (Expression exp, JvmNameResolver resolver) + { + if (exp is null) + return null; + + return new KotlinExpression { + Flags = (KotlinExpressionFlags)exp.Flags, + ValueParameterReference = exp.ValueParameterReference, + ConstantValue = (KotlinConstantValue) exp.constant_value, + IsInstanceType = KotlinType.FromProtobuf (exp.IsInstanceType, resolver), + IsInstanceTypeId = exp.IsInstanceTypeId, + AndArguments = exp.AndArguments.ToList (resolver, KotlinExpression.FromProtobuf), + OrArguments = exp.OrArguments.ToList (resolver, KotlinExpression.FromProtobuf), + }; + } + } + + public class KotlinFunction : KotlinMethodBase + { + public string? Name { get; set; } + public string? JvmName { get; set; } + public string? JvmSignature { get; set; } + public KotlinFunctionFlags Flags { get; set; } + public KotlinType? ReturnType { get; set; } + public int ReturnTypeId { get; set; } + public List? TypeParameters { get; set; } + public KotlinType? ReceiverType { get; set; } + public int ReceiverTypeId { get; set; } + public KotlinTypeTable? TypeTable { get; set; } + public KotlinContract? Contract { get; set; } + public List? ValueParameters { get; set; } + + internal static KotlinFunction? FromProtobuf (Function f, JvmNameResolver resolver) + { + if (f is null) + return null; + + var sig = Extensible.GetValue (f, 100); + + return new KotlinFunction { + Flags = (KotlinFunctionFlags)f.Flags, + Name = resolver.GetString (f.Name), + JvmName = resolver.GetString ((sig is null || sig.Name == 0) ? f.Name : sig.Name), + JvmSignature = sig is null ? null : resolver.GetString (sig.Desc), + ReturnType = KotlinType.FromProtobuf (f.ReturnType, resolver), + ReturnTypeId = f.ReturnTypeId, + ReceiverType = KotlinType.FromProtobuf (f.ReceiverType, resolver), + ReceiverTypeId = f.ReceiverTypeId, + TypeParameters = f.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), + ValueParameters = f.ValueParameters.ToList (resolver, KotlinValueParameter.FromProtobuf), + VersionRequirements = f.VersionRequirements + }; + } + + public override string? ToString () => Name; + + public string GetFlags () + { + var sb = new StringBuilder (); + + foreach (var f in Enum.GetNames (typeof (KotlinFunctionFlags))) { + if (Flags.HasFlag ((KotlinFunctionFlags)Enum.Parse (typeof (KotlinFunctionFlags), f))) + sb.Append (f); + } + + return sb.ToString (); + } + } + + public class KotlinContract + { + public List? Effects { get; set; } + + internal static KotlinContract? FromProtobuf (Contract c, JvmNameResolver resolver) + { + return new KotlinContract { + Effects = c.Effects.ToList (resolver, KotlinEffect.FromProtobuf), + }; + } + } + + public class KotlinProperty : KotlinMethodBase + { + public string? Name { get; set; } + public KotlinPropertyFlags Flags { get; set; } + public KotlinType? ReturnType { get; set; } + public int ReturnTypeId { get; set; } + public List? TypeParameters { get; set; } + public KotlinType? ReceiverType { get; set; } + public int ReceiverTypeId { get; set; } + public KotlinValueParameter? SetterValueParameter { get; set; } + public int GetterFlags { get; set; } + public int SetterFlags { get; set; } + + internal static KotlinProperty? FromProtobuf (Property p, JvmNameResolver resolver) + { + if (p is null) + return null; + + return new KotlinProperty { + Flags = (KotlinPropertyFlags)p.Flags, + Name = resolver.GetString (p.Name), + ReturnTypeId = p.ReturnTypeId, + ReturnType = KotlinType.FromProtobuf (p.ReturnType, resolver), + ReceiverType = KotlinType.FromProtobuf (p.ReceiverType, resolver), + ReceiverTypeId = p.ReceiverTypeId, + SetterValueParameter = KotlinValueParameter.FromProtobuf (p.SetterValueParameter, resolver), + GetterFlags = p.GetterFlags, + SetterFlags = p.SetterFlags, + TypeParameters = p.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), + VersionRequirements = p.VersionRequirements + }; + } + + public override string? ToString () => Name; + + public bool IsInternalVisibility => (Flags & KotlinPropertyFlags.VisibilityMask) == KotlinPropertyFlags.Internal; + + public bool IsPrivateVisibility => (Flags & KotlinPropertyFlags.VisibilityMask) == KotlinPropertyFlags.Private; + } + + public class KotlinType + { + public List? Arguments { get; set; } + public bool Nullable { get; set; } + public int? FlexibleTypeCapabilitiesId { get; set; } + public KotlinType? FlexibleUpperBound { get; set; } + public int FlexibleUpperBoundId { get; set; } + public string? ClassName { get; set; } + public int? TypeParameter { get; set; } + public string? TypeParameterName { get; set; } + public string? TypeAliasName { get; set; } + public KotlinType? OuterType { get; set; } + public int? OuterTypeId { get; set; } + public KotlinType? AbbreviatedType { get; set; } + public int? AbbreviatedTypeId { get; set; } + public KotlinTypeFlags Flags { get; set; } + + internal static KotlinType? FromProtobuf (Type t, JvmNameResolver resolver) + { + if (t is null) + return null; + + return new KotlinType { + Arguments = t.Arguments.ToList (resolver, KotlinTypeArgument.FromProtobuf), + Nullable = t.Nullable, + FlexibleTypeCapabilitiesId = t.FlexibleTypeCapabilitiesId, + FlexibleUpperBound = FromProtobuf (t.FlexibleUpperBound, resolver), + ClassName = t.ClassName >= 0 ? resolver.GetString (t.ClassName.Value) : null, + TypeParameter = t.TypeParameter, + TypeParameterName = t.TypeParameterName >= 0 ? resolver.GetString (t.TypeParameterName.GetValueOrDefault ()) : null, + OuterType = FromProtobuf (t.OuterType, resolver), + OuterTypeId = t.OuterTypeId, + AbbreviatedType = FromProtobuf (t.AbbreviatedType, resolver), + AbbreviatedTypeId = t.AbbreviatedTypeId, + Flags = (KotlinTypeFlags)t.Flags + }; + } + + public string GetSignature (bool convertUnsignedToPrimitive = true) + { + return KotlinUtilities.ConvertKotlinTypeSignature (this, null, convertUnsignedToPrimitive); + } + } + + public class KotlinTypeAlias + { + public int Flags { get; set; } + public string? Name { get; set; } + public List? TypeParameters { get; set; } + public KotlinType? UnderlyingType { get; set; } + public int UnderlyingTypeId { get; set; } + public KotlinType? ExpandedType { get; set; } + public int ExpandedTypeId { get; set; } + public List? Annotations { get; set; } + public int []? VersionRequirements { get; set; } + + internal static KotlinTypeAlias? FromProtobuf (TypeAlias ta, JvmNameResolver resolver) + { + if (ta is null) + return null; + + return new KotlinTypeAlias { + Flags = ta.Flags, + Name = resolver.GetString (ta.Name), + TypeParameters = ta.TypeParameters.ToList (resolver, KotlinTypeParameter.FromProtobuf), + UnderlyingType = KotlinType.FromProtobuf (ta.UnderlyingType, resolver), + UnderlyingTypeId = ta.UnderlyingTypeId, + ExpandedType = KotlinType.FromProtobuf (ta.ExpandedType, resolver), + ExpandedTypeId = ta.ExpandedTypeId, + VersionRequirements = ta.VersionRequirements + }; + } + } + + public class KotlinTypeArgument + { + public KotlinProjection Projection { get; set; } + public KotlinType? Type { get; set; } + public int TypeId { get; set; } + + internal static KotlinTypeArgument? FromProtobuf (Type.Argument ta, JvmNameResolver resolver) + { + if (ta is null) + return null; + + return new KotlinTypeArgument { + Projection = (KotlinProjection) ta.projection, + Type = KotlinType.FromProtobuf (ta.Type, resolver), + TypeId = ta.TypeId + }; + } + } + + public class KotlinTypeParameter + { + public int Id { get; set; } + public string? Name { get; set; } + public bool Reified { get; set; } + public KotlinVariance Variance { get; set; } + public List? UpperBounds { get; set; } + public int []? UpperBoundsIds { get; set; } + + internal static KotlinTypeParameter? FromProtobuf (TypeParameter vp, JvmNameResolver resolver) + { + if (vp is null) + return null; + + return new KotlinTypeParameter { + Id = vp.Id, + Name = resolver.GetString (vp.Name), + Reified = vp.Reified, + Variance = (KotlinVariance) vp.variance, + UpperBounds = vp.UpperBounds.ToList (resolver, KotlinType.FromProtobuf), + UpperBoundsIds = vp.UpperBoundIds + }; + } + } + + public class KotlinTypeTable + { + public List? Types { get; set; } + public int FirstNullable { get; set; } + + internal static KotlinTypeTable? FromProtobuf (TypeTable ta, JvmNameResolver resolver) + { + if (ta is null) + return null; + + return new KotlinTypeTable { + Types = ta.Types.ToList (resolver, KotlinType.FromProtobuf), + FirstNullable = ta.FirstNullable + }; + } + } + + public class KotlinVersionRequirement + { + public int Version { get; set; } + public int VersionFull { get; set; } + public KotlinVersionLevel Level { get; set; } + public int ErrorCode { get; set; } + public int Message { get; set; } + public KotlinVersionKind VersionKind { get; set; } + + internal static KotlinVersionRequirement? FromProtobuf (VersionRequirement vr, JvmNameResolver resolver) + { + if (vr is null) + return null; + + return new KotlinVersionRequirement { + Version = vr.Version, + VersionFull = vr.VersionFull, + Level = (KotlinVersionLevel) vr.level, + ErrorCode = vr.ErrorCode, + Message = vr.Message, + VersionKind = (KotlinVersionKind) vr.version_kind + }; + } + } + + public class KotlinVersionRequirementTable + { + public List? Requirements { get; set; } + + internal static KotlinVersionRequirementTable? FromProtobuf (VersionRequirementTable vrt, JvmNameResolver resolver) + { + if (vrt is null) + return null; + + return new KotlinVersionRequirementTable { + Requirements = vrt.Requirements.ToList (resolver, KotlinVersionRequirement.FromProtobuf), + }; + } + } + + public class KotlinValueParameter + { + public KotlinParameterFlags Flags { get; set; } + public string? Name { get; set; } + public KotlinType? Type { get; set; } + public int TypeId { get; set; } + public KotlinType? VarArgElementType { get; set; } + public int VarArgElementTypeId { get; set; } + + internal static KotlinValueParameter? FromProtobuf (ValueParameter vp, JvmNameResolver resolver) + { + if (vp is null) + return null; + + return new KotlinValueParameter { + Flags = (KotlinParameterFlags)vp.Flags, + Name = resolver.GetString (vp.Name), + Type = KotlinType.FromProtobuf (vp.Type, resolver), + TypeId = vp.TypeId, + VarArgElementType = KotlinType.FromProtobuf (vp.VarargElementType, resolver), + VarArgElementTypeId = vp.VarargElementTypeId + }; + } + + public string? GetSignature () => Type?.GetSignature (); + } + + public enum KotlinVariance + { + In = 0, + Out = 1, + Inv = 2, + } + + public enum KotlinProjection + { + In = 0, + Out = 1, + Inv = 2, + Star = 3, + } + + public enum KotlinEffectType + { + ReturnsConstant = 0, + Calls = 1, + ReturnsNotNull = 2, + } + + public enum KotlinInvocationKind + { + AtMostOnce = 0, + ExactlyOnce = 1, + AtLeastOnce = 2, + } + + public enum KotlinConstantValue + { + True = 0, + False = 1, + Null = 2, + } + + public enum KotlinVersionLevel + { + Warning = 0, + Error = 1, + Hidden = 2, + } + + public enum KotlinVersionKind + { + LanguageVersion = 0, + CompilerVersion = 1, + ApiVersion = 2, + } + + public enum KotlinAnnotationArgumentType + { + Byte = 0, + Char = 1, + Short = 2, + Int = 3, + Long = 4, + Float = 5, + Double = 6, + Boolean = 7, + String = 8, + Class = 9, + Enum = 10, + Annotation = 11, + Array = 12, + } + + [Flags] + public enum KotlinClassFlags + { + HasAnnotations = 0b00_00_000_1, + + IsInner = 0b_00001_000_00_000_0, + IsData = 0b_00010_000_00_000_0, + IsExternalClass = 0b_00100_000_00_000_0, + IsExpectClass = 0b_01000_000_00_000_0, + IsInlineClass = 0b_10000_000_00_000_0 + } + + public enum KotlinClassVisibility + { + Internal = 0, + Private = 1, + Protected = 2, + Public = 3, + PrivateToThis = 4, + Local = 5 + } + + public enum KotlinClassType + { + Class = 0, + Interface = 1, + EnumClass = 2, + EnumEntry = 3, + AnnotationClass = 4, + Object = 5, + CompanionObject = 6 + } + + public enum KotlinClassInheritability + { + Final = 0, + Open = 1, + Abstract = 2, + Sealed = 3 + } + + [Flags] + public enum KotlinConstructorFlags + { + HasAnnotations = 0b0_000_1, + + Internal = 0b0_000_0, + Private = 0b0_001_0, + Protected = 0b0_010_0, + Public = 0b0_011_0, + PrivateToThis = 0b0_100_0, + Local = 0b0_101_0, + + IsSecondary = 0b1_000_0 + } + + [Flags] + public enum KotlinFunctionFlags + { + HasAnnotations = 0b00_00_000_1, + + Internal = 0b00_00_000_0, + Private = 0b00_00_001_0, + Protected = 0b00_00_010_0, + Public = 0b00_00_011_0, + PrivateToThis = 0b00_00_100_0, + Local = 0b00_00_101_0, + + Final = 0b00_00_000_0, + Open = 0b00_01_000_0, + Abstract = 0b00_10_000_0, + Sealed = 0b00_11_000_0, + + Declaration = 0b00_00_000_0, + FakeOverride = 0b01_00_000_0, + Delegation = 0b10_00_000_0, + Synthesized = 0b11_00_000_0, + + IsOperator = 0b_0000001_00_00_000_0, + IsInfix = 0b_0000010_00_00_000_0, + IsInline = 0b_0000100_00_00_000_0, + IsTailrec = 0b_0001000_00_00_000_0, + IsExternalFunction = 0b_0010000_00_00_000_0, + IsSuspend = 0b_0100000_00_00_000_0, + IsExpectFunction = 0b_1000000_00_00_000_0 + } + + [Flags] + public enum KotlinPropertyFlags + { + HasAnnotations = 0b00_00_000_1, + + Internal = 0b00_00_000_0, + Private = 0b00_00_001_0, + Protected = 0b00_00_010_0, + Public = 0b00_00_011_0, + PrivateToThis = 0b00_00_100_0, + Local = 0b00_00_101_0, + + VisibilityMask = 0b00_00_111_0, + + Final = 0b00_00_000_0, + Open = 0b00_01_000_0, + Abstract = 0b00_10_000_0, + Sealed = 0b00_11_000_0, + + Declaration = 0b00_00_000_0, + FakeOverride = 0b01_00_000_0, + Delegation = 0b10_00_000_0, + Synthesized = 0b11_00_000_0, + + IsVar = 0b_000000001_00_00_000_0, + HasGetter = 0b_000000010_00_00_000_0, + HasSetter = 0b_000000100_00_00_000_0, + IsConst = 0b_000001000_00_00_000_0, + IsLateInit = 0b_000010000_00_00_000_0, + HasConstant = 0b_000100000_00_00_000_0, + IsExternalProperty = 0b_001000000_00_00_000_0, + IsDelegated = 0b_010000000_00_00_000_0, + IsExpectProperty = 0b_100000000_00_00_000_0 + } + + [Flags] + public enum KotlinParameterFlags + { + HasAnnotations = 0b000_1, + + DeclaresDefaultValue = 0b001_0, + IsCrossInline = 0b010_0, + IsNoInline = 0b100_0 + } + + [Flags] + public enum KotlinAccessorFlags + { + HasAnnotations = 0b00_00_000_1, + + Internal = 0b00_00_000_0, + Private = 0b00_00_001_0, + Protected = 0b00_00_010_0, + Public = 0b00_00_011_0, + PrivateToThis = 0b00_00_100_0, + Local = 0b00_00_101_0, + + Final = 0b00_00_000_0, + Open = 0b00_01_000_0, + Abstract = 0b00_10_000_0, + Sealed = 0b00_11_000_0, + + IsNotDefault = 0b001_00_000_0, + IsExternalAccessor = 0b010_00_000_0, + IsInlineAccessor = 0b100_00_000_0 + } + + [Flags] + public enum KotlinExpressionFlags + { + IsNegated = 0b01, + IsNullCheckPredicate = 0b10 + } + + [Flags] + public enum KotlinAnnotationFlags + { + IsUnsigned = 0b01 + } + + [Flags] + public enum KotlinTypeFlags + { + SuspendType = 0b01 + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs new file mode 100644 index 00000000000..e3c08ae2454 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs @@ -0,0 +1,657 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Xamarin.Android.Tools.Bytecode +{ + public static class KotlinFixups + { + public static void Fixup (IList classes) + { + // Pre-pass: identify Kotlin `@JvmInline value class` types and record + // each one's JNI name -> backing primitive descriptor. We need this + // map before processing methods so that a method on class A that takes + // an inline class B as a parameter (via Kotlin metadata) can be stamped + // even if B is later in `classes`. See dotnet/java-interop#1431. + var inlineClasses = DetectInlineClasses (classes); + + foreach (var c in classes) { + // See if this is a Kotlin class + var attr = c.Attributes.OfType ().FirstOrDefault (); + var kotlin = attr?.Annotations.SingleOrDefault (a => a.Type == "Lkotlin/Metadata;"); + + if (kotlin is null) + continue; + + try { + var km = KotlinMetadata.FromAnnotation (kotlin); + var metadata = km.ParseMetadata (); + + if (metadata is null) + continue; + + // Do fixups only valid for full classes + var class_metadata = (metadata as KotlinClass); + + if (class_metadata != null) { + FixupClassVisibility (c, class_metadata); + + if (!c.AccessFlags.IsPubliclyVisible ()) + continue; + if (class_metadata.Constructors == null) + continue; + + foreach (var con in class_metadata.Constructors) + FixupConstructor (FindJavaConstructor (class_metadata, con, c), con); + } + + // Do fixups valid for both classes and modules + // (We pass "class_metadata" even though it's sometimes null because it's + // used for generic type resolution if available for class types) + FixupJavaMethods (c.Methods); + + if (metadata.Functions != null) { + // We work from Java methods to Kotlin metadata because they aren't a 1:1 relation + // and we need to find the "best" match for each Java method. + foreach (var java_method in c.Methods) + if (FindKotlinFunctionMetadata (metadata, java_method) is KotlinFunction function_metadata) + FixupFunction (java_method, function_metadata, class_metadata, inlineClasses); + } + + if (metadata.Properties != null) { + foreach (var prop in metadata.Properties) { + var getter = FindJavaPropertyGetter (metadata, prop, c, inlineClasses); + var setter = FindJavaPropertySetter (metadata, prop, c, inlineClasses); + + FixupProperty (getter, setter, prop, inlineClasses); + + FixupField (FindJavaFieldProperty (metadata, prop, c), prop); + } + } + + } catch (Exception ex) { + Log.Warning (0, $"class-parse: warning: Unable to parse Kotlin metadata on '{c.ThisClass.Name}': {ex}"); + } + } + } + + // Identifies Kotlin `@JvmInline value class` types in `classes` and stamps + // each `ClassFile.KotlinInlineClassUnderlyingJniType` with the JNI descriptor + // of its single backing field. Returns a map from the class's *Kotlin metadata* + // class-name representation (e.g. `com/example/MyColor;`) to that descriptor, + // for use when projecting `KotlinType.ClassName` references on parameters and + // return types of OTHER methods. See dotnet/java-interop#1431 (Phase 2). + static Dictionary DetectInlineClasses (IList classes) + { + var map = new Dictionary (StringComparer.Ordinal); + foreach (var c in classes) { + var ann = c.Attributes.OfType ().FirstOrDefault (); + if (ann is null) + continue; + + // `@JvmInline` is the JVM-level marker for Kotlin inline/value classes. + if (!ann.Annotations.Any (a => a.Type == "Lkotlin/jvm/JvmInline;")) + continue; + + // Sanity-check via Kotlin metadata: must be `kind == 1` (Class) and + // have IsInlineClass set. This filters out `@JvmInline` on things + // kotlinc may have emitted in the future for non-class kinds. + var meta = ann.Annotations.SingleOrDefault (a => a.Type == "Lkotlin/Metadata;"); + if (meta is null) + continue; + + try { + var km = KotlinMetadata.FromAnnotation (meta); + if (km.AsClassMetadata () is not KotlinClass kc) + continue; + if ((kc.Flags & KotlinClassFlags.IsInlineClass) == 0) + continue; + + // The single non-synthetic, non-static instance field is the + // inline-class backing value. (Synthetic fields like `Companion` + // are filtered out.) We additionally require: + // - exactly one such field exists (Kotlin inline classes have + // a single property; multiple non-synthetic instance fields + // means something else is going on and we shouldn't trust + // this as the backing field). + // - the field is a JVM *primitive* descriptor — the wrapper + // struct currently emits the underlying as a primitive + // C# type, so reference-backed inline classes (e.g. + // `value class Tag(val s: String)`) would produce wrong + // bindings. Skip these for now; they fall back to the + // standard peer-class binding path. + var instance_fields = c.Fields.Where (f => + !f.AccessFlags.HasFlag (FieldAccessFlags.Synthetic) && + !f.AccessFlags.HasFlag (FieldAccessFlags.Static)).ToList (); + if (instance_fields.Count != 1) + continue; + var backing = instance_fields [0]; + if (!IsJvmPrimitiveDescriptor (backing.Descriptor)) + continue; + + c.KotlinInlineClassUnderlyingJniType = backing.Descriptor; + + // Kotlin's `KotlinType.ClassName` strings are stored without the + // leading `L` but with a trailing `;` (e.g. `com/example/MyColor;`). + // We index by that form so callers can look up directly from + // `kotlin_p.Type.ClassName` without string surgery. + var jvmName = c.ThisClass.Name.Value + ";"; + map [jvmName] = backing.Descriptor; + } catch (Exception ex) { + Log.Warning (0, $"class-parse: warning: Unable to detect inline class on '{c.ThisClass.Name}': {ex}"); + } + } + return map; + } + + // JNI signature for the Kotlin inline class referenced by `kotlinTypeClassName`, + // or null when projection should not apply. The returned form has a + // leading `L` and trailing `;` so it matches `ClassFile.FullJniName` + // and other JNI-signature strings used throughout the pipeline. + // + // `jvmDescriptor` is the *JVM-erased* descriptor of the actual position + // (parameter / return / property) we're considering. We only project + // when it equals the inline class's underlying primitive: that's the + // case where Kotlin truly erased to the primitive and our wrapper + // struct's `implicit operator ` makes JNI marshaling work + // transparently. Boxed / nullable / generic positions keep their JVM + // reference signature (`L...MyColor;` or `Ljava/lang/Object;`); for + // those, projecting to a struct would mismatch JNI marshaling, so we + // fall through and let them keep the legacy peer-class binding path. + static string? GetInlineClassJniType (string? kotlinTypeClassName, string? jvmDescriptor, IDictionary inlineClasses) + { + if (kotlinTypeClassName is null || jvmDescriptor is null) + return null; + if (!inlineClasses.TryGetValue (kotlinTypeClassName, out var underlying)) + return null; + if (jvmDescriptor != underlying) + return null; + return "L" + kotlinTypeClassName; + } + + // Returns true for JVM primitive descriptors (Z/B/C/D/F/I/J/S). Excludes + // `V` (void), reference (`L...;`), and array (`[...`) descriptors. + static bool IsJvmPrimitiveDescriptor (string? descriptor) + { + if (descriptor is null || descriptor.Length != 1) + return false; + return descriptor [0] switch { + 'Z' or 'B' or 'C' or 'D' or 'F' or 'I' or 'J' or 'S' => true, + _ => false, + }; + } + + static void FixupClassVisibility (ClassFile klass, KotlinClass metadata) + { + // Hide class if it isn't Public/Protected + if (klass.AccessFlags.IsPubliclyVisible () && !metadata.Visibility.IsPubliclyVisible ()) { + + // Interfaces should be set to "package-private" + if (klass.AccessFlags.HasFlag (ClassAccessFlags.Interface)) { + Log.Debug ($"Kotlin: Setting internal interface {klass.ThisClass.Name.Value} to package-private"); + klass.AccessFlags = SetVisibility (klass.AccessFlags, null); + + foreach (var ic in klass.InnerClasses) { + Log.Debug ($"Kotlin: Setting nested type {ic.InnerClass.Name.Value} in an internal interface to package-private"); + ic.InnerClassAccessFlags = SetVisibility (ic.InnerClassAccessFlags, null); + } + + return; + } + + Log.Debug ($"Kotlin: Hiding internal class {klass.ThisClass.Name.Value}"); + klass.AccessFlags = SetVisibility (klass.AccessFlags, ClassAccessFlags.Private); + + foreach (var ic in klass.InnerClasses) { + Log.Debug ($"Kotlin: Hiding nested internal type {ic.InnerClass.Name.Value}"); + ic.InnerClassAccessFlags = SetVisibility (ic.InnerClassAccessFlags, ClassAccessFlags.Private); + } + + return; + } + } + + // Passing null for 'newVisibility' parameter means 'package-private' + internal static ClassAccessFlags SetVisibility (ClassAccessFlags existing, ClassAccessFlags? newVisibility) + { + // First we need to remove any existing visibility flags, + // without modifying other flags like Abstract + existing = (existing ^ ClassAccessFlags.Public) & existing; + existing = (existing ^ ClassAccessFlags.Protected) & existing; + existing = (existing ^ ClassAccessFlags.Private) & existing; + + // Package-private is stored as "no visibility flags", so only add flag if specified + if (newVisibility.HasValue) + existing |= newVisibility.Value; + + return existing; + } + + static MethodAccessFlags SetVisibility (MethodAccessFlags existing, MethodAccessFlags newVisibility) + { + // First we need to remove any existing visibility flags, + // without modifying other flags like Abstract + existing = (existing ^ MethodAccessFlags.Public) & existing; + existing = (existing ^ MethodAccessFlags.Protected) & existing; + existing = (existing ^ MethodAccessFlags.Private) & existing; + existing = (existing ^ MethodAccessFlags.Internal) & existing; + + existing |= newVisibility; + + return existing; + } + + static FieldAccessFlags SetVisibility (FieldAccessFlags existing, FieldAccessFlags newVisibility) + { + // First we need to remove any existing visibility flags, + // without modifying other flags like Abstract + existing = (existing ^ FieldAccessFlags.Public) & existing; + existing = (existing ^ FieldAccessFlags.Protected) & existing; + existing = (existing ^ FieldAccessFlags.Private) & existing; + existing = (existing ^ FieldAccessFlags.Internal) & existing; + + existing |= newVisibility; + + return existing; + } + + static void FixupJavaMethods (Methods methods) + { + // We do the following method level fixups here because we can operate on all methods, + // not just ones that have corresponding Kotlin metadata, like FixupFunction does. + + // Hide Kotlin generated methods like "add-impl" that aren't intended for end users + foreach (var method in methods.Where (m => m.IsPubliclyVisible && m.Name.IndexOf ("-impl", StringComparison.Ordinal) >= 0)) { + Log.Debug ($"Kotlin: Hiding implementation method {method.DeclaringType?.ThisClass.Name.Value} - {method.Name}"); + method.AccessFlags = MethodAccessFlags.Private; + } + + // Hide constructor if it's the synthetic DefaultConstructorMarker one + foreach (var method in methods.Where (method => method.IsDefaultConstructorMarker ())) { + Log.Debug ($"Kotlin: Hiding synthetic default constructor in class '{method.DeclaringType?.ThisClass.Name.Value}' with signature '{method.Descriptor}'"); + method.AccessFlags = ((method.AccessFlags ^ MethodAccessFlags.Public) & method.AccessFlags) | MethodAccessFlags.Private; + } + + // Better parameter names in extension methods + foreach (var method in methods.Where (m => m.IsPubliclyVisible && m.AccessFlags.HasFlag (MethodAccessFlags.Static))) + FixupExtensionMethod (method); + } + + static void FixupConstructor (MethodInfo? method, KotlinConstructor metadata) + { + if (method is null) + return; + + // Hide constructor if it isn't Public/Protected + if (method.IsPubliclyVisible && !metadata.Flags.IsPubliclyVisible ()) { + Log.Debug ($"Kotlin: Hiding internal constructor {method.DeclaringType?.ThisClass.Name.Value} - {metadata.GetSignature ()}"); + method.AccessFlags = SetVisibility (method.AccessFlags, MethodAccessFlags.Internal); + } + } + + static void FixupFunction (MethodInfo? method, KotlinFunction metadata, KotlinClass? kotlinClass, IDictionary inlineClasses) + { + if (method is null || !method.IsPubliclyVisible) + return; + + // Hide function if it isn't Public/Protected + if (!metadata.Flags.IsPubliclyVisible ()) { + Log.Debug ($"Kotlin: Hiding internal method {method.DeclaringType?.ThisClass.Name.Value} - {metadata.GetSignature ()}"); + method.AccessFlags = SetVisibility (method.AccessFlags, MethodAccessFlags.Internal); + return; + } + + (var start, var end) = CreateParameterMap (method, metadata, kotlinClass); + + var java_parameters = method.GetParameters (); + + for (var i = 0; i < end - start; i++) { + var java_p = java_parameters [start + i]; + var kotlin_p = metadata.ValueParameters == null ? null : metadata.ValueParameters [i]; + if (kotlin_p == null || kotlin_p.Type == null || kotlin_p.Name == null) + continue; + + // Kotlin provides actual parameter names + if (TypesMatch (java_p.Type, kotlin_p.Type, kotlinClass) && java_p.IsUnnamedParameter () && !kotlin_p.IsUnnamedParameter ()) { + Log.Debug ($"Kotlin: Renaming parameter {method.DeclaringType?.ThisClass.Name.Value} - {method.Name} - {java_p.Name} -> {kotlin_p.Name}"); + java_p.Name = kotlin_p.Name; + } + + // Handle erasure of Kotlin unsigned types + java_p.KotlinType = GetKotlinType (java_p.Type.TypeSignature, kotlin_p.Type.ClassName); + + // Inline-class projection: if the Kotlin source-level type for this + // parameter is a `@JvmInline value class` we know about AND the + // JVM-erased parameter descriptor is the inline class's + // underlying primitive, record its JNI signature so the + // generator can later swap the parameter type for a strongly- + // typed wrapper struct while keeping JNI marshaling on the + // underlying primitive. Boxed positions are skipped. + // See dotnet/java-interop#1431 (Phase 2). + java_p.KotlinInlineClassJniType = GetInlineClassJniType (kotlin_p.Type.ClassName, java_p.Type.TypeSignature, inlineClasses); + } + + // Handle erasure of Kotlin unsigned types + method.KotlinReturnType = GetKotlinType (method.ReturnType.TypeSignature, metadata.ReturnType?.ClassName); + + // Same projection as above, but for the return type. + method.KotlinInlineClassReturnJniType = GetInlineClassJniType (metadata.ReturnType?.ClassName, method.ReturnType.TypeSignature, inlineClasses); + + // Recover the unmangled Kotlin source-level name when the Kotlin + // compiler mangled the JVM name for inline-class binary compat + // (e.g. JVM name `tint-Rn_QMJI`, Kotlin name `tint`). The generator + // will emit this as the C# binding name (PascalCased to match + // `managedName` conventions); the JVM name stays the JNI invocation + // target. See dotnet/java-interop#1431 (Phase 2). + if (metadata.Name != null && metadata.JvmName != null && metadata.Name != metadata.JvmName) + method.KotlinName = PascalCase (metadata.Name); + } + + static string PascalCase (string name) + { + if (string.IsNullOrEmpty (name) || char.IsUpper (name [0])) + return name; + return char.ToUpperInvariant (name [0]) + name.Substring (1); + } + + public static (int start, int end) CreateParameterMap (MethodInfo method, KotlinFunction function, KotlinClass? kotlinClass) + { + var parameters = method.GetParameters (); + var start = 0; + var end = parameters.Length; + + // If the parameter counts are the same, that's good enough (because we know signatures matched) + if (IsValidParameterMap (method, function, start, end)) + return (start, end); + + // Remove the "hidden" receiver type parameter from the start of the parameter list + if (function.ReceiverType != null) + start++; + + if (IsValidParameterMap (method, function, start, end)) + return (start, end); + + var last_p = parameters.Last (); + + // Remove the "hidden" coroutine continuation type parameter from the end of the parameter list + // We try to restrict it to compiler generated paramteres because a user might have actually used it as a parameter + if (last_p.Type.BinaryName == "Lkotlin/coroutines/Continuation;" && (last_p.IsUnnamedParameter () || last_p.IsCompilerNamed ())) + end--; + + if (IsValidParameterMap (method, function, start, end)) + return (start, end); + + // Remove the "hidden" "this" type parameter for a static method from the start of the parameter list + // Note we do this last because sometimes it isn't there. + if (method.AccessFlags.HasFlag (MethodAccessFlags.Static)) + start++; + + if (IsValidParameterMap (method, function, start, end)) + return (start, end); + + return (0, 0); + } + + static bool IsValidParameterMap (MethodInfo method, KotlinFunction function, int start, int end) => function.ValueParameters?.Count == end - start; + + static void FixupExtensionMethod (MethodInfo method) + { + // Kotlin "extension" methods give the first parameter an ugly name + // like "$this$toByteString", we change it to "obj" to be a bit nicer. + var param = method.GetParameters (); + + if (param.Length > 0 && param [0].Name.StartsWith ("$this$", StringComparison.Ordinal)) { + Log.Debug ($"Kotlin: Renaming extension parameter {method.DeclaringType?.ThisClass.Name.Value} - {method.Name} - {param [0].Name} -> obj"); + param [0].Name = "obj"; + } + } + + static void FixupProperty (MethodInfo? getter, MethodInfo? setter, KotlinProperty metadata, IDictionary inlineClasses) + { + if (getter is null && setter is null) + return; + + // Hide getters/setters if property is Internal + if (metadata.IsInternalVisibility) { + + if (getter?.IsPubliclyVisible == true) { + Log.Debug ($"Kotlin: Hiding internal getter method {getter.DeclaringType?.ThisClass.Name.Value} - {getter.Name}"); + getter.AccessFlags = SetVisibility (getter.AccessFlags, MethodAccessFlags.Internal); + } + + if (setter?.IsPubliclyVisible == true) { + Log.Debug ($"Kotlin: Hiding internal setter method {setter.DeclaringType?.ThisClass.Name.Value} - {setter.Name}"); + setter.AccessFlags = SetVisibility (setter.AccessFlags, MethodAccessFlags.Internal); + } + + return; + } + + // Handle erasure of Kotlin unsigned types + if (getter != null) { + getter.KotlinReturnType = GetKotlinType (getter.ReturnType.TypeSignature, metadata.ReturnType?.ClassName); + getter.KotlinInlineClassReturnJniType = GetInlineClassJniType (metadata.ReturnType?.ClassName, getter.ReturnType.TypeSignature, inlineClasses); + } + + if (setter != null) { + var setter_parameter = setter.GetParameters ().First (); + + if (setter_parameter.IsUnnamedParameter () || setter_parameter.Name == "") { + Log.Debug ($"Kotlin: Renaming setter parameter {setter.DeclaringType?.ThisClass.Name.Value} - {setter.Name} - {setter_parameter.Name} -> value"); + setter_parameter.Name = "value"; + } + + // Handle erasure of Kotlin unsigned types + setter_parameter.KotlinType = GetKotlinType (setter_parameter.Type.TypeSignature, metadata.ReturnType?.ClassName); + setter_parameter.KotlinInlineClassJniType = GetInlineClassJniType (metadata.ReturnType?.ClassName, setter_parameter.Type.TypeSignature, inlineClasses); + } + } + + static void FixupField (FieldInfo? field, KotlinProperty metadata) + { + if (field is null) + return; + + // Hide field if it isn't Public/Protected + if (!metadata.Flags.IsPubliclyVisible ()) { + + if (field.IsPubliclyVisible) { + Log.Debug ($"Kotlin: Hiding internal field {field.DeclaringType?.ThisClass.Name.Value} - {field.Name}"); + field.AccessFlags = SetVisibility (field.AccessFlags, FieldAccessFlags.Internal); + } + } + + // Handle erasure of Kotlin unsigned types + field.KotlinType = GetKotlinType (field.Descriptor, metadata.ReturnType?.ClassName); + } + + static MethodInfo? FindJavaConstructor (KotlinClass kotlinClass, KotlinConstructor constructor, ClassFile klass) + { + var all_constructors = klass.Methods.Where (method => method.Name == "" || method.Name == ""); + var possible_constructors = all_constructors.Where (method => method.GetFilteredParameters ().Length == constructor.ValueParameters?.Count); + + foreach (var method in possible_constructors) { + if (ParametersMatch (kotlinClass, method, constructor.ValueParameters!)) + return method; + } + + return null; + } + + static KotlinFunction? FindKotlinFunctionMetadata (KotlinFile? kotlinFile, MethodInfo javaMethod) + { + if (kotlinFile?.Functions is null) + return null; + + var java_descriptor = javaMethod.Descriptor; + + // The method name absolutely has to match + var possible_functions = kotlinFile.Functions.Where (f => f.JvmName == javaMethod.Name).ToArray (); + + // If we have metadata with a Descriptor/JvmSignature match, that means all parameters and return type match + if (possible_functions.SingleOrDefault (f => f.JvmSignature != null && f.JvmSignature == java_descriptor) is KotlinFunction kf) + return kf; + + // Sometimes JvmSignature is null (or unhelpful), so we're going to construct one ourselves and see if they match + if (possible_functions.SingleOrDefault (f => f.ConstructJvmSignature () == java_descriptor) is KotlinFunction kf2) + return kf2; + + // If that didn't work, let's try it the hard way! + // This catches cases where Kotlin only wrote one metadata entry for multiple methods with the same mangled JvmName (ex: contains-WZ4Q5Ns) + var java_param_count = javaMethod.GetFilteredParameters ().Length; + + foreach (var function in possible_functions.Where (f => f.ValueParameters?.Count == java_param_count)) { + if (function.ReturnType == null) + continue; + if (!TypesMatch (javaMethod.ReturnType, function.ReturnType, kotlinFile)) + continue; + + if (!ParametersMatch (kotlinFile, javaMethod, function.ValueParameters!)) + continue; + + return function; + } + + return null; + } + + static FieldInfo? FindJavaFieldProperty (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) + { + var possible_methods = klass.Fields.Where (field => field.Name == property.Name && + property.ReturnType != null && + TypesMatch (new TypeInfo (field.Descriptor, field.Descriptor), property.ReturnType, kotlinClass)); + + return possible_methods.FirstOrDefault (); + } + + static MethodInfo? FindJavaPropertyGetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass, IDictionary inlineClasses) + { + // Private properties do not have getters + if (property.IsPrivateVisibility) + return null; + + // Public/protected getters look like "getFoo" + // Public/protected getters with unsigned types look like "getFoo-abcdefg" + // Internal getters look like "getFoo$main" + // Internal getters with unsigned types look like "getFoo-WZ4Q5Ns$main" + var possible_methods = property.IsInternalVisibility ? + klass.Methods.Where (method => method.GetMethodNameWithoutUnsignedSuffix ().StartsWith ($"get{property.Name.Capitalize ()}$", StringComparison.Ordinal)) : + klass.Methods.Where (method => method.GetMethodNameWithoutUnsignedSuffix ().Equals ($"get{property.Name.Capitalize ()}", StringComparison.Ordinal)); + + possible_methods = possible_methods.Where (method => + method.GetParameters ().Length == 0 && + property.ReturnType != null && + TypesMatch (method.ReturnType, property.ReturnType, kotlinClass, inlineClasses)); + + return possible_methods.FirstOrDefault (); + } + + static MethodInfo? FindJavaPropertySetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass, IDictionary inlineClasses) + { + // Private properties do not have setters + if (property.IsPrivateVisibility) + return null; + + // Public/protected setters look like "setFoo" + // Public/protected setters with unsigned types look like "setFoo-abcdefg" + // Internal setters look like "setFoo$main" + // Internal setters with unsigned types look like "setFoo-WZ4Q5Ns$main" + var possible_methods = property.IsInternalVisibility ? + klass.Methods.Where (method => method.GetMethodNameWithoutUnsignedSuffix ().StartsWith ($"set{property.Name.Capitalize ()}$", StringComparison.Ordinal)) : + klass.Methods.Where (method => method.GetMethodNameWithoutUnsignedSuffix ().Equals ($"set{property.Name.Capitalize ()}", StringComparison.Ordinal)); + + possible_methods = possible_methods.Where (method => + property.ReturnType != null && + method.GetParameters ().Length == 1 && + method.ReturnType.BinaryName == "V" && + TypesMatch (method.GetParameters () [0].Type, property.ReturnType, kotlinClass, inlineClasses)); + + return possible_methods.FirstOrDefault (); + } + + static bool ParametersMatch (KotlinFile kotlinClass, MethodInfo method, List kotlinParameters) + { + var java_parameters = method.GetFilteredParameters (); + + if (java_parameters.Length == 0 && kotlinParameters.Count == 0) + return true; + + for (var i = 0; i < java_parameters.Length; i++) { + var java_p = java_parameters [i]; + var kotlin_p = kotlinParameters [i]; + + if (kotlin_p.Type == null || !TypesMatch (java_p.Type, kotlin_p.Type, kotlinClass)) + return false; + } + + return true; + } + + static bool TypesMatch (TypeInfo javaType, KotlinType kotlinType, KotlinFile? kotlinFile, IDictionary? inlineClasses = null) + { + // Generic type + if (!string.IsNullOrWhiteSpace (kotlinType.TypeParameterName) && $"T{kotlinType.TypeParameterName};" == javaType.TypeSignature) + return true; + + if (javaType.BinaryName == KotlinUtilities.ConvertKotlinTypeSignature (kotlinType, kotlinFile)) + return true; + + // Could be a generic type erasure + if (javaType.BinaryName == "Ljava/lang/Object;") + return true; + + // dotnet/java-interop#1431 (Phase 2): the JVM erases @JvmInline value + // class types to their underlying primitive descriptor, so e.g. a + // `MyColor` property (ULong-backed) appears in the bytecode as `()J` + // even though the Kotlin metadata still says `MyColor`. Accept the + // match when the JVM primitive matches the inline class's recorded + // underlying-primitive descriptor. + if (inlineClasses != null && IsJvmPrimitiveDescriptor (javaType.BinaryName) && + kotlinType.ClassName != null && + inlineClasses.TryGetValue (kotlinType.ClassName, out var underlying) && + underlying == javaType.BinaryName) + return true; + + // Sometimes Kotlin keeps its native types rather than converting them to Java native types + // ie: "Lkotlin/UShort;" instead of "S" + if (javaType.BinaryName.StartsWith ("L", StringComparison.Ordinal) && javaType.BinaryName.EndsWith (";", StringComparison.Ordinal)) { + if (KotlinUtilities.ConvertKotlinClassToJava (javaType.BinaryName.Substring (1, javaType.BinaryName.Length - 2)) == KotlinUtilities.ConvertKotlinTypeSignature (kotlinType, kotlinFile)) + return true; + } + + // Same for some arrays + if (javaType.BinaryName.StartsWith ("[L", StringComparison.Ordinal) && javaType.BinaryName.EndsWith (";", StringComparison.Ordinal)) { + if ("[" + KotlinUtilities.ConvertKotlinClassToJava (javaType.BinaryName.Substring (2, javaType.BinaryName.Length - 3)) == KotlinUtilities.ConvertKotlinTypeSignature (kotlinType, kotlinFile)) + return true; + } + + return false; + } + + static string? GetKotlinType (string? jvmType, string? kotlinClass) + { + // Handle erasure of Kotlin unsigned types + if (jvmType == "I" && kotlinClass == "kotlin/UInt;") + return "uint"; + if (jvmType == "[I" && kotlinClass == "kotlin/UIntArray;") + return "uint[]"; + if (jvmType == "S" && kotlinClass == "kotlin/UShort;") + return "ushort"; + if (jvmType == "[S" && kotlinClass == "kotlin/UShortArray;") + return "ushort[]"; + if (jvmType == "J" && kotlinClass == "kotlin/ULong;") + return "ulong"; + if (jvmType == "[J" && kotlinClass == "kotlin/ULongArray;") + return "ulong[]"; + if (jvmType == "B" && kotlinClass == "kotlin/UByte;") + return "ubyte"; + if (jvmType == "[B" && kotlinClass == "kotlin/UByteArray;") + return "ubyte[]"; + + return null; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinMetadata.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinMetadata.cs new file mode 100644 index 00000000000..237a01fb319 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinMetadata.cs @@ -0,0 +1,161 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using ProtoBuf; + +namespace Xamarin.Android.Tools.Bytecode +{ + // https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jvm/runtime/kotlin/Metadata.kt + public class KotlinMetadata + { + public KotlinMetadataKind Kind { get; set; } + + // The version of the metadata provided in the arguments of this annotation. + public Version? MetadataVersion { get; set; } + + // The version of the bytecode interface (naming conventions, signatures) of the class file annotated with this annotation. + public Version? ByteCodeVersion { get; set; } + + // Metadata in a custom format. The format may be different (or even absent) for different kinds. + public string[]? Data1 { get; set; } + + // An addition to [d1]: array of strings which occur in metadata, written in plain text so that strings already present + // in the constant pool are reused. These strings may be then indexed in the metadata by an integer index in this array. + public string[]? Data2 { get; set; } + + public static KotlinMetadata FromAnnotation (Annotation annotation) + { + var k = GetValue (annotation, "k"); + var km = new KotlinMetadata { + ByteCodeVersion = ParseVersion (annotation, "bv"), + Kind = k == null ? (KotlinMetadataKind) 0 : (KotlinMetadataKind) ParseInteger (k), + MetadataVersion = ParseVersion (annotation, "mv") + }; + + km.Data1 = GetValues (annotation, "d1"); + km.Data2 = GetValues (annotation, "d2"); + + return km; + } + + public KotlinFile? ParseMetadata () + { + switch (Kind) { + case KotlinMetadataKind.Class: + return AsClassMetadata (); + case KotlinMetadataKind.File: + return AsFileMetadata (); + default: + return null; + } + } + + public KotlinClass? AsClassMetadata () + { + if (Kind != KotlinMetadataKind.Class) + return null; + + var data = ParseStream (); + if (data == null) { + return null; + } + return KotlinClass.FromProtobuf (data.Item1, data.Item2); + } + + public KotlinFile? AsFileMetadata () + { + if (Kind != KotlinMetadataKind.File) + return null; + + var data = ParseStream (); + if (data == null) { + return null; + } + return KotlinFile.FromProtobuf (data.Item1, data.Item2); + } + + Tuple? ParseStream () + { + if (Data1 == null || Data2 == null) { + throw new InvalidOperationException ("Data1 is null; should not be reached."); + } + + var md = KotlinBitEncoding.DecodeBytes (Data1); + + using (var ms = ToMemoryStream (md)) { + + // The first element is the length of the string table + var first = ms.ReadByte (); + + if (first == -1) + return null; + + ms.Position = 0; + + var size = KotlinBitEncoding.ReadRawVarint32 (ms); + + using (var partial = new PartialStream (ms, ms.Position, size)) { + + // Read the string table from the stream + var string_table = Serializer.Deserialize (partial); + var resolver = new JvmNameResolver (string_table, Data2.ToList ()); + + partial.MoveNext (); + + // Read the metadata structure from the stream + var metadata = Serializer.Deserialize (partial); + return Tuple.Create (metadata, resolver); + } + } + } + + static MemoryStream ToMemoryStream (byte [] bytes) => new MemoryStream (bytes); + + static Version? ParseVersion (Annotation annotation, string key) + { + var value = GetValue (annotation, key); + + // Version is missing or empty + if (value is null || value == "[]") + return null; + + var values = value.Trim ('[', ']').Split (',').Select (v => ParseInteger (v)).ToArray (); + + return new Version (values [0], values [1], values [2]); + } + + static string? GetValue (Annotation annotation, string key) + { + return annotation.Values.FirstOrDefault (v => v.Key == key).Value?.ToString (); + } + + static string[]? GetValues (Annotation annotation, string key) + { + var array = annotation.Values.FirstOrDefault (v => v.Key == key).Value as AnnotationElementArray; + if (array == null || array.Values == null) { + return null; + } + var constants = array.Values.Cast (); + return constants.Select (c => c.Value!) + .Where (v => v != null) + .ToArray (); + } + + static int ParseInteger (string value) + { + value = value.Replace ("Integer", "").Trim ('(', ')', ' '); + + return int.Parse (value); + } + } + + public enum KotlinMetadataKind + { + Class = 1, + File = 2, + SyntheticClass = 3, + MultiFileClassFacade = 4, + MultiFileClassPart = 5 + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinProtobufDefinition.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinProtobufDefinition.cs new file mode 100644 index 00000000000..2dd0c863909 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinProtobufDefinition.cs @@ -0,0 +1,1440 @@ +#nullable disable + +// This file was generated by a tool; you should avoid making direct changes. +// Consider using 'partial classes' to extend these types +// Input: my.proto + +#pragma warning disable CS1591, CS0612, CS3021, IDE1006 +namespace org.jetbrains.kotlin.metadata.jvm +{ + + [global::ProtoBuf.ProtoContract ()] + partial class StringTable : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"string")] + public global::System.Collections.Generic.List Strings { get; set; } = new global::System.Collections.Generic.List (); + + } + + [global::ProtoBuf.ProtoContract ()] + partial class QualifiedNameTable : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"qualified_name")] + public global::System.Collections.Generic.List QualifiedNames { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoContract ()] + public partial class QualifiedName : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"parent_qualified_name")] + [global::System.ComponentModel.DefaultValue (-1)] + public int ParentQualifiedName { + get { return __pbn__ParentQualifiedName ?? -1; } + set { __pbn__ParentQualifiedName = value; } + } + public bool ShouldSerializeParentQualifiedName () => __pbn__ParentQualifiedName != null; + public void ResetParentQualifiedName () => __pbn__ParentQualifiedName = null; + private int? __pbn__ParentQualifiedName; + + [global::ProtoBuf.ProtoMember (2, Name = @"short_name", IsRequired = true)] + public int ShortName { get; set; } + + [global::ProtoBuf.ProtoMember (3)] + [global::System.ComponentModel.DefaultValue (Kind.Package)] + public Kind kind { + get { return __pbn__kind ?? Kind.Package; } + set { __pbn__kind = value; } + } + public bool ShouldSerializekind () => __pbn__kind != null; + public void Resetkind () => __pbn__kind = null; + private Kind? __pbn__kind; + + [global::ProtoBuf.ProtoContract ()] + public enum Kind + { + [global::ProtoBuf.ProtoEnum (Name = @"CLASS")] + Class = 0, + [global::ProtoBuf.ProtoEnum (Name = @"PACKAGE")] + Package = 1, + [global::ProtoBuf.ProtoEnum (Name = @"LOCAL")] + Local = 2, + } + + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Annotation : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"id", IsRequired = true)] + public int Id { get; set; } + + [global::ProtoBuf.ProtoMember (2, Name = @"argument")] + public global::System.Collections.Generic.List Arguments { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoContract ()] + public partial class Argument : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"name_id", IsRequired = true)] + public int NameId { get; set; } + + [global::ProtoBuf.ProtoMember (2, IsRequired = true)] + public Value value { get; set; } + + [global::ProtoBuf.ProtoContract ()] + public partial class Value : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1)] + [global::System.ComponentModel.DefaultValue (Type.Byte)] + public Type type { + get { return __pbn__type ?? Type.Byte; } + set { __pbn__type = value; } + } + public bool ShouldSerializetype () => __pbn__type != null; + public void Resettype () => __pbn__type = null; + private Type? __pbn__type; + + [global::ProtoBuf.ProtoMember (2, Name = @"int_value", DataFormat = global::ProtoBuf.DataFormat.ZigZag)] + public long IntValue { + get { return __pbn__IntValue.GetValueOrDefault (); } + set { __pbn__IntValue = value; } + } + public bool ShouldSerializeIntValue () => __pbn__IntValue != null; + public void ResetIntValue () => __pbn__IntValue = null; + private long? __pbn__IntValue; + + [global::ProtoBuf.ProtoMember (3, Name = @"float_value")] + public float FloatValue { + get { return __pbn__FloatValue.GetValueOrDefault (); } + set { __pbn__FloatValue = value; } + } + public bool ShouldSerializeFloatValue () => __pbn__FloatValue != null; + public void ResetFloatValue () => __pbn__FloatValue = null; + private float? __pbn__FloatValue; + + [global::ProtoBuf.ProtoMember (4, Name = @"double_value")] + public double DoubleValue { + get { return __pbn__DoubleValue.GetValueOrDefault (); } + set { __pbn__DoubleValue = value; } + } + public bool ShouldSerializeDoubleValue () => __pbn__DoubleValue != null; + public void ResetDoubleValue () => __pbn__DoubleValue = null; + private double? __pbn__DoubleValue; + + [global::ProtoBuf.ProtoMember (5, Name = @"string_value")] + public int StringValue { + get { return __pbn__StringValue.GetValueOrDefault (); } + set { __pbn__StringValue = value; } + } + public bool ShouldSerializeStringValue () => __pbn__StringValue != null; + public void ResetStringValue () => __pbn__StringValue = null; + private int? __pbn__StringValue; + + [global::ProtoBuf.ProtoMember (6, Name = @"class_id")] + public int ClassId { + get { return __pbn__ClassId.GetValueOrDefault (); } + set { __pbn__ClassId = value; } + } + public bool ShouldSerializeClassId () => __pbn__ClassId != null; + public void ResetClassId () => __pbn__ClassId = null; + private int? __pbn__ClassId; + + [global::ProtoBuf.ProtoMember (7, Name = @"enum_value_id")] + public int EnumValueId { + get { return __pbn__EnumValueId.GetValueOrDefault (); } + set { __pbn__EnumValueId = value; } + } + public bool ShouldSerializeEnumValueId () => __pbn__EnumValueId != null; + public void ResetEnumValueId () => __pbn__EnumValueId = null; + private int? __pbn__EnumValueId; + + [global::ProtoBuf.ProtoMember (8, Name = @"annotation")] + public Annotation Annotation { get; set; } + + [global::ProtoBuf.ProtoMember (9, Name = @"array_element")] + public global::System.Collections.Generic.List ArrayElements { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (11, Name = @"array_dimension_count")] + [global::System.ComponentModel.DefaultValue (0)] + public int ArrayDimensionCount { + get { return __pbn__ArrayDimensionCount ?? 0; } + set { __pbn__ArrayDimensionCount = value; } + } + public bool ShouldSerializeArrayDimensionCount () => __pbn__ArrayDimensionCount != null; + public void ResetArrayDimensionCount () => __pbn__ArrayDimensionCount = null; + private int? __pbn__ArrayDimensionCount; + + [global::ProtoBuf.ProtoMember (10, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (0)] + public int Flags { + get { return __pbn__Flags ?? 0; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoContract ()] + public enum Type + { + [global::ProtoBuf.ProtoEnum (Name = @"BYTE")] + Byte = 0, + [global::ProtoBuf.ProtoEnum (Name = @"CHAR")] + Char = 1, + [global::ProtoBuf.ProtoEnum (Name = @"SHORT")] + Short = 2, + [global::ProtoBuf.ProtoEnum (Name = @"INT")] + Int = 3, + [global::ProtoBuf.ProtoEnum (Name = @"LONG")] + Long = 4, + [global::ProtoBuf.ProtoEnum (Name = @"FLOAT")] + Float = 5, + [global::ProtoBuf.ProtoEnum (Name = @"DOUBLE")] + Double = 6, + [global::ProtoBuf.ProtoEnum (Name = @"BOOLEAN")] + Boolean = 7, + [global::ProtoBuf.ProtoEnum (Name = @"STRING")] + String = 8, + [global::ProtoBuf.ProtoEnum (Name = @"CLASS")] + Class = 9, + [global::ProtoBuf.ProtoEnum (Name = @"ENUM")] + Enum = 10, + [global::ProtoBuf.ProtoEnum (Name = @"ANNOTATION")] + Annotation = 11, + [global::ProtoBuf.ProtoEnum (Name = @"ARRAY")] + Array = 12, + } + + } + + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Type : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (2, Name = @"argument")] + public global::System.Collections.Generic.List Arguments { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (3, Name = @"nullable")] + [global::System.ComponentModel.DefaultValue (false)] + public bool Nullable { + get { return __pbn__Nullable ?? false; } + set { __pbn__Nullable = value; } + } + public bool ShouldSerializeNullable () => __pbn__Nullable != null; + public void ResetNullable () => __pbn__Nullable = null; + private bool? __pbn__Nullable; + + [global::ProtoBuf.ProtoMember (4, Name = @"flexible_type_capabilities_id")] + public int? FlexibleTypeCapabilitiesId { + get { return __pbn__FlexibleTypeCapabilitiesId; } + set { __pbn__FlexibleTypeCapabilitiesId = value; } + } + public bool ShouldSerializeFlexibleTypeCapabilitiesId () => __pbn__FlexibleTypeCapabilitiesId != null; + public void ResetFlexibleTypeCapabilitiesId () => __pbn__FlexibleTypeCapabilitiesId = null; + private int? __pbn__FlexibleTypeCapabilitiesId; + + [global::ProtoBuf.ProtoMember (5, Name = @"flexible_upper_bound")] + public Type FlexibleUpperBound { get; set; } + + [global::ProtoBuf.ProtoMember (8, Name = @"flexible_upper_bound_id")] + public int? FlexibleUpperBoundId { + get { return __pbn__FlexibleUpperBoundId; } + set { __pbn__FlexibleUpperBoundId = value; } + } + public bool ShouldSerializeFlexibleUpperBoundId () => __pbn__FlexibleUpperBoundId != null; + public void ResetFlexibleUpperBoundId () => __pbn__FlexibleUpperBoundId = null; + private int? __pbn__FlexibleUpperBoundId; + + [global::ProtoBuf.ProtoMember (6, Name = @"class_name")] + public int? ClassName { + get { return __pbn__ClassName; } + set { __pbn__ClassName = value; } + } + public bool ShouldSerializeClassName () => __pbn__ClassName != null; + public void ResetClassName () => __pbn__ClassName = null; + private int? __pbn__ClassName; + + [global::ProtoBuf.ProtoMember (7, Name = @"type_parameter")] + public int? TypeParameter { + get { return __pbn__TypeParameter; } + set { __pbn__TypeParameter = value; } + } + public bool ShouldSerializeTypeParameter () => __pbn__TypeParameter != null; + public void ResetTypeParameter () => __pbn__TypeParameter = null; + private int? __pbn__TypeParameter; + + [global::ProtoBuf.ProtoMember (9, Name = @"type_parameter_name")] + public int? TypeParameterName { + get { return __pbn__TypeParameterName; } + set { __pbn__TypeParameterName = value; } + } + public bool ShouldSerializeTypeParameterName () => __pbn__TypeParameterName != null; + public void ResetTypeParameterName () => __pbn__TypeParameterName = null; + private int? __pbn__TypeParameterName; + + [global::ProtoBuf.ProtoMember (12, Name = @"type_alias_name")] + public int? TypeAliasName { + get { return __pbn__TypeAliasName; } + set { __pbn__TypeAliasName = value; } + } + public bool ShouldSerializeTypeAliasName () => __pbn__TypeAliasName != null; + public void ResetTypeAliasName () => __pbn__TypeAliasName = null; + private int? __pbn__TypeAliasName; + + [global::ProtoBuf.ProtoMember (10, Name = @"outer_type")] + public Type OuterType { get; set; } + + [global::ProtoBuf.ProtoMember (11, Name = @"outer_type_id")] + public int? OuterTypeId { + get { return __pbn__OuterTypeId; } + set { __pbn__OuterTypeId = value; } + } + public bool ShouldSerializeOuterTypeId () => __pbn__OuterTypeId != null; + public void ResetOuterTypeId () => __pbn__OuterTypeId = null; + private int? __pbn__OuterTypeId; + + [global::ProtoBuf.ProtoMember (13, Name = @"abbreviated_type")] + public Type AbbreviatedType { get; set; } + + [global::ProtoBuf.ProtoMember (14, Name = @"abbreviated_type_id")] + public int? AbbreviatedTypeId { + get { return __pbn__AbbreviatedTypeId; } + set { __pbn__AbbreviatedTypeId = value; } + } + public bool ShouldSerializeAbbreviatedTypeId () => __pbn__AbbreviatedTypeId != null; + public void ResetAbbreviatedTypeId () => __pbn__AbbreviatedTypeId = null; + private int? __pbn__AbbreviatedTypeId; + + [global::ProtoBuf.ProtoMember (1, Name = @"flags")] + public int Flags { + get { return __pbn__Flags.GetValueOrDefault (); } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoContract ()] + public partial class Argument : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1)] + [global::System.ComponentModel.DefaultValue (Projection.Inv)] + public Projection projection { + get { return __pbn__projection ?? Projection.Inv; } + set { __pbn__projection = value; } + } + public bool ShouldSerializeprojection () => __pbn__projection != null; + public void Resetprojection () => __pbn__projection = null; + private Projection? __pbn__projection; + + [global::ProtoBuf.ProtoMember (2, Name = @"type")] + public Type Type { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"type_id")] + public int TypeId { + get { return __pbn__TypeId.GetValueOrDefault (); } + set { __pbn__TypeId = value; } + } + public bool ShouldSerializeTypeId () => __pbn__TypeId != null; + public void ResetTypeId () => __pbn__TypeId = null; + private int? __pbn__TypeId; + + [global::ProtoBuf.ProtoContract ()] + public enum Projection + { + [global::ProtoBuf.ProtoEnum (Name = @"IN")] + In = 0, + [global::ProtoBuf.ProtoEnum (Name = @"OUT")] + Out = 1, + [global::ProtoBuf.ProtoEnum (Name = @"INV")] + Inv = 2, + [global::ProtoBuf.ProtoEnum (Name = @"STAR")] + Star = 3, + } + + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class TypeParameter : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"id", IsRequired = true)] + public int Id { get; set; } + + [global::ProtoBuf.ProtoMember (2, Name = @"name", IsRequired = true)] + public int Name { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"reified")] + [global::System.ComponentModel.DefaultValue (false)] + public bool Reified { + get { return __pbn__Reified ?? false; } + set { __pbn__Reified = value; } + } + public bool ShouldSerializeReified () => __pbn__Reified != null; + public void ResetReified () => __pbn__Reified = null; + private bool? __pbn__Reified; + + [global::ProtoBuf.ProtoMember (4)] + [global::System.ComponentModel.DefaultValue (Variance.Inv)] + public Variance variance { + get { return __pbn__variance ?? Variance.Inv; } + set { __pbn__variance = value; } + } + public bool ShouldSerializevariance () => __pbn__variance != null; + public void Resetvariance () => __pbn__variance = null; + private Variance? __pbn__variance; + + [global::ProtoBuf.ProtoMember (5, Name = @"upper_bound")] + public global::System.Collections.Generic.List UpperBounds { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (6, Name = @"upper_bound_id", IsPacked = true)] + public int [] UpperBoundIds { get; set; } + + [global::ProtoBuf.ProtoContract ()] + public enum Variance + { + [global::ProtoBuf.ProtoEnum (Name = @"IN")] + In = 0, + [global::ProtoBuf.ProtoEnum (Name = @"OUT")] + Out = 1, + [global::ProtoBuf.ProtoEnum (Name = @"INV")] + Inv = 2, + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Class : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (6)] + public int Flags { + get { return __pbn__Flags ?? 6; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoMember (3, Name = @"fq_name", IsRequired = true)] + public int FqName { get; set; } + + [global::ProtoBuf.ProtoMember (4, Name = @"companion_object_name")] + public int CompanionObjectName { + get { return __pbn__CompanionObjectName.GetValueOrDefault (); } + set { __pbn__CompanionObjectName = value; } + } + public bool ShouldSerializeCompanionObjectName () => __pbn__CompanionObjectName != null; + public void ResetCompanionObjectName () => __pbn__CompanionObjectName = null; + private int? __pbn__CompanionObjectName; + + [global::ProtoBuf.ProtoMember (5, Name = @"type_parameter")] + public global::System.Collections.Generic.List TypeParameters { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (6, Name = @"supertype")] + public global::System.Collections.Generic.List Supertypes { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (2, Name = @"supertype_id", IsPacked = true)] + public int [] SupertypeIds { get; set; } + + [global::ProtoBuf.ProtoMember (7, Name = @"nested_class_name", IsPacked = true)] + public int [] NestedClassNames { get; set; } + + [global::ProtoBuf.ProtoMember (8, Name = @"constructor")] + public global::System.Collections.Generic.List Constructors { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (9, Name = @"function")] + public global::System.Collections.Generic.List Functions { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (10, Name = @"property")] + public global::System.Collections.Generic.List Properties { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (11, Name = @"type_alias")] + public global::System.Collections.Generic.List TypeAlias { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (13, Name = @"enum_entry")] + public global::System.Collections.Generic.List EnumEntries { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (16, Name = @"sealed_subclass_fq_name", IsPacked = true)] + public int [] SealedSubclassFqNames { get; set; } + + [global::ProtoBuf.ProtoMember (30, Name = @"type_table")] + public TypeTable TypeTable { get; set; } + + [global::ProtoBuf.ProtoMember (31, Name = @"version_requirement")] + public int [] VersionRequirements { get; set; } + + [global::ProtoBuf.ProtoMember (32, Name = @"version_requirement_table")] + public VersionRequirementTable VersionRequirementTable { get; set; } + + [global::ProtoBuf.ProtoContract ()] + public enum Kind + { + [global::ProtoBuf.ProtoEnum (Name = @"CLASS")] + Class = 0, + [global::ProtoBuf.ProtoEnum (Name = @"INTERFACE")] + Interface = 1, + [global::ProtoBuf.ProtoEnum (Name = @"ENUM_CLASS")] + EnumClass = 2, + [global::ProtoBuf.ProtoEnum (Name = @"ENUM_ENTRY")] + EnumEntry = 3, + [global::ProtoBuf.ProtoEnum (Name = @"ANNOTATION_CLASS")] + AnnotationClass = 4, + [global::ProtoBuf.ProtoEnum (Name = @"OBJECT")] + Object = 5, + [global::ProtoBuf.ProtoEnum (Name = @"COMPANION_OBJECT")] + CompanionObject = 6, + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Package : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (3, Name = @"function")] + public global::System.Collections.Generic.List Functions { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (4, Name = @"property")] + public global::System.Collections.Generic.List Properties { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (5, Name = @"type_alias")] + public global::System.Collections.Generic.List TypeAlias { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (30, Name = @"type_table")] + public TypeTable TypeTable { get; set; } + + [global::ProtoBuf.ProtoMember (32, Name = @"version_requirement_table")] + public VersionRequirementTable VersionRequirementTable { get; set; } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class TypeTable : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"type")] + public global::System.Collections.Generic.List Types { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (2, Name = @"first_nullable")] + [global::System.ComponentModel.DefaultValue (-1)] + public int FirstNullable { + get { return __pbn__FirstNullable ?? -1; } + set { __pbn__FirstNullable = value; } + } + public bool ShouldSerializeFirstNullable () => __pbn__FirstNullable != null; + public void ResetFirstNullable () => __pbn__FirstNullable = null; + private int? __pbn__FirstNullable; + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Constructor : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (6)] + public int Flags { + get { return __pbn__Flags ?? 6; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoMember (2, Name = @"value_parameter")] + public global::System.Collections.Generic.List ValueParameters { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (31, Name = @"version_requirement")] + public int [] VersionRequirements { get; set; } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Function : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (9, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (6)] + public int Flags { + get { return __pbn__Flags ?? 6; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoMember (1, Name = @"old_flags")] + [global::System.ComponentModel.DefaultValue (6)] + public int OldFlags { + get { return __pbn__OldFlags ?? 6; } + set { __pbn__OldFlags = value; } + } + public bool ShouldSerializeOldFlags () => __pbn__OldFlags != null; + public void ResetOldFlags () => __pbn__OldFlags = null; + private int? __pbn__OldFlags; + + [global::ProtoBuf.ProtoMember (2, Name = @"name", IsRequired = true)] + public int Name { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"return_type")] + public Type ReturnType { get; set; } + + [global::ProtoBuf.ProtoMember (7, Name = @"return_type_id")] + public int ReturnTypeId { + get { return __pbn__ReturnTypeId.GetValueOrDefault (); } + set { __pbn__ReturnTypeId = value; } + } + public bool ShouldSerializeReturnTypeId () => __pbn__ReturnTypeId != null; + public void ResetReturnTypeId () => __pbn__ReturnTypeId = null; + private int? __pbn__ReturnTypeId; + + [global::ProtoBuf.ProtoMember (4, Name = @"type_parameter")] + public global::System.Collections.Generic.List TypeParameters { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (5, Name = @"receiver_type")] + public Type ReceiverType { get; set; } + + [global::ProtoBuf.ProtoMember (8, Name = @"receiver_type_id")] + public int ReceiverTypeId { + get { return __pbn__ReceiverTypeId.GetValueOrDefault (); } + set { __pbn__ReceiverTypeId = value; } + } + public bool ShouldSerializeReceiverTypeId () => __pbn__ReceiverTypeId != null; + public void ResetReceiverTypeId () => __pbn__ReceiverTypeId = null; + private int? __pbn__ReceiverTypeId; + + [global::ProtoBuf.ProtoMember (6, Name = @"value_parameter")] + public global::System.Collections.Generic.List ValueParameters { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (30, Name = @"type_table")] + public TypeTable TypeTable { get; set; } + + [global::ProtoBuf.ProtoMember (31, Name = @"version_requirement")] + public int [] VersionRequirements { get; set; } + + [global::ProtoBuf.ProtoMember (32, Name = @"contract")] + public Contract Contract { get; set; } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Property : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (11, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (518)] + public int Flags { + get { return __pbn__Flags ?? 518; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoMember (1, Name = @"old_flags")] + [global::System.ComponentModel.DefaultValue (2054)] + public int OldFlags { + get { return __pbn__OldFlags ?? 2054; } + set { __pbn__OldFlags = value; } + } + public bool ShouldSerializeOldFlags () => __pbn__OldFlags != null; + public void ResetOldFlags () => __pbn__OldFlags = null; + private int? __pbn__OldFlags; + + [global::ProtoBuf.ProtoMember (2, Name = @"name", IsRequired = true)] + public int Name { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"return_type")] + public Type ReturnType { get; set; } + + [global::ProtoBuf.ProtoMember (9, Name = @"return_type_id")] + public int ReturnTypeId { + get { return __pbn__ReturnTypeId.GetValueOrDefault (); } + set { __pbn__ReturnTypeId = value; } + } + public bool ShouldSerializeReturnTypeId () => __pbn__ReturnTypeId != null; + public void ResetReturnTypeId () => __pbn__ReturnTypeId = null; + private int? __pbn__ReturnTypeId; + + [global::ProtoBuf.ProtoMember (4, Name = @"type_parameter")] + public global::System.Collections.Generic.List TypeParameters { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (5, Name = @"receiver_type")] + public Type ReceiverType { get; set; } + + [global::ProtoBuf.ProtoMember (10, Name = @"receiver_type_id")] + public int ReceiverTypeId { + get { return __pbn__ReceiverTypeId.GetValueOrDefault (); } + set { __pbn__ReceiverTypeId = value; } + } + public bool ShouldSerializeReceiverTypeId () => __pbn__ReceiverTypeId != null; + public void ResetReceiverTypeId () => __pbn__ReceiverTypeId = null; + private int? __pbn__ReceiverTypeId; + + [global::ProtoBuf.ProtoMember (6, Name = @"setter_value_parameter")] + public ValueParameter SetterValueParameter { get; set; } + + [global::ProtoBuf.ProtoMember (7, Name = @"getter_flags")] + public int GetterFlags { + get { return __pbn__GetterFlags.GetValueOrDefault (); } + set { __pbn__GetterFlags = value; } + } + public bool ShouldSerializeGetterFlags () => __pbn__GetterFlags != null; + public void ResetGetterFlags () => __pbn__GetterFlags = null; + private int? __pbn__GetterFlags; + + [global::ProtoBuf.ProtoMember (8, Name = @"setter_flags")] + public int SetterFlags { + get { return __pbn__SetterFlags.GetValueOrDefault (); } + set { __pbn__SetterFlags = value; } + } + public bool ShouldSerializeSetterFlags () => __pbn__SetterFlags != null; + public void ResetSetterFlags () => __pbn__SetterFlags = null; + private int? __pbn__SetterFlags; + + [global::ProtoBuf.ProtoMember (31, Name = @"version_requirement")] + public int [] VersionRequirements { get; set; } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class ValueParameter : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (0)] + public int Flags { + get { return __pbn__Flags ?? 0; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoMember (2, Name = @"name", IsRequired = true)] + public int Name { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"type")] + public Type Type { get; set; } + + [global::ProtoBuf.ProtoMember (5, Name = @"type_id")] + public int TypeId { + get { return __pbn__TypeId.GetValueOrDefault (); } + set { __pbn__TypeId = value; } + } + public bool ShouldSerializeTypeId () => __pbn__TypeId != null; + public void ResetTypeId () => __pbn__TypeId = null; + private int? __pbn__TypeId; + + [global::ProtoBuf.ProtoMember (4, Name = @"vararg_element_type")] + public Type VarargElementType { get; set; } + + [global::ProtoBuf.ProtoMember (6, Name = @"vararg_element_type_id")] + public int VarargElementTypeId { + get { return __pbn__VarargElementTypeId.GetValueOrDefault (); } + set { __pbn__VarargElementTypeId = value; } + } + public bool ShouldSerializeVarargElementTypeId () => __pbn__VarargElementTypeId != null; + public void ResetVarargElementTypeId () => __pbn__VarargElementTypeId = null; + private int? __pbn__VarargElementTypeId; + + } + + [global::ProtoBuf.ProtoContract ()] + partial class TypeAlias : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (6)] + public int Flags { + get { return __pbn__Flags ?? 6; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoMember (2, Name = @"name", IsRequired = true)] + public int Name { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"type_parameter")] + public global::System.Collections.Generic.List TypeParameters { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (4, Name = @"underlying_type")] + public Type UnderlyingType { get; set; } + + [global::ProtoBuf.ProtoMember (5, Name = @"underlying_type_id")] + public int UnderlyingTypeId { + get { return __pbn__UnderlyingTypeId.GetValueOrDefault (); } + set { __pbn__UnderlyingTypeId = value; } + } + public bool ShouldSerializeUnderlyingTypeId () => __pbn__UnderlyingTypeId != null; + public void ResetUnderlyingTypeId () => __pbn__UnderlyingTypeId = null; + private int? __pbn__UnderlyingTypeId; + + [global::ProtoBuf.ProtoMember (6, Name = @"expanded_type")] + public Type ExpandedType { get; set; } + + [global::ProtoBuf.ProtoMember (7, Name = @"expanded_type_id")] + public int ExpandedTypeId { + get { return __pbn__ExpandedTypeId.GetValueOrDefault (); } + set { __pbn__ExpandedTypeId = value; } + } + public bool ShouldSerializeExpandedTypeId () => __pbn__ExpandedTypeId != null; + public void ResetExpandedTypeId () => __pbn__ExpandedTypeId = null; + private int? __pbn__ExpandedTypeId; + + [global::ProtoBuf.ProtoMember (8, Name = @"annotation")] + public global::System.Collections.Generic.List Annotations { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (31, Name = @"version_requirement")] + public int [] VersionRequirements { get; set; } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class EnumEntry : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"name")] + public int Name { + get { return __pbn__Name.GetValueOrDefault (); } + set { __pbn__Name = value; } + } + public bool ShouldSerializeName () => __pbn__Name != null; + public void ResetName () => __pbn__Name = null; + private int? __pbn__Name; + + } + + [global::ProtoBuf.ProtoContract ()] + partial class VersionRequirement : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"version")] + public int Version { + get { return __pbn__Version.GetValueOrDefault (); } + set { __pbn__Version = value; } + } + public bool ShouldSerializeVersion () => __pbn__Version != null; + public void ResetVersion () => __pbn__Version = null; + private int? __pbn__Version; + + [global::ProtoBuf.ProtoMember (2, Name = @"version_full")] + public int VersionFull { + get { return __pbn__VersionFull.GetValueOrDefault (); } + set { __pbn__VersionFull = value; } + } + public bool ShouldSerializeVersionFull () => __pbn__VersionFull != null; + public void ResetVersionFull () => __pbn__VersionFull = null; + private int? __pbn__VersionFull; + + [global::ProtoBuf.ProtoMember (3)] + [global::System.ComponentModel.DefaultValue (Level.Error)] + public Level level { + get { return __pbn__level ?? Level.Error; } + set { __pbn__level = value; } + } + public bool ShouldSerializelevel () => __pbn__level != null; + public void Resetlevel () => __pbn__level = null; + private Level? __pbn__level; + + [global::ProtoBuf.ProtoMember (4, Name = @"error_code")] + public int ErrorCode { + get { return __pbn__ErrorCode.GetValueOrDefault (); } + set { __pbn__ErrorCode = value; } + } + public bool ShouldSerializeErrorCode () => __pbn__ErrorCode != null; + public void ResetErrorCode () => __pbn__ErrorCode = null; + private int? __pbn__ErrorCode; + + [global::ProtoBuf.ProtoMember (5, Name = @"message")] + public int Message { + get { return __pbn__Message.GetValueOrDefault (); } + set { __pbn__Message = value; } + } + public bool ShouldSerializeMessage () => __pbn__Message != null; + public void ResetMessage () => __pbn__Message = null; + private int? __pbn__Message; + + [global::ProtoBuf.ProtoMember (6)] + [global::System.ComponentModel.DefaultValue (VersionKind.LanguageVersion)] + public VersionKind version_kind { + get { return __pbn__version_kind ?? VersionKind.LanguageVersion; } + set { __pbn__version_kind = value; } + } + public bool ShouldSerializeversion_kind () => __pbn__version_kind != null; + public void Resetversion_kind () => __pbn__version_kind = null; + private VersionKind? __pbn__version_kind; + + [global::ProtoBuf.ProtoContract ()] + public enum Level + { + [global::ProtoBuf.ProtoEnum (Name = @"WARNING")] + Warning = 0, + [global::ProtoBuf.ProtoEnum (Name = @"ERROR")] + Error = 1, + [global::ProtoBuf.ProtoEnum (Name = @"HIDDEN")] + Hidden = 2, + } + + [global::ProtoBuf.ProtoContract ()] + public enum VersionKind + { + [global::ProtoBuf.ProtoEnum (Name = @"LANGUAGE_VERSION")] + LanguageVersion = 0, + [global::ProtoBuf.ProtoEnum (Name = @"COMPILER_VERSION")] + CompilerVersion = 1, + [global::ProtoBuf.ProtoEnum (Name = @"API_VERSION")] + ApiVersion = 2, + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class VersionRequirementTable : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"requirement")] + public global::System.Collections.Generic.List Requirements { get; set; } = new global::System.Collections.Generic.List (); + + } + + [global::ProtoBuf.ProtoContract ()] + partial class PackageFragment : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"strings")] + public StringTable Strings { get; set; } + + [global::ProtoBuf.ProtoMember (2, Name = @"qualified_names")] + public QualifiedNameTable QualifiedNames { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"package")] + public Package Package { get; set; } + + [global::ProtoBuf.ProtoMember (4, Name = @"class")] + public global::System.Collections.Generic.List Classes { get; set; } = new global::System.Collections.Generic.List (); + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Contract : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"effect")] + public global::System.Collections.Generic.List Effects { get; set; } = new global::System.Collections.Generic.List (); + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Effect : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1)] + [global::System.ComponentModel.DefaultValue (EffectType.ReturnsConstant)] + public EffectType effect_type { + get { return __pbn__effect_type ?? EffectType.ReturnsConstant; } + set { __pbn__effect_type = value; } + } + public bool ShouldSerializeeffect_type () => __pbn__effect_type != null; + public void Reseteffect_type () => __pbn__effect_type = null; + private EffectType? __pbn__effect_type; + + [global::ProtoBuf.ProtoMember (2, Name = @"effect_constructor_argument")] + public global::System.Collections.Generic.List EffectConstructorArguments { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (3, Name = @"conclusion_of_conditional_effect")] + public Expression ConclusionOfConditionalEffect { get; set; } + + [global::ProtoBuf.ProtoMember (4, Name = @"kind")] + [global::System.ComponentModel.DefaultValue (InvocationKind.AtMostOnce)] + public InvocationKind Kind { + get { return __pbn__Kind ?? InvocationKind.AtMostOnce; } + set { __pbn__Kind = value; } + } + public bool ShouldSerializeKind () => __pbn__Kind != null; + public void ResetKind () => __pbn__Kind = null; + private InvocationKind? __pbn__Kind; + + [global::ProtoBuf.ProtoContract ()] + public enum EffectType + { + [global::ProtoBuf.ProtoEnum (Name = @"RETURNS_CONSTANT")] + ReturnsConstant = 0, + [global::ProtoBuf.ProtoEnum (Name = @"CALLS")] + Calls = 1, + [global::ProtoBuf.ProtoEnum (Name = @"RETURNS_NOT_NULL")] + ReturnsNotNull = 2, + } + + [global::ProtoBuf.ProtoContract ()] + public enum InvocationKind + { + [global::ProtoBuf.ProtoEnum (Name = @"AT_MOST_ONCE")] + AtMostOnce = 0, + [global::ProtoBuf.ProtoEnum (Name = @"EXACTLY_ONCE")] + ExactlyOnce = 1, + [global::ProtoBuf.ProtoEnum (Name = @"AT_LEAST_ONCE")] + AtLeastOnce = 2, + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class Expression : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"flags")] + [global::System.ComponentModel.DefaultValue (0)] + public int Flags { + get { return __pbn__Flags ?? 0; } + set { __pbn__Flags = value; } + } + public bool ShouldSerializeFlags () => __pbn__Flags != null; + public void ResetFlags () => __pbn__Flags = null; + private int? __pbn__Flags; + + [global::ProtoBuf.ProtoMember (2, Name = @"value_parameter_reference")] + public int ValueParameterReference { + get { return __pbn__ValueParameterReference.GetValueOrDefault (); } + set { __pbn__ValueParameterReference = value; } + } + public bool ShouldSerializeValueParameterReference () => __pbn__ValueParameterReference != null; + public void ResetValueParameterReference () => __pbn__ValueParameterReference = null; + private int? __pbn__ValueParameterReference; + + [global::ProtoBuf.ProtoMember (3)] + [global::System.ComponentModel.DefaultValue (ConstantValue.True)] + public ConstantValue constant_value { + get { return __pbn__constant_value ?? ConstantValue.True; } + set { __pbn__constant_value = value; } + } + public bool ShouldSerializeconstant_value () => __pbn__constant_value != null; + public void Resetconstant_value () => __pbn__constant_value = null; + private ConstantValue? __pbn__constant_value; + + [global::ProtoBuf.ProtoMember (4, Name = @"is_instance_type")] + public Type IsInstanceType { get; set; } + + [global::ProtoBuf.ProtoMember (5, Name = @"is_instance_type_id")] + public int IsInstanceTypeId { + get { return __pbn__IsInstanceTypeId.GetValueOrDefault (); } + set { __pbn__IsInstanceTypeId = value; } + } + public bool ShouldSerializeIsInstanceTypeId () => __pbn__IsInstanceTypeId != null; + public void ResetIsInstanceTypeId () => __pbn__IsInstanceTypeId = null; + private int? __pbn__IsInstanceTypeId; + + [global::ProtoBuf.ProtoMember (6, Name = @"and_argument")] + public global::System.Collections.Generic.List AndArguments { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (7, Name = @"or_argument")] + public global::System.Collections.Generic.List OrArguments { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoContract ()] + public enum ConstantValue + { + [global::ProtoBuf.ProtoEnum (Name = @"TRUE")] + True = 0, + [global::ProtoBuf.ProtoEnum (Name = @"FALSE")] + False = 1, + [global::ProtoBuf.ProtoEnum (Name = @"NULL")] + Null = 2, + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class StringTableTypes : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"record")] + public global::System.Collections.Generic.List Records { get; set; } = new global::System.Collections.Generic.List (); + + [global::ProtoBuf.ProtoMember (5, Name = @"local_name", IsPacked = true)] + public int [] LocalNames { get; set; } + + [global::ProtoBuf.ProtoContract ()] + public partial class Record : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"range")] + [global::System.ComponentModel.DefaultValue (1)] + public int Range { + get { return __pbn__Range ?? 1; } + set { __pbn__Range = value; } + } + public bool ShouldSerializeRange () => __pbn__Range != null; + public void ResetRange () => __pbn__Range = null; + private int? __pbn__Range; + + [global::ProtoBuf.ProtoMember (2, Name = @"predefined_index")] + public int PredefinedIndex { + get { return __pbn__PredefinedIndex.GetValueOrDefault (); } + set { __pbn__PredefinedIndex = value; } + } + public bool ShouldSerializePredefinedIndex () => __pbn__PredefinedIndex != null; + public void ResetPredefinedIndex () => __pbn__PredefinedIndex = null; + private int? __pbn__PredefinedIndex; + + [global::ProtoBuf.ProtoMember (6, Name = @"string")] + [global::System.ComponentModel.DefaultValue ("")] + public string String { + get { return __pbn__String ?? ""; } + set { __pbn__String = value; } + } + public bool ShouldSerializeString () => __pbn__String != null; + public void ResetString () => __pbn__String = null; + private string __pbn__String; + + [global::ProtoBuf.ProtoMember (3)] + [global::System.ComponentModel.DefaultValue (Operation.None)] + public Operation operation { + get { return __pbn__operation ?? Operation.None; } + set { __pbn__operation = value; } + } + public bool ShouldSerializeoperation () => __pbn__operation != null; + public void Resetoperation () => __pbn__operation = null; + private Operation? __pbn__operation; + + [global::ProtoBuf.ProtoMember (4, Name = @"substring_index", IsPacked = true)] + public int [] SubstringIndexs { get; set; } + + [global::ProtoBuf.ProtoMember (5, Name = @"replace_char", IsPacked = true)] + public int [] ReplaceChars { get; set; } + + [global::ProtoBuf.ProtoContract ()] + public enum Operation + { + [global::ProtoBuf.ProtoEnum (Name = @"NONE")] + None = 0, + [global::ProtoBuf.ProtoEnum (Name = @"INTERNAL_TO_CLASS_ID")] + InternalToClassId = 1, + [global::ProtoBuf.ProtoEnum (Name = @"DESC_TO_CLASS_ID")] + DescToClassId = 2, + } + + } + + } + + [global::ProtoBuf.ProtoContract ()] + partial class JvmMethodSignature : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"name")] + public int Name { + get { return __pbn__Name.GetValueOrDefault (); } + set { __pbn__Name = value; } + } + public bool ShouldSerializeName () => __pbn__Name != null; + public void ResetName () => __pbn__Name = null; + private int? __pbn__Name; + + [global::ProtoBuf.ProtoMember (2, Name = @"desc")] + public int Desc { + get { return __pbn__Desc.GetValueOrDefault (); } + set { __pbn__Desc = value; } + } + public bool ShouldSerializeDesc () => __pbn__Desc != null; + public void ResetDesc () => __pbn__Desc = null; + private int? __pbn__Desc; + + } + + [global::ProtoBuf.ProtoContract ()] + partial class JvmFieldSignature : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"name")] + public int Name { + get { return __pbn__Name.GetValueOrDefault (); } + set { __pbn__Name = value; } + } + public bool ShouldSerializeName () => __pbn__Name != null; + public void ResetName () => __pbn__Name = null; + private int? __pbn__Name; + + [global::ProtoBuf.ProtoMember (2, Name = @"desc")] + public int Desc { + get { return __pbn__Desc.GetValueOrDefault (); } + set { __pbn__Desc = value; } + } + public bool ShouldSerializeDesc () => __pbn__Desc != null; + public void ResetDesc () => __pbn__Desc = null; + private int? __pbn__Desc; + + } + + [global::ProtoBuf.ProtoContract ()] + partial class JvmPropertySignature : global::ProtoBuf.IExtensible + { + private global::ProtoBuf.IExtension __pbn__extensionData; + global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject (bool createIfMissing) + => global::ProtoBuf.Extensible.GetExtensionObject (ref __pbn__extensionData, createIfMissing); + + [global::ProtoBuf.ProtoMember (1, Name = @"field")] + public JvmFieldSignature Field { get; set; } + + [global::ProtoBuf.ProtoMember (2, Name = @"synthetic_method")] + public JvmMethodSignature SyntheticMethod { get; set; } + + [global::ProtoBuf.ProtoMember (3, Name = @"getter")] + public JvmMethodSignature Getter { get; set; } + + [global::ProtoBuf.ProtoMember (4, Name = @"setter")] + public JvmMethodSignature Setter { get; set; } + + } + + [global::ProtoBuf.ProtoContract ()] + enum Modality + { + [global::ProtoBuf.ProtoEnum (Name = @"FINAL")] + Final = 0, + [global::ProtoBuf.ProtoEnum (Name = @"OPEN")] + Open = 1, + [global::ProtoBuf.ProtoEnum (Name = @"ABSTRACT")] + Abstract = 2, + [global::ProtoBuf.ProtoEnum (Name = @"SEALED")] + Sealed = 3, + } + + [global::ProtoBuf.ProtoContract ()] + enum Visibility + { + [global::ProtoBuf.ProtoEnum (Name = @"INTERNAL")] + Internal = 0, + [global::ProtoBuf.ProtoEnum (Name = @"PRIVATE")] + Private = 1, + [global::ProtoBuf.ProtoEnum (Name = @"PROTECTED")] + Protected = 2, + [global::ProtoBuf.ProtoEnum (Name = @"PUBLIC")] + Public = 3, + [global::ProtoBuf.ProtoEnum (Name = @"PRIVATE_TO_THIS")] + PrivateToThis = 4, + [global::ProtoBuf.ProtoEnum (Name = @"LOCAL")] + Local = 5, + } + + [global::ProtoBuf.ProtoContract ()] + enum MemberKind + { + [global::ProtoBuf.ProtoEnum (Name = @"DECLARATION")] + Declaration = 0, + [global::ProtoBuf.ProtoEnum (Name = @"FAKE_OVERRIDE")] + FakeOverride = 1, + [global::ProtoBuf.ProtoEnum (Name = @"DELEGATION")] + Delegation = 2, + [global::ProtoBuf.ProtoEnum (Name = @"SYNTHESIZED")] + Synthesized = 3, + } + + static class Extensions + { + //public static bool GetSkipInComparison (this global::Google.Protobuf.Reflection.FieldOptions obj) + // => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 50000); + + //public static void SetSkipInComparison (this global::Google.Protobuf.Reflection.FieldOptions obj, bool value) + // => global::ProtoBuf.Extensible.AppendValue (obj, 50000, value); + + //public static bool GetNameIdInTable (this global::Google.Protobuf.Reflection.FieldOptions obj) + // => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 50001); + + //public static void SetNameIdInTable (this global::Google.Protobuf.Reflection.FieldOptions obj, bool value) + // => global::ProtoBuf.Extensible.AppendValue (obj, 50001, value); + + //public static bool GetFqNameIdInTable (this global::Google.Protobuf.Reflection.FieldOptions obj) + // => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 50002); + + //public static void SetFqNameIdInTable (this global::Google.Protobuf.Reflection.FieldOptions obj, bool value) + // => global::ProtoBuf.Extensible.AppendValue (obj, 50002, value); + + //public static bool GetStringIdInTable (this global::Google.Protobuf.Reflection.FieldOptions obj) + // => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 50003); + + //public static void SetStringIdInTable (this global::Google.Protobuf.Reflection.FieldOptions obj, bool value) + // => global::ProtoBuf.Extensible.AppendValue (obj, 50003, value); + + public static JvmMethodSignature GetConstructorSignature (this Constructor obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 100); + + public static void SetConstructorSignature (this Constructor obj, JvmMethodSignature value) + => global::ProtoBuf.Extensible.AppendValue (obj, 100, value); + + public static JvmMethodSignature GetMethodSignature (this Function obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 100); + + public static void SetMethodSignature (this Function obj, JvmMethodSignature value) + => global::ProtoBuf.Extensible.AppendValue (obj, 100, value); + + public static int GetLambdaClassOriginName (this Function obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 101); + + public static void SetLambdaClassOriginName (this Function obj, int value) + => global::ProtoBuf.Extensible.AppendValue (obj, 101, value); + + public static JvmPropertySignature GetPropertySignature (this Property obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 100); + + public static void SetPropertySignature (this Property obj, JvmPropertySignature value) + => global::ProtoBuf.Extensible.AppendValue (obj, 100, value); + + public static int GetFlags (this Property obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 101); + + public static void SetFlags (this Property obj, int value) + => global::ProtoBuf.Extensible.AppendValue (obj, 101, value); + + public static global::System.Collections.Generic.IEnumerable GetTypeAnnotations (this Type obj) + => obj == null ? null : global::ProtoBuf.Extensible.GetValues (obj, 100); + + public static void AddTypeAnnotations (this Type obj, Annotation value) + => global::ProtoBuf.Extensible.AppendValue (obj, 100, value); + + public static bool GetIsRaw (this Type obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 101); + + public static void SetIsRaw (this Type obj, bool value) + => global::ProtoBuf.Extensible.AppendValue (obj, 101, value); + + public static global::System.Collections.Generic.IEnumerable GetTypeParameterAnnotations (this TypeParameter obj) + => obj == null ? null : global::ProtoBuf.Extensible.GetValues (obj, 100); + + public static void AddTypeParameterAnnotations (this TypeParameter obj, Annotation value) + => global::ProtoBuf.Extensible.AppendValue (obj, 100, value); + + public static int GetClassModuleName (this Class obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 101); + + public static void SetClassModuleName (this Class obj, int value) + => global::ProtoBuf.Extensible.AppendValue (obj, 101, value); + + public static global::System.Collections.Generic.IEnumerable GetClassLocalVariables (this Class obj) + => obj == null ? null : global::ProtoBuf.Extensible.GetValues (obj, 102); + + public static void AddClassLocalVariables (this Class obj, Property value) + => global::ProtoBuf.Extensible.AppendValue (obj, 102, value); + + public static int GetAnonymousObjectOriginName (this Class obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 103); + + public static void SetAnonymousObjectOriginName (this Class obj, int value) + => global::ProtoBuf.Extensible.AppendValue (obj, 103, value); + + public static int GetPackageModuleName (this Package obj) + => obj == null ? default : global::ProtoBuf.Extensible.GetValue (obj, 101); + + public static void SetPackageModuleName (this Package obj, int value) + => global::ProtoBuf.Extensible.AppendValue (obj, 101, value); + + public static global::System.Collections.Generic.IEnumerable GetPackageLocalVariables (this Package obj) + => obj == null ? null : global::ProtoBuf.Extensible.GetValues (obj, 102); + + public static void AddPackageLocalVariables (this Package obj, Property value) + => global::ProtoBuf.Extensible.AppendValue (obj, 102, value); + + } +} + +#pragma warning restore CS1591, CS0612, CS3021, IDE1006 diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs new file mode 100644 index 00000000000..e27b04c09da --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Xamarin.Android.Tools.Bytecode +{ + public static class KotlinUtilities + { + [return: NotNullIfNotNull (nameof (value))] + public static string? Capitalize (this string? value) + { + if (string.IsNullOrWhiteSpace (value)) + return value; + + if (value.Length < 1) + return value; + + return char.ToUpperInvariant (value [0]) + value.Substring (1); + } + + public static string ConvertKotlinTypeSignature (KotlinType? type, KotlinFile? metadata = null, bool convertUnsignedToPrimitive = true) + { + if (type is null) + return string.Empty; + + var class_name = type.ClassName; + + if (string.IsNullOrWhiteSpace (class_name)) { + if (metadata is KotlinClass klass) { + + var tp = klass.TypeParameters?.FirstOrDefault (t => t.Id == type.TypeParameter); + + if (tp?.UpperBounds?.FirstOrDefault ()?.ClassName != null) + return ConvertKotlinClassToJava (tp.UpperBounds.FirstOrDefault ()?.ClassName); + } + + return "Ljava/lang/Object;"; + } + + var result = ConvertKotlinClassToJava (class_name, convertUnsignedToPrimitive); + + if (result == "[") + result += ConvertKotlinTypeSignature (type.Arguments?.FirstOrDefault ()?.Type, null, convertUnsignedToPrimitive); + + return result; + } + + public static string ConvertKotlinClassToJava (string? className, bool convertUnsignedToPrimitive = true) + { + if (className == null || string.IsNullOrWhiteSpace (className)) + return string.Empty; + + className = className.Replace ('.', '$'); + + if (type_map.TryGetValue (className.TrimEnd (';'), out var result)) + return result; + + if (convertUnsignedToPrimitive && unsigned_type_map.TryGetValue (className.TrimEnd (';'), out var result2)) + return result2; + + return "L" + className; + } + + public static string GetSignature (this List parameters) + { + return string.Join (string.Empty, parameters.Select (p => ConvertKotlinTypeSignature (p.Type))); + } + + public static ParameterInfo[] GetFilteredParameters (this MethodInfo method) + { + // Kotlin adds this to some constructors but I cannot tell which ones, + // so we'll just ignore them if we see them on the Java side + return method.GetParameters ().Where (p => p.Type.BinaryName != "Lkotlin/jvm/internal/DefaultConstructorMarker;" && !p.Name.StartsWith ("$", StringComparison.Ordinal)).ToArray (); + } + + public static string GetMethodNameWithoutUnsignedSuffix (this MethodInfo method) + => GetMethodNameWithoutUnsignedSuffix (method.Name); + + public static string GetMethodNameWithoutUnsignedSuffix (string name) + { + // Kotlin will add a type hash suffix to the end of the method name that use unsigned types + // - add-H3FcsT8 + // We strip them for trying to match up the metadata to the MethodInfo + // Additionally, generated setters for unsigned types have multiple suffixes, + // we only want to remove the unsigned suffix. + // - getFoo-pVg5ArA$main + var dollar_index = name.IndexOf ('$'); + var dollar_suffix = dollar_index >= 0 ? name.Substring (dollar_index) : string.Empty; + + var index = name.IndexOf ('-'); + + return index >= 0 ? name.Substring (0, index) + dollar_suffix : name; + } + + public static bool IsDefaultConstructorMarker (this MethodInfo method) + { + // A default constructor is synthetic and has a DefaultConstructorMarker as its final parameter. + if (method.Name != "") + return false; + + if (!method.AccessFlags.HasFlag (MethodAccessFlags.Synthetic)) + return false; + + var parameters = method.GetParameters (); + + if (parameters.Length < 1) + return false; + + // Parameter list ends with `DefaultConstructorMarker`. + return parameters [parameters.Length - 1].Type.TypeSignature == "Lkotlin/jvm/internal/DefaultConstructorMarker;"; + } + + // Sometimes the Kotlin provided JvmSignature is null (or unhelpful), so we need to construct one ourselves + public static string ConstructJvmSignature (this KotlinFunction function) + { + // The receiver type (if specified) is a "hidden" parameter passed at the beginning + // of the Java parameter list, so we include it so the Signature/Descriptors match. + return $"({function.ReceiverType?.GetSignature (false)}{string.Concat (function.ValueParameters?.Select (p => p.Type?.GetSignature (false)) ?? Enumerable.Empty ())}){function.ReturnType?.GetSignature (false)}"; + } + + internal static List? ToList (this IEnumerable? self, JvmNameResolver resolver, Func creator) + where TResult: class + { + if (self == null) + return null; + return self.Select (v => creator (v, resolver)!) + .Where (v => v != null) + .ToList (); + } + + public static bool IsPubliclyVisible (this ClassAccessFlags flags) => flags.HasFlag (ClassAccessFlags.Public) || flags.HasFlag (ClassAccessFlags.Protected); + + public static bool IsPubliclyVisible (this KotlinClassVisibility flags) => flags == KotlinClassVisibility.Public || flags == KotlinClassVisibility.Protected; + + public static bool IsPubliclyVisible (this KotlinFunctionFlags flags) => flags.HasFlag (KotlinFunctionFlags.Public) || flags.HasFlag (KotlinFunctionFlags.Protected); + + public static bool IsPubliclyVisible (this KotlinConstructorFlags flags) => flags.HasFlag (KotlinConstructorFlags.Public) || flags.HasFlag (KotlinConstructorFlags.Protected); + + public static bool IsPubliclyVisible (this KotlinPropertyFlags flags) => flags.HasFlag (KotlinPropertyFlags.Public) || flags.HasFlag (KotlinPropertyFlags.Protected); + + public static bool IsUnnamedParameter (this ParameterInfo parameter) => parameter.Name.Length > 1 && parameter.Name.StartsWith ("p", StringComparison.Ordinal) && int.TryParse (parameter.Name.Substring (1), out var _); + + public static bool IsCompilerNamed (this ParameterInfo parameter) => parameter.Name.Length > 0 && parameter.Name.StartsWith ("$", StringComparison.Ordinal); + + public static bool IsUnnamedParameter (this KotlinValueParameter parameter) => parameter.Name?.Length > 1 && + parameter.Name.StartsWith ("p", StringComparison.Ordinal) && + int.TryParse (parameter.Name.Substring (1), out var _); + + static Dictionary unsigned_type_map = new Dictionary { + { "kotlin/UInt", "I" }, + { "kotlin/ULong", "J" }, + { "kotlin/UShort", "S" }, + { "kotlin/UByte", "B" }, + { "kotlin/UIntArray", "[I" }, + { "kotlin/ULongArray", "[J" }, + { "kotlin/UShortArray", "[S" }, + { "kotlin/UByteArray", "[B" }, + }; + + static Dictionary type_map = new Dictionary { + { "kotlin/Int", "I" }, + { "kotlin/Double", "D" }, + { "kotlin/Char", "C" }, + { "kotlin/Long", "J" }, + { "kotlin/Float", "F" }, + { "kotlin/Short", "S" }, + { "kotlin/Byte", "B" }, + { "kotlin/Boolean", "Z" }, + { "kotlin/Unit", "V" }, + + { "kotlin/Array", "[" }, + { "kotlin/IntArray", "[I" }, + { "kotlin/DoubleArray", "[D" }, + { "kotlin/CharArray", "[C" }, + { "kotlin/LongArray", "[J" }, + { "kotlin/FloatArray", "[F" }, + { "kotlin/ShortArray", "[S" }, + { "kotlin/ByteArray", "[B" }, + { "kotlin/BooleanArray", "[Z" }, + + { "kotlin/Any", "Ljava/lang/Object;" }, + { "kotlin/Nothing", "Ljava/lang/Void;" }, + { "kotlin/Annotation", "Ljava/lang/annotation/Annotation;" }, + { "kotlin/String", "Ljava/lang/String;" }, + { "kotlin/CharSequence", "Ljava/lang/CharSequence;" }, + { "kotlin/Throwable", "Ljava/lang/Throwable;" }, + { "kotlin/Cloneable", "Ljava/lang/Cloneable;" }, + { "kotlin/Number", "Ljava/lang/Number;" }, + { "kotlin/Comparable", "Ljava/lang/Comparable;" }, + { "kotlin/Enum", "Ljava/lang/Enum;" }, + + { "kotlin/collections/Iterator", "Ljava/util/Iterator;" }, + { "kotlin/collections/MutableIterator", "Ljava/util/Iterator;" }, + { "kotlin/collections/Collection", "Ljava/util/Collection;" }, + { "kotlin/collections/MutableCollection", "Ljava/util/Collection;" }, + { "kotlin/collections/List", "Ljava/util/List;" }, + { "kotlin/collections/MutableList", "Ljava/util/List;" }, + { "kotlin/collections/Set", "Ljava/util/Set;" }, + { "kotlin/collections/MutableSet", "Ljava/util/Set;" }, + { "kotlin/collections/Map", "Ljava/util/Map;" }, + { "kotlin/collections/MutableMap", "Ljava/util/Map;" }, + { "kotlin/collections/ListIterator", "Ljava/util/ListIterator;" }, + { "kotlin/collections/MutableListIterator", "Ljava/util/ListIterator;" }, + + { "kotlin/collections/Iterable", "Ljava/lang/Iterable;" }, + { "kotlin/collections/MutableIterable", "Ljava/lang/Iterable;" }, + { "kotlin/collections/Map$Entry", "Ljava/util/Map$Entry;" }, + { "kotlin/collections/MutableMap$MutableEntry", "Ljava/util/Map$Entry;" }, + + { "kotlin/Function0", "Lkotlin/jvm/functions/Function0;" }, + { "kotlin/Function1", "Lkotlin/jvm/functions/Function1;" }, + { "kotlin/Function2", "Lkotlin/jvm/functions/Function2;" }, + { "kotlin/Function3", "Lkotlin/jvm/functions/Function3;" }, + { "kotlin/Function4", "Lkotlin/jvm/functions/Function4;" }, + { "kotlin/Function5", "Lkotlin/jvm/functions/Function5;" }, + { "kotlin/Function6", "Lkotlin/jvm/functions/Function6;" }, + { "kotlin/Function7", "Lkotlin/jvm/functions/Function7;" }, + { "kotlin/Function8", "Lkotlin/jvm/functions/Function8;" }, + { "kotlin/Function9", "Lkotlin/jvm/functions/Function9;" }, + { "kotlin/Function10", "Lkotlin/jvm/functions/Function10;" }, + { "kotlin/Function11", "Lkotlin/jvm/functions/Function11;" }, + { "kotlin/Function12", "Lkotlin/jvm/functions/Function12;" }, + { "kotlin/Function13", "Lkotlin/jvm/functions/Function13;" }, + { "kotlin/Function14", "Lkotlin/jvm/functions/Function14;" }, + { "kotlin/Function15", "Lkotlin/jvm/functions/Function15;" }, + { "kotlin/Function16", "Lkotlin/jvm/functions/Function16;" }, + { "kotlin/Function17", "Lkotlin/jvm/functions/Function17;" }, + { "kotlin/Function18", "Lkotlin/jvm/functions/Function18;" }, + { "kotlin/Function19", "Lkotlin/jvm/functions/Function19;" }, + { "kotlin/Function20", "Lkotlin/jvm/functions/Function20;" }, + { "kotlin/Function21", "Lkotlin/jvm/functions/Function21;" }, + { "kotlin/Function22", "Lkotlin/jvm/functions/Function22;" }, + }; + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/PartialStream.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/PartialStream.cs new file mode 100644 index 00000000000..95053cb6bb7 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Kotlin/PartialStream.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; + +namespace Xamarin.Android.Tools.Bytecode +{ + // This takes a Stream that contains several separate messages and provides callers + // a slice of it so it appears like a Stream that only contains a single message. + // This is more efficient than copying each message into a separate Stream. + public class PartialStream : Stream + { + readonly Stream stream; + long start; + long length; + + public PartialStream (Stream stream, long start) : this (stream, start, stream.Length - start) { } + + public PartialStream (Stream stream, long start, long length) + { + this.stream = stream; + this.start = start; + this.length = length; + + this.stream.Position = start; + } + + public void MoveNext () => MoveNext (stream.Length - start - length); + + // Move to the next message in the original Stream + public void MoveNext (long length) + { + start += this.length; + this.length = length; + } + + public override bool CanRead => stream.CanRead; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => length; + + public override long Position { + get => stream.Position - start; + set => stream.Position = value + start; + } + + public override void Flush () => stream.Flush (); + + public override int Read (byte [] buffer, int offset, int count) => stream.Read (buffer, offset, (int) Math.Min (count, Length - Position)); + + public override long Seek (long offset, SeekOrigin origin) => throw new NotImplementedException (); + + public override void SetLength (long value) => throw new NotImplementedException (); + + public override void Write (byte [] buffer, int offset, int count) => throw new NotImplementedException (); + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Log.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Log.cs new file mode 100644 index 00000000000..fdd77466df4 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Log.cs @@ -0,0 +1,51 @@ +using System; +using System.Diagnostics; + +namespace Xamarin.Android.Tools.Bytecode +{ + public class Log + { + public static Action? OnLog; + + public static void Warning (int verbosity, string format, params object[] args) + { + var log = OnLog; + if (log == null) + return; + log (TraceLevel.Warning, verbosity, format, args); + } + + public static void Warning (int verbosity, string message) => Warning (verbosity, "{0}", message); + + public static void Error (string format, params object[] args) + { + var log = OnLog; + if (log == null) + return; + log (TraceLevel.Error, 0, format, args); + } + + public static void Error (string message) => Error ("{0}", message); + + public static void Message (string format, params object[] args) + { + var log = OnLog; + if (log == null) + return; + log (TraceLevel.Info, 0, format, args); + } + + public static void Message (string message) => Message ("{0}", message); + + public static void Debug (string format, params object[] args) + { + var log = OnLog; + if (log == null) + return; + log (TraceLevel.Verbose, 0, format, args); + } + + public static void Debug (string message) => Debug ("{0}", message); + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Methods.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Methods.cs new file mode 100644 index 00000000000..753a90f336c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Methods.cs @@ -0,0 +1,472 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode { + + public sealed class Methods : Collection { + + public ConstantPool ConstantPool {get; private set;} + + public Methods (ConstantPool constantPool, ClassFile declaringClass, Stream stream) + { + ConstantPool = constantPool; + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + Add (new MethodInfo (constantPool, declaringClass, stream)); + } + } + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6 + public sealed class MethodInfo { + + ushort nameIndex; + ushort descriptorIndex; + + public ConstantPool ConstantPool {get; private set;} + public ClassFile DeclaringType {get; private set;} + public MethodAccessFlags AccessFlags {get; set;} + public AttributeCollection Attributes {get; private set;} + public string? KotlinReturnType {get; set;} + + // JNI signature of the Kotlin `@JvmInline` class that this method's return + // type was originally declared as in Kotlin source, when the JVM-erased + // return type is the inline class's underlying primitive. e.g. + // `Lcom/example/MyColor;` for a method declared `fun f(): MyColor` whose + // JVM signature is `()J`. null when no projection applies. + // See dotnet/java-interop#1431 (Phase 2). + public string? KotlinInlineClassReturnJniType { get; set; } + + // Unmangled Kotlin source-level method name when it differs from the + // JVM-level `Name`. Populated for methods that the Kotlin compiler + // mangles for inline-class binary compatibility (e.g. JVM name + // `tint-Rn_QMJI`, Kotlin name `tint`). Surfaced into api.xml as + // `managedName` so the generator emits a clean C# overload while the + // JVM `Name` stays in `name`/`jni-signature` for native invocation. + // See dotnet/java-interop#1431 (Phase 2). + public string? KotlinName { get; set; } + + public MethodInfo (ConstantPool constantPool, ClassFile declaringType, Stream stream) + { + ConstantPool = constantPool; + DeclaringType = declaringType; + AccessFlags = (MethodAccessFlags) stream.ReadNetworkUInt16 (); + nameIndex = stream.ReadNetworkUInt16 (); + descriptorIndex = stream.ReadNetworkUInt16 (); + Attributes = new AttributeCollection (constantPool, stream); + } + + public string Name { + get { + return ((ConstantPoolUtf8Item) ConstantPool [nameIndex]).Value; + } + } + + public string Descriptor { + get { + return ((ConstantPoolUtf8Item) ConstantPool [descriptorIndex]).Value; + } + } + + public bool IsConstructor { + get {return Name == "";} + } + + public bool IsPubliclyVisible => AccessFlags.HasFlag (MethodAccessFlags.Public) || AccessFlags.HasFlag (MethodAccessFlags.Protected); + + public TypeInfo ReturnType { + get { + int endParams; + GetParametersFromDescriptor (out endParams); + endParams++; + var r = new TypeInfo (Descriptor.Substring (endParams)); + r.TypeSignature = r.BinaryName; + var s = GetSignature (); + if (s != null) + r.TypeSignature = s.ReturnTypeSignature; + return r; + } + } + + bool IsEnumCtor => IsConstructor && DeclaringType.IsEnum; + + ParameterInfo[]? parameters = null; + + public ParameterInfo[] GetParameters () + { + if (parameters != null) + return parameters; + int _; + parameters = GetParametersFromDescriptor (out _).ToArray (); + UpdateParametersFromLocalVariables (parameters); + UpdateParametersFromSignature (parameters); + UpdateParametersFromMethodParametersAttribute (parameters); + return parameters; + } + + static IEnumerable ExtractTypesFromSignature (string signature) + { + if (signature == null || signature.Length < "()V".Length) + throw new InvalidOperationException (string.Format ("Invalid method descriptor '{0}'.", signature)); + if (signature [0] != '(') + throw new InvalidOperationException (string.Format ("Invalid method descriptor '{0}'; expected '(' at index 0.", signature)); + + int index = 1; + + while (index < signature.Length && signature [index] != ')') { + yield return Signature.ExtractType (signature, ref index); + } + } + + List GetParametersFromDescriptor (out int endParams) + { + var signature = Descriptor; + if (signature == null || signature.Length < "()V".Length) + throw new InvalidOperationException (string.Format ("Invalid method descriptor '{0}'.", signature)); + if (signature [0] != '(') + throw new InvalidOperationException (string.Format ("Invalid method descriptor '{0}'; expected '(' at index 0.", signature)); + + int index = 1; + + int c = 0; + var first = true; + var ps = new List (); + while (index < signature.Length && signature [index] != ')') { + var type = Signature.ExtractType (signature, ref index); + + if (first) { + first = false; + if (IsConstructor && + !DeclaringType.IsStatic && + DeclaringType.TryGetEnclosingMethodInfo (out var declaringClass, out var _, out var _) && + type == "L" + declaringClass + ";") { + continue; + } + if (IsConstructor && + !DeclaringType.IsStatic && + DeclaringType.InnerClass?.OuterClassName != null && + type == "L" + DeclaringType.InnerClass.OuterClassName + ";") { + continue; + } + } + + if (first && + IsConstructor && + DeclaringType.InnerClass?.OuterClassName != null && + type == "L" + DeclaringType.InnerClass.OuterClassName + ";") { + first = false; + continue; + } + + var p = new ParameterInfo ("p" + c, type, type, c); + c++; + ps.Add (p); + } + endParams = index; + return ps; + } + + void UpdateParametersFromLocalVariables (ParameterInfo[] parameters) + { + var locals = GetLocalVariables (); + if (locals == null) + return; + + var names = locals.LocalVariables.Where (p => p.StartPC == 0).ToList (); + + int parametersCount = GetDeclaredParametersCount (parameters); + + for (int pi = parametersCount-1; pi >= 0; --pi) { + for (int ni = names.Count-1; ni >= 0; --ni) { + if (parameters [pi].Type.BinaryName != names [ni].Descriptor) { + continue; + } + parameters [pi].Name = names [ni].Name; + names.RemoveAt (ni); + break; + } + } + } + + LocalVariableTableAttribute? GetLocalVariables () + { + var code = Attributes.Get (); + if (code == null) + return null; + var locals = (LocalVariableTableAttribute?) code.Attributes.FirstOrDefault (a => a.Name == "LocalVariableTable"); + return locals; + } + + int GetDeclaredParametersCount (ParameterInfo[] parameters) + { + // Consider the `MyStringList` inner class declared within `JavaType.staticActionWithGenerics()`. + // The inner class acts as a closure over method parameters; *some* parameters are stored as + // fields within the class, and provided as "trailing parameters" to the constructor. + // + // The problem is that I can't see a "clean" way to tell which parameters are "closure trailing parameters" + // vs. "real" parameters. + // + // Thus, a hacky way: a "closure trailing parameter" is a type: + // 1. Declared in the enclosing method, which is also + // 2. The type of a field in the current declaring type, and + // 3. The field name starts with `val$`. + + int parametersEnd = parameters.Length; + if (parametersEnd == 0 || + !IsConstructor || + !DeclaringType.TryGetEnclosingMethodInfo (out var declaringClass, out var declaringMethodName, out var declaringMethodDescriptor) || + declaringMethodDescriptor == null || + string.IsNullOrEmpty (declaringMethodDescriptor)) + return parametersEnd; + + var enclosingMethodTypes = ExtractTypesFromSignature (declaringMethodDescriptor).ToList (); + var closureFieldsTypes = DeclaringType.Fields + .Where (f => f.Name.StartsWith ("val$", StringComparison.Ordinal) && + f.AccessFlags.HasFlag (FieldAccessFlags.Final) && + f.AccessFlags.HasFlag (FieldAccessFlags.Synthetic)) + .Select (f => f.Descriptor) + .ToList (); + + for (int i = closureFieldsTypes.Count; i > 0; --i) { + if (!enclosingMethodTypes.Contains (closureFieldsTypes [i-1])) { + closureFieldsTypes.RemoveAt (i-1); + } + } + + for (int i = closureFieldsTypes.Count; i > 0; --i) { + if (parametersEnd == 0) + break; + if (parameters [parametersEnd-1].Type.BinaryName != closureFieldsTypes [i-1]) + break; + parametersEnd--; + } + return parametersEnd; + } + + void UpdateParametersFromSignature (ParameterInfo[] parameters) + { + var sig = GetSignature (); + if (sig == null) + return; + + int parametersCount = GetDeclaredParametersCount (parameters); + CheckDescriptorVariablesToSignatureParameters (parameters, parametersCount, sig); + int max = Math.Min (parametersCount, sig.Parameters.Count); + for (int i = 0; i < max; ++i) { + parameters [i].Type.TypeSignature = sig.Parameters [i]; + } + } + + void CheckDescriptorVariablesToSignatureParameters (ParameterInfo[] parameters, int parametersCount, MethodTypeSignature sig) + { + if (IsEnumCtor) + return; + if (sig.Parameters.Count == parametersCount) + return; + + Log.Debug ($"class-parse: method {DeclaringType.ThisClass.Name.Value}.{Name}.{Descriptor}: " + + $"Signature ('{Attributes.Get()}') has {sig.Parameters.Count} entries; " + + $"Descriptor '{Descriptor}' has {parametersCount} entries!"); + } + + public List GetThrows () + { + var throws = new List (); + foreach (var exceptions in Attributes.Where (a => a.Name == "Exceptions")) { + var ex = (ExceptionsAttribute) exceptions; + foreach (var t in ex.CheckedExceptions) { + throws.Add (new TypeInfo (t.Name.Value)); + } + } + var signature = GetSignature (); + if (signature == null) + return throws; + + if (signature.Throws.Count > 0 && throws.Count != signature.Throws.Count) { + Log.Warning (1, $"class-parse: warning: differing number of `throws` declarations on `{Name}{Descriptor}`!"); + } + int c = Math.Min (signature.Throws.Count, throws.Count); + for (int i = 0; i < c; ++i) + throws [i].TypeSignature = signature.Throws [i]; + return throws; + } + + public MethodTypeSignature? GetSignature () + { + var signature = (SignatureAttribute?) Attributes.SingleOrDefault (a => a.Name == "Signature"); + return signature != null + ? new MethodTypeSignature (signature.Value) + : null; + } + + void UpdateParametersFromMethodParametersAttribute (ParameterInfo[] parameters) + { + var methodParams = (MethodParametersAttribute?) Attributes.SingleOrDefault (a => a.Name == AttributeInfo.MethodParameters); + if (methodParams == null) + return; + + const MethodParameterAccessFlags OuterThis1 = + MethodParameterAccessFlags.Final | MethodParameterAccessFlags.Mandated; + const MethodParameterAccessFlags OuterThis2 = + MethodParameterAccessFlags.Final | MethodParameterAccessFlags.Synthetic; + var pinfo = methodParams.ParameterInfo; + int startIndex = 0; + while (IsConstructor && + startIndex < pinfo.Count && + ((pinfo [startIndex].AccessFlags & OuterThis1) == OuterThis1 || + (pinfo [startIndex].AccessFlags & OuterThis2) == OuterThis2)) { + startIndex++; + } + Debug.Assert ( + parameters.Length == pinfo.Count - startIndex, + $"Unexpected number of method parameters in `{DeclaringType.FullJniName}.{Name}{Descriptor}`: expected {parameters.Length}, got {pinfo.Count - startIndex}! " + + $"pinfo.Count={pinfo.Count}, startIndex={startIndex}, pinfo={string.Join (", ", pinfo.Select (p => p.ToString ()))}"); + int end = Math.Min (parameters.Length, pinfo.Count - startIndex); + for (int i = 0; i < end; ++i) { + var p = pinfo [i + startIndex]; + + parameters [i].AccessFlags = p.AccessFlags; + if (p.Name != null) { + parameters [i].Name = p.Name; + } + } + } + + public override string ToString () => Name; + } + + public sealed class TypeInfo : IEquatable { + + // "raw" name, as used in method descriptors and type references + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.2.1 + public string BinaryName; + + // FieldTypeSignature, as extracted from the Signature attribute, which contains + // generic type information. + public string? TypeSignature; + + public TypeInfo (string binaryName, string? typeSignature = null) + { + BinaryName = binaryName; + TypeSignature = typeSignature; + } + + public override int GetHashCode () + { + return (BinaryName ?? "").GetHashCode () ^ (TypeSignature ?? "").GetHashCode (); + } + + public override bool Equals (object? obj) + { + var o = obj as TypeInfo; + if (o == null) + return false; + return Equals (o); + } + + public bool Equals (TypeInfo? other) + { + if (other == null) + return false; + if (object.ReferenceEquals (this, other)) + return true; + return object.Equals (BinaryName, other.BinaryName) && + object.Equals (TypeSignature, other.TypeSignature); + } + + public override string ToString () + { + if (TypeSignature != null) + return string.Format ("TypeInfo({0}={1})", BinaryName, TypeSignature); + return string.Format ("TypeInfo({0})", BinaryName); + } + } + + public sealed class ParameterInfo : IEquatable { + + public string Name; + public int Position; + public TypeInfo Type; + public string? KotlinType; + + // JNI signature of the Kotlin `@JvmInline` class that this parameter was + // originally declared as in Kotlin source, when the JVM-erased parameter + // type is the inline class's underlying primitive. e.g. + // `Lcom/example/MyColor;` for a Kotlin parameter declared `color: MyColor` + // whose JVM type is `J`. null when no projection applies. + // See dotnet/java-interop#1431 (Phase 2). + public string? KotlinInlineClassJniType; + + public MethodParameterAccessFlags AccessFlags; + + public ParameterInfo (string name, string binaryName, string? typeSignature = null, int position = 0) + { + Name = name; + Position = position; + Type = new TypeInfo (binaryName, typeSignature); + } + + public override int GetHashCode () + { + return (Name ?? "").GetHashCode () ^ Position.GetHashCode () ^ + (Type ?? new TypeInfo ("")).GetHashCode (); + } + + public override bool Equals (object? obj) + { + var o = obj as ParameterInfo; + if (o == null) + return false; + return Equals (o); + } + + public bool Equals (ParameterInfo? other) + { + if (other == null) + return false; + if (object.ReferenceEquals (this, other)) + return true; + return object.Equals (Name, other.Name) && + Position == other.Position && + object.Equals (Type, other.Type); + } + + public override string ToString () + { + return $"ParameterInfo(Name={Name}, Position={Position}, Type={Type}, AccessFlags={AccessFlags})"; + } + } + + [Flags] + public enum MethodAccessFlags { + Public = 0x0001, + Private = 0x0002, + Protected = 0x0004, + Static = 0x0008, + Final = 0x0010, + Synchronized = 0x0020, + Bridge = 0x0040, + Varargs = 0x0080, + Native = 0x0100, + Abstract = 0x0400, + Strict = 0x0800, + Synthetic = 0x1000, + + // This is not a real Java MethodAccessFlags, it is used to denote Kotlin "internal" access. + Internal = 0x10000000, + } + + [Flags] + public enum MethodParameterAccessFlags { + None, + Final = 0x0010, + Synthetic = 0x1000, + Mandated = 0x8000, + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Modules.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Modules.cs new file mode 100644 index 00000000000..2371eb6d53e --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Modules.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode { + + public enum ModuleFlags { + Open = 0x0020, + Synthetic = 0x1000, + Mandated = 0x8000, + } + + public enum ModuleRequiresInfoFlags { + Transitive = 0x0020, + StaticPhase = 0x0040, + Synthetic = 0x1000, + Mandated = 0x8000, + } + + // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.25 + public sealed class ModuleRequiresInfo { + ushort requiresIndex; + ushort requiresVersionIndex; + + + public ConstantPool ConstantPool {get; private set;} + public ModuleRequiresInfoFlags RequiresFlags {get; private set;} + + public string Requires => + ((ConstantPoolModuleItem) ConstantPool [requiresIndex]).Name.Value; + public string RequiresVersion => + ((ConstantPoolUtf8Item) ConstantPool [requiresVersionIndex]).Value; + + public ModuleRequiresInfo (ConstantPool constantPool, Stream stream) + { + ConstantPool = constantPool; + + requiresIndex = stream.ReadNetworkUInt16 (); + RequiresFlags = (ModuleRequiresInfoFlags) stream.ReadNetworkUInt16 (); + requiresVersionIndex = stream.ReadNetworkUInt16 (); + } + + public override string ToString () + { + return $"Requires({Requires}, Version={RequiresVersion}, Flags={RequiresFlags})"; + } + } + + public enum ModuleExportsPackageInfoFlags { + Synthetic = 0x1000, + Mandated = 0x8000, + } + + // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.25 + public sealed class ModuleExportsPackageInfo { + ushort exportsIndex; + public string Exports => + ((ConstantPoolPackageItem) ConstantPool [exportsIndex]).Name.Value; + + public ConstantPool ConstantPool {get; private set;} + public ModuleExportsPackageInfoFlags Flags {get; private set;} + public Collection ExportsTo {get;} = new (); + + + public ModuleExportsPackageInfo (ConstantPool constantPool, Stream stream) + { + ConstantPool = constantPool; + + exportsIndex = stream.ReadNetworkUInt16 (); + Flags = (ModuleExportsPackageInfoFlags) stream.ReadNetworkUInt16 (); + + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + var exports_to_index = stream.ReadNetworkUInt16 (); + ExportsTo.Add ((ConstantPoolModuleItem) constantPool [exports_to_index]); + } + } + + public override string ToString () + { + var s = new StringBuilder () + .Append ("ExportsPackage(Name=\"").Append (Exports).Append ("\""); + if (Flags != 0) { + s.Append (", Flags=").Append (Flags); + } + if (ExportsTo.Count > 0) { + s.Append (", To={"); + s.Append (ExportsTo [0].Name.Value); + for (int i = 1; i < ExportsTo.Count; ++i) { + s.Append (", "); + s.Append (ExportsTo [i].Name.Value); + } + s.Append ("}"); + } + s.Append (")"); + return s.ToString (); + } + } + + + public enum ModuleOpensPackageInfoFlags { + Synthetic = 0x1000, + Mandated = 0x8000, + } + + // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.25 + public sealed class ModuleOpensPackageInfo { + ushort opensIndex; + + public ConstantPool ConstantPool {get; private set;} + + public ModuleOpensPackageInfoFlags Flags {get; private set;} + + public Collection OpensTo {get;} = new (); + public string Opens => + ((ConstantPoolPackageItem) ConstantPool [opensIndex]).Name.Value; + + public ModuleOpensPackageInfo (ConstantPool constantPool, Stream stream) + { + ConstantPool = constantPool; + + opensIndex = stream.ReadNetworkUInt16 (); + Flags = (ModuleOpensPackageInfoFlags) stream.ReadNetworkUInt16 (); + + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + var opens_to_index = stream.ReadNetworkUInt16 (); + OpensTo.Add ((ConstantPoolModuleItem) constantPool [opens_to_index]); + } + } + + public override string ToString () + { + var to = string.Join (", ", OpensTo.Select (e => e.Name.Value)); + return $"Opens({Opens}, Flags={Flags}, To={to})"; + } + } + + // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.25 + public sealed class ModuleProvidesInfo { + ushort providesIndex; + + public string Provides => + ((ConstantPoolClassItem) ConstantPool [providesIndex]).Name.Value; + + public ConstantPool ConstantPool {get; private set;} + + public Collection ProvidesWith {get;} = new (); + + public ModuleProvidesInfo (ConstantPool constantPool, Stream stream) + { + ConstantPool = constantPool; + + providesIndex = stream.ReadNetworkUInt16 (); + + var count = stream.ReadNetworkUInt16 (); + for (int i = 0; i < count; ++i) { + var provides_with_index = stream.ReadNetworkUInt16 (); + ProvidesWith.Add ((ConstantPoolClassItem) constantPool [provides_with_index]); + } + } + + public override string ToString () + { + var with = string.Join (", ", ProvidesWith.Select (e => e.Name.Value)); + return $"Service(ServiceInterface={Provides}, ServiceImplementations={{{with}}})"; + } + } +} \ No newline at end of file diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Signatures.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Signatures.cs new file mode 100644 index 00000000000..e514b9d2a6a --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Signatures.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode { + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.4 + static class Signature { + + internal static string ExtractType (string signature, ref int index) + { + AssertSignatureIndex (signature, index); + var i = index++; + switch (signature [i]) { + case '[': + ++i; + if (i >= signature.Length) + throw new InvalidOperationException (string.Format ("Missing array type after '[' at index {0} in: {1}", i, signature)); + string r = ExtractType (signature, ref index); + return "[" + r; + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'V': + case 'Z': + return signature [i].ToString (); + case 'L': + case 'T': + int depth = 0; + int e = index; + while (e < signature.Length) { + var c = signature [e++]; + if (depth == 0 && c == ';') + break; + + if (c == '<') + depth++; + else if (c == '>') + depth--; + } + if (e > signature.Length) + throw new InvalidOperationException (string.Format ("Missing reference type after '{0}' at index {1} in: {2}", signature [i], i, signature)); + index = e; + return signature.Substring (i, (e - i)); + default: + throw new InvalidOperationException ("Unknown JNI Type '" + signature [i] + "' within: " + signature); + } + } + + internal static void AssertSignatureIndex (string signature, int index) + { + if (signature == null) + throw new ArgumentNullException ("signature"); + if (signature.Length == 0) + throw new ArgumentException ("Descriptor cannot be empty string", "descriptor"); + if (index >= signature.Length) + throw new ArgumentException ("index >= descriptor.Length", "index"); + } + + internal static string ExtractIdentifier (string signature, ref int index) + { + int s = index; + int e = s + 1; + while (e < signature.Length && IsUnqualifiedChar (signature [e]) && signature [e] != ':') + e++; + index = e; + return signature.Substring (s, e - s); + } + + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.2.2 + static bool IsUnqualifiedChar (char c) + { + switch (c) { + case '.': + case ';': + case '[': + case '/': + return false; + } + return true; + } + + internal static void ExtractFormalTypeParameters (ICollection typeParameters, string signature, ref int index) + { + AssertSignatureIndex (signature, index); + if (signature [index] != '<') + return; + index++; + string t; + while ((t = ExtractIdentifier (signature, ref index)) != null) { + var bounds = new TypeParameterInfo (t); + typeParameters.Add (bounds); + + AssertSignatureIndex (signature, index); + + if (signature [index] == '>') + break; + + if (signature [index] == ':') { + index++; + if (signature [index] != ':') + bounds.ClassBound = ExtractType (signature, ref index); + } + + if (signature [index] == '>') + break; + + AssertSignatureIndex (signature, index); + + while (signature [index] == ':') { + index++; + bounds.InterfaceBounds.Add (ExtractType (signature, ref index)); + AssertSignatureIndex (signature, index); + } + + if (signature [index] == '>') + break; + } + index++; + } + } + + public sealed class TypeParameterInfo { + + public string Identifier; + public string? ClassBound; + public List InterfaceBounds = new List (); + + public TypeParameterInfo (string identifier, string? classBound = null, string[]? interfaceBounds = null) + { + Identifier = identifier; + ClassBound = classBound; + + if (interfaceBounds != null) + InterfaceBounds.AddRange (interfaceBounds); + } + + public override string ToString () + { + var sb = new StringBuilder ("TypeParameterInfo(") + .Append (Identifier) + .Append (" : ").Append (ClassBound); + foreach (var iface in InterfaceBounds) { + sb.Append (", ").Append (iface); + } + sb.Append (")"); + return sb.ToString (); + } + } + + public sealed class ClassSignature { + + public TypeParameterInfoCollection TypeParameters = new TypeParameterInfoCollection (); + public string SuperclassSignature; + public Collection SuperinterfaceSignatures = new Collection (); + + public ClassSignature (string signature) + { + int index = 0; + Signature.AssertSignatureIndex (signature, index); + Signature.ExtractFormalTypeParameters (TypeParameters, signature, ref index); + Signature.AssertSignatureIndex (signature, index); + SuperclassSignature = Signature.ExtractType (signature, ref index); + while (index < signature.Length) { + var t = Signature.ExtractType (signature, ref index); + SuperinterfaceSignatures.Add (t); + } + } + + public override string ToString () + { + var sb = new StringBuilder ("ClassSignature"); + if (TypeParameters.Count > 0) { + sb.Append ("<").Append (string.Join (", ", TypeParameters.Select (t => t.ToString ()))).Append (">"); + } + sb.Append ("(").Append ("Superclass=").Append (SuperclassSignature); + if (SuperinterfaceSignatures.Count > 0) { + sb.Append (", Superinterfaces(") + .Append (string.Join (", ", SuperinterfaceSignatures)) + .Append (")"); + } + sb.Append (")"); + return sb.ToString (); + } + } + + public class TypeParameterInfoCollection : KeyedCollection { + + protected override string GetKeyForItem (TypeParameterInfo item) + { + return item.Identifier; + } + } + + public sealed class MethodTypeSignature { + + public TypeParameterInfoCollection TypeParameters = new TypeParameterInfoCollection (); + public Collection Parameters = new Collection (); + public Collection Throws = new Collection (); + + public string ReturnTypeSignature; + + public MethodTypeSignature (string signature) + { + int index = 0; + Signature.AssertSignatureIndex (signature, index); + Signature.ExtractFormalTypeParameters (TypeParameters, signature, ref index); + Signature.AssertSignatureIndex (signature, index); + if (signature [index] != '(') + throw new ArgumentException (string.Format ("Method signature needs to contain '(' at index {0} in: {1}", index, signature)); + index++; + while (index < signature.Length && signature [index] != ')') { + Parameters.Add (Signature.ExtractType (signature, ref index)); + } + if (signature [index] != ')') + throw new ArgumentException (string.Format ("Method signature needs to contain ')' at index {0} in: {1}", index, signature)); + index++; + ReturnTypeSignature = Signature.ExtractType (signature, ref index); + if (index == signature.Length) + return; + if (signature [index] != '^') + throw new ArgumentException (string.Format ("Method signature should end with exception '^' types; found: '{0}' at {1} in: {2}", + signature [index], index, signature)); + while (index < signature.Length && signature [index] == '^') { + index++; + var t = Signature.ExtractType (signature, ref index); + Throws.Add (t); + } + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/StreamCoda.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/StreamCoda.cs new file mode 100644 index 00000000000..9a9bedd5b05 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/StreamCoda.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using System.Net; + +namespace Xamarin.Android.Tools { + + static class StreamCoda { + + internal static byte ReadNetworkByte (this Stream stream) + { + int v = stream.ReadByte (); + if (v < 0) + throw new BadImageFormatException (); + return (byte) v; + } + + internal static ushort ReadNetworkUInt16 (this Stream stream) + { + var a = stream.ReadNetworkByte (); + var b = stream.ReadNetworkByte (); + return (ushort) ((a << 8) | b); + } + + internal static uint ReadNetworkUInt32 (this Stream stream) + { + var a = stream.ReadNetworkByte (); + var b = stream.ReadNetworkByte (); + var c = stream.ReadNetworkByte (); + var d = stream.ReadNetworkByte (); + return (uint) ((uint) (a << 24)) | + ((uint) (b << 16)) | + ((uint) (c << 8)) | + ((uint) d); + } + + internal static long ReadNetworkInt64 (this Stream stream) + { + var hi = (long) stream.ReadNetworkUInt32 (); + var lo = (long) stream.ReadNetworkUInt32 (); + return ((hi << 32) + lo); + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/TypeAnnotation.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/TypeAnnotation.cs new file mode 100644 index 00000000000..6053b8960fe --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/TypeAnnotation.cs @@ -0,0 +1,129 @@ +using System; +using System.IO; + +namespace Xamarin.Android.Tools.Bytecode +{ + // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20 + public enum TypeAnnotationTargetType : byte + { + ClassTypeParameter = 0x00, + MethodTypeParameter = 0x01, + ClassExtends = 0x10, + ClassTypeParameterBound = 0x11, + MethodTypeParameterBound = 0x12, + Field = 0x13, + MethodReturn = 0x14, + MethodReceiver = 0x15, + MethodFormalParameter = 0x16, + Throws = 0x17, + LocalVariable = 0x40, + ResourceVariable = 0x41, + ExceptionParameter = 0x42, + Instanceof = 0x43, + New = 0x44, + ConstructorReference = 0x45, + MethodReference = 0x46, + Cast = 0x47, + ConstructorInvocationTypeArgument = 0x48, + MethodInvocationTypeArgument = 0x49, + ConstructorReferenceTypeArgument = 0x4A, + MethodReferenceTypeArgument = 0x4B, + } + + // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20 + public sealed class TypeAnnotation + { + public TypeAnnotationTargetType TargetType { get; } + + // `formal_parameter_index` for MethodFormalParameter; otherwise 0. + public int FormalParameterIndex { get; } + + // `path_length` from `type_path`; we don't retain the individual + // path entries — see AppliesToTopLevelType. + public int TypePathLength { get; } + + public Annotation Annotation { get; } + + // JSpecify-style nullness annotations only apply to the top-level + // type when there is no `type_path`. Annotations with a non-empty + // path describe inner types (e.g. `Map<@Nullable K, V>`) which the + // API XML schema cannot currently represent. + public bool AppliesToTopLevelType => TypePathLength == 0; + + public TypeAnnotation (ConstantPool constantPool, Stream stream) + { + TargetType = (TypeAnnotationTargetType) stream.ReadNetworkByte (); + + // target_info — size depends on target_type. + switch (TargetType) { + case TypeAnnotationTargetType.ClassTypeParameter: + case TypeAnnotationTargetType.MethodTypeParameter: + stream.ReadNetworkByte (); // type_parameter_index + break; + case TypeAnnotationTargetType.ClassExtends: + stream.ReadNetworkUInt16 (); // supertype_index + break; + case TypeAnnotationTargetType.ClassTypeParameterBound: + case TypeAnnotationTargetType.MethodTypeParameterBound: + stream.ReadNetworkByte (); // type_parameter_index + stream.ReadNetworkByte (); // bound_index + break; + case TypeAnnotationTargetType.Field: + case TypeAnnotationTargetType.MethodReturn: + case TypeAnnotationTargetType.MethodReceiver: + // empty_target — no bytes + break; + case TypeAnnotationTargetType.MethodFormalParameter: + FormalParameterIndex = stream.ReadNetworkByte (); + break; + case TypeAnnotationTargetType.Throws: + stream.ReadNetworkUInt16 (); // throws_type_index + break; + case TypeAnnotationTargetType.LocalVariable: + case TypeAnnotationTargetType.ResourceVariable: { + var table_length = stream.ReadNetworkUInt16 (); + for (int i = 0; i < table_length; ++i) { + stream.ReadNetworkUInt16 (); // start_pc + stream.ReadNetworkUInt16 (); // length + stream.ReadNetworkUInt16 (); // index + } + break; + } + case TypeAnnotationTargetType.ExceptionParameter: + stream.ReadNetworkUInt16 (); // exception_table_index + break; + case TypeAnnotationTargetType.Instanceof: + case TypeAnnotationTargetType.New: + case TypeAnnotationTargetType.ConstructorReference: + case TypeAnnotationTargetType.MethodReference: + stream.ReadNetworkUInt16 (); // offset + break; + case TypeAnnotationTargetType.Cast: + case TypeAnnotationTargetType.ConstructorInvocationTypeArgument: + case TypeAnnotationTargetType.MethodInvocationTypeArgument: + case TypeAnnotationTargetType.ConstructorReferenceTypeArgument: + case TypeAnnotationTargetType.MethodReferenceTypeArgument: + stream.ReadNetworkUInt16 (); // offset + stream.ReadNetworkByte (); // type_argument_index + break; + default: + throw new NotSupportedException ($"Unknown type_annotation target_type: 0x{(byte)TargetType:X2}"); + } + + // type_path: u1 path_length, then path_length * { u1 type_path_kind; u1 type_argument_index; } + TypePathLength = stream.ReadNetworkByte (); + for (int i = 0; i < TypePathLength; ++i) { + stream.ReadNetworkByte (); // type_path_kind + stream.ReadNetworkByte (); // type_argument_index + } + + // The remaining bytes match the regular `annotation` structure. + Annotation = new Annotation (constantPool, stream); + } + + public override string ToString () + { + return $"TypeAnnotation({TargetType}, paramIndex={FormalParameterIndex}, pathLength={TypePathLength}, {Annotation})"; + } + } +} diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj new file mode 100644 index 00000000000..51f8e331970 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj @@ -0,0 +1,25 @@ + + + + $(DotNetTargetFramework) + true + ..\..\product.snk + enable + + + + + + $(TestOutputFullPath) + + + + + + + + $(PkgProtobuf-net)\lib\netstandard2.0\protobuf-net.dll + + + + diff --git a/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs new file mode 100644 index 00000000000..7f6113a750d --- /dev/null +++ b/external/Java.Interop/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs @@ -0,0 +1,954 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Xml.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.Bytecode { + + public class XmlClassDeclarationBuilder { + + ClassFile classFile; + ClassFile? packageInfo; + ClassSignature? signature; + bool isNullMarked; + + bool IsInterface { + get {return (classFile.AccessFlags & ClassAccessFlags.Interface) != 0;} + } + + public XmlClassDeclarationBuilder (ClassFile classFile) + : this (classFile, packageInfo: null) + { + } + + public XmlClassDeclarationBuilder (ClassFile classFile, ClassFile? packageInfo) + { + if (classFile == null) + throw new ArgumentNullException ("classFile"); + + this.classFile = classFile; + this.packageInfo = packageInfo; + signature = classFile.GetSignature (); + isNullMarked = ComputeIsNullMarked (); + } + + // Module-level and inner-class scope inheritance are not yet implemented. + bool ComputeIsNullMarked () + { + var classScope = GetJSpecifyScope (classFile.Attributes); + if (classScope.HasValue) + return classScope.Value; + + if (packageInfo != null) { + var pkgScope = GetJSpecifyScope (packageInfo.Attributes); + if (pkgScope.HasValue) + return pkgScope.Value; + } + + return false; + } + + // `@NullMarked` / `@NullUnmarked` are `@Retention(RUNTIME)`, so + // check both Visible and Invisible annotation tables. + static bool? GetJSpecifyScope (AttributeCollection? attributes) + { + if (attributes == null) + return null; + foreach (var a in EnumerateDeclarationAnnotations (attributes)) { + if (a.Type == "Lorg/jspecify/annotations/NullUnmarked;") + return false; + if (a.Type == "Lorg/jspecify/annotations/NullMarked;") + return true; + } + return null; + } + + static IEnumerable EnumerateDeclarationAnnotations (AttributeCollection attributes) + { + foreach (var v in attributes.OfType ()) + foreach (var a in v.Annotations) + yield return a; + foreach (var i in attributes.OfType ()) + foreach (var a in i.Annotations) + yield return a; + } + + public XElement ToXElement () + { + return new XElement (GetElementName (), + new XAttribute ("abstract", (classFile.AccessFlags & ClassAccessFlags.Abstract) != 0), + new XAttribute ("deprecated", GetDeprecatedValue (classFile.Attributes)), + GetEnclosingMethod (), + GetExtends (), + GetExtendsGenericAware (), + new XAttribute ("final", (classFile.AccessFlags & ClassAccessFlags.Final) != 0), + new XAttribute ("name", GetThisClassName ()), + new XAttribute ("jni-signature", classFile.FullJniName), + GetSourceFile (), + new XAttribute ("static", classFile.IsStatic), + new XAttribute ("visibility", GetVisibility (classFile.Visibility)), + GetAnnotatedVisibility (classFile.Visibility, classFile.Attributes), + GetKotlinInlineClassAttributes (), + GetTypeParmeters (signature == null ? null : signature.TypeParameters), + GetImplementedInterfaces (), + GetConstructors (), + GetMethods (), + GetFields () + ); + } + + // dotnet/java-interop#1431 (Phase 2): when this class is a Kotlin + // `@JvmInline value class`, emit two extra attributes that drive + // generator-side wrapper-struct emission and parameter/return projection. + IEnumerable GetKotlinInlineClassAttributes () + { + var underlying = classFile.KotlinInlineClassUnderlyingJniType; + if (string.IsNullOrEmpty (underlying)) + yield break; + yield return new XAttribute ("kotlin-inline-class", "true"); + yield return new XAttribute ("kotlin-inline-class-underlying-jni-type", underlying); + } + + string GetElementName () + { + if (IsInterface) + return "interface"; + return "class"; + } + + static string GetDeprecatedValue (AttributeCollection attributes) + { + if (attributes.Get () == null) + return "not deprecated"; + return "deprecated"; + } + + IEnumerable GetEnclosingMethod () + { + string? declaringClass, declaringMethod, declaringDescriptor; + if (!classFile.TryGetEnclosingMethodInfo (out declaringClass, out declaringMethod, out declaringDescriptor)) { + yield break; + } + if (declaringClass != null) + yield return new XAttribute ("enclosing-method-jni-type", "L" + declaringClass + ";"); + if (declaringMethod != null) + yield return new XAttribute ("enclosing-method-name", declaringMethod); + if (declaringDescriptor != null) + yield return new XAttribute ("enclosing-method-signature", declaringDescriptor); + } + + XAttribute[]? GetExtends () + { + if (IsInterface) + return null; + if (classFile.SuperClass == null) + return null; + return new []{ + new XAttribute ("jni-extends", "L" + classFile.SuperClass.Name.Value + ";"), + new XAttribute ("extends", BinaryNameToJavaClassName (classFile.SuperClass.Name.Value)), + }; + } + + XAttribute? GetExtendsGenericAware () + { + if (IsInterface) + return null; + if (classFile.SuperClass == null) + return null; + var superSig = classFile.SuperClass.Name.Value; + return new XAttribute ("extends-generic-aware", + signature != null + ? SignatureToGenericJavaTypeName (signature.SuperclassSignature) + : BinaryNameToJavaClassName (superSig)); + } + + static string GetVisibility (ClassAccessFlags accessFlags) + { + if ((accessFlags & ClassAccessFlags.Public) != 0) + return "public"; + if ((accessFlags & ClassAccessFlags.Protected) != 0) + return "protected"; + if ((accessFlags & ClassAccessFlags.Private) != 0) + return "private"; + if (accessFlags.HasFlag (ClassAccessFlags.Internal)) + return "public"; // TODO: `kotlin-internal` at some point? See also GetAnnotatedVisibility() + return ""; + } + + string GetThisClassName () + { + return GetName (classFile.ThisClass.Name.Value); + } + + static string GetName (string value) + { + int s = value.LastIndexOf ('/'); + if (s >= 0) + value = value.Substring (s + 1); + return value.Replace ('$', '.'); + } + + static string BinaryNameToJavaClassName (string? value) + { + if (value == null || string.IsNullOrEmpty (value)) + return string.Empty; + return value.Replace ('/', '.').Replace ('$', '.'); + } + + string SignatureToJavaTypeName (string? value) + { + if (value == null || string.IsNullOrEmpty (value)) + return string.Empty; + int index = 0; + var array = GetArraySuffix (value, ref index); + var builtin = GetBuiltinName (value, ref index); + if (builtin != null) + return builtin + array; + if (value [index] == 'L') { + index++; + var type = new StringBuilder (); + int depth = 0; + int e = index; + while (e < value.Length) { + var c = value [e++]; + if (depth == 0 && c == ';') + break; + + if (c == '<') { + depth++; + } else if (c == '>') { + depth--; + } else if (depth > 0) { + ; + } else if (c == '/' || c == '$') { + type.Append ('.'); + } else { + type.Append (c); + } + } + return type.Append (array).ToString (); + } + if (value [index] == 'T') { + index++; + var tp = Signature.ExtractIdentifier (value, ref index); + if (signature != null) + return SignatureToJavaTypeName (signature.TypeParameters [tp].ClassBound) + array; + } + return value; + } + + static string SignatureToGenericJavaTypeName (string? value) + { + if (value == null || string.IsNullOrEmpty (value)) + return string.Empty; + int index = 0; + var type = new StringBuilder (); + return AppendGenericTypeNameFromSignature (type, value, ref index) + .ToString (); + } + + static StringBuilder AppendGenericTypeNameFromSignature (StringBuilder typeBuilder, string value, ref int index) + { + var array = GetArraySuffix (value, ref index); + var builtin = GetBuiltinName (value, ref index); + if (builtin != null) { + return typeBuilder.Append (builtin).Append (array); + } + switch (value [index]) { + case 'L': + index++; + int depth = 0; + while (index < value.Length) { + var c = value [index++]; + if (depth == 0 && c == ';') + break; + + if (c == '<') { + depth++; + typeBuilder.Append ("<"); + AppendGenericTypeNameFromSignature (typeBuilder, value, ref index); + } else if (c == '>') { + typeBuilder.Append (">"); + depth--; + } else if (depth > 0) { + index--; + typeBuilder.Append (", "); + AppendGenericTypeNameFromSignature (typeBuilder, value, ref index); + } else if (c == '/' || c == '$') { + typeBuilder.Append ('.'); + } else { + typeBuilder.Append (c); + } + } + return typeBuilder.Append (array); + case 'T': + index++; + typeBuilder.Append (Signature.ExtractIdentifier (value, ref index)); + index++; // consume ';' + return typeBuilder.Append(array); + case '*': + index++; + return typeBuilder.Append ("?"); + case '+': + index++; + typeBuilder.Append ("? extends "); + return AppendGenericTypeNameFromSignature (typeBuilder, value, ref index); + case '-': + index++; + typeBuilder.Append ("? super "); + return AppendGenericTypeNameFromSignature (typeBuilder, value, ref index); + } + typeBuilder.Append ("/* should not be reached */").Append (value.Substring (index)); + index = value.Length; + return typeBuilder; + } + + static string? GetArraySuffix (string value, ref int index) + { + int o = index; + while (value [index] == '[') { + index++; + } + if (o == index) + return null; + return string.Join ("", Enumerable.Repeat ("[]", index - o)); + } + + static string? GetBuiltinName (string value, ref int index) + { + switch (value [index]) { + case 'B': index++; return "byte"; + case 'C': index++; return "char"; + case 'D': index++; return "double"; + case 'F': index++; return "float"; + case 'I': index++; return "int"; + case 'J': index++; return "long"; + case 'S': index++; return "short"; + case 'V': index++; return "void"; + case 'Z': index++; return "boolean"; + } + return null; + } + + XAttribute? GetSourceFile () + { + var sourceFile = classFile.SourceFileName; + if (sourceFile == null) + return null; + return new XAttribute ("source-file-name", sourceFile); + } + + XElement? GetTypeParmeters (TypeParameterInfoCollection? typeParameters) + { + if (typeParameters == null || typeParameters.Count == 0) + return null; + return new XElement ("typeParameters", + typeParameters.Select (tp => + new XElement ("typeParameter", + new XAttribute ("name", tp.Identifier), + new XAttribute ("jni-classBound", tp.ClassBound ?? ""), + new XAttribute ("classBound", SignatureToGenericJavaTypeName (tp.ClassBound)), + new XAttribute ("interfaceBounds", string.Join (":", tp.InterfaceBounds.Select (_ => SignatureToGenericJavaTypeName (_)))), + new XAttribute ("jni-interfaceBounds", string.Join (":", tp.InterfaceBounds))))); + } + + IEnumerable GetImplementedInterfaces () + { + if (signature != null) { + if (signature.SuperinterfaceSignatures.Count != classFile.Interfaces.Count) { + Console.Error.WriteLine ("class-parse: warning: class' Signature's superinterfaces count doesn't match Interfaces count!"); + } + int max = Math.Min (signature.SuperinterfaceSignatures.Count, classFile.Interfaces.Count); + for (int i = 0; i < max; ++i) { + yield return new XElement ("implements", + new XAttribute ("name", BinaryNameToJavaClassName (classFile.Interfaces [i].Name.Value)), + new XAttribute ("name-generic-aware", SignatureToGenericJavaTypeName (signature.SuperinterfaceSignatures [i])), + new XAttribute ("jni-type", signature.SuperinterfaceSignatures [i])); + } + yield break; + } + foreach (var c in classFile.Interfaces) { + var n = BinaryNameToJavaClassName (c.Name.Value); + yield return new XElement ("implements", + new XAttribute ("name", n), + new XAttribute ("name-generic-aware", n), + new XAttribute ("jni-type", "L" + c.Name.Value + ";")); + } + } + + IEnumerable GetConstructors () + { + return classFile.Methods.Where (m => m.Name == "" + && (GetMethodVisibility(m.AccessFlags) == "public" || GetMethodVisibility(m.AccessFlags) == "protected" || GetMethodVisibility (m.AccessFlags) == "kotlin-internal")) + .OrderBy (m => m.Name + m.Descriptor, StringComparer.OrdinalIgnoreCase) + .Select (c => GetMethod ("constructor", GetThisClassName (), c, null)); + } + + XElement GetMethod (string element, string name, MethodInfo method, string? returns = null) + { + var abstr = element == "method" + ? new XAttribute ("abstract", (method.AccessFlags & MethodAccessFlags.Abstract) != 0) + : null; + var ret = returns != null + ? new XAttribute ("return", SignatureToGenericJavaTypeName (returns)) + : null; + if (!string.IsNullOrWhiteSpace (method.KotlinReturnType)) + ret?.SetValue (method.KotlinReturnType); + var jniRet = returns != null + ? new XAttribute ("jni-return", returns) + : null; + var msig = method.GetSignature (); + return new XElement (element, + abstr, + new XAttribute ("deprecated", GetDeprecatedValue (method.Attributes)), + new XAttribute ("final", (method.AccessFlags & MethodAccessFlags.Final) != 0), + new XAttribute ("name", name), + GetManagedName (method), + GetNative (method), + ret, + jniRet, + GetKotlinInlineClassReturnJniType (method), + new XAttribute ("static", (method.AccessFlags & MethodAccessFlags.Static) != 0), + GetSynchronized (method), + new XAttribute ("visibility", GetVisibility (method.AccessFlags)), + GetAnnotatedVisibility (method.Attributes), + new XAttribute ("bridge", (method.AccessFlags & MethodAccessFlags.Bridge) != 0), + new XAttribute ("synthetic", (method.AccessFlags & MethodAccessFlags.Synthetic) != 0), + new XAttribute ("jni-signature", method.Descriptor), + GetNotNull (method), + GetTypeParmeters (msig == null ? null : msig.TypeParameters), + GetMethodParameters (method), + GetExceptions (method)); + } + + // dotnet/java-interop#1431 (Phase 2): when the Kotlin compiler mangled + // the JVM method name for inline-class binary compatibility (e.g. + // `tint-Rn_QMJI`), expose the unmangled Kotlin source name via + // `managedName` so the generator emits a clean C# overload. The JVM + // name remains in `name`/`jni-signature` for JNI invocation. + static XAttribute? GetManagedName (MethodInfo method) + { + if (string.IsNullOrEmpty (method.KotlinName)) + return null; + return new XAttribute ("managedName", method.KotlinName); + } + + // dotnet/java-interop#1431 (Phase 2): when a method's Kotlin source-level + // return type was a `@JvmInline value class`, surface that type's JNI + // signature so the generator can project the return type to a wrapper struct. + static XAttribute? GetKotlinInlineClassReturnJniType (MethodInfo method) + { + if (string.IsNullOrEmpty (method.KotlinInlineClassReturnJniType)) + return null; + return new XAttribute ("kotlin-inline-class-return-jni-type", method.KotlinInlineClassReturnJniType); + } + + static XAttribute? GetNative (MethodInfo method) + { + if (method.IsConstructor) + return null; + return new XAttribute ("native", (method.AccessFlags & MethodAccessFlags.Native) != 0); + } + + static XAttribute? GetSynchronized (MethodInfo method) + { + if (method.IsConstructor) + return null; + return new XAttribute ("synchronized", (method.AccessFlags & MethodAccessFlags.Synchronized) != 0); + } + + static string GetVisibility (MethodAccessFlags accessFlags) + { + if (accessFlags.HasFlag (MethodAccessFlags.Internal)) + return "kotlin-internal"; + if ((accessFlags & MethodAccessFlags.Public) != 0) + return "public"; + if ((accessFlags & MethodAccessFlags.Protected) != 0) + return "protected"; + if ((accessFlags & MethodAccessFlags.Private) != 0) + return "private"; + return ""; + } + + IEnumerable GetMethodParameters (MethodInfo method) + { + var invisible = method.Attributes?.OfType ().FirstOrDefault ()?.Annotations; + var visible = method.Attributes?.OfType ().FirstOrDefault ()?.Annotations; + IList? annotations = invisible; + if (annotations == null) { + annotations = visible; + } else if (visible != null) { + var merged = new List (annotations); + merged.AddRange (visible); + annotations = merged; + } + var varargs = (method.AccessFlags & MethodAccessFlags.Varargs) != 0; + var parameters = method.GetParameters (); + for (int i = 0; i < parameters.Length; ++i) { + var p = parameters [i]; + var type = p.Type.BinaryName; + var genericType = p.Type.TypeSignature; + var varargArray = (i == (parameters.Length - 1)) && varargs; + if (varargArray) { + Debug.Assert (p.Type.BinaryName.StartsWith ("[", StringComparison.Ordinal), + "Varargs parameters MUST be arrays!"); + Debug.Assert (p.Type.TypeSignature != null && p.Type.TypeSignature.StartsWith ("[", StringComparison.Ordinal), + "Varargs parameters MUST be arrays!"); + type = type.Substring (1); + genericType = genericType?.Substring (1); + } + genericType = SignatureToGenericJavaTypeName (genericType); + if (!string.IsNullOrWhiteSpace (p.KotlinType)) + genericType = p.KotlinType; + if (varargArray) { + type += "..."; + genericType += "..."; + } + yield return new XElement ("parameter", + new XAttribute ("name", p.Name), + new XAttribute ("type", genericType), + new XAttribute ("jni-type", p.Type.TypeSignature ?? p.Type.BinaryName), + GetKotlinInlineClassJniType (p), + GetNotNull (method, annotations, i)); + } + } + + // dotnet/java-interop#1431 (Phase 2): when the parameter's Kotlin source-level + // type was a `@JvmInline value class`, surface that type's JNI signature so + // the generator can project the parameter to a strongly-typed wrapper struct. + static XAttribute? GetKotlinInlineClassJniType (ParameterInfo p) + { + if (string.IsNullOrEmpty (p.KotlinInlineClassJniType)) + return null; + return new XAttribute ("kotlin-inline-class-jni-type", p.KotlinInlineClassJniType); + } + + IEnumerable GetExceptions (MethodInfo method) + { + foreach (var t in method.GetThrows ()) { + yield return new XElement ("exception", + new XAttribute ("name", t.BinaryName), + new XAttribute ("type", BinaryNameToJavaClassName (t.BinaryName)), + new XAttribute ("type-generic-aware", t.TypeSignature != null + ? SignatureToGenericJavaTypeName (t.TypeSignature) + : BinaryNameToJavaClassName (t.BinaryName))); + } + } + + static XAttribute? GetAnnotatedVisibility (ClassAccessFlags flags, AttributeCollection attributes) + { + var attr = GetAnnotatedVisibility (attributes); + if (flags.HasFlag (ClassAccessFlags.Internal)) { + if (attr == null) { + attr = new XAttribute ("annotated-visibility", "module-info"); + } else { + attr.Value += " module-info"; + } + } + return attr; + } + + static XAttribute? GetAnnotatedVisibility (AttributeCollection attributes) + { + var annotations = attributes?.OfType ().FirstOrDefault ()?.Annotations; + + if (annotations?.FirstOrDefault (a => a.Type == "Landroidx/annotation/RestrictTo;") is Annotation annotation) { + var annotation_element_values = (annotation.Values.FirstOrDefault ().Value as AnnotationElementArray)?.Values?.OfType (); + + if (annotation_element_values is null || !annotation_element_values.Any ()) + return null; + + var value_string = string.Join (" ", annotation_element_values.Select (v => v.ConstantName).Where (p => p != null)); + + if (string.IsNullOrWhiteSpace (value_string)) + return null; + + return new XAttribute ("annotated-visibility", value_string); + } + + return null; + } + + XAttribute? GetNotNull (MethodInfo method) + { + var nullness = GetMethodReturnNullness (method); + if (nullness == true) + return new XAttribute ("return-not-null", "true"); + return null; + } + + XAttribute? GetNotNull (MethodInfo method, IList? annotations, int parameterIndex) + { + var nullness = GetParameterNullness (method, annotations, parameterIndex); + if (nullness == true) + return new XAttribute ("not-null", "true"); + return null; + } + + XAttribute? GetNotNull (FieldInfo field) + { + var nullness = GetFieldNullness (field); + if (nullness == true) + return new XAttribute ("not-null", "true"); + return null; + } + + bool? GetMethodReturnNullness (MethodInfo method) + { + if (HasDeclarationNotNullAnnotation (method.Attributes)) + return true; + if (HasDeclarationNullableAnnotation (method.Attributes)) + return null; + var typeNullness = GetTypeUseNullness (method.Attributes, + ta => ta.TargetType == TypeAnnotationTargetType.MethodReturn); + if (typeNullness.HasValue) + return typeNullness; + if (isNullMarked && IsReferenceTypeDescriptor (GetReturnDescriptor (method.Descriptor)) + && !IsTopLevelTypeVariableSignature (method.ReturnType.TypeSignature)) + return true; + return null; + } + + bool? GetParameterNullness (MethodInfo method, IList? annotations, int parameterIndex) + { + bool hasDeclarationNullable = false; + if (annotations != null) { + foreach (var pa in annotations) { + if (pa.ParameterIndex != parameterIndex) + continue; + foreach (var a in pa.Annotations) { + if (IsNotNullAnnotation (a)) + return true; + if (IsNullableAnnotation (a)) + hasDeclarationNullable = true; + } + } + } + if (hasDeclarationNullable) + return null; + + var typeNullness = GetTypeUseNullness (method.Attributes, + ta => ta.TargetType == TypeAnnotationTargetType.MethodFormalParameter + && ta.FormalParameterIndex == parameterIndex); + if (typeNullness.HasValue) + return typeNullness; + + if (isNullMarked) { + var parameters = method.GetParameters (); + if (parameterIndex >= 0 && parameterIndex < parameters.Length + && IsReferenceTypeDescriptor (parameters [parameterIndex].Type.BinaryName) + && !IsTopLevelTypeVariableSignature (parameters [parameterIndex].Type.TypeSignature)) + return true; + } + return null; + } + + bool? GetFieldNullness (FieldInfo field) + { + if (HasDeclarationNotNullAnnotation (field.Attributes)) + return true; + if (HasDeclarationNullableAnnotation (field.Attributes)) + return null; + var typeNullness = GetTypeUseNullness (field.Attributes, + ta => ta.TargetType == TypeAnnotationTargetType.Field); + if (typeNullness.HasValue) + return typeNullness; + if (isNullMarked && IsReferenceTypeDescriptor (field.Descriptor) + && !IsTopLevelTypeVariableSignature (field.GetSignature ())) + return true; + return null; + } + + static bool HasDeclarationNotNullAnnotation (AttributeCollection? attributes) + { + if (attributes == null) + return false; + foreach (var a in EnumerateDeclarationAnnotations (attributes)) { + if (IsNotNullAnnotation (a)) + return true; + } + return false; + } + + static bool HasDeclarationNullableAnnotation (AttributeCollection? attributes) + { + if (attributes == null) + return false; + foreach (var a in EnumerateDeclarationAnnotations (attributes)) { + if (IsNullableAnnotation (a)) + return true; + } + return false; + } + + // Look in `RuntimeInvisibleTypeAnnotations` and `RuntimeVisibleTypeAnnotations` + // for entries matching `predicate` (e.g. METHOD_RETURN, FIELD, or + // a specific METHOD_FORMAL_PARAMETER index) at the top of the type + // (no `type_path`). Returns true for `@NonNull`, false for + // `@Nullable`, null for no match. + static bool? GetTypeUseNullness (AttributeCollection? attributes, Func predicate) + { + if (attributes == null) + return null; + bool? result = null; + foreach (var ta in EnumerateTypeAnnotations (attributes)) { + if (!ta.AppliesToTopLevelType) + continue; + if (!predicate (ta)) + continue; + if (IsNotNullAnnotation (ta.Annotation)) + return true; + if (IsNullableAnnotation (ta.Annotation)) + result = false; + } + return result; + } + + static IEnumerable EnumerateTypeAnnotations (AttributeCollection attributes) + { + foreach (var v in attributes.OfType ()) + foreach (var a in v.Annotations) + yield return a; + foreach (var i in attributes.OfType ()) + foreach (var a in i.Annotations) + yield return a; + } + + static bool IsNullableAnnotation (Annotation annotation) + { + switch (annotation.Type) { + case "Landroid/annotation/Nullable;": + case "Landroid/support/annotation/Nullable;": + case "Landroidx/annotation/Nullable;": + case "Landroidx/annotation/RecentlyNullable;": + case "Lcom/android/annotations/Nullable;": + case "Ledu/umd/cs/findbugs/annotations/Nullable;": + case "Ljakarta/annotation/Nullable;": + case "Ljavax/annotation/Nullable;": + case "Lorg/checkerframework/checker/nullness/compatqual/NullableDecl;": + case "Lorg/checkerframework/checker/nullness/qual/Nullable;": + case "Lorg/eclipse/jdt/annotation/Nullable;": + case "Lorg/jetbrains/annotations/Nullable;": + case "Lorg/jspecify/annotations/Nullable;": + return true; + } + return false; + } + + static string GetReturnDescriptor (string descriptor) + { + var i = descriptor.LastIndexOf (')'); + return i < 0 ? descriptor : descriptor.Substring (i + 1); + } + + static bool IsReferenceTypeDescriptor (string descriptor) + { + if (string.IsNullOrEmpty (descriptor)) + return false; + var c = descriptor [0]; + return c == 'L' || c == '['; + } + + // JSpecify gives unannotated type-variable *usages* parametric + // nullness, so e.g. ` T get()` must not gain `not-null="true"` + // in a null-marked scope. A JVMS signature for a type-variable + // use begins with 'T' (followed by the variable name and ';'). + // Returns false for `null` so callers can pass the raw signature + // when no Signature attribute is present. + static bool IsTopLevelTypeVariableSignature (string? signature) + { + return !string.IsNullOrEmpty (signature) && signature [0] == 'T'; + } + + static bool IsNotNullAnnotation (Annotation annotation) + { + // Android ones plus the list from here: + // https://stackoverflow.com/questions/4963300/which-notnull-java-annotation-should-i-use + // https://github.com/JetBrains/kotlin/blob/03360c0108797b2a98b6608e2bddfacd5f4e87ce/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt#L64-L91 + switch (annotation.Type) { + case "Landroid/annotation/NonNull;": + case "Landroid/support/annotation/NonNull;": + case "Landroidx/annotation/NonNull;": + case "Landroidx/annotation/RecentlyNonNull;": + case "Lcom/android/annotations/NonNull;": + case "Ledu/umd/cs/findbugs/annotations/NonNull;": + case "Ljakarta/annotation/Nonnull;": + case "Ljavax/annotation/Nonnull;": + case "Ljavax/validation/constraints/NotNull;": + case "Llombok/NonNull;": + case "Lorg/checkerframework/checker/nullness/compatqual/NonNullDecl;": + case "Lorg/checkerframework/checker/nullness/qual/NonNull;": + case "Lorg/eclipse/jdt/annotation/NonNull;": + case "Lorg/jetbrains/annotations/NotNull;": + case "Lorg/jspecify/annotations/NonNull;": + return true; + } + + return false; + } + + IEnumerable GetFields () + { + foreach (var field in classFile.Fields.OrderBy (n => n.Name, StringComparer.OrdinalIgnoreCase)) { + var visibility = GetVisibility (field.AccessFlags); + if (visibility == "private" || visibility == "") + continue; + var type = new XAttribute ("type", SignatureToJavaTypeName (field.Descriptor)); + if (!string.IsNullOrWhiteSpace (field.KotlinType)) + type.SetValue (field.KotlinType); + yield return new XElement ("field", + new XAttribute ("deprecated", GetDeprecatedValue (field.Attributes)), + new XAttribute ("final", (field.AccessFlags & FieldAccessFlags.Final) != 0), + new XAttribute ("name", field.Name), + new XAttribute ("static", (field.AccessFlags & FieldAccessFlags.Static) != 0), + new XAttribute ("synthetic", (field.AccessFlags & FieldAccessFlags.Synthetic) != 0), + new XAttribute ("transient", (field.AccessFlags & FieldAccessFlags.Transient) != 0), + type, + new XAttribute ("type-generic-aware", GetGenericType (field)), + new XAttribute ("jni-signature", field.Descriptor), + GetNotNull (field), + GetValue (field), + new XAttribute ("visibility", visibility), + GetAnnotatedVisibility (field.Attributes), + new XAttribute ("volatile", (field.AccessFlags & FieldAccessFlags.Volatile) != 0)); + } + } + + string GetGenericType (FieldInfo field) + { + var signature = field.GetSignature (); + if (signature == null) + return SignatureToJavaTypeName (field.Descriptor); + return SignatureToGenericJavaTypeName (signature); + } + + static XAttribute? GetValue (FieldInfo field) + { + var constantValue = (ConstantValueAttribute?) field.Attributes.FirstOrDefault (a => a.Name == "ConstantValue"); + if (constantValue == null) + return null; + var value = ""; + var constant = constantValue.Constant; + switch (constant.Type) { + case ConstantPoolItemType.Double: + var doubleItem = (ConstantPoolDoubleItem)constant; + if (Double.IsNaN (doubleItem.Value)) + value = "(0.0 / 0.0)"; + else if (Double.IsNegativeInfinity (doubleItem.Value)) + value = "(-1.0 / 0.0)"; + else if (Double.IsPositiveInfinity (doubleItem.Value)) + value = "(1.0 / 0.0)"; + else + value = doubleItem.Value.ToString ("G17", CultureInfo.InvariantCulture); + break; + case ConstantPoolItemType.Float: + var floatItem = (ConstantPoolFloatItem) constant; + if (Double.IsNaN (floatItem.Value)) + value = "(0.0f / 0.0f)"; + else if (Double.IsNegativeInfinity (floatItem.Value)) + value = "(-1.0f / 0.0f)"; + else if (Double.IsPositiveInfinity (floatItem.Value)) + value = "(1.0f / 0.0f)"; + else + value = floatItem.Value.ToString ("G9", CultureInfo.InvariantCulture); + break; + case ConstantPoolItemType.Long: value = ((ConstantPoolLongItem) constant).Value.ToString (); break; + case ConstantPoolItemType.Integer: + if (field.Descriptor == "Z") + value = ((ConstantPoolIntegerItem) constant).Value == 1 ? bool.TrueString.ToLower () : bool.FalseString.ToLower (); + else + value = ((ConstantPoolIntegerItem) constant).Value.ToString (); + break; + case ConstantPoolItemType.String: + value = '"' + EscapeLiteral (((ConstantPoolStringItem) constant).StringData.Value) + '"'; + break; + default: + throw new InvalidOperationException ("Unable to get value for: " + constant); + } + return new XAttribute ("value", value); + } + + static string EscapeLiteral (string value) + { + bool fixup = false; + for (int i = 0; i < value.Length; ++i) { + var c = value [i]; + if (c < 0x20 || c > 0xff || c == '\\' || c == '"') { + fixup = true; + break; + } + } + if (fixup) { + var sb = new StringBuilder (); + for (int i = 0; i < value.Length; ++i) { + var c = value [i]; + if (c == '\\') { + sb.Append (@"\\"); + continue; + } + if (c == '"') { + sb.Append ("\\\""); + continue; + } + if (c < 0x20 || c > 0xff) { + sb.Append ("\\u").AppendFormat ("{0:x4}", (int)c); + continue; + } + sb.Append (c); + } + value = sb.ToString (); + } + return value; + } + + static string GetVisibility (FieldAccessFlags accessFlags) + { + if (accessFlags.HasFlag (FieldAccessFlags.Internal)) + return "kotlin-internal"; + if ((accessFlags & FieldAccessFlags.Public) != 0) + return "public"; + if ((accessFlags & FieldAccessFlags.Protected) != 0) + return "protected"; + if ((accessFlags & FieldAccessFlags.Private) != 0) + return "private"; + return ""; + } + + static string GetMethodVisibility (MethodAccessFlags accessFlags) + { + if (accessFlags.HasFlag (MethodAccessFlags.Internal)) + return "kotlin-internal"; + if ((accessFlags & MethodAccessFlags.Public) != 0) + return "public"; + if ((accessFlags & MethodAccessFlags.Protected) != 0) + return "protected"; + if ((accessFlags & MethodAccessFlags.Private) != 0) + return "private"; + return ""; + } + + static string GetClassVisibility (ClassAccessFlags accessFlags) + { + if ((accessFlags & ClassAccessFlags.Public) != 0) + return "public"; + if ((accessFlags & ClassAccessFlags.Protected) != 0) + return "protected"; + if ((accessFlags & ClassAccessFlags.Private) != 0) + return "private"; + return ""; + } + + IEnumerable GetMethods () + { + return classFile.Methods.Where (m => !m.Name.StartsWith ("<", StringComparison.OrdinalIgnoreCase) + && (GetMethodVisibility(m.AccessFlags) == "public" || GetMethodVisibility(m.AccessFlags) == "protected" || GetMethodVisibility (m.AccessFlags) == "kotlin-internal")) + .OrderBy (m => m.Name + m.Descriptor, StringComparer.OrdinalIgnoreCase) + .Select (m => GetMethod ("method", m.Name, m, + returns: m.ReturnType.TypeSignature)); + } + } +} + diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/CodeWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/CodeWriter.cs new file mode 100644 index 00000000000..3424d518778 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/CodeWriter.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class CodeWriter : IDisposable + { + TextWriter stream; + bool owns_stream; + int indent; + bool need_indent = true; + string base_indent; + + public CodeWriter (string filename) + { + stream = File.CreateText (filename); + owns_stream = true; + } + + public CodeWriter (TextWriter streamWriter, string baseIndent = "") + { + stream = streamWriter; + base_indent = baseIndent; + } + + public void Write (string value) + { + WriteIndent (); + stream.Write (value); + } + + public void WriteLine () + { + stream.WriteLine (); + need_indent = true; + } + + public void WriteLine (string value) + { + if (value?.Length > 0) + WriteIndent (); + + stream.WriteLine (value); + need_indent = true; + } + + public void WriteLine (string format, params object[] args) + { + if (format?.Length > 0) + WriteIndent (); + + stream.WriteLine (format, args); + need_indent = true; + } + + public void WriteLineNoIndent (string value) + { + stream.WriteLine (value); + need_indent = true; + } + + public void Indent (int count = 1) => indent += count; + public void Unindent (int count = 1) => indent -= count; + + private void WriteIndent () + { + if (!need_indent) + return; + + stream.Write (base_indent + new string ('\t', indent)); + + need_indent = false; + } + + public void Dispose () + { + if (owns_stream) + stream?.Dispose (); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Enumerations/Visibility.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Enumerations/Visibility.cs new file mode 100644 index 00000000000..3e97b710b55 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Enumerations/Visibility.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public enum Visibility + { + Default = 0, + Private = 1, + Public = 2, + Protected = 4, + Internal = 8 + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Extensions/StringExtensions.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Extensions/StringExtensions.cs new file mode 100644 index 00000000000..6399236b342 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Extensions/StringExtensions.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public static class StringExtensions + { + public static bool HasValue (this string str) => !string.IsNullOrWhiteSpace (str); + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/AttributeWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/AttributeWriter.cs new file mode 100644 index 00000000000..7f9f5b4961c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/AttributeWriter.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public abstract class AttributeWriter + { + public virtual void WriteAttribute (CodeWriter writer) { } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/ClassWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ClassWriter.cs new file mode 100644 index 00000000000..dc80166e744 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ClassWriter.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class ClassWriter : TypeWriter + { + public ObservableCollection Constructors { get; } = new ObservableCollection (); + + public ClassWriter () + { + Constructors.CollectionChanged += MemberAdded; + } + + public override void WriteConstructors (CodeWriter writer) + { + foreach (var ctor in Constructors) { + ctor.Write (writer); + writer.WriteLine (); + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/CommentWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/CommentWriter.cs new file mode 100644 index 00000000000..d3ec6e48530 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/CommentWriter.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class CommentWriter : ISourceWriter + { + public string Value { get; set; } + public int Priority { get; set; } + + public CommentWriter (string value) + { + Value = value; + } + + public virtual void Write (CodeWriter writer) + { + if (Value.StartsWith ("#pragma", StringComparison.Ordinal)) + writer.WriteLineNoIndent (Value); + else + writer.WriteLine (Value); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/ConstructorWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ConstructorWriter.cs new file mode 100644 index 00000000000..7d1ff7121c1 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ConstructorWriter.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class ConstructorWriter : MethodWriter + { + public string BaseCall { get; set; } + + protected override void WriteReturnType (CodeWriter writer) + { + } + + protected override void WriteConstructorBaseCall (CodeWriter writer) + { + if (BaseCall.HasValue ()) + writer.Write ($" : {BaseCall}"); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/DelegateWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/DelegateWriter.cs new file mode 100644 index 00000000000..9fc56032b81 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/DelegateWriter.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class DelegateWriter : ISourceWriter, ITakeParameters + { + Visibility visibility; + + public string Name { get; set; } + public List Parameters { get; } = new List (); + public TypeReferenceWriter Type { get; set; } + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public bool IsPublic { get => visibility.HasFlag (Visibility.Public); set => visibility = value ? Visibility.Public : Visibility.Default; } + public bool UseExplicitPrivateKeyword { get; set; } + public bool IsInternal { get => visibility.HasFlag (Visibility.Internal); set => visibility = value ? Visibility.Internal : Visibility.Default; } + public bool IsConst { get; set; } + public string Value { get; set; } + public bool IsStatic { get; set; } + public bool IsReadonly { get; set; } + public bool IsPrivate { get => visibility.HasFlag (Visibility.Private); set => visibility = value ? Visibility.Private : Visibility.Default; } + public bool IsProtected { get => visibility.HasFlag (Visibility.Protected); set => visibility = value ? Visibility.Protected : Visibility.Default; } + public int Priority { get; set; } + public bool IsShadow { get; set; } + + public void SetVisibility (string visibility) + { + switch (visibility?.ToLowerInvariant ()) { + case "public": + IsPublic = true; + break; + case "internal": + IsInternal = true; + break; + case "protected": + IsProtected = true; + break; + case "private": + IsPrivate = true; + break; + } + } + + public virtual void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (IsPublic) + writer.Write ("public "); + else if (IsInternal) + writer.Write ("internal "); + else if (IsPrivate) + writer.Write ("private "); + + if (IsStatic) + writer.Write ("static "); + if (IsReadonly) + writer.Write ("readonly "); + if (IsConst) + writer.Write ("const "); + + if (IsShadow) + writer.Write ("new "); + + writer.Write ("delegate "); + + WriteType (writer); + + writer.Write (Name + " "); + writer.Write ("("); + + WriteParameters (writer); + + writer.Write (")"); + + writer.Write (";"); + } + + protected virtual void WriteParameters (CodeWriter writer) + { + for (var i = 0; i < Parameters.Count; i++) { + var p = Parameters [i]; + p.WriteParameter (writer); + + if (i < Parameters.Count - 1) + writer.Write (", "); + } + } + + protected virtual void WriteType (CodeWriter writer) + { + Type.WriteTypeReference (writer); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/EnumMemberWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/EnumMemberWriter.cs new file mode 100644 index 00000000000..91ff9cc655a --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/EnumMemberWriter.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.SourceWriter +{ + public class EnumMemberWriter : ISourceWriter + { + public string Name { get; set; } + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public string Value { get; set; } + public int Priority { get; set; } + + public virtual void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (Value.HasValue ()) { + writer.Write (Name + " = "); + writer.Write (Value); + writer.WriteLine (","); + } else { + writer.WriteLine ($"{Name},"); + } + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/EnumWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/EnumWriter.cs new file mode 100644 index 00000000000..302ae938b54 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/EnumWriter.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.SourceWriter +{ + public class EnumWriter : ISourceWriter + { + Visibility visibility; + + public string Name { get; set; } + public bool IsPublic { get => visibility.HasFlag (Visibility.Public); set => visibility = value ? Visibility.Public : Visibility.Default; } + public bool IsInternal { get => visibility.HasFlag (Visibility.Internal); set => visibility = value ? Visibility.Internal : Visibility.Default; } + public bool IsPrivate { get => visibility.HasFlag (Visibility.Private); set => visibility = value ? Visibility.Private : Visibility.Default; } + public bool IsProtected { get => visibility.HasFlag (Visibility.Protected); set => visibility = value ? Visibility.Protected : Visibility.Default; } + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public List Members { get; } = new List (); + + public int Priority { get; set; } + + public void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + WriteMembers (writer); + WriteTypeClose (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (IsPublic) + writer.Write ("public "); + if (IsProtected) + writer.Write ("protected "); + if (IsInternal) + writer.Write ("internal "); + if (IsPrivate) + writer.Write ("private "); + + writer.Write ("enum "); + writer.WriteLine (Name + " "); + + writer.WriteLine ("{"); + writer.Indent (); + } + + public virtual void WriteMembers (CodeWriter writer) + { + foreach (var member in Members) { + member.Write (writer); + writer.WriteLine (); + } + } + + public virtual void WriteTypeClose (CodeWriter writer) + { + writer.Unindent (); + writer.WriteLine ("}"); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/EventWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/EventWriter.cs new file mode 100644 index 00000000000..3edbfa703e2 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/EventWriter.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class EventWriter : ISourceWriter + { + Visibility visibility; + + public string Name { get; set; } + public TypeReferenceWriter EventType { get; set; } + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public bool IsPublic { get => visibility.HasFlag (Visibility.Public); set => visibility |= Visibility.Public; } + public bool UseExplicitPrivateKeyword { get; set; } + public bool IsInternal { get => visibility.HasFlag (Visibility.Internal); set => visibility |= Visibility.Internal; } + public List AddBody { get; } = new List (); + public List RemoveBody { get; } = new List (); + public bool IsStatic { get; set; } + public bool IsProtected { get => visibility.HasFlag (Visibility.Protected); set => visibility |= Visibility.Protected; } + public bool IsPrivate { get => visibility == Visibility.Private; set => visibility = value ? Visibility.Private : Visibility.Default; } + public bool IsOverride { get; set; } + public bool HasAdd { get; set; } + public bool HasRemove { get; set; } + public bool IsShadow { get; set; } + public bool IsAutoProperty { get; set; } + public bool IsAbstract { get; set; } + public bool IsVirtual { get; set; } + public bool IsUnsafe { get; set; } + public List GetterComments { get; } = new List (); + public List SetterComments { get; } = new List (); + public List GetterAttributes { get; } = new List (); + public List SetterAttributes { get; } = new List (); + public int Priority { get; set; } + + public void SetVisibility (string visibility) + { + switch (visibility?.ToLowerInvariant ()) { + case "public": + IsPublic = true; + break; + case "internal": + IsInternal = true; + break; + case "protected": + IsProtected = true; + break; + case "private": + IsPrivate = true; + break; + } + } + + public virtual void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteAddComments (CodeWriter writer) + { + foreach (var c in GetterComments) + writer.WriteLine (c); + } + + public virtual void WriteRemoveComments (CodeWriter writer) + { + foreach (var c in SetterComments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteAddAttributes (CodeWriter writer) + { + foreach (var att in GetterAttributes) + att.WriteAttribute (writer); + } + + public virtual void WriteRemoveAttributes (CodeWriter writer) + { + foreach (var att in SetterAttributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (IsPublic) + writer.Write ("public "); + if (IsInternal) + writer.Write ("internal "); + if (IsProtected) + writer.Write ("protected "); + if (visibility == Visibility.Private && UseExplicitPrivateKeyword) + writer.Write ("private "); + + if (IsOverride) + writer.Write ("override "); + + if (IsStatic) + writer.Write ("static "); + + if (IsShadow) + writer.Write ("new "); + + if (IsAbstract) + writer.Write ("abstract "); + if (IsVirtual) + writer.Write ("virtual "); + + if (IsUnsafe) + writer.Write ("unsafe "); + + writer.Write ("event "); + + WriteEventType (writer); + writer.Write (Name); + + WriteBody (writer); + } + + protected virtual void WriteBody (CodeWriter writer) + { + if (!HasAdd && !HasRemove) { + writer.WriteLine (";"); + return; + } + + writer.Write (" "); + + if (IsAutoProperty || IsAbstract) { + WriteAutomaticEventBody (writer); + return; + } + + writer.WriteLine ("{"); + + writer.Indent (); + + WriteAdd (writer); + WriteRemove (writer); + + writer.Unindent (); + + writer.WriteLine ("}"); + } + + protected virtual void WriteAutomaticEventBody (CodeWriter writer) + { + writer.Write ("{ "); + + if (HasAdd) { + WriteAddComments (writer); + WriteAddAttributes (writer); + writer.Write ("add; "); + } + + if (HasRemove) { + WriteRemoveComments (writer); + WriteRemoveAttributes (writer); + writer.Write ("remove; "); + } + + writer.WriteLine ("}"); + } + + protected virtual void WriteAdd (CodeWriter writer) + { + if (HasAdd) { + WriteAddComments (writer); + WriteAddAttributes (writer); + + if (AddBody.Count == 1) + writer.WriteLine ("add { " + AddBody [0] + " }"); + else { + writer.WriteLine ("add {"); + writer.Indent (); + + WriteAddBody (writer); + + writer.Unindent (); + writer.WriteLine ("}"); + } + } + } + + protected virtual void WriteAddBody (CodeWriter writer) + { + foreach (var b in AddBody) + writer.WriteLine (b); + } + + protected virtual void WriteRemove (CodeWriter writer) + { + if (HasRemove) { + WriteRemoveComments (writer); + WriteRemoveAttributes (writer); + + if (RemoveBody.Count == 1) + writer.WriteLine ("remove { " + RemoveBody [0] + " }"); + else { + writer.WriteLine ("remove {"); + writer.Indent (); + + WriteRemoveBody (writer); + + writer.Unindent (); + writer.WriteLine ("}"); + } + } + } + + protected virtual void WriteEventType (CodeWriter writer) + { + EventType.WriteTypeReference (writer); + } + + protected virtual void WriteRemoveBody (CodeWriter writer) + { + foreach (var b in RemoveBody) + writer.WriteLine (b); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/FieldWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/FieldWriter.cs new file mode 100644 index 00000000000..059fafb2197 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/FieldWriter.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class FieldWriter : ISourceWriter + { + Visibility visibility; + + public string Name { get; set; } + public TypeReferenceWriter Type { get; set; } + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public bool IsPublic { get => visibility.HasFlag (Visibility.Public); set => visibility = value ? Visibility.Public : Visibility.Default; } + public bool UseExplicitPrivateKeyword { get; set; } + public bool IsInternal { get => visibility.HasFlag (Visibility.Internal); set => visibility = value ? Visibility.Internal : Visibility.Default; } + public bool IsConst { get; set; } + public string Value { get; set; } + public bool IsStatic { get; set; } + public bool IsReadonly { get; set; } + public bool IsPrivate { get => visibility.HasFlag (Visibility.Private); set => visibility = value ? Visibility.Private : Visibility.Default; } + public bool IsProtected { get => visibility.HasFlag (Visibility.Protected); set => visibility = value ? Visibility.Protected : Visibility.Default; } + public int Priority { get; set; } + public bool IsShadow { get; set; } + + public void SetVisibility (string visibility) + { + switch (visibility?.ToLowerInvariant ().Trim ()) { + case "public": + IsPublic = true; + break; + case "internal": + IsInternal = true; + break; + case "protected": + IsProtected = true; + break; + case "private": + IsPrivate = true; + break; + default: + Console.WriteLine ($"Unrecognized field visibility: `{visibility}`"); + break; + } + } + + public virtual void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (IsPublic) + writer.Write ("public "); + else if (IsProtected) + writer.Write ("protected "); + else if (IsInternal) + writer.Write ("internal "); + else if (IsPrivate) + writer.Write ("private "); + + if (IsStatic) + writer.Write ("static "); + if (IsReadonly) + writer.Write ("readonly "); + if (IsConst) + writer.Write ("const "); + + if (IsShadow) + writer.Write ("new "); + + WriteType (writer); + + if (Value.HasValue ()) { + writer.Write (Name + " = "); + writer.Write (Value); + writer.WriteLine (";"); + } else { + writer.WriteLine ($"{Name};"); + } + } + + protected virtual void WriteType (CodeWriter writer) + { + Type.WriteTypeReference (writer); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/ISourceWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ISourceWriter.cs new file mode 100644 index 00000000000..ab1caea07c7 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ISourceWriter.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public interface ISourceWriter + { + void Write (CodeWriter writer); + + // This is for testing compatibility, allowing us to write members + // in the same order as previous generator. + int Priority { get; set; } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/ITakeParameters.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ITakeParameters.cs new file mode 100644 index 00000000000..8efdda26475 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/ITakeParameters.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public interface ITakeParameters + { + List Parameters { get; } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/InterfaceWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/InterfaceWriter.cs new file mode 100644 index 00000000000..1b6ff038014 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/InterfaceWriter.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class InterfaceWriter : TypeWriter + { + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/MethodParameterWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/MethodParameterWriter.cs new file mode 100644 index 00000000000..e8f2571ef9c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/MethodParameterWriter.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class MethodParameterWriter + { + public TypeReferenceWriter Type { get; set; } + public List Attributes { get; } = new List (); + public string Name { get; set; } + public bool IsExtension { get; set; } + + public MethodParameterWriter (string name, TypeReferenceWriter type) + { + Name = name; + Type = type; + } + + public virtual void WriteParameter (CodeWriter writer) + { + WriteAttributes (writer); + + if (IsExtension) + writer.Write ("this "); + + Type.WriteTypeReference (writer); + writer.Write (Name); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/MethodWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/MethodWriter.cs new file mode 100644 index 00000000000..0d8135c2c0c --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/MethodWriter.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class MethodWriter : ISourceWriter, ITakeParameters + { + Visibility visibility; + + public string Name { get; set; } + public List Parameters { get; } = new List (); + public TypeReferenceWriter ReturnType { get; set; } + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public bool IsPublic { get => visibility == Visibility.Public; set => visibility = value ? Visibility.Public : Visibility.Default; } + public bool UseExplicitPrivateKeyword { get; set; } + public bool IsInternal { get => visibility == Visibility.Internal; set => visibility = value ? Visibility.Internal : Visibility.Default; } + public List Body { get; set; } = new List (); + public bool IsSealed { get; set; } + public bool IsStatic { get; set; } + public bool IsPartial { get; set; } + public bool IsPrivate { get => visibility == Visibility.Private; set => visibility = value ? Visibility.Private : Visibility.Default; } + public bool IsProtected { get => visibility == Visibility.Protected; set => visibility = value ? Visibility.Protected : Visibility.Default; } + public bool IsOverride { get; set; } + public bool IsUnsafe { get; set; } + public bool IsVirtual { get; set; } + public bool IsShadow { get; set; } + public bool IsAbstract { get; set; } + public int Priority { get; set; } + public bool IsDeclaration { get; set; } + + public string ExplicitInterfaceImplementation { get; set; } + public bool NewFirst { get; set; } // TODO: Temporary to match unit tests + + public void SetVisibility (string visibility) + { + switch (visibility?.ToLowerInvariant ()) { + case "public": + IsPublic = true; + break; + case "internal": + IsInternal = true; + break; + case "protected": + IsProtected = true; + break; + case "private": + IsPrivate = true; + break; + } + } + + public virtual void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (IsShadow && NewFirst) + writer.Write ("new "); + + if (IsPublic) + writer.Write ("public "); + if (IsInternal) + writer.Write ("internal "); + if (IsProtected) + writer.Write ("protected "); + if (IsPrivate) + writer.Write ("private "); + + if (IsShadow && !NewFirst) + writer.Write ("new "); + + if (IsOverride) + writer.Write ("override "); + + if (IsVirtual) + writer.Write ("virtual "); + else if (IsAbstract) + writer.Write ("abstract "); + + if (IsSealed) + writer.Write ("sealed "); + + if (IsStatic) + writer.Write ("static "); + + if (IsUnsafe) + writer.Write ("unsafe "); + + if (IsPartial) + writer.Write ("partial "); + + WriteReturnType (writer); + + if (ExplicitInterfaceImplementation.HasValue ()) + writer.Write (ExplicitInterfaceImplementation + "."); + + writer.Write (Name + " "); + writer.Write ("("); + + WriteParameters (writer); + + writer.Write (")"); + + if (IsAbstract || IsDeclaration) { + writer.WriteLine (";"); + return; + } + + WriteConstructorBaseCall (writer); + + writer.WriteLine (); + writer.WriteLine ("{"); + writer.Indent (); + + WriteBody (writer); + + writer.Unindent (); + + writer.WriteLine ("}"); + } + + protected virtual void WriteBody (CodeWriter writer) + { + foreach (var s in Body) + writer.WriteLine (s); + } + + protected virtual void WriteParameters (CodeWriter writer) + { + for (var i = 0; i < Parameters.Count; i++) { + var p = Parameters [i]; + p.WriteParameter (writer); + + if (i < Parameters.Count - 1) + writer.Write (", "); + } + } + + protected virtual void WriteReturnType (CodeWriter writer) + { + ReturnType.WriteTypeReference (writer); + } + + protected virtual void WriteConstructorBaseCall (CodeWriter writer) { } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/PropertyWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/PropertyWriter.cs new file mode 100644 index 00000000000..c06eceb02bd --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/PropertyWriter.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class PropertyWriter : ISourceWriter + { + Visibility visibility; + + public string Name { get; set; } + public List Parameters { get; } = new List (); + public TypeReferenceWriter PropertyType { get; set; } + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public bool IsPublic { get => visibility.HasFlag (Visibility.Public); set => visibility |= Visibility.Public; } + public bool UseExplicitPrivateKeyword { get; set; } + public bool IsInternal { get => visibility.HasFlag (Visibility.Internal); set => visibility |= Visibility.Internal; } + public List GetBody { get; } = new List (); + public List SetBody { get; } = new List (); + public bool IsStatic { get; set; } + public bool IsProtected { get => visibility.HasFlag (Visibility.Protected); set => visibility |= Visibility.Protected; } + public bool IsPrivate { get => visibility == Visibility.Private; set => visibility = value ? Visibility.Private : Visibility.Default; } + public bool IsOverride { get; set; } + public bool HasGet { get; set; } + public bool HasSet { get; set; } + public bool IsShadow { get; set; } + public bool IsAutoProperty { get; set; } + public bool IsAbstract { get; set; } + public bool IsVirtual { get; set; } + public bool IsUnsafe { get; set; } + public List GetterComments { get; } = new List (); + public List SetterComments { get; } = new List (); + public List GetterAttributes { get; } = new List (); + public List SetterAttributes { get; } = new List (); + public int Priority { get; set; } + public string ExplicitInterfaceImplementation { get; set; } + public Visibility AutoSetterVisibility { get; set; } + + public void SetVisibility (string visibility) + { + switch (visibility?.ToLowerInvariant ()) { + case "public": + IsPublic = true; + break; + case "internal": + IsInternal = true; + break; + case "protected": + IsProtected = true; + break; + case "private": + IsPrivate = true; + break; + } + } + + public virtual void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteGetterComments (CodeWriter writer) + { + foreach (var c in GetterComments) + writer.WriteLine (c); + } + + public virtual void WriteSetterComments (CodeWriter writer) + { + foreach (var c in SetterComments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteGetterAttributes (CodeWriter writer) + { + foreach (var att in GetterAttributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSetterAttributes (CodeWriter writer) + { + foreach (var att in SetterAttributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (IsPublic) + writer.Write ("public "); + if (IsInternal) + writer.Write ("internal "); + if (IsProtected) + writer.Write ("protected "); + if (visibility == Visibility.Private && UseExplicitPrivateKeyword) + writer.Write ("private "); + + if (IsOverride) + writer.Write ("override "); + + if (IsStatic) + writer.Write ("static "); + + if (IsShadow) + writer.Write ("new "); + + if (IsAbstract) + writer.Write ("abstract "); + if (IsVirtual) + writer.Write ("virtual "); + + if (IsUnsafe) + writer.Write ("unsafe "); + + WritePropertyType (writer); + + if (ExplicitInterfaceImplementation.HasValue ()) + writer.Write (ExplicitInterfaceImplementation + "."); + + writer.Write (Name + " "); + + WriteBody (writer); + } + + protected virtual void WriteBody (CodeWriter writer) + { + if (IsAutoProperty || IsAbstract) { + WriteAutomaticPropertyBody (writer); + return; + } + + writer.WriteLine ("{"); + + writer.Indent (); + + WriteGetter (writer); + WriteSetter (writer); + + writer.Unindent (); + + writer.WriteLine ("}"); + } + + protected virtual void WriteAutomaticPropertyBody (CodeWriter writer) + { + var need_unindent = false; + + writer.Write ("{"); + + if (HasGet) { + if (GetterComments.Count > 0 || GetterAttributes.Count > 0) { + writer.WriteLine (); + writer.Indent (); + need_unindent = true; + } else { + writer.Write (" "); + } + + WriteGetterComments (writer); + WriteGetterAttributes (writer); + writer.Write ("get; "); + + if (need_unindent) { + writer.WriteLine (); + writer.Unindent (); + need_unindent = false; + } + } + + if (HasSet) { + if (SetterComments.Count > 0 || SetterAttributes.Count > 0) { + writer.WriteLine (); + writer.Indent (); + need_unindent = true; + } + + WriteSetterComments (writer); + WriteSetterAttributes (writer); + + if (AutoSetterVisibility == Visibility.Private && !IsPrivate) + writer.Write ("private "); + else if (AutoSetterVisibility == Visibility.Protected && !IsProtected) + writer.Write ("protected "); + if (AutoSetterVisibility == Visibility.Internal && !IsInternal) + writer.Write ("internal "); + + writer.Write ("set; "); + + if (need_unindent) { + writer.WriteLine (); + writer.Unindent (); + } + } + + writer.WriteLine ("}"); + } + + protected virtual void WriteGetter (CodeWriter writer) + { + if (HasGet) { + WriteGetterComments (writer); + WriteGetterAttributes (writer); + + if (GetBody.Count == 1) + writer.WriteLine ("get { " + GetBody [0] + " }"); + else { + writer.WriteLine ("get {"); + writer.Indent (); + + WriteGetterBody (writer); + + writer.Unindent (); + writer.WriteLine ("}"); + } + } + } + + protected virtual void WriteGetterBody (CodeWriter writer) + { + foreach (var b in GetBody) + writer.WriteLine (b); + } + + protected virtual void WriteSetter (CodeWriter writer) + { + if (HasSet) { + WriteSetterComments (writer); + WriteSetterAttributes (writer); + + if (SetBody.Count == 1) + writer.WriteLine ("set { " + SetBody [0] + " }"); + else { + writer.WriteLine ("set {"); + writer.Indent (); + + WriteSetterBody (writer); + + writer.Unindent (); + writer.WriteLine ("}"); + } + } + } + + protected virtual void WriteSetterBody (CodeWriter writer) + { + foreach (var b in SetBody) + writer.WriteLine (b); + } + + protected virtual void WritePropertyType (CodeWriter writer) + { + PropertyType.WriteTypeReference (writer); + } + + protected virtual void WriteConstructorBaseCall (CodeWriter writer) { } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/TypeReferenceWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/TypeReferenceWriter.cs new file mode 100644 index 00000000000..4d6746ce636 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/TypeReferenceWriter.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xamarin.SourceWriter +{ + public class TypeReferenceWriter + { + public string Namespace { get; set; } + public string Name { get; set; } + public bool Nullable { get; set; } + + // These purposely create new instances, as they are not immutable. + // For example you may intend to make an instance null, but if there + // was only one, you would make them all null. + public static TypeReferenceWriter Bool => new TypeReferenceWriter ("bool"); + public static TypeReferenceWriter Delegate => new TypeReferenceWriter ("Delegate"); + public static TypeReferenceWriter IntPtr => new TypeReferenceWriter ("IntPtr"); + public static TypeReferenceWriter Float => new TypeReferenceWriter ("float"); + public static TypeReferenceWriter Object => new TypeReferenceWriter ("object"); + public static TypeReferenceWriter Void => new TypeReferenceWriter ("void"); + + public TypeReferenceWriter (string name) + { + var index = name.LastIndexOf ('.'); + + if (index >= 0) { + Namespace = name.Substring (0, index); + Name = name.Substring (index + 1); + } else { + Name = name; + } + } + + public TypeReferenceWriter (string ns, string name) + { + Namespace = ns; + Name = name; + } + + public virtual void WriteTypeReference (CodeWriter writer) + { + if (Namespace.HasValue ()) + writer.Write ($"{Namespace}.{Name}{NullableOperator} "); + else + writer.Write ($"{Name}{NullableOperator} "); + } + + string NullableOperator => Nullable ? "?" : string.Empty; + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Models/TypeWriter.cs b/external/Java.Interop/src/Xamarin.SourceWriter/Models/TypeWriter.cs new file mode 100644 index 00000000000..a71105c6920 --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Models/TypeWriter.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace Xamarin.SourceWriter +{ + public abstract class TypeWriter : ISourceWriter + { + Visibility visibility; + int current_priority = 1; + + public string Name { get; set; } + public string Inherits { get; set; } + public List Implements { get; } = new List (); + public bool IsPartial { get; set; } + public bool IsPublic { get => visibility.HasFlag (Visibility.Public); set => visibility = value ? Visibility.Public : Visibility.Default; } + public bool IsAbstract { get; set; } + public bool IsInternal { get => visibility.HasFlag (Visibility.Internal); set => visibility = value ? Visibility.Internal : Visibility.Default; } + public bool IsShadow { get; set; } + public bool IsSealed { get; set; } + public bool IsStatic { get; set; } + public bool IsPrivate { get => visibility.HasFlag (Visibility.Private); set => visibility = value ? Visibility.Private : Visibility.Default; } + public bool IsProtected { get => visibility.HasFlag (Visibility.Protected); set => visibility = value ? Visibility.Protected : Visibility.Default; } + public ObservableCollection Methods { get; } = new ObservableCollection (); + public List Comments { get; } = new List (); + public List Attributes { get; } = new List (); + public ObservableCollection Events { get; } = new ObservableCollection (); + public ObservableCollection Fields { get; } = new ObservableCollection (); + public ObservableCollection Properties { get; } = new ObservableCollection (); + public ObservableCollection InlineComments { get; } = new ObservableCollection (); + public ObservableCollection Delegates { get; } = new ObservableCollection (); + public int Priority { get; set; } + public int GetNextPriority () => current_priority++; + public bool UsePriorityOrder { get; set; } + + public ObservableCollection NestedTypes { get; } = new ObservableCollection (); + + protected TypeWriter () + { + Methods.CollectionChanged += MemberAdded; + Events.CollectionChanged += MemberAdded; + Fields.CollectionChanged += MemberAdded; + Properties.CollectionChanged += MemberAdded; + InlineComments.CollectionChanged += MemberAdded; + Delegates.CollectionChanged += MemberAdded; + NestedTypes.CollectionChanged += MemberAdded; + } + + protected void MemberAdded (object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + foreach (var member in e.NewItems.OfType ()) + if (member.Priority == 0) + member.Priority = GetNextPriority (); + } + + public void SetVisibility (string visibility) + { + switch (visibility?.ToLowerInvariant ().Trim ()) { + case "public": + IsPublic = true; + break; + case "internal": + IsInternal = true; + break; + case "protected": + IsProtected = true; + break; + case "protected internal": + this.visibility = Visibility.Protected | Visibility.Internal; + break; + case "private": + IsPrivate = true; + break; + } + } + + public virtual void Write (CodeWriter writer) + { + WriteComments (writer); + WriteAttributes (writer); + WriteSignature (writer); + WriteMembers (writer); + WriteTypeClose (writer); + } + + public virtual void WriteComments (CodeWriter writer) + { + foreach (var c in Comments) + writer.WriteLine (c); + } + + public virtual void WriteAttributes (CodeWriter writer) + { + foreach (var att in Attributes) + att.WriteAttribute (writer); + } + + public virtual void WriteSignature (CodeWriter writer) + { + if (IsPublic) + writer.Write ("public "); + if (IsProtected) + writer.Write ("protected "); + if (IsInternal) + writer.Write ("internal "); + if (IsPrivate) + writer.Write ("private "); + + if (IsShadow) + writer.Write ("new "); + + if (IsStatic) + writer.Write ("static "); + + if (IsAbstract) + writer.Write ("abstract "); + + if (IsSealed) + writer.Write ("sealed "); + + if (IsPartial) + writer.Write ("partial "); + + writer.Write (this is InterfaceWriter ? "interface " : "class "); + writer.Write (Name + " "); + + if (Inherits.HasValue () || Implements.Count > 0) + writer.Write (": "); + + if (Inherits.HasValue ()) { + writer.Write (Inherits); + + if (Implements.Count > 0) + writer.Write (","); + + writer.Write (" "); + } + + if (Implements.Count > 0) + writer.Write (string.Join (", ", Implements) + " "); + + writer.WriteLine ("{"); + writer.Indent (); + } + + public virtual void WriteMembers (CodeWriter writer) + { + if (UsePriorityOrder) { + WriteMembersByPriority (writer); + return; + } + + if (Fields.Count > 0) { + writer.WriteLine (); + WriteFields (writer); + } + + WriteConstructors (writer); + + WriteEvents (writer); + WriteDelegates (writer); + WriteProperties (writer); + WriteMethods (writer); + } + + public void AddInlineComment (string comment) + { + InlineComments.Add (new CommentWriter (comment)); + } + + public virtual void WriteMembersByPriority (CodeWriter writer) + { + var members = Fields.Cast ().Concat (Properties).Concat (Methods).Concat (NestedTypes).Concat (Events).Concat (InlineComments).Concat (Delegates); + + if (this is ClassWriter klass) + members = members.Concat (klass.Constructors); + + foreach (var member in members.OrderBy (p => p.Priority)) { + member.Write (writer); + writer.WriteLine (); + } + } + + public virtual void WriteConstructors (CodeWriter writer) { } + + public virtual void WriteEvents (CodeWriter writer) + { + foreach (var ev in Events) { + ev.Write (writer); + writer.WriteLine (); + } + } + + public virtual void WriteFields (CodeWriter writer) + { + foreach (var field in Fields) { + field.Write (writer); + writer.WriteLine (); + } + } + + public virtual void WriteMethods (CodeWriter writer) + { + foreach (var method in Methods) { + method.Write (writer); + writer.WriteLine (); + } + } + + public virtual void WriteProperties (CodeWriter writer) + { + foreach (var prop in Properties) { + prop.Write (writer); + writer.WriteLine (); + } + } + + public virtual void WriteDelegates (CodeWriter writer) + { + foreach (var del in Delegates) { + del.Write (writer); + writer.WriteLine (); + } + } + + public virtual void WriteTypeClose (CodeWriter writer) + { + writer.Unindent (); + writer.WriteLine ("}"); + } + } +} diff --git a/external/Java.Interop/src/Xamarin.SourceWriter/Xamarin.SourceWriter.csproj b/external/Java.Interop/src/Xamarin.SourceWriter/Xamarin.SourceWriter.csproj new file mode 100644 index 00000000000..c6efdc8990e --- /dev/null +++ b/external/Java.Interop/src/Xamarin.SourceWriter/Xamarin.SourceWriter.csproj @@ -0,0 +1,13 @@ + + + + $(DotNetTargetFramework) + + + + + + + + + diff --git a/external/Java.Interop/src/java-interop/CMakeLists.txt b/external/Java.Interop/src/java-interop/CMakeLists.txt new file mode 100644 index 00000000000..4e29d9d278b --- /dev/null +++ b/external/Java.Interop/src/java-interop/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.10.2) + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +project( + java-interop-validation + DESCRIPTION "Java.Interop native source validation" + HOMEPAGE_URL "https://github.com/dotnet/java-interop/" + LANGUAGES CXX C +) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) + +if(ENABLE_OSX_ARCHITECTURES) + set(CMAKE_OSX_ARCHITECTURES ${ENABLE_OSX_ARCHITECTURES}) +endif() + +foreach(dir ${MONO_INCLUDE_LIST}) + include_directories(${dir}) +endforeach() + +if(OUTPUT_DIR) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_DIR}") +endif() + +add_library( + java-interop-validation + STATIC + java-interop-dlfcn.cc + java-interop-mono.cc + java-interop-util.cc + java-interop.cc +) diff --git a/external/Java.Interop/src/java-interop/java-interop-dlfcn.cc b/external/Java.Interop/src/java-interop/java-interop-dlfcn.cc new file mode 100644 index 00000000000..0ce6256875f --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop-dlfcn.cc @@ -0,0 +1,194 @@ +#include "java-interop.h" +#include "java-interop-dlfcn.h" +#include "java-interop-util.h" + +#ifdef _WINDOWS +#include +#else +#include +#include +#endif + +namespace microsoft::java_interop { + +static char * +_get_last_dlerror () +{ +#ifdef _WINDOWS + + DWORD error = GetLastError (); + if (error == ERROR_SUCCESS /* 0 */) { + return nullptr; + } + + wchar_t *buf = nullptr; + + DWORD size = FormatMessageW ( + /* dwFlags */ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + /* lpSource */ NULL, + /* dwMessageId */ error, + /* dwLanguageId */ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + /* lpBuffer */ (LPWSTR) &buf, + /* nSize */ 0, + /* Arguments */ NULL + ); + if (size == 0) + return nullptr; + + char *message = utf16_to_utf8 (buf); + LocalFree (buf); + + return message; + +#else // ndef _WINDOWS + + return java_interop_strdup (dlerror ()); + +#endif // ndef _WINDOWS +} + +static void +_free_error (char **error) +{ + if (error == nullptr) + return; + java_interop_free (*error); + *error = nullptr; +} + +static void +_set_error (char **error, const char *message) +{ + if (error == nullptr) + return; + *error = java_interop_strdup (message); +} + +static void +_set_error_to_last_error (char **error) +{ + if (error == nullptr) + return; + *error = _get_last_dlerror (); +} + +void* +java_interop_lib_load (const char *path, [[maybe_unused]] unsigned int flags, char **error) +{ + _free_error (error); + if (path == nullptr) { + _set_error (error, "path=nullptr is not supported"); + return nullptr; + } + + void *handle = nullptr; + +#ifdef _WINDOWS + + wchar_t *wpath = utf8_to_utf16 (path); + if (wpath == nullptr) { + _set_error (error, "could not convert path to UTF-16"); + return nullptr; + } + HMODULE module = LoadLibraryExW ( + /* lpLibFileName */ wpath, + /* hFile */ nullptr, + /* dwFlags */ LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 + ); + java_interop_free (wpath); + + handle = reinterpret_cast(module); + +#else // ndef _WINDOWS + + int mode = 0; + if ((flags & JAVA_INTEROP_LIB_LOAD_GLOBALLY) == JAVA_INTEROP_LIB_LOAD_GLOBALLY) { + mode = RTLD_GLOBAL; + } + if ((flags & JAVA_INTEROP_LIB_LOAD_LOCALLY) == JAVA_INTEROP_LIB_LOAD_LOCALLY) { + mode = RTLD_LOCAL; + } + + if (mode == 0) { + mode = RTLD_LOCAL; + } + mode |= RTLD_NOW; + + handle = dlopen (path, mode); + +#endif // ndef _WINDOWS + + if (handle == nullptr) { + _set_error_to_last_error (error); + } + + return handle; +} + +void* +java_interop_lib_symbol (void *library, const char *symbol, char **error) +{ + _free_error (error); + + if (library == nullptr) { + _set_error (error, "library=nullptr"); + return nullptr; + } + if (symbol == nullptr) { + _set_error (error, "symbol=nullptr"); + return nullptr; + } + + void *address = nullptr; + +#ifdef _WINDOWS + + HMODULE module = reinterpret_cast(library); + FARPROC a = GetProcAddress (module, symbol); + address = reinterpret_cast(a); + +#else // ndef _WINDOWS + + address = dlsym (library, symbol); + +#endif // ndef _WINDOWS + + if (address == nullptr) { + _set_error_to_last_error (error); + } + + return address; +} + +int +java_interop_lib_close (void* library, char **error) +{ + _free_error (error); + if (library == nullptr) { + _set_error (error, "library=nullptr"); + return JAVA_INTEROP_LIB_INVALID_PARAM; + } + + int r = 0; + +#ifdef _WINDOWS + HMODULE h = reinterpret_cast(library); + BOOL v = FreeLibrary (h); + if (!v) { + r = JAVA_INTEROP_LIB_CLOSE_FAILED; + } +#else // ndef _WINDOWS + r = dlclose (library); + if (r != 0) { + r = JAVA_INTEROP_LIB_CLOSE_FAILED; + } +#endif // ndef _WINDOWS + + if (r != 0) { + _set_error_to_last_error (error); + } + + return r; +} + +} // namespace microsoft::java_interop diff --git a/external/Java.Interop/src/java-interop/java-interop-dlfcn.h b/external/Java.Interop/src/java-interop/java-interop-dlfcn.h new file mode 100644 index 00000000000..0411c7e39f7 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop-dlfcn.h @@ -0,0 +1,28 @@ +#ifndef INC_JAVA_INTEROP_DLFCN_H +#define INC_JAVA_INTEROP_DLFCN_H + +#include "java-interop.h" + +namespace microsoft::java_interop { + +// Possible flags values for java_interop_lib_load +constexpr unsigned int JAVA_INTEROP_LIB_LOAD_GLOBALLY = (1 << 0); +constexpr unsigned int JAVA_INTEROP_LIB_LOAD_LOCALLY = (1 << 1); + + +// Possible error codes from java_interop_lib_close +constexpr int JAVA_INTEROP_LIB_FAILED = -1000; +constexpr int JAVA_INTEROP_LIB_CLOSE_FAILED = JAVA_INTEROP_LIB_FAILED-1; +constexpr int JAVA_INTEROP_LIB_INVALID_PARAM = JAVA_INTEROP_LIB_FAILED-2; + +JAVA_INTEROP_BEGIN_DECLS + +JAVA_INTEROP_API void* java_interop_lib_load (const char *path, unsigned int flags, char **error); +JAVA_INTEROP_API void* java_interop_lib_symbol (void* library, const char *symbol, char **error); +JAVA_INTEROP_API int java_interop_lib_close (void* library, char **error); + +JAVA_INTEROP_END_DECLS + +} + +#endif /* INC_JAVA_INTEROP_DLFCN_H */ diff --git a/external/Java.Interop/src/java-interop/java-interop-logger.h b/external/Java.Interop/src/java-interop/java-interop-logger.h new file mode 100644 index 00000000000..57e4cd0ae74 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop-logger.h @@ -0,0 +1,41 @@ +#ifndef __JAVA_INTEROP_LOGGER_H__ +#define __JAVA_INTEROP_LOGGER_H__ + +// Keep in sync with java-interop-logger.c's LogCategories enum +typedef enum _LogCategories { + LOG_NONE = 0, + LOG_DEFAULT = 1 << 0, + LOG_ASSEMBLY = 1 << 1, + LOG_DEBUGGER = 1 << 2, + LOG_GC = 1 << 3, + LOG_GREF = 1 << 4, + LOG_LREF = 1 << 5, + LOG_TIMING = 1 << 6, + LOG_BUNDLE = 1 << 7, + LOG_NET = 1 << 8, + LOG_NETLINK = 1 << 9, +} LogCategories; + +extern unsigned int log_categories; + +void log_error (LogCategories category, const char *format, ...); + +void log_fatal (LogCategories category, const char *format, ...); + +void log_info_nocheck (LogCategories category, const char *format, ...); + +void log_warn (LogCategories category, const char *format, ...); + +void log_debug_nocheck (LogCategories category, const char *format, ...); + +#define DO_LOG(_level, _category_, ...) \ + do { \ + if ((log_categories & ((_category_))) != 0) { \ + ::log_ ## _level ## _nocheck ((_category_), __VA_ARGS__); \ + } \ + } while (0) + +#define log_debug(_category_, ...) DO_LOG (debug, (_category_), __VA_ARGS__) +#define log_info(_category_, ...) DO_LOG (info, (_category_), __VA_ARGS__) + +#endif /* __JAVA_INTEROP_LOGGER_H__ */ diff --git a/external/Java.Interop/src/java-interop/java-interop-mono.cc b/external/Java.Interop/src/java-interop/java-interop-mono.cc new file mode 100644 index 00000000000..a3a1487e755 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop-mono.cc @@ -0,0 +1,4 @@ +#include +#include "java-interop-mono.h" + + diff --git a/external/Java.Interop/src/java-interop/java-interop-mono.h b/external/Java.Interop/src/java-interop/java-interop-mono.h new file mode 100644 index 00000000000..16ec344a56f --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop-mono.h @@ -0,0 +1,19 @@ +#ifndef INC_JAVA_INTEROP_MONO_H +#define INC_JAVA_INTEROP_MONO_H + +#include "java-interop.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +JAVA_INTEROP_BEGIN_DECLS + +JAVA_INTEROP_END_DECLS + +#endif /* ndef INC_JAVA_INTEROP_MONO_H */ diff --git a/external/Java.Interop/src/java-interop/java-interop-util.cc b/external/Java.Interop/src/java-interop/java-interop-util.cc new file mode 100644 index 00000000000..d80f22249d1 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop-util.cc @@ -0,0 +1,51 @@ +#ifdef _WINDOWS +#include +#include +#include + +char* +utf16_to_utf8 (const wchar_t *widestr) +{ + int required_size = WideCharToMultiByte (CP_UTF8, 0, widestr, -1, NULL, 0, NULL, NULL); + if (required_size <= 0) { + return nullptr; + } + + char *mbstr = static_cast (calloc (required_size, sizeof (char))); + if (mbstr == nullptr) { + return nullptr; + } + + int converted_size = WideCharToMultiByte (CP_UTF8, 0, widestr, -1, mbstr, required_size, NULL, NULL); + assert (converted_size == required_size); + if (required_size != converted_size) { + free (mbstr); + return nullptr; + } + + return mbstr; +} + +wchar_t* +utf8_to_utf16 (const char *mbstr) +{ + int required_chars = MultiByteToWideChar (CP_UTF8, 0, mbstr, -1, NULL, 0); + if (required_chars <= 0) { + return nullptr; + } + + wchar_t *widestr = static_cast (calloc (required_chars, sizeof (wchar_t))); + if (widestr == nullptr) { + return nullptr; + } + + int converted_chars = MultiByteToWideChar (CP_UTF8, 0, mbstr, -1, widestr, required_chars); + assert (converted_chars == required_chars); + if (required_chars != converted_chars) { + free (widestr); + return nullptr; + } + + return widestr; +} +#endif // def _WINDOWS diff --git a/external/Java.Interop/src/java-interop/java-interop-util.h b/external/Java.Interop/src/java-interop/java-interop-util.h new file mode 100644 index 00000000000..a76060d3f5f --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop-util.h @@ -0,0 +1,73 @@ +#ifndef __JAVA_INTEROP_UTIL_H__ +#define __JAVA_INTEROP_UTIL_H__ + +#include + +#ifdef _WINDOWS +/* Those two conversion functions are only properly implemented on Windows + * because that's the only place where they should be useful. + */ +char* utf16_to_utf8 (const wchar_t *widestr); +wchar_t* utf8_to_utf16 (const char *mbstr); +#endif // def _WINDOWS + +#include "java-interop-logger.h" + +enum FatalExitCodes { + FATAL_EXIT_CANNOT_FIND_MONO = 1, + FATAL_EXIT_ATTACH_JVM_FAILED = 2, + FATAL_EXIT_DEBUGGER_CONNECT = 3, + FATAL_EXIT_CANNOT_FIND_JNIENV = 4, + FATAL_EXIT_CANNOT_FIND_APK = 10, + FATAL_EXIT_TRIAL_EXPIRED = 11, + FATAL_EXIT_PTHREAD_FAILED = 12, + FATAL_EXIT_MISSING_ASSEMBLY = 13, + FATAL_EXIT_CANNOT_LOAD_BUNDLE = 14, + FATAL_EXIT_CANNOT_FIND_LIBMONOSGEN = 15, + FATAL_EXIT_NO_ASSEMBLIES = 'A', + FATAL_EXIT_MONO_MISSING_SYMBOLS = 'B', + FATAL_EXIT_FORK_FAILED = 'F', + FATAL_EXIT_MISSING_INIT = 'I', + FATAL_EXIT_MISSING_TIMEZONE_MEMBERS = 'T', + FATAL_EXIT_MISSING_ZIPALIGN = 'Z', + FATAL_EXIT_OUT_OF_MEMORY = 'M', + FATAL_EXIT_JVM_MISSING_SYMBOLS = 'J', +}; + +static inline void* +_assert_valid_pointer (void *p, size_t size) +{ + if (!p) { + if (size == 0) { + /* In this case it's "ok" to return NULL, although a malloc + * implementation may choose to do something else + */ + return p; + } + + log_fatal (LOG_DEFAULT, "Out of memory!"); + std::exit (FATAL_EXIT_OUT_OF_MEMORY); + } + + return p; +} + +static inline void* +xmalloc (size_t size) +{ + return _assert_valid_pointer (malloc (size), size); +} + +static inline void* +xrealloc (void *ptr, size_t size) +{ + return _assert_valid_pointer (realloc (ptr, size), size); +} + +static inline void* +xcalloc (size_t nmemb, size_t size) +{ + return _assert_valid_pointer (calloc (nmemb, size), nmemb * size); +} + +#endif /* __JAVA_INTEROP_UTIL_H__ */ diff --git a/external/Java.Interop/src/java-interop/java-interop.cc b/external/Java.Interop/src/java-interop/java-interop.cc new file mode 100644 index 00000000000..282333753a0 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop.cc @@ -0,0 +1,22 @@ +#include +#include + +#include "java-interop.h" + +#ifdef _WINDOWS +// Warning C4996: 'strdup': The POSIX name for this item is deprecated. +#define strdup _strdup +#endif // ndef _WINDOWS + +char* +java_interop_strdup (const char* value) +{ + return strdup (value); +} + +void +java_interop_free (void *p) +{ + free (p); +} + diff --git a/external/Java.Interop/src/java-interop/java-interop.csproj b/external/Java.Interop/src/java-interop/java-interop.csproj new file mode 100644 index 00000000000..4f1c20e4617 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop.csproj @@ -0,0 +1,28 @@ + + + + $(DotNetTargetFramework) + false + + + + + + $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\ + $(ToolOutputFullPath) + + + + 8.0.13 + + + + + + + + + diff --git a/external/Java.Interop/src/java-interop/java-interop.h b/external/Java.Interop/src/java-interop/java-interop.h new file mode 100644 index 00000000000..1a205121567 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop.h @@ -0,0 +1,45 @@ +#ifndef INC_JAVA_INTEROP_H +#define INC_JAVA_INTEROP_H + +#include + +#if defined(_MSC_VER) + + #define JAVA_INTEROP_API_EXPORT __declspec(dllexport) + #define JAVA_INTEROP_API_IMPORT __declspec(dllimport) + +#else /* defined(_MSC_VER */ + + #ifdef __GNUC__ + #define JAVA_INTEROP_API_EXPORT __attribute__ ((visibility ("default"))) + #else + #define JAVA_INTEROP_API_EXPORT + #endif + #define JAVA_INTEROP_API_IMPORT + +#endif /* !defined(_MSC_VER) */ + +#if defined(MONO_DLL_EXPORT) || defined(JAVA_INTEROP_DLL_EXPORT) + #define JAVA_INTEROP_API JAVA_INTEROP_API_EXPORT +#elif defined(MONO_DLL_IMPORT) || defined(JAVA_INTEROP_DLL_IMPORT) + #define JAVA_INTEROP_API JAVA_INTEROP_API_IMPORT +#else /* !defined(MONO_DLL_IMPORT) && !defined(MONO_DLL_EXPORT) */ + #define JAVA_INTEROP_API +#endif /* MONO_DLL_EXPORT... */ + +#ifdef __cplusplus + #define JAVA_INTEROP_BEGIN_DECLS extern "C" { + #define JAVA_INTEROP_END_DECLS } +#else /* ndef __cplusplus */ + #define JAVA_INTEROP_BEGIN_DECLS + #define JAVA_INTEROP_END_DECLS +#endif /* ndef __cplusplus */ + +JAVA_INTEROP_BEGIN_DECLS + +JAVA_INTEROP_API char *java_interop_strdup (const char* value); +JAVA_INTEROP_API void java_interop_free (void *p); + +JAVA_INTEROP_END_DECLS + +#endif /* ndef INC_JAVA_INTEROP_H */ diff --git a/external/Java.Interop/src/java-interop/java-interop.targets b/external/Java.Interop/src/java-interop/java-interop.targets new file mode 100644 index 00000000000..b778afa1521 --- /dev/null +++ b/external/Java.Interop/src/java-interop/java-interop.targets @@ -0,0 +1,67 @@ + + + + + + <_JavaInteropValidationLibName Condition=" $([MSBuild]::IsOSPlatform ('windows')) ">java-interop-validation.lib + <_JavaInteropValidationLibName Condition=" '$(_JavaInteropValidationLibName)' == '' ">libjava-interop-validation.a + + + + <_JavaInteropValidationSource Include="*.cc" /> + <_JavaInteropValidationHeader Include="*.h" /> + + + + + <_PrepareArch Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'win-x64' ">x86_amd64 + + + + <_CmakeOsxArch Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'osx-x64' ">x86_64 + <_CmakeOsxArch Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'osx-arm64' ">arm64 + + + + <_MonoNativePath>$(NuGetPackageRoot)microsoft.netcore.app.runtime.mono.$(NETCoreSdkRuntimeIdentifier)/$(DotNetRuntimePacksVersion)/runtimes/$(NETCoreSdkRuntimeIdentifier)/native/ + <_MonoIncludePath>$(_MonoNativePath)include/mono-2.0 + <_DEnableOsxArchitectures Condition=" $([MSBuild]::IsOSPlatform ('osx')) ">"-DENABLE_OSX_ARCHITECTURES=$(_CmakeOsxArch)" + <_DMonoDirs>"-DMONO_INCLUDE_LIST=$(_MonoIncludePath)" + <_DOutputDir>"-DOUTPUT_DIR=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)" + <_ExtraArgs>$([MSBuild]::Escape('$(_DMonoDirs) $(_DEnableOsxArchitectures) $(_DOutputDir)')) + + + + + + + <_Cmake + Condition=" '$(PrepareNativeToolchain)' != '' " + Include="PrepareNativeToolchain=$(PrepareNativeToolchain) $(_PrepareArch)" + /> + <_Cmake Include="CmakePath=$(CmakePath)" /> + <_Cmake Include="CmakeGenerator=$(CmakeGenerator)" /> + <_Cmake Include="CmakeSourceDir=$(MSBuildThisFileDirectory)" /> + <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)" /> + <_Cmake Include="CmakeExtraArgs=$(_ExtraArgs)" /> + + + + + + + + + + + diff --git a/external/Java.Interop/src/utils/EnumMappings.Xml.cs b/external/Java.Interop/src/utils/EnumMappings.Xml.cs new file mode 100644 index 00000000000..fb593275b7c --- /dev/null +++ b/external/Java.Interop/src/utils/EnumMappings.Xml.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using Xamarin.Android.Tools; + +namespace MonoDroid.Generation { + + partial class EnumMappings { + + internal static bool IsXml (string file) + { + using (var s = File.OpenText (file)) { + int c = s.Read (); + return c == '<'; + } + } + + internal static TextReader FieldXmlToCsv (string file) + { + if (file == null) + return null; + + return FieldXmlToCsv (XDocument.Load (file, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo)); + } + + internal static TextReader FieldXmlToCsv (XDocument doc) + { + var sw = new StringWriter (); + + foreach (var e in doc.XPathSelectElements ("/enum-field-mappings/mapping")) { + + var enu = GetMandatoryAttribute (e, "clr-enum-type"); + var jni_type = e.XGetAttribute ("jni-class") ?? "I:" + e.XGetAttribute ("jni-interface"); + + // If neither jni was specified leave it blank + if (jni_type == "I:") + jni_type = string.Empty; + + var bitfield = e.XGetAttribute ("bitfield") == "true"; + + foreach (var m in e.XPathSelectElements ("field")) { + var verstr = m.XGetAttribute ("api-level") ?? "0"; + var member = GetMandatoryAttribute (m, "clr-name"); + var jni_name = m.XGetAttribute ("jni-name"); + var value = GetMandatoryAttribute (m, "value"); + + var jni_member = string.IsNullOrWhiteSpace (jni_name) ? string.Empty : jni_type + '.' + jni_name; + + sw.WriteLine ("{0}, {1}, {2}, {3}, {4}{5}", verstr, enu, member, jni_member, value, bitfield ? ", Flags" : null); + } + } + + return new StringReader (sw.ToString ()); + } + + static string GetMandatoryAttribute (XElement e, string name) + { + if (e.Attribute (name) == null) { + throw new InvalidOperationException (String.Format ("Mandatory attribute '{0}' is missing on a mapping element: {1}", name, e.ToString ())); + } + return e.XGetAttribute (name); + } + } +} + diff --git a/external/Java.Interop/src/utils/NullableAttributes.cs b/external/Java.Interop/src/utils/NullableAttributes.cs new file mode 100644 index 00000000000..62d0f308449 --- /dev/null +++ b/external/Java.Interop/src/utils/NullableAttributes.cs @@ -0,0 +1,200 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics.CodeAnalysis +{ + ///

Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class AllowNullAttribute : Attribute + { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DisallowNullAttribute : Attribute + { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullAttribute : Attribute + { } + + /// Specifies that an output will not be null even if the corresponding type allows it. + [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullAttribute : Attribute + { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage (AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute (bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage (AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute (bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage (AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute (string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage (AttributeTargets.Method, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnAttribute : Attribute + { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage (AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute (bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute (string member) => Members = new [] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute (params string [] members) => Members = members; + + /// Gets field or property member names. + public string [] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute (bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new [] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute (bool returnValue, params string [] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string [] Members { get; } + } +} diff --git a/external/Java.Interop/src/utils/StringRocks.cs b/external/Java.Interop/src/utils/StringRocks.cs new file mode 100644 index 00000000000..971856dbb51 --- /dev/null +++ b/external/Java.Interop/src/utils/StringRocks.cs @@ -0,0 +1,59 @@ +using System; +using System.Linq; + +namespace MonoDroid.Utils { + + static class StringRocks { + + public static string ToLowerCase (string value) + { + if (string.IsNullOrEmpty (value)) + return value; + string[] parts = value.Split ('.'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = parts [i].ToLowerInvariant (); + } + return string.Join (".", parts); + } + + public static string MemberToPascalCase (string value) + { + if (string.IsNullOrEmpty (value)) + return value; + + if (value.Contains (".")) + throw new NotSupportedException ("Methods cannot contain '.'."); + + return ToPascalCasePart (value, 1); + } + + public static string TypeToPascalCase (string value) + { + return ToPascalCase (value, 1); + } + + public static string PackageToPascalCase (string value) + { + return ToPascalCase (value, 2); + } + + static string ToPascalCase (string value, int minLength) + { + if (string.IsNullOrEmpty (value)) + return value; + + string[] parts = value.Split ('.'); + for (int i = 0; i < parts.Length; ++i) { + parts [i] = ToPascalCasePart (parts [i], minLength); + } + return string.Join (".", parts); + } + + static string ToPascalCasePart (string value, int minLength) + { + return value.Length <= minLength + ? value.ToUpperInvariant () + : char.ToUpperInvariant (value [0]) + value.Substring (1); + } + } +} diff --git a/external/Java.Interop/src/utils/XmlExtensions.cs b/external/Java.Interop/src/utils/XmlExtensions.cs new file mode 100644 index 00000000000..83fbc2ed72b --- /dev/null +++ b/external/Java.Interop/src/utils/XmlExtensions.cs @@ -0,0 +1,39 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; + +using Java.Interop.Tools.Generator; + +namespace Xamarin.Android.Tools { + + static class XmlExtensions { + + public static string XGetAttribute (this XElement element, string name) + { + var attr = element.Attribute (name); + return attr != null ? attr.Value.Trim () : null; + } + + public static string XGetAttribute (this XPathNavigator nav, string name, string ns) + { + var attr = nav.GetAttribute (name, ns); + return attr != null ? attr.Trim () : null; + } + + public static AndroidSdkVersion? XGetAttributeAsAndroidSdkVersionOrNull (this XElement element, string name) + { + var attr = element.Attribute (name); + + if (attr?.Value is null) + return null; + + if (AndroidSdkVersion.TryParse (attr.Value, out var val)) + return val; + + return null; + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/CollectionContract.cs b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/CollectionContract.cs new file mode 100644 index 00000000000..af09a701afc --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/CollectionContract.cs @@ -0,0 +1,252 @@ +// +// IEnumerableContract.cs +// +// Author: +// Jonathan Pryor +// +// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) +// +// 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. +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using NUnit.Framework; + +using Cadenza.Collections; +using Cadenza.Tests; + +namespace Cadenza.Collections.Tests { + + // NOTE: when adding new tests to this type, add them to the + // RunAllTests() method as well. + // RunAllTests() is used by IDictionaryContract.Keys()/.Values() + // to test the behavior of the .Keys/.Values read-only collections. + // + // NOTE: No test may use [ExpectedException]; use Assert.Throws instead. + public abstract class CollectionContract : BaseRocksFixture { + + protected abstract ICollection CreateCollection (IEnumerable values); + protected abstract T CreateValueA (); + protected abstract T CreateValueB (); + + public void RunAllTests () + { + Add (); + Clear (); + Contains (); + CopyTo_Exceptions (); + CopyTo_SequenceComparison (); + CopyTo (); + Ctor_CopySequence (); + Ctor_Initial_Count_Is_Zero (); + Remove (); + } + + [Test] + public void Ctor_Initial_Count_Is_Zero () + { + var c = CreateCollection (new T [0]); + Assert.AreEqual (0, c.Count); + Dispose (c); + } + + protected static void Dispose (object value) + { + var d = value as IDisposable; + if (d != null) + d.Dispose (); + } + + protected static void DisposeCollection (IEnumerable c) + { + if (c == null) + return; + foreach (var e in c) + Dispose (e); + } + + [Test] + public void Ctor_CopySequence () + { + var e = new[] { + CreateValueA (), + CreateValueB (), + }; + var c = CreateCollection (e); + Assert.AreEqual (e.Length, c.Count); + + Dispose (c); + DisposeCollection (e); + } + + [Test] + public void Add () + { + var c = CreateCollection (new T [0]); + var n = c.Count; + var a = CreateValueA (); + + try { + c.Add (a); + Assert.AreEqual (n+1, c.Count); + } + catch (NotSupportedException) { + Assert.IsTrue (c.IsReadOnly || IsFixedSize (c)); + } + + Dispose (c); + Dispose (a); + } + + protected static bool IsFixedSize (ICollection c) + { + var l = c as IList; + return l != null && l.IsFixedSize; + } + + [Test] + public void Clear () + { + var a = CreateValueA (); + var c = CreateCollection (new []{a}); + try { + c.Clear (); + Assert.AreEqual (IsFixedSize (c) ? 1 : 0, c.Count); + } + catch (NotSupportedException) { + Assert.IsTrue (c.IsReadOnly); + } + + Dispose (c); + Dispose (a); + } + + [Test] + public void Contains () + { + var a = CreateValueA (); + + var c = CreateCollection (new []{a}); + Assert.IsTrue (c.Contains (a)); + var b = CreateValueB (); + Assert.IsFalse (c.Contains (b)); + + Dispose (c); + Dispose (b); + Dispose (a); + } + + [Test] + public void CopyTo_Exceptions () + { + var e = new[] { + CreateValueA (), + CreateValueB (), + }; + var c = CreateCollection (e); + Assert.Throws(() => c.CopyTo (null, 0)); + Assert.Throws(() => c.CopyTo (new T [3], -1)); + var d = new T[e.Length + 2]; + // not enough space from d[3..d.Length-1] to hold c.Count elements. + Assert.Throws(() => c.CopyTo (d, 3)); + Assert.Throws(() => c.CopyTo (new T [0], 0)); + + Dispose (c); + DisposeCollection (e); + } + + // can fail for IDictionary implementations; override if appropriate. + [Test] + public virtual void CopyTo_SequenceComparison () + { + var a = CreateValueA (); + var b = CreateValueB (); + + var coll = CreateCollection (new []{a, b}); + var d = new T [4]; + coll.CopyTo (d, 1); + Assert.IsTrue ( + SequenceEqual ( + new []{default (T), a, b, default (T)}, + d)); + + Dispose (coll); + DisposeCollection (d); + Dispose (b); + Dispose (a); + } + + protected virtual bool SequenceEqual (IEnumerable a, IEnumerable b) + { + return a.SequenceEqual (b); + } + + [Test] + public void CopyTo () + { + var a = CreateValueA (); + var b = CreateValueB (); + + var coll = CreateCollection (new []{a, b}); + var d = new T [5]; + coll.CopyTo (d, 1); + Assert.IsTrue (IndexOf (d, a) >= 0); + Assert.IsTrue (IndexOf (d, b) >= 0); + + Dispose (coll); + DisposeCollection (d); + Dispose (b); + Dispose (a); + } + + protected virtual int IndexOf (T[] array, T value) + { + return Array.IndexOf (array, value); + } + + [Test] + public void Remove () + { + var a = CreateValueA (); + var b = CreateValueB (); + + var coll = CreateCollection (new []{a}); + int n = coll.Count; + try { + Assert.IsFalse (coll.Remove (b)); + Assert.AreEqual (n, coll.Count); + Assert.IsTrue (coll.Remove (a)); + Assert.AreEqual (n-1, coll.Count); + } + catch (NotSupportedException) { + Assert.IsTrue (coll.IsReadOnly || IsFixedSize (coll)); + } + + Dispose (coll); + Dispose (b); + Dispose (a); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/EnumerableContract.cs b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/EnumerableContract.cs new file mode 100644 index 00000000000..e7d39d25d01 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/EnumerableContract.cs @@ -0,0 +1,81 @@ +// +// IEnumerableContract.cs +// +// Author: +// Jonathan Pryor +// +// Copyright (c) 2008 Novell, Inc. (http://www.novell.com) +// +// 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. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +using NUnit.Framework; + +using Cadenza.Collections; +using Cadenza.Tests; + +namespace Cadenza.Collections.Tests { + + public abstract class EnumerableContract : BaseRocksFixture { + + protected abstract IEnumerable CreateSequence (IEnumerable source); + + protected class DisposedCounter { + public int Disposed; + public IEnumerable Values (int max) + { + int v = 0; + try { + for (int i = 0; i < max; ++i) + yield return v++; + } + finally { + Disposed++; + } + } + } + + [Test] + public void Create_SequencEqual () + { + var a = new List (); + for (int i = 0; i < 10; ++i) { + a.Add (i); + Assert.IsTrue (CreateSequence (a).SequenceEqual (a), "Count=" + (i+1)); + } + } + + [Test] + public void GetEnumerator_DisposeDisposesIterator () + { + var d = new DisposedCounter (); + var s = CreateSequence (d.Values (2)); + var i = s.GetEnumerator (); + Assert.IsTrue (i.MoveNext ()); + i.Dispose (); + Assert.AreEqual (1, d.Disposed); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/ListContract.cs b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/ListContract.cs new file mode 100644 index 00000000000..68c6775a364 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza.Collections/ListContract.cs @@ -0,0 +1,200 @@ +// +// IListContract.cs +// +// Author: +// Jonathan Pryor +// +// Copyright (c) 2010 Novell, Inc. (http://www.novell.com) +// +// 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. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +using NUnit.Framework; + +using Cadenza.Collections; +using Cadenza.Tests; + +namespace Cadenza.Collections.Tests { + + public abstract class ListContract : CollectionContract { + + private IList CreateList (IEnumerable values) + { + return (IList) CreateCollection (values); + } + + [Test] + public void IndexOf () + { + var a = CreateValueA (); + var b = CreateValueB (); + + var list = CreateList (new T[0]); + + Assert.AreEqual (-1, list.IndexOf (a)); + + try { + list.Add (a); + Assert.AreEqual (0, list.IndexOf (a)); + + list.Add (b); + Assert.AreEqual (1, list.IndexOf (b)); + + list.Remove (a); + Assert.AreEqual (-1, list.IndexOf (a)); + Assert.AreEqual (0, list.IndexOf (b)); + + list.Remove (b); + Assert.AreEqual (-1, list.IndexOf (b)); + } + catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly || IsFixedSize (list)); + } + Dispose (list); + + list = CreateList (new T[]{ a, b }); + Assert.AreEqual (0, list.IndexOf (a)); + Assert.AreEqual (1, list.IndexOf (b)); + + Dispose (list); + Dispose (a); + Dispose (b); + } + + [Test] + public void Insert () + { + var a = CreateValueA (); + var b = CreateValueB (); + + var list = CreateList (new T[0]); + + try { + list.Insert (-1, a); + } catch (ArgumentOutOfRangeException) { + } catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly || IsFixedSize (list)); + } + + try { + list.Insert (1, a); + } catch (ArgumentOutOfRangeException) { + } catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly || IsFixedSize (list)); + } + + try { + list.Insert (0, a); + Assert.AreEqual (0, list.IndexOf (a)); + + list.Insert (0, b); + Assert.AreEqual (2, list.Count); + Assert.AreEqual (0, list.IndexOf (b)); + Assert.AreEqual (1, list.IndexOf (a)); + } + catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly || IsFixedSize (list)); + } + + Dispose (list); + Dispose (a); + Dispose (b); + } + + [Test] + public void RemoveAt () + { + var a = CreateValueA (); + var b = CreateValueB (); + + var list = CreateList (new T [0]); + + try { + list.RemoveAt (-1); + } catch (ArgumentOutOfRangeException) { + } catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly || IsFixedSize (list)); + } + + try { + list.RemoveAt (0); + } catch (ArgumentOutOfRangeException) { + } catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly || IsFixedSize (list)); + } + + try { + list.Add (a); + Assert.AreEqual (1, list.Count); + + list.RemoveAt (0); + Assert.AreEqual (0, list.Count); + + list.Add (a); + list.Add (b); + list.RemoveAt (0); + Assert.AreEqual (1, list.Count); + Assert.AreEqual (0, list.IndexOf (b)); + } + catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly || IsFixedSize (list)); + } + + Dispose (list); + Dispose (a); + Dispose (b); + } + + [Test] + public void Item () + { + var a = CreateValueA (); + var b = CreateValueB (); + + var list = CreateList (new []{a}); + + var e = list [0]; + Assert.AreEqual (a, e); + Assert.Throws(() => Ignore (list [-1])); + + try { + Assert.Throws(() => list [-1] = a); + Assert.Throws(() => list [1] = a); + + list [0] = b; + Assert.AreEqual (-1, list.IndexOf (a)); + Assert.AreEqual (0, list.IndexOf (b)); + } + catch (NotSupportedException) { + Assert.IsTrue (list.IsReadOnly); + } + + Dispose (list); + Dispose (a); + Dispose (b); + Dispose (e); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Cadenza/BaseRocksFixture.cs b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza/BaseRocksFixture.cs new file mode 100644 index 00000000000..fa3e531c721 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Cadenza/BaseRocksFixture.cs @@ -0,0 +1,65 @@ +// +// BaseRocksTestFixture.cs +// +// Author: +// Jb Evain (jbevain@novell.com) +// +// Copyright (c) 2007 Novell, Inc. (http://www.novell.com) +// +// 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. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +using NUnit.Framework; + +using Cadenza; + +namespace Cadenza.Tests { + + public abstract class BaseRocksFixture : Java.InteropTests.JavaVMFixture { + + public void AssertAreSame (IEnumerable expected, IEnumerable data) + { + Assert.IsTrue (data.SequenceEqual (expected)); + } + + public static void AssertException (Action action) + { + try { + action (); + } + catch (Exception e) + { + if (e.GetType () != typeof (TException)) + throw new InvalidOperationException ( + string.Format ("invalid exception type! Expected {0}, got {1}.", + typeof (TException).FullName, e.GetType().FullName)); + } + } + + // Exists so that you can use a variable and shut up the compiler. + public static void Ignore(T value) + { + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop-Tests.csproj b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop-Tests.csproj new file mode 100644 index 00000000000..174e7bb1864 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop-Tests.csproj @@ -0,0 +1,57 @@ + + + + $(DotNetTargetFramework) + false + true + ..\..\product.snk + true + $(DefineConstants);NO_MARSHAL_MEMBER_BUILDER_SUPPORT;NO_GC_BRIDGE_SUPPORT + + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop-Tests.targets b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop-Tests.targets new file mode 100644 index 00000000000..3f6e36bc659 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop-Tests.targets @@ -0,0 +1,56 @@ + + + + <_BuildJavaInteropTestsJarInputs Include="$(TargetPath)" /> + <_BuildJavaInteropTestsJarInputs Include="$(MSBuildThisFileFullPath)" /> + <_BuildJavaInteropTestsJarInputs Include="java\**\*.java" /> + + + + + + + + <_RefAsmDirs Include="@(ReferencePathWithRefAssemblies->'%(RootDir)%(Directory).'->Distinct())" /> + + + <_JcwGen>"$(UtilityOutputFullPath)/jcw-gen.dll" + <_Target>--codegen-target JavaInterop1 + <_Output>-o "$(IntermediateOutputPath)/java" + <_Libpath>@(_RefAsmDirs->'-L "%(Identity)"', ' ') + + + + + + + + <_GeneratedJcwSource Include="$(IntermediateOutputPath)java\**\*.java" /> + + + + + + + <_Source Include="@(JavaInteropTestJar->Replace('%5c', '/'))" /> + <_Source Include="@(_GeneratedJcwSource->Replace('%5c', '/'))" /> + + + + + + + + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualBase.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualBase.cs new file mode 100644 index 00000000000..ba63e0d9859 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualBase.cs @@ -0,0 +1,33 @@ +using System; + +using Java.Interop; + +namespace Java.InteropTests +{ + [JniTypeSignature (CallNonvirtualBase.JniTypeName, GenerateJavaPeer=false)] + public class CallNonvirtualBase : JavaObject + { + internal const string JniTypeName = "net/dot/jni/test/CallNonvirtualBase"; + + readonly static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (CallNonvirtualBase)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public CallNonvirtualBase () + { + } + + public virtual unsafe void Method () + { + _members.InstanceMethods.InvokeVirtualVoidMethod ("method.()V", this, null); + } + + public bool MethodInvoked { + get {return _members.InstanceFields.GetBooleanValue ("methodInvoked.Z" ,this);} + set {_members.InstanceFields.SetValue ("methodInvoked.Z", this, value);} + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualDerived.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualDerived.cs new file mode 100644 index 00000000000..29ffee0f0d1 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualDerived.cs @@ -0,0 +1,28 @@ +using System; + +using Java.Interop; + +namespace Java.InteropTests +{ + [JniTypeSignature (CallNonvirtualDerived.JniTypeName, GenerateJavaPeer=false)] + public class CallNonvirtualDerived : CallNonvirtualBase + { + internal new const string JniTypeName = "net/dot/jni/test/CallNonvirtualDerived"; + + readonly static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (CallNonvirtualDerived)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public CallNonvirtualDerived () + { + } + + public new bool MethodInvoked { + get {return _members.InstanceFields.GetBooleanValue ("methodInvoked.Z", this);} + set {_members.InstanceFields.SetValue ("methodInvoked.Z", this, value);} + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualDerived2.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualDerived2.cs new file mode 100644 index 00000000000..b2d4c08bd56 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallNonvirtualDerived2.cs @@ -0,0 +1,17 @@ +using System; + +using Java.Interop; + +namespace Java.InteropTests +{ + [JniTypeSignature (CallNonvirtualDerived2.JniTypeName, GenerateJavaPeer=false)] + public class CallNonvirtualDerived2 : CallNonvirtualDerived + { + internal new const string JniTypeName = "net/dot/jni/test/CallNonvirtualDerived2"; + + public CallNonvirtualDerived2 () + { + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallVirtualFromConstructorBase.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallVirtualFromConstructorBase.cs new file mode 100644 index 00000000000..ce298734b93 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallVirtualFromConstructorBase.cs @@ -0,0 +1,55 @@ +using System; +using System.Runtime.CompilerServices; + +using Java.Interop; +namespace Java.InteropTests { + + [JniTypeSignature (CallVirtualFromConstructorBase.JniTypeName, GenerateJavaPeer=false)] + public class CallVirtualFromConstructorBase : JavaObject { + + internal const string JniTypeName = "net/dot/jni/test/CallVirtualFromConstructorBase"; + readonly static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (CallVirtualFromConstructorBase)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public unsafe CallVirtualFromConstructorBase (int value) + : this (value, useNewObject: false) + { + } + + public unsafe CallVirtualFromConstructorBase (int value, bool useNewObject) + : this (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + if (PeerReference.IsValid) + return; + + const string __id = "(I)V"; + + if (useNewObject) { + var ctors = JniPeerMembers.InstanceMethods.GetConstructorsForType (GetType ()); + var init = ctors.GetConstructor (__id); + + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var lref = JniEnvironment.Object.NewObject (ctors.JniPeerType.PeerReference, init, __args); + Construct (ref lref, JniObjectReferenceOptions.CopyAndDispose); + return; + } + var peer = JniPeerMembers.InstanceMethods.StartGenericCreateInstance (__id, GetType (), value); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + JniPeerMembers.InstanceMethods.FinishGenericCreateInstance (__id, this, value); + } + + public CallVirtualFromConstructorBase (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } + + public virtual void CalledFromConstructor (int value) + { + _members.InstanceMethods.InvokeGenericVirtualVoidMethod ("calledFromConstructor.(I)V", this, value); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallVirtualFromConstructorDerived.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallVirtualFromConstructorDerived.cs new file mode 100644 index 00000000000..739b85e08c9 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/CallVirtualFromConstructorDerived.cs @@ -0,0 +1,101 @@ +#nullable enable + +using System; +using System.Runtime.CompilerServices; + +using Java.Interop; + +namespace Java.InteropTests +{ + [JniTypeSignature (CallVirtualFromConstructorDerived.JniTypeName, GenerateJavaPeer=false)] + public class CallVirtualFromConstructorDerived : CallVirtualFromConstructorBase { + new internal const string JniTypeName = "net/dot/jni/test/CallVirtualFromConstructorDerived"; + static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (CallVirtualFromConstructorDerived)); + + [JniAddNativeMethodRegistrationAttribute] + static void RegisterNativeMembers (JniNativeMethodRegistrationArguments args) + { + args.Registrations.Add (new JniNativeMethodRegistration ("calledFromConstructor", "(I)V", (CalledFromConstructorMarshalMethod)CalledFromConstructorHandler)); + } + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + int calledValue; + + public bool InvokedConstructor; + + public CallVirtualFromConstructorDerived (int value) + : this (value, useNewObject: false) + { + } + + public CallVirtualFromConstructorDerived (int value, bool useNewObject) + : base (value, useNewObject) + { + InvokedConstructor = true; + + if (useNewObject && calledValue != 0) { + // calledValue was set on a *different* instance! So it's 0 here. + throw new ArgumentException ( + string.Format ("value '{0}' doesn't match expected value '{1}'.", value, 0), + "value"); + } + if (!useNewObject && value != calledValue) + throw new ArgumentException ( + string.Format ("value '{0}' doesn't match expected value '{1}'.", value, calledValue), + "value"); + } + + public bool InvokedActivationConstructor; + + public static CallVirtualFromConstructorDerived? Intermediate_FromCalledFromConstructor; + public static CallVirtualFromConstructorDerived? Intermediate_FromActivationConstructor; + + public CallVirtualFromConstructorDerived (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + InvokedActivationConstructor = true; + + Intermediate_FromActivationConstructor = this; + } + + public bool Called; + + public override void CalledFromConstructor (int value) + { + Called = true; + calledValue = value; + + Intermediate_FromCalledFromConstructor = this; + } + + public static unsafe CallVirtualFromConstructorDerived NewInstance (int value) + { + JniArgumentValue* args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + var o = _members.StaticMethods.InvokeObjectMethod ("newInstance.(I)Lnet/dot/jni/test/CallVirtualFromConstructorDerived;", args); + return JniEnvironment.Runtime.ValueManager.GetValue (ref o, JniObjectReferenceOptions.CopyAndDispose)!; + } + + delegate void CalledFromConstructorMarshalMethod (IntPtr jnienv, IntPtr n_self, int value); + static void CalledFromConstructorHandler (IntPtr jnienv, IntPtr n_self, int value) + { + var envp = new JniTransition (jnienv); + try { + var r_self = new JniObjectReference (n_self); + var self = JniEnvironment.Runtime.ValueManager.GetValue(ref r_self, JniObjectReferenceOptions.Copy)!; + self.CalledFromConstructor (value); + self.DisposeUnlessReferenced (); + } + catch (Exception e) when (JniEnvironment.Runtime.ExceptionShouldTransitionToJni (e)) { + envp.SetPendingException (e); + } + finally { + envp.Dispose (); + } + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/FinalizerHelpers.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/FinalizerHelpers.cs new file mode 100644 index 00000000000..26a1397b021 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/FinalizerHelpers.cs @@ -0,0 +1,47 @@ +// Originally from: https://github.com/mono/mono/blob/8266c5604b8c03882f2b06af27fdea46b142d6b9/mono/mini/TestHelpers.cs#L12 + +using System; +using System.Threading; + +namespace Java.InteropTests +{ + // False pinning cases are still possible. For example the thread can die + // and its stack reused by another thread. It also seems that a thread that + // does a GC can keep on the stack references to objects it encountered + // during the collection which are never released afterwards. This would + // be more likely to happen with the interpreter which reuses more stack. + static class FinalizerHelpers + { + private static IntPtr aptr; + + private static unsafe void NoPinActionHelper (int depth, Action act) + { + // Avoid tail calls + int* values = stackalloc int [20]; + aptr = new IntPtr (values); + + if (depth <= 0) { + // + // When the action is called, this new thread might have not allocated + // anything yet in the nursery. This means that the address of the first + // object that would be allocated would be at the start of the tlab and + // implicitly the end of the previous tlab (address which can be in use + // when allocating on another thread, at checking if an object fits in + // this other tlab). We allocate a new dummy object to avoid this type + // of false pinning for most common cases. + // + new object (); + act (); + } else { + NoPinActionHelper (depth - 1, act); + } + } + + public static void PerformNoPinAction (Action act) + { + Thread thr = new Thread (() => NoPinActionHelper (128, act)); + thr.Start (); + thr.Join (); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/GetThis.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/GetThis.cs new file mode 100644 index 00000000000..45e908853c2 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/GetThis.cs @@ -0,0 +1,47 @@ +using System; + +using Java.Interop; + +namespace Java.InteropTests +{ + [JniTypeSignature (GetThis.JniTypeName, GenerateJavaPeer=false)] + public class GetThis : JavaObject + { + internal const string JniTypeName = "net/dot/jni/test/GetThis"; + + bool _isDisposed; + + readonly static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (GetThis)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public GetThis () + { + } + + public unsafe GetThis This { + get { + var o = _members.InstanceMethods.InvokeNonvirtualObjectMethod ("getThis.()Lnet/dot/jni/test/GetThis;", this, null); + return JniEnvironment.Runtime.ValueManager.GetValue (ref o, JniObjectReferenceOptions.CopyAndDispose); + } + } + + protected override void Dispose (bool disposing) + { + if (_isDisposed) { + return; + } + _isDisposed = true; + if (disposing) { + var t = This; + if (t != this) { + throw new InvalidOperationException ("SHOULD NOT BE REACHED"); + } + } + base.Dispose (disposing); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/InvokeVirtualFromConstructorTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/InvokeVirtualFromConstructorTests.cs new file mode 100644 index 00000000000..949f1902997 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/InvokeVirtualFromConstructorTests.cs @@ -0,0 +1,156 @@ +using System; +using System.Runtime.CompilerServices; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests { + + [TestFixture] + [Category ("TrimmableTypeMapUnsupported")] +#if !__ANDROID__ + // We want stability around the CallVirtualFromConstructorDerived static fields + [NonParallelizable] +#endif // !__ANDROID__ + public class InvokeVirtualFromConstructorTests : JavaVMFixture + { + [Test] + [Category ("NativeAOTIgnore")] // https://github.com/dotnet/android/issues/10950 + public void CreateManagedInstanceFirst_WithAllocObject () + { + CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor = null; + CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor = null; + + using var t = new CallVirtualFromConstructorDerived (42); + Assert.IsTrue ( + t.Called, + "CalledFromConstructor method override should have been called."); + Assert.IsFalse ( + t.InvokedActivationConstructor, + "Activation Constructor should have been called, as calledFromConstructor() is invoked before ManagedPeer.construct()."); + Assert.IsTrue ( + t.InvokedConstructor, + "(int) constructor should have been called, via ManagedPeer.construct()."); + + var registered = JniRuntime.CurrentRuntime.ValueManager.PeekValue (t.PeerReference); + var acIntermediate = CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor; + var cfIntermediate = CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor; + + Assert.AreSame (t, registered, + "Expected t and registered to be the same instance; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"registered={RuntimeHelpers.GetHashCode (registered).ToString ("x")}"); + Assert.IsNull (acIntermediate, + "Activation Constructor should not have been called, because of AllocObject semantics"); + Assert.AreSame (t, cfIntermediate, + "Expected t and cfIntermediate to be the same instance; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"cfIntermediate={RuntimeHelpers.GetHashCode (cfIntermediate).ToString ("x")}"); + + Dispose (ref CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor); + Dispose (ref CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor); + } + + static void Dispose (ref T peer) + where T : class, IJavaPeerable + { + if (peer == null) + return; + + peer.Dispose (); + peer = null; + } + + [Test] + [Category ("NativeAOTIgnore")] // https://github.com/dotnet/android/issues/10950 + public void CreateManagedInstanceFirst_WithNewObject () + { + CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor = null; + CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor = null; + + using var t = new CallVirtualFromConstructorDerived (42, useNewObject: true); + Assert.IsFalse ( + t.Called, + "CalledFromConstructor method override was called on a different instance."); + Assert.IsFalse ( + t.InvokedActivationConstructor, + "Activation Constructor should not have been called, as calledFromConstructor() is invoked before ManagedPeer.construct()."); + Assert.IsTrue ( + t.InvokedConstructor, + "(int) constructor should have been called, via ManagedPeer.construct()."); + + var registered = JniRuntime.CurrentRuntime.ValueManager.PeekValue (t.PeerReference); + var acIntermediate = CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor; + var cfIntermediate = CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor; + + Assert.AreSame (t, registered, + "Expected t and registered to be the same instance; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"registered={RuntimeHelpers.GetHashCode (registered).ToString ("x")}"); + Assert.IsNotNull (acIntermediate, + "Activation Constructor should have been called, because of NewObject"); + Assert.IsTrue ( + acIntermediate.Called, + "CalledFromConstructor method override should have been called on acIntermediate."); + Assert.IsTrue ( + acIntermediate.InvokedActivationConstructor, + "Activation Constructor should have been called on intermediate instance, as calledFromConstructor() is invoked before ManagedPeer.construct()."); + Assert.AreNotSame (t, acIntermediate, + "Expected t and registered to be different instances; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"acIntermediate={RuntimeHelpers.GetHashCode (acIntermediate).ToString ("x")}"); + Assert.AreNotSame (t, cfIntermediate, + "Expected t and cfIntermediate to be different instances; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"cfIntermediate={RuntimeHelpers.GetHashCode (cfIntermediate).ToString ("x")}"); + Assert.AreSame (acIntermediate, cfIntermediate, + "Expected acIntermediate and cfIntermediate to be the same instance; " + + $"acIntermediate={RuntimeHelpers.GetHashCode (acIntermediate).ToString ("x")}, " + + $"cfIntermediate={RuntimeHelpers.GetHashCode (cfIntermediate).ToString ("x")}"); + + Dispose (ref CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor); + Dispose (ref CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor); + } + + [Test] + [Category ("NativeAOTIgnore")] // https://github.com/dotnet/android/issues/10950 + public void CreateJavaInstanceFirst () + { + CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor = null; + CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor = null; + + using var t = CallVirtualFromConstructorDerived.NewInstance (42); + + Assert.IsTrue ( + t.Called, + "CalledFromConstructor method override should have been called."); + Assert.IsTrue ( + t.InvokedActivationConstructor, + "Activation Constructor should have been called, as calledFromConstructor() is invoked before ManagedPeer.construct()."); + Assert.IsTrue ( + t.InvokedConstructor, + "(int) constructor should have been called, via ManagedPeer.construct()."); + + var registered = JniRuntime.CurrentRuntime.ValueManager.PeekValue (t.PeerReference); + var acIntermediate = CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor; + var cfIntermediate = CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor; + + Assert.AreSame (t, registered, + "Expected t and registered to be the same instance; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"registered={RuntimeHelpers.GetHashCode (registered).ToString ("x")}"); + Assert.AreSame (t, acIntermediate, + "Expected t and registered to be the same instance; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"acIntermediate={RuntimeHelpers.GetHashCode (acIntermediate).ToString ("x")}"); + Assert.AreSame (t, cfIntermediate, + "Expected t and cfIntermediate to be the same instance; " + + $"t={RuntimeHelpers.GetHashCode (t).ToString ("x")}, " + + $"cfIntermediate={RuntimeHelpers.GetHashCode (cfIntermediate).ToString ("x")}"); + + Dispose (ref CallVirtualFromConstructorDerived.Intermediate_FromActivationConstructor); + Dispose (ref CallVirtualFromConstructorDerived.Intermediate_FromCalledFromConstructor); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaArrayContract.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaArrayContract.cs new file mode 100644 index 00000000000..1279e28426c --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaArrayContract.cs @@ -0,0 +1,44 @@ +using System; +using System.Linq; + +using Java.Interop; + +using Cadenza.Collections.Tests; +using NUnit.Framework; + +namespace Java.InteropTests +{ + public abstract class JavaArrayContract : ListContract + { + int lrefStartCount; + + [OneTimeSetUp] + public void StartArrayTests () + { + lrefStartCount = JniEnvironment.LocalReferenceCount; + } + + [OneTimeTearDown] + public void EndArrayTests () + { + int lref = JniEnvironment.LocalReferenceCount; + Assert.AreEqual (lrefStartCount, lref, "JNI local references"); + } + + [Test] + public void ToArray () + { + var expected = new[] { + CreateValueA (), + CreateValueB (), + }; + var ja = (JavaArray) CreateCollection (expected); + var a = ja.ToArray (); + Assert.IsTrue (SequenceEqual (expected, a)); + ja.Dispose (); + DisposeCollection (a); + DisposeCollection (expected); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaBooleanArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaBooleanArrayContractTests.cs new file mode 100644 index 00000000000..3f13eaa42fb --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaBooleanArrayContractTests.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaBooleanArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaBooleanArray (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaBooleanArray (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaBooleanArray (length); + } + + protected override bool CreateValueA () + { + return true; + } + + protected override bool CreateValueB () + { + return false; + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaCharArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaCharArrayContractTests.cs new file mode 100644 index 00000000000..350df67face --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaCharArrayContractTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaCharArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaCharArray (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaCharArray (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaCharArray (length); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaDoubleArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaDoubleArrayContractTests.cs new file mode 100644 index 00000000000..6f00e3ccc40 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaDoubleArrayContractTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaDoubleArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaDoubleArray (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaDoubleArray (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaDoubleArray (length); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaExceptionTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaExceptionTests.cs new file mode 100644 index 00000000000..d82a7ac0a87 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaExceptionTests.cs @@ -0,0 +1,111 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaExceptionTests + { + [Test] + public void StackTrace () + { + void AssertMembers (string message, string stackTraceMember, string stackTrace) { + var containsMessage = message.Replace ('/', '.'); + Assert.IsTrue ( + containsMessage.IndexOf ("this.type.had.better.not.exist", StringComparison.OrdinalIgnoreCase) >= 0, + $"Message: {message}"); + Assert.IsTrue ( + // ART + (stackTrace.IndexOf ("java.lang.ClassNotFoundException: ", StringComparison.Ordinal) >= 0) || + // Dalvik, JVM + (stackTrace.IndexOf ("java.lang.NoClassDefFoundError: this/type/had/better/not/exist", StringComparison.Ordinal) >= 0), + $"{stackTraceMember}: {stackTrace}"); + } + + try { + new JniType ("this/type/had/better/not/exist"); + } +#if __ANDROID__ + catch (Java.Lang.Throwable e) { + AssertMembers (e.Message, "Throwable.StackTrace", e.StackTrace); + e.Dispose (); + } +#endif // __ANDROID__ + catch (JavaException e) { + AssertMembers (e.Message, "JavaException.JavaStackTrace", e.JavaStackTrace); + e.Dispose (); + } + } + + [Test] + public void InnerException () + { + using (var t = new JniType ("java/lang/Throwable")) { + var outer = CreateThrowable (t, "Outer Exception"); + SetThrowableCause (t, outer, "Inner Exception"); + using (var e = new JavaException (ref outer, JniObjectReferenceOptions.CopyAndDispose)) { + Assert.IsNotNull (e.InnerException); + Assert.AreEqual ("Inner Exception", e.InnerException.Message); + Assert.AreEqual ("Outer Exception", e.Message); + } + } + } + + static unsafe JniObjectReference CreateThrowable (JniType type, string message) + { + var c = type.GetConstructor ("(Ljava/lang/String;)V"); + var s = JniEnvironment.Strings.NewString (message); + try { + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (s); + return type.NewObject (c, args); + } finally { + JniObjectReference.Dispose (ref s); + } + } + + static void SetThrowableCause (JniType type, JniObjectReference outer, string message) + { + var cause = CreateThrowable (type, message); + SetThrowableCause (type, outer, cause); + JniObjectReference.Dispose (ref cause); + } + + static unsafe void SetThrowableCause (JniType type, JniObjectReference outer, JniObjectReference inner) + { + var a = stackalloc JniArgumentValue [1]; + a [0] = new JniArgumentValue (inner); + + var i = type.GetInstanceMethod ("initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;"); + var l = JniEnvironment.InstanceMethods.CallObjectMethod (outer, i, a); + JniObjectReference.Dispose (ref l); + } + + [Test] + public void InnerExceptionIsNotAProxy () + { + using (var t = new JniType ("java/lang/Throwable")) { + var outer = CreateThrowable (t, "Outer Exception"); + var ex = new InvalidOperationException ("Managed Exception!"); + var exp = CreateJavaProxyThrowable (ex); + SetThrowableCause (t, outer, exp.PeerReference); + using (var e = new JavaException (ref outer, JniObjectReferenceOptions.CopyAndDispose)) { + Assert.IsNotNull (e.InnerException); + Assert.AreSame (ex, e.InnerException); + } + exp.Dispose (); + } + } + + static JavaException CreateJavaProxyThrowable (Exception value) + { + var JavaProxyThrowable_type = Type.GetType ("Java.Interop.JavaProxyThrowable, Java.Interop", throwOnError :true); + var proxy = (JavaException) Activator.CreateInstance (JavaProxyThrowable_type, value); + return proxy; + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt16ArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt16ArrayContractTests.cs new file mode 100644 index 00000000000..1705edd8463 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt16ArrayContractTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaInt16ArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaInt16Array (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaInt16Array (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaInt16Array (length); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt32ArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt32ArrayContractTests.cs new file mode 100644 index 00000000000..ddc2bc91195 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt32ArrayContractTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaInt32ArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaInt32Array (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaInt32Array (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaInt32Array (length); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt64ArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt64ArrayContractTests.cs new file mode 100644 index 00000000000..f384760e8d1 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaInt64ArrayContractTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaInt64ArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaInt64Array (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaInt64Array (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaInt64Array (length); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaManagedGCBridgeTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaManagedGCBridgeTests.cs new file mode 100644 index 00000000000..79b64ef2fd5 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaManagedGCBridgeTests.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests { + + [TestFixture] + [Category ("TrimmableTypeMapUnsupported")] + public class JavaManagedGCBridgeTests : JavaVMFixture { + +#if !NO_GC_BRIDGE_SUPPORT + // https://github.com/mono/mono/blob/98d2314/mono/tests/sgen-bridge-xref.cs + [Test] + public void CrossReferences () + { + using (var array = new JavaObjectArray (2)) { + WeakReference root = null, child = null; + var t = new Thread (() => SetupLinks (array, out root, out child)); + t.Start (); + t.Join (); + + JniEnvironment.Runtime.ValueManager.CollectPeers (); + CrossReferenceBridge a, b; + a = b = null; + Console.WriteLine ("try get A {0}", root.TryGetTarget (out a)); + Console.WriteLine ("try get B {0}", child.TryGetTarget (out b)); + Console.WriteLine ("a is null {0}", a == null); + Console.WriteLine ("b is null {0}", b == null); + + Assert.IsNotNull (a); + Assert.IsNotNull (b); + } + } +#endif // !NO_GC_BRIDGE_SUPPORT + + static void SetupLinks (JavaObjectArray array, out WeakReference root, out WeakReference child) + { + var a = new CrossReferenceBridge () { + id = "bridge", + }; + var b = new CrossReferenceBridge () { + id = "child", + }; + a.link.Add (b); + + array [0] = a; + array [1] = b; + + root = new WeakReference (a, true); + child = new WeakReference (b, true); + } + } + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + public class CrossReferenceBridge : JavaObject { + internal const string JniTypeName = "net/dot/jni/test/CrossReferenceBridge"; + + public string id; + public List link = new List (); + + protected override void Dispose (bool disposing) + { + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs new file mode 100644 index 00000000000..3e5b9c9fc56 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + public abstract class JavaObjectArrayContractTest< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + T + > : JavaArrayContract + { + protected override System.Collections.Generic.ICollection CreateCollection (System.Collections.Generic.IEnumerable values) + { + return new JavaObjectArray (values); + } + + [Test] + public void Constructor_Exceptions () + { + Assert.Throws (() => new JavaObjectArray ((IEnumerable)null)); + Assert.Throws (() => new JavaObjectArray ((IList)null)); + Assert.Throws (() => new JavaObjectArray (-1)); + } + + protected override int IndexOf (T[] array, T value) + { + for (int i = 0; i < array.Length; ++i) + if (JniMarshal.RecursiveEquals (array [i], value)) + return i; + return -1; + } + + protected override bool SequenceEqual (IEnumerable a, IEnumerable b) + { + return JniMarshal.RecursiveEquals (a, b); + } + + int beforeTestGrefCount; + + [SetUp] + public void LogBeginCurrentTestGrefCount () + { + beforeTestGrefCount = JniEnvironment.Runtime.GlobalReferenceCount; + JniEnvironment.Runtime.ObjectReferenceManager.WriteGlobalReferenceLine( + "{0}", + $"Begin {TestContext.CurrentContext.Test.FullName}; " + + $"GREFs={beforeTestGrefCount}; " + ); + } + + [TearDown] + public void LogEndCurrentTestToGrefCount () + { + int afterTestGrefCount = JniEnvironment.Runtime.GlobalReferenceCount; + JniEnvironment.Runtime.ObjectReferenceManager.WriteGlobalReferenceLine( + "{0}", + $"End {TestContext.CurrentContext.Test.FullName}; " + + $"GREFs={afterTestGrefCount}; diff={afterTestGrefCount - beforeTestGrefCount}" + ); + } + } + + [TestFixture] + public class JavaObjectArrayContractTest : JavaObjectArrayContractTest { + protected override JavaObject CreateValueA () {return new JavaObject ();} + protected override JavaObject CreateValueB () {return new JavaObject ();} + + [Test] + public void ObjectArrayType () + { + var c = CreateCollection (new JavaObject [0]); + Assert.AreEqual ("[Ljava/lang/Object;", ((IJavaPeerable) c).GetJniTypeName ()); + Dispose (c); + } + } + + [TestFixture] + public class JavaObjectArray_Int32_ContractTest : JavaObjectArrayContractTest { + protected override int CreateValueA () {return 1;} + protected override int CreateValueB () {return 2;} + + [Test] + public void ObjectArrayType () + { + var c = CreateCollection (new int[0]); + Assert.AreEqual ("[Ljava/lang/Integer;", ((IJavaPeerable) c).GetJniTypeName ()); + Dispose (c); + } + } + + [TestFixture] + public class JavaObjectArray_Int32Array_ContractTest : JavaObjectArrayContractTest { + protected override int[] CreateValueA () {return new[]{1};} + protected override int[] CreateValueB () {return new[]{2};} + + [Test] + public void ObjectArrayType () + { + var c = CreateCollection (new int[0][]); + Assert.AreEqual ("[[I", ((IJavaPeerable) c).GetJniTypeName ()); + Dispose (c); + } + } + + [TestFixture] + public class JavaObjectArray_Int32ArrayArray_ContractTest : JavaObjectArrayContractTest { + protected override int[][] CreateValueA () {return new[]{new[]{1}};} + protected override int[][] CreateValueB () {return new[]{new[]{2}};} + + [Test] + public void ObjectArrayType () + { + var c = CreateCollection (new int[0][][]); + Assert.AreEqual ("[[[I", ((IJavaPeerable) c).GetJniTypeName ()); + Dispose (c); + } + } + + [TestFixture] + public class JavaObjectArray_JavaInt32Array_ContractTest : JavaObjectArrayContractTest { + protected override JavaInt32Array CreateValueA () {return new JavaInt32Array (new[]{1});} + protected override JavaInt32Array CreateValueB () {return new JavaInt32Array (new[]{2});} + + [Test] + public void ObjectArrayType () + { + var c = CreateCollection (new JavaInt32Array [0]); + Assert.AreEqual ("[[I", ((IJavaPeerable) c).GetJniTypeName ()); + Dispose (c); + } + } + + [TestFixture] + public class JavaObjectArray_string_ContractTest : JavaObjectArrayContractTest { + protected override string CreateValueA () {return "a";} + protected override string CreateValueB () {return "b";} + + [Test] + public void ObjectArrayType () + { + var c = CreateCollection (new string[0]); + Assert.AreEqual ("[Ljava/lang/String;", ((IJavaPeerable) c).GetJniTypeName ()); + Dispose (c); + } + } + + [TestFixture] + [Category ("TrimmableTypeMapUnsupported")] + public class JavaObjectArray_object_ContractTest : JavaObjectArrayContractTest { + static readonly object a = new object (); + + protected override object CreateValueA () {return a;} + protected override object CreateValueB () {return 42;} + + int grefStartCount; + + [OneTimeSetUp] + public void BeginCheckGlobalRefCount () + { + // So that the JavaProxyObject.TypeRef GREF isn't counted. + using (var o = new JavaObjectArray (1)) + o [0] = a; + grefStartCount = JniEnvironment.Runtime.GlobalReferenceCount; + } + + [OneTimeTearDown] + public void EndCheckGlobalRefCount () + { + int gref = JniEnvironment.Runtime.GlobalReferenceCount; + Assert.IsTrue (gref <= (grefStartCount), + string.Format ("JNI global references: grefStartCount={0}; gref={1}", grefStartCount, gref)); + JniEnvironment.Runtime.ValueManager.CollectPeers (); + } + + [Test] + public void ObjectArrayType () + { + var c = CreateCollection (new object[0]); + Assert.AreEqual ("[Ljava/lang/Object;", ((IJavaPeerable) c).GetJniTypeName ()); + Dispose (c); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectExtensionsTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectExtensionsTests.cs new file mode 100644 index 00000000000..9a4921cc576 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectExtensionsTests.cs @@ -0,0 +1,34 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests { + + [TestFixture] + public class JavaObjectExtensionsTests + { + [Test] + public void GetJniTypeName () + { + using (var o = new JavaObject ()) { + Assert.AreEqual ("java/lang/Object", o.GetJniTypeName ()); + } + using (var o = new JavaInt32Array (0)) { + Assert.AreEqual ("[I", o.GetJniTypeName ()); + } + } + + [Test] + public void GetJniTypeName_Exceptions () + { + IJavaPeerable o = null; + Assert.Throws (() => o.GetJniTypeName ()); + o = new JavaObject (); + o.Dispose (); + Assert.Throws (() => o.GetJniTypeName ()); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs new file mode 100644 index 00000000000..fcd3a37aa06 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs @@ -0,0 +1,280 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaObjectTest : JavaVMFixture + { +#if !NO_GC_BRIDGE_SUPPORT + [Test] + public void JavaReferencedInstanceSurvivesCollection () + { + Console.WriteLine ("JavaReferencedInstanceSurvivesCollection"); + using (var t = new JniType ("java/lang/Object")) { + var oldHandle = IntPtr.Zero; + var array = new JavaObjectArray (1); + FinalizerHelpers.PerformNoPinAction (() => { + var v = new JavaObject (); + oldHandle = v.PeerReference.Handle; + array [0] = v; + }); + JniEnvironment.Runtime.ValueManager.CollectPeers (); + GC.WaitForPendingFinalizers (); + GC.WaitForPendingFinalizers (); + var first = array [0]; + Assert.IsNotNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (first.PeerReference)); + var f = first.PeerReference; + var o = (JavaObject) JniRuntime.CurrentRuntime.ValueManager.GetValue (ref f, JniObjectReferenceOptions.Copy); + Assert.AreSame (first, o); + if (oldHandle != o.PeerReference.Handle) { + Console.WriteLine ("Yay, object handle changed; value survived a GC!"); + } else { + Console.WriteLine ("What is this, Android pre-ICS?!"); + } + o.Dispose (); + array.Dispose (); + } + } +#endif // !NO_GC_BRIDGE_SUPPORT + + [Test] + public void UnregisterFromRuntime () + { + int registeredCount = JniRuntime.CurrentRuntime.ValueManager.GetSurfacedPeers ().Count; + JniObjectReference l; + JavaObject o; + using (o = new JavaObject ()) { + l = o.PeerReference.NewLocalRef (); + Assert.AreEqual (JniObjectReferenceType.Global, o.PeerReference.Type); + Assert.AreEqual (registeredCount+1, JniRuntime.CurrentRuntime.ValueManager.GetSurfacedPeers ().Count, "registeredCount+1 should match!"); + Assert.IsNotNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (l)); + Assert.AreNotSame (l, o.PeerReference); + Assert.AreSame (o, JniRuntime.CurrentRuntime.ValueManager.PeekValue (l)); + } + Assert.AreEqual (registeredCount, JniRuntime.CurrentRuntime.ValueManager.GetSurfacedPeers ().Count, "registeredCount should match!"); + Assert.IsNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (l)); + JniObjectReference.Dispose (ref l); + Assert.Throws (() => o.UnregisterFromRuntime ()); + } + + [Test] + public void RegisterWithVM_PermitsAliases () + { + using (var original = new JavaObject ()) { + var p = original.PeerReference; + var alias = new JavaObject (ref p, JniObjectReferenceOptions.Copy); + alias.Dispose (); + } + } + +#if !NO_GC_BRIDGE_SUPPORT + [Test] + public async Task UnreferencedInstanceIsCollected () + { + JniObjectReference oldHandle = new JniObjectReference (); + WeakReference r = null; + FinalizerHelpers.PerformNoPinAction (() => { + var v = new JavaObject (); + oldHandle = v.PeerReference.NewWeakGlobalRef (); + r = new WeakReference (v); + }); + JniEnvironment.Runtime.ValueManager.CollectPeers (); + await WaitForGC ( + () => !r.IsAlive && JniRuntime.CurrentRuntime.ValueManager.PeekValue (oldHandle) == null, + "Expected the unreferenced instance to be collected."); + Assert.IsFalse (r.IsAlive); + Assert.IsNull (r.Target); + Assert.IsNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (oldHandle)); + JniObjectReference.Dispose (ref oldHandle); + } +#endif // !NO_GC_BRIDGE_SUPPORT + + [Test] + public void Dispose () + { + var d = false; + var f = false; + var o = new JavaDisposedObject (() => d = true, () => f = true); + o.Dispose (); + Assert.IsTrue (d); + Assert.IsFalse (f); + } + +#if !NO_GC_BRIDGE_SUPPORT + [Test] + public async Task Dispose_Finalized () + { + var disposed = new TaskCompletionSource (TaskCreationOptions.RunContinuationsAsynchronously); + var finalized = new TaskCompletionSource (TaskCreationOptions.RunContinuationsAsynchronously); + FinalizerHelpers.PerformNoPinAction (() => { + FinalizerHelpers.PerformNoPinAction (() => { + var v = new JavaDisposedObject ( + () => disposed.TrySetResult (true), + () => finalized.TrySetResult (true)); + GC.KeepAlive (v); + }); + JniEnvironment.Runtime.ValueManager.CollectPeers (); + }); + JniEnvironment.Runtime.ValueManager.CollectPeers (); + await WaitForGC ( + () => disposed.Task.IsCompleted || finalized.Task.IsCompleted, + "Expected JavaDisposedObject.Dispose(disposing: false) to run."); + Assert.IsFalse (disposed.Task.IsCompleted); + Assert.IsTrue (finalized.Task.IsCompleted); + } +#endif // !NO_GC_BRIDGE_SUPPORT + + static async Task WaitForGC (Func predicate, string message, int timeoutMilliseconds = 2000) + { + var timeout = TimeSpan.FromMilliseconds (timeoutMilliseconds); + var stopwatch = Stopwatch.StartNew (); + while (!predicate () && stopwatch.Elapsed < timeout) { + GC.Collect (generation: 2, mode: GCCollectionMode.Forced, blocking: true); + GC.WaitForPendingFinalizers (); + JniEnvironment.Runtime.ValueManager.CollectPeers (); + await Task.Yield (); + } + Assert.IsTrue (predicate (), message); + } + + [Test] + public void ObjectDisposed () + { + var o = new JavaObject (); + o.Dispose (); + + // These should not throw + var h = o.PeerReference; + var p = o.JniPeerMembers; + + // These should throw + Assert.Throws (() => o.GetHashCode ()); + Assert.Throws (() => o.UnregisterFromRuntime ()); + Assert.Throws (() => o.ToString ()); + Assert.Throws (() => o.Equals (o)); + } + + [Test] + public unsafe void Ctor () + { + using (var t = new JniType ("java/lang/Object")) { + var c = t.GetConstructor ("()V"); + var lref = t.NewObject (c, null); + Assert.IsTrue (lref.IsValid); + using (var o = new JavaObject (ref lref, JniObjectReferenceOptions.Copy)) { + Assert.IsTrue (lref.IsValid); + Assert.AreNotSame (lref, o.PeerReference); + } + using (var o = new JavaObject (ref lref, JniObjectReferenceOptions.CopyAndDispose)) { + Assert.IsFalse (lref.IsValid); + Assert.AreNotSame (lref, o.PeerReference); + } + } + } + + [Test] + public void Ctor_Exceptions () + { + var r = new JniObjectReference (); + Assert.Throws (() => new JavaObject (ref r, JniObjectReferenceOptions.CopyAndDispose)); + +#if __ANDROID__ + Assert.Throws (() => new JavaObjectWithMissingJavaPeer ()).Dispose (); +#else // !__ANDROID__ + // Note: `JavaObjectWithNoJavaPeer` creation works on Android because tooling provides all + // typemap entries. On desktop, we use the hardcoded dictionary in JavaVMFixture, which + // deliberately *lacks* an entry for `JavaObjectWithNoJavaPeer`. + Assert.Throws (() => new JavaObjectWithNoJavaPeer ()); + Assert.Throws (() => new JavaObjectWithMissingJavaPeer ()).Dispose (); +#endif // !__ANDROID__ + } + + [Test] + public void CrossThreadSharingRequresRegistration () + { + JavaObject o = null; + FinalizerHelpers.PerformNoPinAction (() => { + o = new JavaObject (); + }); + o.ToString (); + o.Dispose (); + } + + [Test] + public void NestedDisposeInvocations () + { + var value = new MyDisposableObject (); + value.Dispose (); + value.Dispose (); + } + + [Test] + public void DisposeAccessesThis () + { + var value = new GetThis (); + value.Dispose (); + value.Dispose (); + } + } + +#if !__ANDROID__ + class JavaObjectWithNoJavaPeer : JavaObject { + } +#endif // !__ANDROID__ + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + class JavaObjectWithMissingJavaPeer : JavaObject { + internal const string JniTypeName = "__this__/__type__/__had__/__better__/__not__/__Exist__"; + } + + [JniTypeSignature (JniTypeName)] + class JavaDisposedObject : JavaObject { + + internal const string JniTypeName = "net/dot/jni/test/JavaDisposedObject"; + + public Action OnDisposed; + public Action OnFinalized; + + public JavaDisposedObject (Action disposed, Action finalized) + { + OnDisposed = disposed; + OnFinalized = finalized; + } + + protected override void Dispose (bool disposing) + { + if (disposing) + OnDisposed (); + else + OnFinalized (); + } + } + + [JniTypeSignature (JniTypeName)] + class MyDisposableObject : JavaObject { + internal const string JniTypeName = "net/dot/jni/test/MyDisposableObject"; + + bool _isDisposed; + + public MyDisposableObject () + { + } + + protected override void Dispose (bool disposing) + { + if (_isDisposed) { + return; + } + _isDisposed = true; + if (this.PeerReference.IsValid) + this.Dispose (); + base.Dispose (disposing); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaPeerableExtensionsTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaPeerableExtensionsTests.cs new file mode 100644 index 00000000000..48e6580cd8c --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaPeerableExtensionsTests.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests; + +[TestFixture] +public class JavaPeerableExtensionsTests { + + [Test] + public void JavaAs_Exceptions () + { + using var v = new MyJavaInterfaceImpl (); + + // The Java type corresponding to JavaObjectWithMissingJavaPeer doesn't exist + Assert.Throws(() => v.JavaAs()); + + var r = v.PeerReference; + using var o = new JavaObject (ref r, JniObjectReferenceOptions.Copy); + // MyJavaInterfaceImpl doesn't provide an activation constructor + Assert.Throws(() => o.JavaAs()); +#if !__ANDROID__ + // JavaObjectWithNoJavaPeer has no Java peer + Assert.Throws(() => v.JavaAs()); +#endif // !__ANDROID__ + } + + [Test] + public void JavaAs_NullSelfReturnsNull () + { + Assert.AreEqual (null, JavaPeerableExtensions.JavaAs (null)); + } + + public void JavaAs_InvalidPeerRefReturnsNull () + { + var v = new MyJavaInterfaceImpl (); + v.Dispose (); + Assert.AreEqual (null, JavaPeerableExtensions.JavaAs (v)); + } + + [Test] + public void JavaAs_InstanceThatDoesNotImplementInterfaceReturnsNull () + { + using var v = new MyJavaInterfaceImpl (); + Assert.AreEqual (null, JavaPeerableExtensions.JavaAs (v)); + } + + [Test] + public void JavaAs () + { + using var impl = new MyJavaInterfaceImpl (); + using var iface = impl.JavaAs (); + Assert.IsNotNull (iface); + Assert.AreEqual ("Hello from Java!", iface.Value); + } +} + +// Note: Java side implements JavaInterface, while managed binding DOES NOT. +[JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] +public class MyJavaInterfaceImpl : JavaObject { + internal const string JniTypeName = "net/dot/jni/test/MyJavaInterfaceImpl"; + + internal static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (MyJavaInterfaceImpl)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public unsafe MyJavaInterfaceImpl () + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string id = "()V"; + var peer = _members.InstanceMethods.StartCreateInstance (id, GetType (), null); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (id, this, null); + } +} + +[JniTypeSignature (JniTypeName, GenerateJavaPeer=false, InvokerType=typeof(IJavaInterfaceInvoker))] +interface IJavaInterface : IJavaPeerable { + internal const string JniTypeName = "net/dot/jni/test/JavaInterface"; + + public string Value { + [JniMethodSignatureAttribute("getValue", "()Ljava/lang/String;")] + get; + } +} + +[JniTypeSignature (IJavaInterface.JniTypeName, GenerateJavaPeer=false)] +internal class IJavaInterfaceInvoker : JavaObject, IJavaInterface { + + internal static readonly JniPeerMembers _members = new JniPeerMembers (IJavaInterface.JniTypeName, typeof (IJavaInterfaceInvoker)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public IJavaInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } + + public unsafe string Value { + get { + const string id = "getValue.()Ljava/lang/String;"; + var r = JniPeerMembers.InstanceMethods.InvokeVirtualObjectMethod (id, this, null); + return JniEnvironment.Strings.ToString (ref r, JniObjectReferenceOptions.CopyAndDispose); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaPrimitiveArrayContract.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaPrimitiveArrayContract.cs new file mode 100644 index 00000000000..d20c52a865f --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaPrimitiveArrayContract.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + public abstract class JavaPrimitiveArrayContract : JavaArrayContract + where TArray : JavaPrimitiveArray + { + protected override TElement CreateValueA () + { + return FromInt32 ((int) 'A'); + } + + protected override TElement CreateValueB () + { + return FromInt32 ((int) 'B'); + } + + protected abstract ICollection CreateCollection (IList values); + + protected abstract ICollection CreateCollection (int length); + + protected TElement FromInt32 (int value) + { + return (TElement) Convert.ChangeType (value, typeof(TElement)); + } + + [Test] + public void Constructor_Exceptions () + { + Assert.Throws(() => CreateCollection ((IEnumerable) null)); + Assert.Throws(() => CreateCollection ((IList) null)); + Assert.Throws(() => CreateCollection (-1)); + } + + [Test] + public void GetElements () + { + var a = (TArray) CreateCollection (new[]{FromInt32 ('A')}); + JniArrayElements e; + using (e = a.GetElements ()) { + if (e == null) // OOM? + return; + Assert.IsTrue (e.Elements != IntPtr.Zero); + // Multi-dispose is supported. + e.Dispose (); + } + Assert.Throws (() => e.Release (JniReleaseArrayElementsMode.Abort)); + Assert.Throws (() => { + #pragma warning disable 0219 + var _ = e.Elements; + #pragma warning restore 0219 + }); + a.Dispose (); + } + + // TODO: http://developer.android.com/training/articles/perf-jni.html#arrays + // "Also, if the Get call fails, you must ensure that your code doesn't + // try to Release a NULL pointer later." + // This implies that JNIEnv::GetArrayElements() can return NULL; how/when? + // Theory: this happens if the array is empty (kinda like what C# `fixed` does?). + // Try to test this. + // (Alas, on OpenJDK JNIEnv::GetArrayElements() returns a non-NULL pointer + // when the array is empty, so we'll need to run this on Android.) + [Test] + public void GetElements_EmptyArray () + { + var a = (TArray) CreateCollection (new TElement[0]); + JniArrayElements e; + using (e = a.GetElements ()) { + if (e == null) + return; + Assert.IsTrue (e.Elements != IntPtr.Zero); + // Multi-dispose is supported. + e.Dispose (); + } + Assert.Throws (() => e.Release (JniReleaseArrayElementsMode.Abort)); + Assert.Throws (() => { + #pragma warning disable 0219 + var _ = e.Elements; + #pragma warning restore 0219 + }); + a.Dispose (); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaSByteArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaSByteArrayContractTests.cs new file mode 100644 index 00000000000..64228bd273b --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaSByteArrayContractTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaSByteArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaSByteArray (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaSByteArray (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaSByteArray (length); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaSingleArrayContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaSingleArrayContractTests.cs new file mode 100644 index 00000000000..7d3d3c303df --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaSingleArrayContractTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JavaSingleArrayContractTests : JavaPrimitiveArrayContract + { + protected override ICollection CreateCollection (IEnumerable values) + { + return new JavaSingleArray (values); + } + + protected override ICollection CreateCollection (IList values) + { + return new JavaSingleArray (values); + } + + protected override ICollection CreateCollection (int length) + { + return new JavaSingleArray (length); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs new file mode 100644 index 00000000000..63063751f79 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs @@ -0,0 +1,30 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +using Java.Interop; + +namespace Java.InteropTests { + + public abstract partial class JavaVMFixture { + + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "JavaVMFixture intentionally uses reflection-backed managers for non-AOT tests.")] + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "JavaVMFixture intentionally uses reflection-backed managers for non-trimming tests.")] + static JavaVMFixture () + { + CreateJavaVM (); + } + + static partial void CreateJavaVM (); + + // VM supports specifying a class to JNIEnv::CallNonvirtualVoidMethod() + // that isn't where the jmethodID came from. + public static bool CallNonvirtualVoidMethodSupportsDeclaringClassMismatch; + + public static readonly bool HaveSafeHandles = typeof (JniObjectReference).GetField ("gcHandle", BindingFlags.NonPublic | BindingFlags.Instance) != null; + + protected JavaVMFixture () + { + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs new file mode 100644 index 00000000000..99004f98c2b --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs @@ -0,0 +1,174 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +using Java.Interop; + +namespace Java.InteropTests { + + partial class JavaVMFixture { + + internal static TestJVM? VM; + internal static JavaVMFixtureTypeManager? TypeManager; + + static partial void CreateJavaVM () + { + var o = new TestJVMOptions { + JarFilePaths = { + "interop-test.jar", + }, + TypeManager = new JavaVMFixtureTypeManager (), + }; + VM = new TestJVM (o); + TypeManager = (JavaVMFixtureTypeManager) VM.TypeManager; + JniRuntime.SetCurrent (VM); + } + } + + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "JavaVMFixtureTypeManager intentionally uses reflection-backed type manager behavior for tests.")] + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "JavaVMFixtureTypeManager intentionally uses reflection-backed type manager behavior for tests.")] + class JavaVMFixtureTypeManager : JniRuntime.ReflectionJniTypeManager { + + Dictionary TypeMappings = new() { +#if !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + [TestType.JniTypeName] = typeof (TestType), +#endif // !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + [GenericHolder.JniTypeName] = typeof (GenericHolder<>), + [RenameClassBase.JniTypeName] = typeof (RenameClassBase), + [RenameClassDerived.JniTypeName] = typeof (RenameClassDerived), + [AnotherJavaInterfaceImpl.JniTypeName] = typeof (AnotherJavaInterfaceImpl), + [CallVirtualFromConstructorBase.JniTypeName] = typeof (CallVirtualFromConstructorBase), + [CallVirtualFromConstructorDerived.JniTypeName] = typeof (CallVirtualFromConstructorDerived), + [CrossReferenceBridge.JniTypeName] = typeof (CrossReferenceBridge), + [GetThis.JniTypeName] = typeof (GetThis), + [IAndroidInterface.JniTypeName] = typeof (IAndroidInterface), + [IJavaInterface.JniTypeName] = typeof (IJavaInterface), + [JavaDisposedObject.JniTypeName] = typeof (JavaDisposedObject), + [JavaObjectWithMissingJavaPeer.JniTypeName] = typeof (JavaObjectWithMissingJavaPeer), + [MyDisposableObject.JniTypeName] = typeof (JavaDisposedObject), + [MyJavaInterfaceImpl.JniTypeName] = typeof (MyJavaInterfaceImpl), + }; + + public JavaVMFixtureTypeManager () + { + } + + protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) + { + foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) + yield return t; + Type target; +#pragma warning disable CS8600 // huh? + if (TypeMappings.TryGetValue (jniSimpleReference, out target)) + yield return target; +#pragma warning restore CS8600 + } + + protected override Type? GetTypeForSimpleReference (string jniSimpleReference) + { + return base.GetTypeForSimpleReference (jniSimpleReference) ?? + (TypeMappings.TryGetValue (jniSimpleReference, out var target) ? target : null); + } + + protected override IEnumerable GetSimpleReferences (Type type) + { + return base.GetSimpleReferences (type) + .Concat (CreateSimpleReferencesEnumerator (type)); + } + + IEnumerable CreateSimpleReferencesEnumerator (Type type) + { + foreach (var e in TypeMappings) { + if (e.Value == type) { + if (ReplacmentTypes.TryGetValue (e.Key, out var alt)) { + yield return alt; + continue; + } + yield return e.Key; + } + } + } + + public string? RequestedFallbackTypesForSimpleReference; + protected override IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimpleReference) + { + RequestedFallbackTypesForSimpleReference = jniSimpleReference; + Debug.WriteLine ($"# GetStaticMethodFallbackTypes (jniSimpleReference={jniSimpleReference})"); + + var slash = jniSimpleReference.LastIndexOf ('/'); + var desugarType = slash <= 0 + ? "Desugar" + jniSimpleReference + : jniSimpleReference.Substring (0, slash+1) + "Desugar" + jniSimpleReference.Substring (slash+1); + + // These types likely won't ever exist on Desktop, but providing + // "potentially non-existent" types ensures that we don't throw + // from places we don't want to internally throw. + return new[]{ + $"{desugarType}$_CC", // For JniPeerMembersTests.DesugarInterfaceStaticMethod() + $"{jniSimpleReference}$-CC", + }; + } + + Dictionary ReplacmentTypes = new() { + ["net/dot/jni/test/RenameClassBase1"] = "net/dot/jni/test/RenameClassBase2", + }; + + protected override string? GetReplacementTypeCore (string jniSimpleReference) => + ReplacmentTypes.TryGetValue (jniSimpleReference, out var v) + ? v + : null; + + Dictionary<(string SourceType, string SourceName, string? SourceSignature), (string? TargetType, string? TargetName, string? TargetSignature, int? ParamCount, bool TurnStatic)> ReplacementMethods = new() { + [("java/lang/Object", "remappedToToString", "()Ljava/lang/String;")] = (null, "toString", null, null, false), + [("java/lang/Object", "remappedToStaticHashCode", null)] = ("net/dot/jni/test/ObjectHelper", "getHashCodeHelper", null, null, true), + [("java/lang/Runtime", "remappedToGetRuntime", null)] = (null, "getRuntime", null, null, false), + + // NOTE: key must use *post-renamed* value, not pre-renamed value + // NOTE: SourceSignature lacking return type; "closer in spirit" to what `remapping-config.json` allows + [("net/dot/jni/test/RenameClassBase2", "hashCode", "()")] = ("net/dot/jni/test/RenameClassBase2", "myNewHashCode", null, null, false), + }; + + protected override JniRuntime.ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSourceType, string jniMethodName, string jniMethodSignature) + { + // Console.Error.WriteLine ($"# jonp: looking for replacement method for (\"{jniSourceType}\", \"{jniMethodName}\", \"{jniMethodSignature}\")"); + if (!ReplacementMethods.TryGetValue ((jniSourceType, jniMethodName, jniMethodSignature), out var r) && + !ReplacementMethods.TryGetValue ((jniSourceType, jniMethodName, GetAlternateMethodSignature ()), out r) && + !ReplacementMethods.TryGetValue ((jniSourceType, jniMethodName, null), out r)) { + return null; + } + var targetSig = r.TargetSignature; + var paramCount = r.ParamCount; + if (targetSig == null && r.TurnStatic) { + targetSig = $"(L{jniSourceType};" + jniMethodSignature.Substring ("(".Length); + paramCount = paramCount ?? JniMemberSignature.GetParameterCountFromMethodSignature (jniMethodSignature); + paramCount++; + } + // Console.Error.WriteLine ($"# jonp: found replacement: ({GetValue (r.TargetType)}, {GetValue (r.TargetName)}, {GetValue (r.TargetSignature)}, {r.ParamCount?.ToString () ?? "null"}, {r.IsStatic})"); + return new JniRuntime.ReplacementMethodInfo { + SourceJniType = jniSourceType, + SourceJniMethodName = jniMethodName, + SourceJniMethodSignature = jniMethodSignature, + TargetJniType = r.TargetType ?? jniSourceType, + TargetJniMethodName = r.TargetName ?? jniMethodName, + TargetJniMethodSignature = targetSig ?? jniMethodSignature, + TargetJniMethodParameterCount = paramCount, + TargetJniMethodInstanceToStatic = r.TurnStatic, + }; + + string GetAlternateMethodSignature () + { + int i = jniMethodSignature.IndexOf (')'); + return jniMethodSignature.Substring (0, i+1); + } + + // string GetValue (string? value) + // { + // return value == null ? "null" : $"\"{value}\""; + // } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniEnvironmentTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniEnvironmentTests.cs new file mode 100644 index 00000000000..fd91beb3d72 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniEnvironmentTests.cs @@ -0,0 +1,147 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniEnvironmentTests : JavaVMFixture + { + [Test] + public unsafe void Types_IsSameObject () + { + using (var t = new JniType ("java/lang/Object")) { + var c = t.GetConstructor ("()V"); + var o = t.NewObject (c, null); + try { + using (var ot = JniEnvironment.Types.GetTypeFromInstance (o)) { + Assert.IsTrue (JniEnvironment.Types.IsSameObject (t.PeerReference, ot.PeerReference)); + } + } finally { + JniObjectReference.Dispose (ref o); + } + } + } + + [Test] + public void Types_GetJniTypeNameFromInstance () + { + using (var o = new JavaObject ()) + Assert.AreEqual ("java/lang/Object", JniEnvironment.Types.GetJniTypeNameFromInstance (o.PeerReference)); + using (var o = new JavaInt32Array (0)) + Assert.AreEqual ("[I", JniEnvironment.Types.GetJniTypeNameFromInstance (o.PeerReference)); + } + + [Test] + public unsafe void Handles_NewReturnToJniRef () + { + using (var t = new JniType ("java/lang/Object")) { + var c = t.GetConstructor ("()V"); + var o = t.NewObject (c, null); + try { + var n = o.NewLocalRef (); + JniObjectReference.Dispose (ref n); + // warning: lref 'leak' + var r = JniEnvironment.References.NewReturnToJniRef (o); + var h = new JniObjectReference (r); + Assert.AreEqual (JniEnvironment.References.GetIdentityHashCode (o), JniEnvironment.References.GetIdentityHashCode (h)); + } finally { + JniObjectReference.Dispose (ref o); + } + } + } + + [Test] + public void References_CreatedReference_InvalidRef () + { + var c = JniEnvironment.LocalReferenceCount; + var r = new JniObjectReference (); + JniEnvironment.References.CreatedReference (r); + Assert.AreEqual (c, JniEnvironment.LocalReferenceCount); + } + + [Test] + public void References_CreatedReference_LocalRef () + { + var NewLocalRef = GetNewRefFunc ("java_interop_jnienv_new_local_ref"); + if (NewLocalRef == null) { + Assert.Ignore ("This version of Java.Interop.dll doesn't use P/Invoke-based JNI invokes."); + return; + } + using (var t = new JniType ("java/lang/Object")) { + var c = JniEnvironment.LocalReferenceCount; + var r = NewLocalRef (JniEnvironment.EnvironmentPointer, t.PeerReference.Handle); + + // This is the "problem": direct use of JNI functions don't contribute to + // our reference count accounting + Assert.AreEqual (c, JniEnvironment.LocalReferenceCount); + + var o = new JniObjectReference (r, JniObjectReferenceType.Local); + JniEnvironment.References.CreatedReference (o); + + Assert.AreEqual (c + 1, JniEnvironment.LocalReferenceCount); + JniObjectReference.Dispose (ref o); + Assert.AreEqual (c, JniEnvironment.LocalReferenceCount); + } + } + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] + static readonly Type NativeMethods_type = + Type.GetType ("Java.Interop.NativeMethods, Java.Interop", throwOnError: false) ?? + Type.GetType ("Java.Interop.JIPinvokes.NativeMethods, Java.Interop", throwOnError: false); + + static Func GetNewRefFunc (string method) + { + if (NativeMethods_type == null) + return null; + return (Func)Delegate.CreateDelegate ( + typeof (Func), + NativeMethods_type, + method, + ignoreCase: false, + throwOnBindFailure: true); + } + + static Action GetDeleteRefFunc (string method) + { + if (NativeMethods_type == null) + return null; + return (Action)Delegate.CreateDelegate ( + typeof (Action), + NativeMethods_type, + method, + ignoreCase: false, + throwOnBindFailure: true); + } + + [Test] + public void References_CreatedReference_GlobalRef () + { + var NewGlobalRef = GetNewRefFunc ("java_interop_jnienv_new_global_ref"); + if (NewGlobalRef == null) { + Assert.Ignore ("This version of Java.Interop.dll doesn't use P/Invoke-based JNI invokes."); + return; + } + using (var t = new JniType ("java/lang/Object")) { + var c = JniEnvironment.Runtime.GlobalReferenceCount; + var r = NewGlobalRef (JniEnvironment.EnvironmentPointer, t.PeerReference.Handle); + + // This is the "problem": direct use of JNI functions don't contribute to + // our reference count accounting + Assert.AreEqual (c, JniEnvironment.Runtime.GlobalReferenceCount); + + var o = new JniObjectReference (r, JniObjectReferenceType.Global); + Assert.Throws (() => JniEnvironment.References.CreatedReference (o)); + + Assert.AreEqual (c, JniEnvironment.Runtime.GlobalReferenceCount); + + GetDeleteRefFunc ("java_interop_jnienv_delete_global_ref")?.Invoke (JniEnvironment.EnvironmentPointer, o.Handle); + } + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniInstanceMethodIDTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniInstanceMethodIDTest.cs new file mode 100644 index 00000000000..bce118ca8e7 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniInstanceMethodIDTest.cs @@ -0,0 +1,41 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniInstanceMethodIDTest : JavaVMFixture + { + // https://code.google.com/p/android/issues/detail?id=65710 + [Test] + [Category ("TrimmableTypeMapUnsupported")] + public unsafe void CallNonvirtualVoidMethod_WithBaseMethodIDAndDerivedType () + { + using (var b = new JniType ("net/dot/jni/test/CallNonvirtualBase")) + using (var d = new JniType ("net/dot/jni/test/CallNonvirtualDerived")) { + var m = b.GetInstanceMethod ("method", "()V"); + var f = b.GetInstanceField ("methodInvoked", "Z"); + + var c = d.GetConstructor ("()V"); + var g = d.GetInstanceField ("methodInvoked", "Z"); + var o = d.NewObject (c, null); + try { + if (JavaVMFixture.CallNonvirtualVoidMethodSupportsDeclaringClassMismatch) { + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (o, d.PeerReference, m); + Assert.IsFalse (JniEnvironment.InstanceFields.GetBooleanField (o, f)); + Assert.IsTrue (JniEnvironment.InstanceFields.GetBooleanField (o, g)); + } else { + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (o, d.PeerReference, m); + Assert.IsTrue (JniEnvironment.InstanceFields.GetBooleanField (o, f)); + Assert.IsFalse (JniEnvironment.InstanceFields.GetBooleanField (o, g)); + } + } finally { + JniObjectReference.Dispose (ref o); + } + } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniMarshalTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniMarshalTests.cs new file mode 100644 index 00000000000..372fb9c30b5 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniMarshalTests.cs @@ -0,0 +1,36 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniMarshalTests + { + [Test] + public void RecursiveEquals () + { + Assert.IsTrue (JniMarshal.RecursiveEquals (null, null)); + Assert.IsFalse (JniMarshal.RecursiveEquals (null, new object ())); + Assert.IsFalse (JniMarshal.RecursiveEquals (new object (), null)); + Assert.IsTrue (JniMarshal.RecursiveEquals (1, 1)); + Assert.IsFalse (JniMarshal.RecursiveEquals (1, 2)); + Assert.IsTrue (JniMarshal.RecursiveEquals (new[]{ 1, 2, 3 }, new[]{ 1, 2, 3 })); + Assert.IsFalse (JniMarshal.RecursiveEquals (new[]{ 1, 2, 3 }, new[]{ 1, 2 })); + Assert.IsFalse (JniMarshal.RecursiveEquals (new[]{ 1, 2 }, new[]{ 1, 2, 3 })); + Assert.IsFalse (JniMarshal.RecursiveEquals (new[]{ 1, 2 }, null)); + Assert.IsFalse (JniMarshal.RecursiveEquals (null, new[]{ 1, 2 })); + Assert.IsTrue (JniMarshal.RecursiveEquals ( + new[]{new[]{1,2,3}, new[]{4,5,6}}, + new[]{new[]{1,2,3}, new[]{4,5,6}} + )); + Assert.IsFalse (JniMarshal.RecursiveEquals ( + new[]{new[]{1,2,3}, new[]{4,5}}, + new[]{new[]{1,2,3}, new[]{4,5,6}} + )); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersExtensions.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersExtensions.cs new file mode 100644 index 00000000000..0bbe6cb7430 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersExtensions.cs @@ -0,0 +1,125 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +using Java.Interop; + +namespace Java.InteropTests { + + static class JniPeerMembersExtensions { + const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + + public static unsafe JniObjectReference StartGenericCreateInstance ( + this JniPeerMembers.JniInstanceMethods peer, + string constructorSignature, + Type declaringType, + T value) + { + if (peer == null) + throw new ArgumentNullException (nameof (peer)); + _ = value; + + return peer.StartCreateInstance (constructorSignature, declaringType, null); + } + + public static unsafe void FinishGenericCreateInstance< + [DynamicallyAccessedMembers (Constructors)] + T> ( + this JniPeerMembers.JniInstanceMethods peer, + string constructorSignature, + IJavaPeerable self, + T value) + { + if (peer == null) + throw new ArgumentNullException (nameof (peer)); + if (self == null) + throw new ArgumentNullException (nameof (self)); + + var __vm = JniEnvironment.Runtime.ValueManager.GetValueMarshaler (); + var arg = __vm.CreateGenericArgumentState (value); + + var args = stackalloc JniArgumentValue [1]; + args [0] = arg.JniArgumentValue; + + try { + peer.FinishCreateInstance (constructorSignature, self, args); + } finally { + __vm.DestroyGenericArgumentState (value, ref arg); + } + } + + public static unsafe void InvokeGenericVirtualVoidMethod< + [DynamicallyAccessedMembers (Constructors)] + T> ( + this JniPeerMembers.JniInstanceMethods peer, + string encodedMember, + IJavaPeerable self, + T value) + { + if (peer == null) + throw new ArgumentNullException (nameof (peer)); + if (self == null) + throw new ArgumentNullException (nameof (self)); + + var __vm = JniEnvironment.Runtime.ValueManager.GetValueMarshaler (); + var arg = __vm.CreateGenericArgumentState (value); + + var args = stackalloc JniArgumentValue [1]; + args [0] = arg.JniArgumentValue; + + try { + peer.InvokeVirtualVoidMethod (encodedMember, self, args); + } finally { + __vm.DestroyGenericArgumentState (value, ref arg); + } + } + + public static unsafe int InvokeGenericVirtualInt32Method< + [DynamicallyAccessedMembers (Constructors)] + T> ( + this JniPeerMembers.JniInstanceMethods peer, + string encodedMember, + IJavaPeerable self, + T value) + { + if (peer == null) + throw new ArgumentNullException (nameof (peer)); + if (self == null) + throw new ArgumentNullException (nameof (self)); + + var __vm = JniEnvironment.Runtime.ValueManager.GetValueMarshaler (); + var arg = __vm.CreateGenericArgumentState (value); + + var args = stackalloc JniArgumentValue [1]; + args [0] = arg.JniArgumentValue; + + try { + return peer.InvokeVirtualInt32Method (encodedMember, self, args); + } finally { + __vm.DestroyGenericArgumentState (value, ref arg); + } + } + + public static unsafe int InvokeGenericInt32Method< + [DynamicallyAccessedMembers (Constructors)] + T> ( + this JniPeerMembers.JniStaticMethods peer, + string encodedMember, + T value) + { + if (peer == null) + throw new ArgumentNullException (nameof (peer)); + + var __vm = JniEnvironment.Runtime.ValueManager.GetValueMarshaler (); + var arg = __vm.CreateGenericArgumentState (value); + + var args = stackalloc JniArgumentValue [1]; + args [0] = arg.JniArgumentValue; + + try { + return peer.InvokeInt32Method (encodedMember, args); + } finally { + __vm.DestroyGenericArgumentState (value, ref arg); + } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs new file mode 100644 index 00000000000..b065dd8c14c --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using Java.Interop; +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniPeerMembersTests : JavaVMFixture + { + [Test] + public void Ctor_CanReferenceNonexistentType () + { + var members = new JniPeerMembers (JavaObjectWithMissingJavaPeer.JniTypeName, typeof(JavaObjectWithMissingJavaPeer)); + JniPeerMembers.Dispose (members); + } + + [Test] + [Category ("TrimmableTypeMapUnsupported")] + public void VirtualInvokeOnBaseInvokesMostDerivedJavaMethod () + { + var registered = GetInstanceMethods (MyString._members.InstanceMethods); + Assert.AreEqual (0, registered.Count); + using (var s = new MyString ("hello!")) { + Assert.AreEqual (1, registered.Count); // for the constructor + Assert.AreEqual ("hello!", s.ToString ()); + Assert.AreEqual (1, registered.Count); + } + } + + static Dictionary GetInstanceMethods (JniPeerMembers.JniInstanceMethods methods) + { + var f = typeof (JniPeerMembers.JniInstanceMethods).GetField ("InstanceMethods", BindingFlags.NonPublic | BindingFlags.Instance); + return (Dictionary) f.GetValue (methods); + } + + [Test] + public void MethodLookupForNonexistentStaticMethodWillTryFallbacks () + { + try { + JavaLangRemappingTestRuntime.doesNotExist (); + Assert.Fail ("java.lang.Runtime.doesNotExist() exists?! Not expected to exist."); + } + catch (Exception e) { + Console.WriteLine ($"# jonp: MethodLookupForNonexistentStaticMethodWillTryFallbacks: e={e}"); + // On Desktop, expect `e` to be: + // ``` + // Java.Interop.JavaException: doesNotExist + // at Java.Interop.JniEnvironment.StaticMethods.GetMethodID(JniObjectReference type, String name, String signature) + // … + // at Java.InteropTests.JavaLangRuntime.doesNotExist() + // at Java.InteropTests.JniStaticMethodIDTest.MethodLookupForNonexistentMethodWillTryFallbacks() + // --- End of managed Java.Interop.JavaException stack trace --- + // java.lang.NoSuchMethodError: doesNotExist + // ``` + // On Android, expect `e` to be: + // ``` + // Java.Lang.NoSuchMethodError: no static method "Ljava/lang/Runtime;.doesNotExist()V" + // at Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(JniObjectReference type, String name, String signature) + // at Java.Interop.JniType.GetStaticMethod(String name, String signature) + // at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String method, String signature) + // at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String encodedMember) + // at Java.Interop.JniPeerMembers.JniStaticMethods.InvokeVoidMethod(String encodedMember, JniArgumentValue* parameters) + // at Java.InteropTests.JavaLangRemappingTestRuntime.doesNotExist() + // at Java.InteropTests.JniPeerMembersTests.MethodLookupForNonexistentStaticMethodWillTryFallbacks() + // --- End of managed Java.Lang.NoSuchMethodError stack trace --- + // ``` + Assert.IsTrue (e.Message.Contains ("doesNotExist", StringComparison.Ordinal)); +#if !ANDROID // Android doesn't allow providing a custom TypeManager + Assert.AreEqual ("java/lang/Runtime", + JavaVMFixture.TypeManager.RequestedFallbackTypesForSimpleReference); +#endif // !ANDROID + } + } + + [Test] + [Category ("NativeAOTIgnore")] + [Category ("TrimmableTypeMapUnsupported")] + public void ReplacementTypeUsedForMethodLookup () + { + using var o = new RenameClassDerived (); + int r = o.hashCode(); + Assert.AreEqual (33, r); + } + + [Test] + [Category ("NativeAOTIgnore")] + public void ReplaceInstanceMethodName () + { + using var o = new JavaLangRemappingTestObject (); + // Shouldn't throw; should instead invoke Object.toString() + var r = o.remappedToToString (); + JniObjectReference.Dispose (ref r); + } + + [Test] + [Category ("NativeAOTIgnore")] + public void ReplaceStaticMethodName () + { + var r = JavaLangRemappingTestRuntime.remappedToGetRuntime (); + JniObjectReference.Dispose (ref r); + } + + [Test] + [Category ("NativeAOTIgnore")] + public void ReplaceInstanceMethodWithStaticMethod () + { + using var o = new JavaLangRemappingTestObject (); + // Shouldn't throw; should instead invoke ObjectHelper.getHashCodeHelper(Object) + o.remappedToStaticHashCode (); + } + +#if !__ANDROID__ + // Note: this test looks up a static method from one class, then + // calls `JNIEnv::CallStaticObjectMethod()` passing in a jclass + // for a *different* class. + // + // This appears to work on Desktop JVM. + // + // On Android, this will ABORT the app: + // JNI DETECTED ERROR IN APPLICATION: can't call static int com.xamarin.interop.DesugarAndroidInterface$_CC.getClassName() with class java.lang.Class + // in call to CallStaticObjectMethodA + // + // This *also* aborts on JDK-17 + macOS + arm64: + // FATAL ERROR in native method: Wrong object class or methodID passed to JNI call + // Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) + // V [libjvm.dylib+0x4f718c] jniCheck::validate_call(JavaThread*, _jclass*, _jmethodID*, _jobject*)+0x98 + // V [libjvm.dylib+0x506474] checked_jni_CallStaticObjectMethodA+0x150 + // C [native JNI wrapper] java_interop_jnienv_call_static_object_method_a+0x48 + // C 0x000000010798a8d8 + // C 0x000000010798a540 + // C 0x000000010798fa94 + // C [libcoreclr.dylib+0x2db774] CallDescrWorkerInternal+0x84 + // C [libcoreclr.dylib+0x150db4] CallDescrWorkerWithHandler(CallDescrData*, int)+0x74 + // C [libcoreclr.dylib+0x1f92d0] RuntimeMethodHandle::InvokeMethod(Object*, void**, SignatureNative*, bool)+0x79c + // C 0x0000000104020ce4 + // … + // + // *Fascinating* the differences that can appear between JVM implementations + [Test] + public unsafe void DoesTheJmethodNeedToMatchDeclaringType () + { + if (Environment.GetEnvironmentVariable ("CPUTYPE") is string cpu && cpu == "arm64") { + Assert.Ignore ("nope!"); + } + if (VM.JdkInfo.Version is Version v && v >= new Version (17, 0)) { + // JDK-17 now crashes on this test as well: + // FATAL ERROR in native method: Wrong object class or methodID passed to JNI call + Assert.Ignore ("nope!"); + } + var iface = new JniType ("net/dot/jni/test/AndroidInterface"); + var desugar = new JniType ("net/dot/jni/test/DesugarAndroidInterface$_CC"); + var m = desugar.GetStaticMethod ("getClassName", "()Ljava/lang/String;"); + + var r = JniEnvironment.StaticMethods.CallStaticObjectMethod (iface.PeerReference, m, null); + var s = JniEnvironment.Strings.ToString (ref r, JniObjectReferenceOptions.CopyAndDispose); + Assert.AreEqual ("DesugarAndroidInterface$-CC", s); + } +#endif // !__ANDROID__ + + [Test] + public void DesugarInterfaceStaticMethod () + { + var s = IAndroidInterface.getClassName (); + Assert.AreEqual ("DesugarAndroidInterface$-CC", s); + } + } + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + class MyString : JavaObject { + internal const string JniTypeName = "java/lang/String"; + + internal static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (MyString)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + public unsafe MyString (string value) + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string id = "(Ljava/lang/String;)V"; + var peer = _members.InstanceMethods.StartGenericCreateInstance (id, GetType (), value); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishGenericCreateInstance (id, this, value); + } + } + + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + class JavaLangRemappingTestObject : JavaObject { + internal const string JniTypeName = "java/lang/Object"; + static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaLangRemappingTestObject)); + + public JavaLangRemappingTestObject () + { + } + + public unsafe void doesNotExist () + { + const string id = "doesNotExist.()V"; + _members.InstanceMethods.InvokeNonvirtualVoidMethod (id, this, null); + } + + public unsafe JniObjectReference remappedToToString () + { + const string id = "remappedToToString.()Ljava/lang/String;"; + return _members.InstanceMethods.InvokeNonvirtualObjectMethod (id, this, null); + } + + public unsafe int remappedToStaticHashCode () + { + const string id = "remappedToStaticHashCode.()I"; + return _members.InstanceMethods.InvokeVirtualInt32Method (id, this, null); + } + } + + [JniTypeSignature (JavaLangRemappingTestRuntime.JniTypeName, GenerateJavaPeer=false)] + internal class JavaLangRemappingTestRuntime : JavaObject { + internal const string JniTypeName = "java/lang/Runtime"; + static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaLangRemappingTestRuntime)); + + public static unsafe JniObjectReference remappedToGetRuntime() + { + const string id = "remappedToGetRuntime.()Ljava/lang/Runtime;"; + return _members.StaticMethods.InvokeObjectMethod (id, null); + } + + public static unsafe void doesNotExist () + { + const string id = "doesNotExist.()V"; + _members.StaticMethods.InvokeVoidMethod (id, null); + } + } + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + class RenameClassBase : JavaObject { + internal const string JniTypeName = "net/dot/jni/test/RenameClassBase1"; + static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (RenameClassBase)); + + public override JniPeerMembers JniPeerMembers => _members; + + public RenameClassBase () + { + } + + public virtual unsafe int hashCode () + { + const string id = "hashCode.()I"; + return _members.InstanceMethods.InvokeVirtualInt32Method (id, this, null); + } + } + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + class RenameClassDerived : RenameClassBase { + internal new const string JniTypeName = "net/dot/jni/test/RenameClassDerived"; + public RenameClassDerived () + { + } + + public override unsafe int hashCode () + { + return base.hashCode (); + } + } + + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + interface IAndroidInterface : IJavaPeerable { + internal const string JniTypeName = "net/dot/jni/test/AndroidInterface"; + + internal static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (IAndroidInterface), isInterface: true); + + public static unsafe string getClassName () + { + var s = _members.StaticMethods.InvokeObjectMethod ("getClassName.()Ljava/lang/String;", null); + return JniEnvironment.Strings.ToString (ref s, JniObjectReferenceOptions.CopyAndDispose); + } + } + + [JniTypeSignature (IAndroidInterface.JniTypeName, GenerateJavaPeer=false)] + internal class IAndroidInterfaceInvoker : JavaObject, IAndroidInterface { + + public override JniPeerMembers JniPeerMembers => IAndroidInterface._members; + + public IAndroidInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniTypeManagerTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniTypeManagerTests.cs new file mode 100644 index 00000000000..1994a073b72 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniTypeManagerTests.cs @@ -0,0 +1,37 @@ +using System.Diagnostics.CodeAnalysis; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests { + + [TestFixture] + public class JniRuntimeJniTypeManagerTests : JavaVMFixture { + + [Test] + [RequiresDynamicCode ("This test uses ReflectionJniTypeManager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("This test uses ReflectionJniTypeManager, which is reflection-based and not trimming-compatible.")] + public void GetInvokerType () + { + using (var vm = new MyTypeManager ()) { + // Concrete type; no invoker + Assert.IsNull (vm.GetInvokerType (typeof (JavaObject))); + + // Not a bound abstract Java type; no invoker + Assert.IsNull (vm.GetInvokerType (typeof (System.ICloneable))); + + // Bound abstract Java type; has an invoker + Assert.AreSame (typeof (IJavaInterfaceInvoker), vm.GetInvokerType (typeof (IJavaInterface))); + } + } + + [RequiresDynamicCode ("MyTypeManager uses ReflectionJniTypeManager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("MyTypeManager uses ReflectionJniTypeManager, which is reflection-based and not trimming-compatible.")] + class MyTypeManager : JniRuntime.ReflectionJniTypeManager { + public MyTypeManager () + { + } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs new file mode 100644 index 00000000000..a712105d7be --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs @@ -0,0 +1,149 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Collections.Generic; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests { + + [TestFixture] + public class JniRuntimeJniValueManagerTests : JavaVMFixture { + + [Test] + public void CreateValue () + { + using (var vm = new MyValueManager ()) + using (var o = new JavaObject ()) { + vm.OnSetRuntime (JniRuntime.CurrentRuntime); + + var r = o.PeerReference; + var x = (IJavaPeerable) vm.CreateValue (ref r, JniObjectReferenceOptions.Copy); + Assert.AreNotSame (o, x); + x.Dispose (); + + x = vm.CreateValue (ref r, JniObjectReferenceOptions.Copy); + Assert.AreNotSame (o, x); + x.Dispose (); + } + } + + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "MyValueManager intentionally uses reflection-backed value manager behavior for tests.")] + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "MyValueManager intentionally uses reflection-backed value manager behavior for tests.")] + class MyValueManager : JniRuntime.ReflectionJniValueManager { + + public override void WaitForGCBridgeProcessing () + { + } + + public override void CollectPeers () + { + } + + public override void AddPeer (IJavaPeerable reference) + { + } + + public override void RemovePeer (IJavaPeerable reference) + { + } + + public override void FinalizePeer (IJavaPeerable reference) + { + } + + public override List GetSurfacedPeers () + { + return null; + } + + public override IJavaPeerable PeekPeer (JniObjectReference reference) + { + return null; + } + + } + + [Test] + public void GetValue_ReturnsAlias () + { + var local = new JavaObject (); + local.UnregisterFromRuntime (); + Assert.IsNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (local.PeerReference)); + // GetObject must always return a value (unless handle is null, etc.). + // However, since we called local.UnregisterFromRuntime(), + // JniRuntime.PeekObject() is null (asserted above), but GetObject() must + // **still** return _something_. + // In this case, it returns an _alias_. + // TODO: "most derived type" alias generation. (Not relevant here, but...) + var p = local.PeerReference; + var alias = JniRuntime.CurrentRuntime.ValueManager.GetValue (ref p, JniObjectReferenceOptions.Copy); + Assert.AreNotSame (local, alias); + alias.Dispose (); + local.Dispose (); + } + + [Test] + public void GetValue_ReturnsNullWithNullHandle () + { + var r = new JniObjectReference (); + var o = JniRuntime.CurrentRuntime.ValueManager.GetValue (ref r, JniObjectReferenceOptions.Copy); + Assert.IsNull (o); + } + + [Test] + public void PeekValue () + { + JniObjectReference lref; + using (var o = new JavaObject ()) { + lref = o.PeerReference.NewLocalRef (); + Assert.AreSame (o, JniRuntime.CurrentRuntime.ValueManager.PeekValue (lref)); + } + // At this point, the Java-side object is kept alive by `lref`, + // but the wrapper instance has been disposed, and thus should + // be unregistered, and thus unfindable. + Assert.IsNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (lref)); + JniObjectReference.Dispose (ref lref); + } + + public void PeekValue_BoxedObjects () + { + var vm = JniRuntime.CurrentRuntime.ValueManager; + var marshaler = vm.GetValueMarshaler (); + var ad = AppDomain.CurrentDomain; + + var proxy = marshaler.CreateGenericArgumentState (ad); + Assert.AreSame (ad, vm.PeekValue (proxy.ReferenceValue)); + marshaler.DestroyGenericArgumentState (ad, ref proxy); + + var ex = new InvalidOperationException ("boo!"); + proxy = marshaler.CreateGenericArgumentState (ex); + Assert.AreSame (ex, vm.PeekValue (proxy.ReferenceValue)); + marshaler.DestroyGenericArgumentState (ex, ref proxy); + } + + [Test] + public void GetValue_ReturnsNullWithInvalidSafeHandle () + { + var invalid = new JniObjectReference (); + Assert.IsNull (JniRuntime.CurrentRuntime.ValueManager.GetValue (ref invalid, JniObjectReferenceOptions.CopyAndDispose)); + } + +#if !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + [Test] + public unsafe void GetValue_FindBestMatchType () + { + using (var t = new JniType (TestType.JniTypeName)) { + var c = t.GetConstructor ("()V"); + var o = t.NewObject (c, null); + using (var w = JniRuntime.CurrentRuntime.ValueManager.GetValue (ref o, JniObjectReferenceOptions.CopyAndDispose)) { + Assert.AreEqual (typeof (TestType), w.GetType ()); + Assert.IsTrue (((TestType) w).ExecutedActivationConstructor); + } + } + } +#endif // !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntimeJniValueManagerContract.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntimeJniValueManagerContract.cs new file mode 100644 index 00000000000..dc41461b685 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntimeJniValueManagerContract.cs @@ -0,0 +1,450 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Threading; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests { + + // Android doesn't support `[NonParallelizable]`, but runs tests sequentially by default. +#if !__ANDROID__ + // Modifies JniRuntime.valueManager instance field; can't be done in parallel + [NonParallelizable] +#endif // !__ANDROID__ + [Category ("TrimmableTypeMapUnsupported")] + public abstract class JniRuntimeJniValueManagerContract : JavaVMFixture { + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + protected abstract Type ValueManagerType { + get; + } + + protected virtual JniRuntime.JniValueManager CreateValueManager () + { + var manager = Activator.CreateInstance (ValueManagerType) as JniRuntime.JniValueManager; + return manager ?? throw new InvalidOperationException ($"Could not create instance of `{ValueManagerType}`!"); + } + +#pragma warning disable CS8618 + JniRuntime.JniValueManager systemManager; + JniRuntime.JniValueManager valueManager; +#pragma warning restore CS8618 + + [SetUp] + public void CreateVM () + { + systemManager = JniRuntime.CurrentRuntime.valueManager!; + valueManager = CreateValueManager (); + valueManager.OnSetRuntime (JniRuntime.CurrentRuntime); + JniRuntime.CurrentRuntime.valueManager = valueManager; + } + + [TearDown] + public void DestroyVM () + { + JniRuntime.CurrentRuntime.valueManager = systemManager; + systemManager = null!; + valueManager?.Dispose (); + valueManager = null!; + } + + [Test] + public void AddPeer () + { + } + + int GetSurfacedPeersCount () + { + return valueManager.GetSurfacedPeers ().Count; + } + + [Test] + public void AddPeer_NoDuplicates () + { + int startPeerCount = GetSurfacedPeersCount (); + using (var v = new MyDisposableObject ()) { + // MyDisposableObject ctor implicitly calls AddPeer(); + Assert.AreEqual (startPeerCount + 1, GetSurfacedPeersCount (), DumpPeers ()); + valueManager.AddPeer (v); + Assert.AreEqual (startPeerCount + 1, GetSurfacedPeersCount (), DumpPeers ()); + } + } + + [Test] + public void ConstructPeer_ImplicitViaBindingConstructor_PeerIsInSurfacedPeers () + { + int startPeerCount = GetSurfacedPeersCount (); + + var g = new GetThis (); + var surfaced = valueManager.GetSurfacedPeers (); + Assert.AreEqual (startPeerCount + 1, surfaced.Count); + + var found = false; + foreach (var pr in surfaced) { + if (!pr.SurfacedPeer.TryGetTarget (out var p)) + continue; + if (object.ReferenceEquals (g, p)) { + found = true; + } + } + Assert.IsTrue (found); + + var localRef = g.PeerReference.NewLocalRef (); + g.Dispose (); + Assert.AreEqual (startPeerCount, GetSurfacedPeersCount ()); + Assert.IsNull (valueManager.PeekPeer (localRef)); + JniObjectReference.Dispose (ref localRef); + } + + [Test] + public void ConstructPeer_ImplicitViaBindingMethod_PeerIsInSurfacedPeers () + { + int startPeerCount = GetSurfacedPeersCount (); + + var g = new GetThis (); + var surfaced = valueManager.GetSurfacedPeers (); + Assert.AreEqual (startPeerCount + 1, surfaced.Count); + + var found = false; + foreach (var pr in surfaced) { + if (!pr.SurfacedPeer.TryGetTarget (out var p)) + continue; + if (object.ReferenceEquals (g, p)) { + found = true; + } + } + Assert.IsTrue (found); + + var localRef = g.PeerReference.NewLocalRef (); + g.Dispose (); + Assert.AreEqual (startPeerCount, GetSurfacedPeersCount ()); + Assert.IsNull (valueManager.PeekPeer (localRef)); + JniObjectReference.Dispose (ref localRef); + } + + // https://github.com/dotnet/android/issues/11101 + [Test] + public void ConstructPeer_CalledMultipleTimes_ShouldNotLeakGlobalRefs () + { + // Simulate what TypeManager.Activate does in dotnet/android: + // 1. Create an uninitialized JavaObject + // 2. Set a peer reference (storing the raw handle) + // 3. The constructor chain then calls ConstructPeer multiple times + // + // This should not leak JNI global references. + + using (var original = new MyDisposableObject ()) { + // Get the jobject handle, simulating the IntPtr jobject param in Activate + var handle = original.PeerReference; + + // Create an uninitialized peer and set its reference (simulating Activate) + var peer = (IJavaPeerable) RuntimeHelpers.GetUninitializedObject (typeof (MyDisposableObject)); + peer.SetPeerReference (new JniObjectReference (handle.Handle)); + + try { + // Now simulate the constructor chain calling ConstructPeer multiple times + var ref1 = new JniObjectReference (handle.Handle); + valueManager.ConstructPeer (peer, ref ref1, JniObjectReferenceOptions.Copy); + + int grefAfterFirst = JniEnvironment.Runtime.GlobalReferenceCount; + + var ref2 = new JniObjectReference (handle.Handle); + valueManager.ConstructPeer (peer, ref ref2, JniObjectReferenceOptions.Copy); + + int grefAfterSecond = JniEnvironment.Runtime.GlobalReferenceCount; + + // The second ConstructPeer should NOT create an additional global ref + Assert.AreEqual (grefAfterFirst, grefAfterSecond, + "Second ConstructPeer call should not create an additional global ref"); + } finally { + peer.Dispose (); + } + } + } + + + [Test] + public void CollectPeers () + { + // TODO + } + + [Test] + public void CreatePeer_InvalidHandleReturnsNull () + { + var r = new JniObjectReference (); + var o = valueManager.CreatePeer (ref r, JniObjectReferenceOptions.Copy, null); + Assert.IsNull (o); + } + + [Test] + public unsafe void CreatePeer_UsesFallbackType () + { + using var t = new JniType (AnotherJavaInterfaceImpl.JniTypeName); + + var ctor = t.GetConstructor ("()V"); + var lref = t.NewObject (ctor, null); + + using var p = valueManager.CreatePeer (ref lref, JniObjectReferenceOptions.CopyAndDispose, typeof (IJavaInterface)); + + Assert.IsFalse (lref.IsValid); // .CopyAndDispose disposes + + Assert.IsNotNull (p); + Assert.AreSame (typeof (IJavaInterfaceInvoker), p!.GetType ()); + } + + [Test] + public void CreatePeer_CreatesNewValueUsingActivationConstructor () + { + using var v1 = new AnotherJavaInterfaceImpl (); + var lref = v1.PeerReference.NewLocalRef (); + try { + using var v2 = valueManager.CreatePeer (ref lref, JniObjectReferenceOptions.CopyAndDispose, typeof (AnotherJavaInterfaceImpl)); + Assert.AreNotSame (v1, v2, "CreatePeer() should create new values"); + } + finally { + JniObjectReference.Dispose (ref lref); + } + } + + [Test] + public void CreatePeer_ThrowsIfNoActivationConstructorPresent () + { + using var v1 = new GetThis (); + var lref = v1.PeerReference.NewLocalRef (); + var ex = Assert.Throws ( + () => valueManager.CreatePeer (ref lref, JniObjectReferenceOptions.CopyAndDispose, typeof (GetThis)), + $"`GetThis` has no activation constructor, so attempting to use it should throw NotSupportedException."); + Assert.IsTrue (lref.IsValid, "lref should still be valid"); + JniObjectReference.Dispose (ref lref); + } + + [Test] + public void CreatePeer_ReplaceableDoesNotReplace () + { + var v = new AnotherJavaInterfaceImpl (); + var lref = v.PeerReference.NewLocalRef (); + v.Dispose (); + + try { + Assert.IsNull (valueManager.PeekPeer (lref), "v.Dispose() should have unregistered the peer."); + var peer1 = valueManager.CreatePeer (ref lref, JniObjectReferenceOptions.Copy, typeof (AnotherJavaInterfaceImpl)); + Assert.IsTrue ( + peer1!.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable), + $"Expected peer1.JniManagedPeerState to have .Replaceable, but was {peer1.JniManagedPeerState}."); + Assert.AreSame (peer1, valueManager.PeekPeer (lref), + $"Expected peer1==PeekValue(peer1.PeerReference); it's the only one that should exist!"); + + var peer2 = valueManager.CreatePeer (ref lref, JniObjectReferenceOptions.Copy, typeof (AnotherJavaInterfaceImpl)); + Assert.IsTrue ( + peer2!.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable), + $"Expected peer2.JniManagedPeerState to have .Replaceable, but was {peer2.JniManagedPeerState}."); + Assert.AreNotSame (peer1, peer2, "Expected peer1 and peer2 to be different instances."); + + var peeked = valueManager.PeekPeer (lref); + Assert.AreSame (peer1, peeked, + "Expected peer1 and peeked to be the same instance; " + + $"peeked={RuntimeHelpers.GetHashCode (peeked).ToString ("x")}, " + + $"peer1={RuntimeHelpers.GetHashCode (peer1).ToString ("x")}, " + + $"peer2={RuntimeHelpers.GetHashCode (peer2).ToString ("x")}"); + } finally { + JniObjectReference.Dispose (ref lref); + } + } + + [Test] + public void CreateValue () + { + using (var o = new JavaObject ()) { + var r = o.PeerReference; + var x = (IJavaPeerable) valueManager.CreateValue (ref r, JniObjectReferenceOptions.Copy)!; + Assert.AreNotSame (o, x); + x.Dispose (); + + x = valueManager.CreateValue (ref r, JniObjectReferenceOptions.Copy); + Assert.AreNotSame (o, x); + x!.Dispose (); + } + } + + [Test] + public void GetValue_ReturnsAlias () + { + var local = new JavaObject (); + local.UnregisterFromRuntime (); + Assert.IsNull (valueManager.PeekValue (local.PeerReference)); + // GetObject must always return a value (unless handle is null, etc.). + // However, since we called local.UnregisterFromRuntime(), + // JniRuntime.PeekObject() is null (asserted above), but GetObject() must + // **still** return _something_. + // In this case, it returns an _alias_. + // TODO: "most derived type" alias generation. (Not relevant here, but...) + var p = local.PeerReference; + var alias = JniRuntime.CurrentRuntime.ValueManager.GetValue (ref p, JniObjectReferenceOptions.Copy); + Assert.AreNotSame (local, alias); + alias!.Dispose (); + local.Dispose (); + } + + [Test] + public void GetValue_ReturnsNullWithNullHandle () + { + var r = new JniObjectReference (); + var o = valueManager.GetValue (ref r, JniObjectReferenceOptions.Copy); + Assert.IsNull (o); + } + + [Test] + public void GetValue_ReturnsNullWithInvalidSafeHandle () + { + var invalid = new JniObjectReference (); + Assert.IsNull (valueManager.GetValue (ref invalid, JniObjectReferenceOptions.CopyAndDispose)); + } + + [Test] + public unsafe void GetValue_FindBestMatchType () + { +#if !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + using (var t = new JniType (TestType.JniTypeName)) { + var c = t.GetConstructor ("()V"); + var o = t.NewObject (c, null); + using (var w = valueManager.GetValue (ref o, JniObjectReferenceOptions.CopyAndDispose)) { + Assert.AreEqual (typeof (TestType), w!.GetType ()); + Assert.IsTrue (((TestType) w).ExecutedActivationConstructor); + } + } +#endif // !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + } + + [Test] + public void PeekPeer () + { + Assert.IsNull (valueManager.PeekPeer (new JniObjectReference ())); + + using (var v = new MyDisposableObject ()) { + Assert.IsNotNull (valueManager.PeekPeer (v.PeerReference)); + Assert.AreSame (v, valueManager.PeekPeer (v.PeerReference)); + } + } + + [Test] + public void PeekValue () + { + JniObjectReference lref; + using (var o = new JavaObject ()) { + lref = o.PeerReference.NewLocalRef (); + Assert.AreSame (o, valueManager.PeekValue (lref)); + } + // At this point, the Java-side object is kept alive by `lref`, + // but the wrapper instance has been disposed, and thus should + // be unregistered, and thus unfindable. + Assert.IsNull (valueManager.PeekValue (lref)); + JniObjectReference.Dispose (ref lref); + } + + [Test] + public void PeekValue_BoxedObjects () + { + var marshaler = valueManager.GetValueMarshaler (); + var ad = AppDomain.CurrentDomain; + + var proxy = marshaler.CreateGenericArgumentState (ad); + Assert.AreSame (ad, valueManager.PeekValue (proxy.ReferenceValue)); + marshaler.DestroyGenericArgumentState (ad, ref proxy); + + var ex = new InvalidOperationException ("boo!"); + proxy = marshaler.CreateGenericArgumentState (ex); + Assert.AreSame (ex, valueManager.PeekValue (proxy.ReferenceValue)); + marshaler.DestroyGenericArgumentState (ex, ref proxy); + } + + void AllNestedRegistrationScopeTests () + { + AddPeer (); + AddPeer_NoDuplicates (); + ConstructPeer_ImplicitViaBindingConstructor_PeerIsInSurfacedPeers (); + CreateValue (); + GetValue_FindBestMatchType (); + GetValue_ReturnsAlias (); + GetValue_ReturnsNullWithInvalidSafeHandle (); + GetValue_ReturnsNullWithNullHandle (); + PeekPeer (); + PeekValue (); + PeekValue_BoxedObjects (); + } + + string DumpPeers () + { + return DumpPeers (valueManager.GetSurfacedPeers ()); + } + + static string DumpPeers (IEnumerable peers) + { + return string.Join ("," + Environment.NewLine, peers); + } + + + // also test: + // Singleton scenario + // Types w/o "activation" constructors -- need to support checking parent scopes + // nesting of scopes + // Adding an instance already added in a previous scope? + } + + public abstract class JniRuntimeJniValueManagerContract< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + T + > : JniRuntimeJniValueManagerContract + { + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + protected override Type ValueManagerType => typeof (T); + } + +#if !__ANDROID__ + [TestFixture] + public class JniRuntimeJniValueManagerContract_NoGCIntegration : JniRuntimeJniValueManagerContract { + } +#endif // !__ANDROID__ + + // Note: Java side implements JavaInterface, while managed binding DOES NOT. + // This is so that `CreatePeer(…, typeof(IJavaInterface))` tests don't use an existing AnotherJavaInterfaceImpl instance. + // + // This is mostly identical to MyJavaInterfaceImpl; the important difference is that + // it contains an activation constructor, while MyJavaInterfaceImpl does not. + // MyJavaInterfaceImpl can't have one, as that's what provokes the NotSupportedException in the JavaAs() tests. + // + // We want one here so that in "bad" `CreatePeer()` implementations, we'll find this peer and construct it + // before verifying that it satisfies the targetType requirement. + [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] + public class AnotherJavaInterfaceImpl : JavaObject { + internal const string JniTypeName = "net/dot/jni/test/AnotherJavaInterfaceImpl"; + + internal static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (AnotherJavaInterfaceImpl)); + + public override JniPeerMembers JniPeerMembers { + get {return _members;} + } + + AnotherJavaInterfaceImpl (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } + + public unsafe AnotherJavaInterfaceImpl () + : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string id = "()V"; + var peer = _members.InstanceMethods.StartCreateInstance (id, GetType (), null); + Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (id, this, null); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs new file mode 100644 index 00000000000..f28d24727aa --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs @@ -0,0 +1,199 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Diagnostics.CodeAnalysis; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ +#if !__ANDROID__ + [NonParallelizable] +#endif // !__ANDROID__ + [TestFixture] + public class JniRuntimeTest : JavaVMFixture + { + [Test] + public void CreateJavaVM () + { + Assert.AreSame (JniRuntime.CurrentRuntime, JniRuntime.CurrentRuntime); + Assert.IsTrue (JniRuntime.CurrentRuntime.InvocationPointer != IntPtr.Zero); + Assert.IsTrue (JniEnvironment.EnvironmentPointer != IntPtr.Zero); + } + +#if !__ANDROID__ + [Test] + [RequiresDynamicCode ("This test intentionally uses the default JRE type manager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("This test intentionally uses the default JRE type manager, which is reflection-based and not trimming-compatible.")] + public void JDK_OnlySupportsOneVM () + { + try { + var second = new TestJVM (new TestJVMOptions () { + JvmLibraryPath = TestJVM.GetJvmLibraryPath (), + }); + // If we reach here, we're in a JVM that supports > 1 VM + second.Dispose (); + Assert.Ignore (); + } catch (NotSupportedException) { + } catch (Exception e){ + Assert.Fail ("Expected NotSupportedException; got: {0}", e); + } + } + + [Test] + [RequiresDynamicCode ("This test intentionally uses the default JRE type manager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("This test intentionally uses the default JRE type manager, which is reflection-based and not trimming-compatible.")] + public void UseInvocationPointerOnNewThread () + { + var InvocationPointer = JniRuntime.CurrentRuntime.InvocationPointer; + + var t = new Thread (() => { + try { + var second = new TestJVM (new TestJVMOptions () { + InvocationPointer = InvocationPointer, + }); + } + catch (Exception e) { + Assert.Fail ("Expected no exception, got: {0}", e); + } + }); + t.Start (); + t.Join (); + } +#endif // !__ANDROID__ + + [Test] + public void CreateJavaVMWithNullBuilder () + { + Assert.Throws (() => new JavaVMWithNullBuilder ()); + } + + [Test] + [Category ("TrimmableTypeMapUnsupported")] + public void BuiltInSimpleReferenceMap_ContainsManagedPeerByDefault () + { + var types = JniRuntime.CurrentRuntime.TypeManager.GetTypes (new JniTypeSignature (ManagedPeer.JniTypeName)); + Assert.IsTrue (types.Contains (typeof (ManagedPeer))); + } + + class JavaVMWithNullBuilder : JniRuntime { + public JavaVMWithNullBuilder () + : base ((JniRuntime.CreationOptions) null) + { + } + } + + [Test] + [RequiresDynamicCode ("This test uses ReflectionJniTypeManager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("This test uses ReflectionJniTypeManager, which is reflection-based and not trimming-compatible.")] + public void Dispose_ClearsJniEnvironment () + { + var c = JniRuntime.CurrentRuntime; + JniRuntime r = null; + var t = new Thread (() => { + r = new JniProxyRuntime (c); + JniRuntime.SetCurrent (r); + Assert.AreEqual (r, JniEnvironment.Runtime); + r.Dispose (); + Assert.Throws(() => { + var env = JniEnvironment.Runtime; + }); + }); + t.Start (); + t.Join (); + Assert.IsNotNull (r); + JniRuntime.SetCurrent (c); + } + + + [Test] + public void GetRegisteredJavaVM_ExistingInstance () + { + Assert.AreEqual (JniRuntime.CurrentRuntime, JniRuntime.GetRegisteredRuntime (JniRuntime.CurrentRuntime.InvocationPointer)); + } + } + + class JniProxyRuntime : JniRuntime + { + JniRuntime Proxy; + + [RequiresDynamicCode ("JniProxyRuntime uses ReflectionJniTypeManager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("JniProxyRuntime uses ReflectionJniTypeManager, which is reflection-based and not trimming-compatible.")] + public JniProxyRuntime (JniRuntime proxy) + : base (CreateOptions (proxy)) + { + Proxy = proxy; + } + + [RequiresDynamicCode ("JniProxyRuntime uses ReflectionJniTypeManager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("JniProxyRuntime uses ReflectionJniTypeManager, which is reflection-based and not trimming-compatible.")] + static JniRuntime.CreationOptions CreateOptions (JniRuntime proxy) + { + return new JniRuntime.CreationOptions { + DestroyRuntimeOnDispose = false, + InvocationPointer = proxy.InvocationPointer, + ObjectReferenceManager = new ProxyObjectReferenceManager (), + ValueManager = new ProxyValueManager (), + TypeManager = new ProxyTypeManager (), + }; + } + + class ProxyObjectReferenceManager : JniObjectReferenceManager { + + public override int GlobalReferenceCount { + get {return 1;} + } + + public override int WeakGlobalReferenceCount { + get {return 0;} + } + } + + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "ProxyValueManager intentionally uses reflection-backed value manager behavior for tests.")] + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "ProxyValueManager intentionally uses reflection-backed value manager behavior for tests.")] + class ProxyValueManager : ReflectionJniValueManager { + + public override void AddPeer (IJavaPeerable peer) + { + } + + public override void CollectPeers () + { + } + + public override void FinalizePeer (IJavaPeerable peer) + { + } + + public override List GetSurfacedPeers () + { + return null; + } + + public override IJavaPeerable PeekPeer (JniObjectReference reference) + { + return null; + } + + public override void RemovePeer (IJavaPeerable peer) + { + } + + public override void WaitForGCBridgeProcessing () + { + } + } + + [RequiresDynamicCode ("ProxyTypeManager uses ReflectionJniTypeManager, which is reflection-based and not NativeAOT-compatible.")] + [RequiresUnreferencedCode ("ProxyTypeManager uses ReflectionJniTypeManager, which is reflection-based and not trimming-compatible.")] + class ProxyTypeManager : ReflectionJniTypeManager { + public ProxyTypeManager () + { + } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTransitionTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTransitionTest.cs new file mode 100644 index 00000000000..565d100a8c4 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTransitionTest.cs @@ -0,0 +1,28 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniTransitionTests : JavaVMFixture + { + [Test] + public void Dispose_ClearsLocalReferences () + { + if (!HaveSafeHandles) { + Assert.Ignore ("SafeHandles aren't used, so magical disposal from a distance isn't supported."); + return; + } + JniObjectReference lref; + using (var envp = new JniTransition (JniEnvironment.EnvironmentPointer)) { + lref = new JavaObject ().PeerReference.NewLocalRef (); + Assert.IsTrue (lref.IsValid); + } + Assert.IsFalse (lref.IsValid); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs new file mode 100644 index 00000000000..198cb9c97fd --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs @@ -0,0 +1,248 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniTypeManagerTests : JavaVMFixture + { + [Test] + public void GetTypeSignature_Type () + { + Assert.Throws (() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature ((Type) null)); + Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (int[,]))); + Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (int[,][]))); + Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (int[][,]))); + Assert.AreEqual (null, JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (JniRuntimeTest)).SimpleReference); + + AssertGetJniTypeInfoForType (typeof (string), "java/lang/String", false, 0); + + AssertGetJniTypeInfoForType (typeof (sbyte), "B", true, 0); + AssertGetJniTypeInfoForType (typeof (short), "S", true, 0); + AssertGetJniTypeInfoForType (typeof (int), "I", true, 0); + AssertGetJniTypeInfoForType (typeof (long), "J", true, 0); + AssertGetJniTypeInfoForType (typeof (float), "F", true, 0); + AssertGetJniTypeInfoForType (typeof (double), "D", true, 0); + AssertGetJniTypeInfoForType (typeof (char), "C", true, 0); + AssertGetJniTypeInfoForType (typeof (bool), "Z", true, 0); + AssertGetJniTypeInfoForType (typeof (void), "V", true, 0); + + AssertGetJniTypeInfoForType (typeof (float?), "java/lang/Float", true, 0); + + AssertGetJniTypeInfoForType (typeof (JavaObject), "java/lang/Object", false, 0); + + // Enums are their underlying type + AssertGetJniTypeInfoForType (typeof (StringComparison), "I", true, 0); + AssertGetJniTypeInfoForType (typeof (StringComparison[]), "[I", true, 1); + AssertGetJniTypeInfoForType (typeof (StringComparison[][]), "[[I", true, 2); + + AssertGetJniTypeInfoForType (typeof (int[]), "[I", true, 1); + AssertGetJniTypeInfoForType (typeof (int[][]), "[[I", true, 2); + AssertGetJniTypeInfoForType (typeof (int[][][]), "[[[I", true, 3); + + // We map unsigned types to their signed counterparts + AssertGetJniTypeInfoForType (typeof (byte[]), "[B", true, 1); + AssertGetJniTypeInfoForType (typeof (ushort[]), "[S", true, 1); + AssertGetJniTypeInfoForType (typeof (uint[]), "[I", true, 1); + AssertGetJniTypeInfoForType (typeof (ulong[]), "[J", true, 1); + + AssertGetJniTypeInfoForType (typeof (JavaSByteArray), "[B", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaInt16Array), "[S", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaInt32Array), "[I", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaInt64Array), "[J", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaSingleArray), "[F", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaDoubleArray), "[D", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaCharArray), "[C", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaBooleanArray), "[Z", true, 1); + + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[B", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[S", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[I", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[J", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[F", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[D", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[C", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaPrimitiveArray), "[Z", true, 1); + + AssertGetJniTypeInfoForType (typeof (JavaArray), "[B", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[S", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[I", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[J", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[F", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[D", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[C", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[Z", true, 1); + + AssertGetJniTypeInfoForType (typeof (JavaArray[]), "[[Z", true, 2); + + AssertGetJniTypeInfoForType (typeof (JavaArray), "[Ljava/lang/Object;", false, 1); + AssertGetJniTypeInfoForType (typeof (JavaArray), "[[I", true, 2); + AssertGetJniTypeInfoForType (typeof (JavaArray[]), "[[[I", true, 3); + +#if !__ANDROID__ + // Re-enable once typemap files contain `JavaObject` subclasses, not just Java.Lang.Object subclasses + // + // Note: dotnet/android@5c23bcda updates Java.Lang.Object to inherit JavaObject; this is not enough, + // as `` only processes assemblies if they reference Mono.Android.dll. + AssertGetJniTypeInfoForType (typeof (GenericHolder), GenericHolder.JniTypeName, false, 0); + + // XAJavaInterop1 Java Callable Wrappers, as used in dotnet/android, may contain + // `Runtime.register("Java.InteropTests.GenericHolder`1, Mono.Android-Tests", …)`, + // which results in a generic type definition. Permit this. + AssertGetJniTypeInfoForType (typeof (GenericHolder<>), GenericHolder.JniTypeName, false, 0); +#endif // !__ANDROID__ + } + + static void AssertGetJniTypeInfoForType (Type type, string jniType, bool isKeyword, int arrayRank) + { + var info = JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (type); + Assert.IsTrue (info.IsValid, $"info.IsValid for `{type}`"); + + // `GetTypeSignature() and `GetTypeSignatures()` should be "in sync"; verify that! + var info2 = JniRuntime.CurrentRuntime.TypeManager.GetTypeSignatures (type).FirstOrDefault (); + Assert.IsTrue (info2.IsValid, $"info2.IsValid for `{type}`"); + + Assert.AreEqual (jniType, info.Name, $"info.Name for `{type}`"); + Assert.AreEqual (jniType, info2.Name, $"info2.Name for `{type}`"); + Assert.AreEqual (arrayRank, info.ArrayRank, $"info.ArrayRank for `{type}`"); + Assert.AreEqual (arrayRank, info2.ArrayRank, $"info2.ArrayRank for `{type}`"); + } + + [Test] + public new void GetType () + { + var manager = JniRuntime.CurrentRuntime.TypeManager; + Func GetType = s => { + var sig = JniTypeSignature.Parse (s); + return manager.GetType (sig); + }; + Assert.Throws (() => GetType (null)); + Assert.Throws (() => GetType ("java.lang.String")); + Assert.Throws (() => GetType ("Ljava/lang/String;I")); + Assert.Throws (() => GetType ("ILjava/lang/String;")); + + Assert.AreEqual (typeof (void), GetType ("V")); + Assert.AreEqual (typeof (bool), GetType ("Z")); + Assert.AreEqual (typeof (char), GetType ("C")); + Assert.AreEqual (typeof (sbyte), GetType ("B")); + Assert.AreEqual (typeof (short), GetType ("S")); + Assert.AreEqual (typeof (int), GetType ("I")); + Assert.AreEqual (typeof (long), GetType ("J")); + Assert.AreEqual (typeof (float), GetType ("F")); + Assert.AreEqual (typeof (double), GetType ("D")); + Assert.AreEqual (typeof (string), GetType ("java/lang/String")); + Assert.AreEqual (typeof (float?), GetType ("java/lang/Float")); + Assert.AreEqual (null, GetType ("com/example/does/not/exist")); + Assert.AreEqual (null, GetType ("Lcom/example/does/not/exist;")); + Assert.AreEqual (null, GetType ("[Lcom/example/does/not/exist;")); + + AssertPrimitiveArrayTypesFromSignature (manager, "[Z", typeof (JavaBooleanArray)); + AssertPrimitiveArrayTypesFromSignature (manager, "[C", typeof (JavaCharArray)); + AssertPrimitiveArrayTypesFromSignature (manager, "[B", typeof (JavaSByteArray)); + AssertPrimitiveArrayTypesFromSignature (manager, "[S", typeof (JavaInt16Array)); + AssertPrimitiveArrayTypesFromSignature (manager, "[I", typeof (JavaInt32Array)); + AssertPrimitiveArrayTypesFromSignature (manager, "[J", typeof (JavaInt64Array)); + AssertPrimitiveArrayTypesFromSignature (manager, "[F", typeof (JavaSingleArray)); + AssertPrimitiveArrayTypesFromSignature (manager, "[D", typeof (JavaDoubleArray)); + AssertArrayTypesFromSignature (manager, "[Ljava/lang/String;", typeof (JavaObjectArray)); + + AssertArrayTypesFromSignature (manager, "[[Z", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[C", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[B", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[S", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[I", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[J", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[F", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[D", typeof (JavaObjectArray>)); + AssertArrayTypesFromSignature (manager, "[[Ljava/lang/String;", typeof (JavaObjectArray>)); + + // Yes, these look weird... + // Assume: class II {} + Assert.AreEqual (null, GetType ("II")); + // Assume: package Ljava.lang; class String {} + Assert.AreEqual (null, GetType ("Ljava/lang/String")); + } + + static void AssertPrimitiveArrayTypesFromSignature (JniRuntime.JniTypeManager manager, string signature, params Type[] expectedTypes) + { + var sig = JniTypeSignature.Parse (signature); + var types = manager.GetTypes (sig).ToList (); + var messageFormat = $"Types for signature `{signature}` should contain `{{0}}`, instead contains: {string.Join (", ", types)}"; + var arrayTypes = new[]{ + typeof (JavaArray), + typeof (JavaPrimitiveArray), + typeof (T[]), + }.Concat (expectedTypes); + foreach (var t in arrayTypes) { + Assert.IsTrue (types.Contains (t), string.Format (messageFormat, t)); + } + } + + static void AssertArrayTypesFromSignature (JniRuntime.JniTypeManager manager, string signature, params Type[] expectedTypes) + { + var sig = JniTypeSignature.Parse (signature); + var types = manager.GetTypes (sig).ToList (); + var messageFormat = $"Types for signature `{signature}` should contain `{{0}}`, instead contains: {string.Join (", ", types)}"; + var arrayTypes = new[]{ + typeof (T[]), + }.Concat (expectedTypes); + foreach (var t in arrayTypes) { + Assert.IsTrue (types.Contains (t), string.Format (messageFormat, t)); + } + } + + [Test] + public void GetTypeSignature () + { + var jvm = JniRuntime.CurrentRuntime; + Func GetTypeForSimpleReference = s => { + var sig = JniTypeSignature.Parse (s); + return jvm.TypeManager.GetType (sig); + }; + Assert.Throws (() => GetTypeForSimpleReference (null)); + Assert.Throws (() => GetTypeForSimpleReference ("foo.bar")); + + Assert.AreEqual (typeof (void), GetTypeForSimpleReference ("V")); + Assert.AreEqual (typeof (bool), GetTypeForSimpleReference ("Z")); + Assert.AreEqual (typeof (char), GetTypeForSimpleReference ("C")); + Assert.AreEqual (typeof (sbyte), GetTypeForSimpleReference ("B")); + Assert.AreEqual (typeof (short), GetTypeForSimpleReference ("S")); + Assert.AreEqual (typeof (int), GetTypeForSimpleReference ("I")); + Assert.AreEqual (typeof (long), GetTypeForSimpleReference ("J")); + Assert.AreEqual (typeof (float), GetTypeForSimpleReference ("F")); + Assert.AreEqual (typeof (double), GetTypeForSimpleReference ("D")); + Assert.AreEqual (typeof (string), GetTypeForSimpleReference ("java/lang/String")); + Assert.AreEqual (null, GetTypeForSimpleReference ("com/example/does/not/exist")); + } + + [Test] + public void CanCreateGenericHolder () + { + using var holder = new GenericHolder (); + } + + [Test] + public unsafe void CannotCreateGenericHolderFromJava () + { + var signature = JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (GenericHolder<>)); + using var type = new JniType (signature.Name); + var ctor = type.GetConstructor ("()V"); + var instance = type.AllocObject (); + + Assert.Throws(() => + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (instance, type.PeerReference, ctor)); + } + } + + [JniTypeSignature (JniTypeName)] + class GenericHolder : JavaObject { + public const string JniTypeName = "net/dot/jni/test/GenericHolder"; + + public T Value {get; set;} + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeSignatureAttributeTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeSignatureAttributeTest.cs new file mode 100644 index 00000000000..114d76b507f --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeSignatureAttributeTest.cs @@ -0,0 +1,39 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniTypeSignatureAttributeTest + { + [Test] + public void Constructor_Exceptions () + { + Assert.Throws (() => new JniTypeSignatureAttribute (null)); + Assert.Throws (() => new JniTypeSignatureAttribute ("java.lang.Object")); + Assert.Throws (() => new JniTypeSignatureAttribute ("[[I")); + Assert.Throws (() => new JniTypeSignatureAttribute ("Ljava/lang/Object;")); + } + + [Test] + public void Sanity () + { + var a = new JniTypeSignatureAttribute ("java/lang/Object") { + ArrayRank = 2, + }; + Assert.AreEqual ("java/lang/Object", a.SimpleReference); + Assert.AreEqual (2, a.ArrayRank); + } + + [Test] + public void ArrayRank_Exceptions () + { + var a = new JniTypeSignatureAttribute ("I"); + Assert.Throws (() => a.ArrayRank = -1); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeSignatureTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeSignatureTest.cs new file mode 100644 index 00000000000..32cc66698d5 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeSignatureTest.cs @@ -0,0 +1,98 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniTypeSignatureTest + { + [Test] + public void Constructor_Exceptions () + { + Assert.Throws (() => new JniTypeSignature ("java.lang.Object")); + Assert.Throws (() => new JniTypeSignature ("[[I")); + Assert.Throws (() => new JniTypeSignature ("Ljava/lang/Object;")); + Assert.Throws (() => new JniTypeSignature ("")); + } + + [Test] + public void DefaultConstructor () + { + var t = new JniTypeSignature (); + Assert.False (t.IsValid); + } + + [Test] + public void Sanity () + { + var a = new JniTypeSignature ("java/lang/Object", arrayRank: 2); + Assert.AreEqual ("java/lang/Object", a.SimpleReference); + Assert.AreEqual (2, a.ArrayRank); + Assert.AreEqual ("[[Ljava/lang/Object;", a.Name); + Assert.AreEqual ("[[Ljava/lang/Object;", a.QualifiedReference); + } + + [Test] + public void QualifiedReference () + { + var info = new JniTypeSignature ("java/lang/String"); + Assert.AreEqual ("Ljava/lang/String;", info.QualifiedReference); + Assert.AreEqual ("java/lang/String", info.SimpleReference); + Assert.AreEqual ("java/lang/String", info.Name); + + info = new JniTypeSignature ("java/lang/String", arrayRank:1); + Assert.AreEqual ("java/lang/String", info.SimpleReference); + Assert.AreEqual ("[Ljava/lang/String;", info.QualifiedReference); + Assert.AreEqual ("[Ljava/lang/String;", info.Name); + + info = new JniTypeSignature ("B", keyword: true); + Assert.AreEqual ("B", info.Name); + Assert.AreEqual ("B", info.QualifiedReference); + Assert.AreEqual ("B", info.SimpleReference); + + info = new JniTypeSignature ("B", arrayRank: 2, keyword: true); + Assert.AreEqual ("[[B", info.Name); + Assert.AreEqual ("[[B", info.QualifiedReference); + Assert.AreEqual ("B", info.SimpleReference); + } + + [Test] + public void Parse () + { + Assert.Throws (() => JniTypeSignature.Parse ((string) null)); + Assert.Throws (() => JniTypeSignature.Parse ("")); + Assert.Throws (() => JniTypeSignature.Parse ("java.lang.String")); + Assert.Throws (() => JniTypeSignature.Parse ("Ljava/lang/String;I")); + Assert.Throws (() => JniTypeSignature.Parse ("ILjava/lang/String;")); + + AssertGetJniTypeInfoForJniTypeReference ("java/lang/String", "java/lang/String"); + AssertGetJniTypeInfoForJniTypeReference ("Ljava/lang/String;", "java/lang/String"); + AssertGetJniTypeInfoForJniTypeReference ("[I", "I", true, 1); + AssertGetJniTypeInfoForJniTypeReference ("[[I", "I", true, 2); + AssertGetJniTypeInfoForJniTypeReference ("[Ljava/lang/Object;", "java/lang/Object", false, 1); + + // Yes, these look _really_ weird... + // Assume: class II {} + AssertGetJniTypeInfoForJniTypeReference ("II", "II"); + // Assume: package Ljava.lang; class String {} + AssertGetJniTypeInfoForJniTypeReference ("Ljava/lang/String", "Ljava/lang/String"); + } + + static void AssertGetJniTypeInfoForJniTypeReference (string jniTypeReference, string jniTypeName, bool typeIsKeyword = false, int arrayRank = 0) + { + var sig = JniTypeSignature.Parse (jniTypeReference); + Assert.AreEqual (jniTypeName, sig.SimpleReference, "JniTypeName for: " + jniTypeReference); + Assert.AreEqual (arrayRank, sig.ArrayRank, "ArrayRank for: " + jniTypeReference); + } + + [Test] + public void TryParse () + { + Assert.False (JniTypeSignature.TryParse ("", out var _)); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeTest.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeTest.cs new file mode 100644 index 00000000000..9120d400345 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeTest.cs @@ -0,0 +1,289 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniTypeTest : JavaVMFixture { + + [Test] + public unsafe void Sanity () + { + using (var Integer_class = new JniType ("java/lang/Integer")) { + Assert.AreEqual ("java/lang/Integer", Integer_class.Name); + + var ctor_args = stackalloc JniArgumentValue [1]; + ctor_args [0] = new JniArgumentValue (42); + + var Integer_ctor = Integer_class.GetConstructor ("(I)V"); + var Integer_intValue = Integer_class.GetInstanceMethod ("intValue", "()I"); + var o = Integer_class.NewObject (Integer_ctor, ctor_args); + try { + int v = JniEnvironment.InstanceMethods.CallIntMethod (o, Integer_intValue); + Assert.AreEqual (42, v); + } finally { + JniObjectReference.Dispose (ref o); + } + } + } + + [Test] + public void Ctor_ThrowsIfTypeNotFound () + { +#if __ANDROID__ + Assert.Throws (() => new JniType ("__this__/__type__/__had__/__better__/__not__/__Exist__")).Dispose (); +#else // __ANDROID__ + Assert.Throws (() => new JniType ("__this__/__type__/__had__/__better__/__not__/__Exist__")).Dispose (); +#endif // __ANDROID__ + } + + [Test] + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Test exercises non-AOT-compatible JniType.RegisterNativeMethods API.")] + public unsafe void Dispose_Exceptions () + { + var t = new JniType ("java/lang/Object"); + t.Dispose (); + Assert.Throws (() => t.AllocObject ()); + Assert.Throws (() => t.NewObject (null, null)); + Assert.Throws (() => t.GetConstructor ((string) null)); + Assert.Throws (() => t.GetInstanceField ((string) null, (string) null)); + Assert.Throws (() => t.GetInstanceMethod ((string) null, (string) null)); + Assert.Throws (() => t.GetStaticField ((string) null, (string) null)); + Assert.Throws (() => t.GetStaticMethod ((string) null, (string) null)); + Assert.Throws (() => t.GetSuperclass ()); + Assert.Throws (() => t.IsAssignableFrom (null)); + Assert.Throws (() => t.IsInstanceOfType (new JniObjectReference ())); + Assert.Throws (() => t.RegisterWithRuntime ()); + Assert.Throws (() => t.RegisterNativeMethods (null)); + Assert.Throws (() => t.UnregisterNativeMethods ()); + + JniFieldInfo jif = null; + Assert.Throws (() => t.GetCachedInstanceField (ref jif, (string) null, (string) null)); + JniMethodInfo jim = null; + Assert.Throws (() => t.GetCachedConstructor (ref jim, (string) null)); + Assert.Throws (() => t.GetCachedInstanceMethod (ref jim, (string) null, (string) null)); + JniFieldInfo jsf = null; + Assert.Throws (() => t.GetCachedStaticField (ref jsf, (string) null, (string) null)); + JniMethodInfo jsm = null; + Assert.Throws (() => t.GetCachedStaticMethod (ref jsm, (string) null, (string) null)); + } + + [Test] + public void GetSuperclass () + { + using (var t = new JniType ("java/lang/Object")) { + var b = t.GetSuperclass (); + Assert.IsNull (b); + using (var s = new JniType ("java/lang/String")) { + using (var st = s.GetSuperclass ()) { + Assert.IsFalse (object.ReferenceEquals (t, st)); + Assert.IsTrue (JniEnvironment.Types.IsSameObject (t.PeerReference, st.PeerReference)); + } + } + } + } + + [Test] + public void IsAssignableFrom () + { + using (var o = new JniType ("java/lang/Object")) + using (var s = new JniType ("java/lang/String")) { + Assert.IsTrue (o.IsAssignableFrom (s)); + Assert.IsFalse (s.IsAssignableFrom (o)); + } + } + + [Test] + public unsafe void IsInstanceOfType () + { + using (var Object_class = new JniType ("java/lang/Object")) + using (var String_class = new JniType ("java/lang/String")) { + var String_ctor = String_class.GetConstructor ("()V"); + var s = String_class.NewObject (String_ctor, null); + try { + Assert.IsTrue (Object_class.IsInstanceOfType (s), "java.lang.String IS-NOT-A java.lang.Object?!"); + } finally { + JniObjectReference.Dispose (ref s); + } + } + } + + [Test] + public void InvalidSignatureThrowsJniException () + { + using (var Integer_class = new JniType ("java/lang/Integer")) { +#if __ANDROID__ + Assert.Throws (() => Integer_class.GetConstructor ("(C)V")).Dispose (); +#else // __ANDROID__ + Assert.Throws (() => Integer_class.GetConstructor ("(C)V")).Dispose (); +#endif // __ANDROID__ + } + } + + [Test] + public void GetStaticFieldID () + { + using (var System_class = new JniType ("java/lang/System")) { + var System_in = System_class.GetStaticField ("in", "Ljava/io/InputStream;"); + Assert.IsNotNull (System_in); + Assert.IsTrue (System_in.ID != IntPtr.Zero); + } + } + + [Test] + public unsafe void Name () + { + using (var Object_class = new JniType ("java/lang/Object")) + using (var Class_class = new JniType ("java/lang/Class")) + using (var Method_class = new JniType ("java/lang/reflect/Method")) { + var Class_getMethod = Class_class.GetInstanceMethod ("getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"); + var Method_getReturnType = Method_class.GetInstanceMethod ("getReturnType", "()Ljava/lang/Class;"); + var hashCode_str = JniEnvironment.Strings.NewString ("hashCode"); + var emptyArray = JniEnvironment.Arrays.NewObjectArray (0, Class_class.PeerReference, new JniObjectReference ()); + var getHashcodeMethodArgs = stackalloc JniArgumentValue [2]; + getHashcodeMethodArgs [0] = new JniArgumentValue (hashCode_str); + getHashcodeMethodArgs [1] = new JniArgumentValue (emptyArray); + var Object_hashCode = JniEnvironment.InstanceMethods.CallObjectMethod (Object_class.PeerReference, Class_getMethod, getHashcodeMethodArgs); + var Object_hashCode_rt = JniEnvironment.InstanceMethods.CallObjectMethod (Object_hashCode, Method_getReturnType); + try { + Assert.AreEqual ("java/lang/Object", Object_class.Name); + + using (var t = new JniType (ref Object_hashCode_rt, JniObjectReferenceOptions.Copy)) + Assert.AreEqual ("I", t.Name); + } finally { + JniObjectReference.Dispose (ref hashCode_str); + JniObjectReference.Dispose (ref Object_hashCode); + JniObjectReference.Dispose (ref Object_hashCode_rt); + JniObjectReference.Dispose (ref emptyArray); + } + } + } + + [Test] + public void RegisterWithRuntime () + { + using (var Object_class = new JniType ("java/lang/Object")) { + Assert.AreEqual (JniObjectReferenceType.Global, Object_class.PeerReference.Type); + var cur = Object_class.PeerReference; + Object_class.RegisterWithRuntime (); + Assert.AreEqual (JniObjectReferenceType.Global, Object_class.PeerReference.Type); + Assert.IsTrue (Object_class.PeerReference.IsValid); + } + } + + [Test] + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Test exercises non-AOT-compatible JniType.RegisterNativeMethods API.")] + public void RegisterNativeMethods () + { + using (var TestType_class = new JniType ("net/dot/jni/test/CallNonvirtualBase")) { + Assert.AreEqual (JniObjectReferenceType.Global, TestType_class.PeerReference.Type); + TestType_class.RegisterNativeMethods (); + Assert.AreEqual (JniObjectReferenceType.Global, TestType_class.PeerReference.Type); + } + } + + [Test] + public unsafe void RegisterNativeMethods_JniNativeMethod () + { + using (var nativeClass = new JniType ("net/dot/jni/test/RegisterNativesTestType")) { + Span methods = stackalloc JniNativeMethod [1]; + fixed (byte* namePtr = "add"u8) + fixed (byte* sigPtr = "(II)I"u8) { + methods [0] = new JniNativeMethod (namePtr, sigPtr, + (IntPtr) (delegate* unmanaged) &NativeAdd); + JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, methods); + } + + // Call the native method from Java to verify registration worked + var ctor = JniEnvironment.InstanceMethods.GetMethodID (nativeClass.PeerReference, "", "()V"); + var obj = JniEnvironment.Object.NewObject (nativeClass.PeerReference, ctor); + try { + var addMethod = JniEnvironment.InstanceMethods.GetMethodID (nativeClass.PeerReference, "add", "(II)I"); + var args = stackalloc JniArgumentValue [2]; + args [0] = new JniArgumentValue (3); + args [1] = new JniArgumentValue (4); + int result = JniEnvironment.InstanceMethods.CallIntMethod (obj, addMethod, args); + Assert.AreEqual (7, result); + } finally { + JniObjectReference.Dispose (ref obj); + } + } + } + + [UnmanagedCallersOnly] + static int NativeAdd (IntPtr jnienv, IntPtr self, int a, int b) => a + b; + + [Test] + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Test exercises non-AOT-compatible JniNativeMethodRegistration[] registration path.")] + public unsafe void RegisterNativeMethods_JniNativeMethodRegistration () + { + using (var nativeClass = new JniType ("net/dot/jni/test/RegisterNativesTestType")) { + // Test the JniNativeMethodRegistration[] registration path (the one that marshals to blittable) + var methods = new JniNativeMethodRegistration [1]; + methods [0] = new JniNativeMethodRegistration ( + "add", + "(II)I", + new AddDelegate (ManagedAdd)); + + JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, methods, methods.Length); + + // Call the native method from Java to verify registration worked + var ctor = JniEnvironment.InstanceMethods.GetMethodID (nativeClass.PeerReference, "", "()V"); + var obj = JniEnvironment.Object.NewObject (nativeClass.PeerReference, ctor); + try { + var addMethod = JniEnvironment.InstanceMethods.GetMethodID (nativeClass.PeerReference, "add", "(II)I"); + var args = stackalloc JniArgumentValue [2]; + args [0] = new JniArgumentValue (5); + args [1] = new JniArgumentValue (6); + int result = JniEnvironment.InstanceMethods.CallIntMethod (obj, addMethod, args); + Assert.AreEqual (11, result); + } finally { + JniObjectReference.Dispose (ref obj); + } + } + } + + delegate int AddDelegate (IntPtr jnienv, IntPtr self, int a, int b); + + static int ManagedAdd (IntPtr jnienv, IntPtr self, int a, int b) => a + b; + + [Test] + [UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Test exercises non-AOT-compatible JniNativeMethodRegistration[] registration path with many methods.")] + public unsafe void RegisterNativeMethods_JniNativeMethodRegistration_ManyMethods () + { + using (var nativeClass = new JniType ("net/dot/jni/test/RegisterNativesTestType")) { + // Test the heap allocation path (> 32 methods) to ensure the marshalling loop handles it + var methods = new JniNativeMethodRegistration [40]; + for (int i = 0; i < methods.Length; ++i) { + methods [i] = new JniNativeMethodRegistration ( + "add", + "(II)I", + new AddDelegate (ManagedAdd)); + } + + // This should not crash even with > 32 methods + JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, methods, methods.Length); + + // Verify the registration worked by calling the method + var ctor = JniEnvironment.InstanceMethods.GetMethodID (nativeClass.PeerReference, "", "()V"); + var obj = JniEnvironment.Object.NewObject (nativeClass.PeerReference, ctor); + try { + var addMethod = JniEnvironment.InstanceMethods.GetMethodID (nativeClass.PeerReference, "add", "(II)I"); + var args = stackalloc JniArgumentValue [2]; + args [0] = new JniArgumentValue (10); + args [1] = new JniArgumentValue (20); + int result = JniEnvironment.InstanceMethods.CallIntMethod (obj, addMethod, args); + Assert.AreEqual (30, result); + } finally { + JniObjectReference.Dispose (ref obj); + } + } + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeUtf8Test.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeUtf8Test.cs new file mode 100644 index 00000000000..c5e0fc0d6c0 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeUtf8Test.cs @@ -0,0 +1,232 @@ +#nullable enable + +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + public class JniTypeUtf8Test : JavaVMFixture { + + [Test] + public unsafe void Sanity_Utf8 () + { + using (var Integer_class = new JniType ("java/lang/Integer"u8)) { + Assert.AreEqual ("java/lang/Integer", Integer_class.Name); + + var ctor_args = stackalloc JniArgumentValue [1]; + ctor_args [0] = new JniArgumentValue (42); + + var Integer_ctor = Integer_class.GetConstructor ("(I)V"u8); + var Integer_intValue = Integer_class.GetInstanceMethod ("intValue"u8, "()I"u8); + var o = Integer_class.NewObject (Integer_ctor, ctor_args); + try { + int v = JniEnvironment.InstanceMethods.CallIntMethod (o, Integer_intValue); + Assert.AreEqual (42, v); + } finally { + JniObjectReference.Dispose (ref o); + } + } + } + + [Test] + public void FindClass_Utf8_ReturnsValidReference () + { + var r = JniEnvironment.Types.FindClass ("java/lang/Object"u8); + try { + Assert.IsTrue (r.IsValid); + } finally { + JniObjectReference.Dispose (ref r); + } + } + + [Test] + public void FindClass_Utf8_UsesSameFallbackAsStringOverload () + { + var fromString = JniEnvironment.Types.FindClass ("java.lang.Object"); + var fromUtf8 = JniEnvironment.Types.FindClass ("java.lang.Object"u8); + try { + Assert.IsTrue (JniEnvironment.Types.IsSameObject (fromString, fromUtf8)); + } finally { + JniObjectReference.Dispose (ref fromString); + JniObjectReference.Dispose (ref fromUtf8); + } + } + + [Test] + public void Ctor_Utf8_UsesSameFallbackAsStringOverload () + { + using (var fromString = new JniType ("java.lang.Object")) + using (var fromUtf8 = new JniType ("java.lang.Object"u8)) { + Assert.IsTrue (JniEnvironment.Types.IsSameObject (fromString.PeerReference, fromUtf8.PeerReference)); + Assert.AreEqual ("java/lang/Object", fromUtf8.Name); + } + } + + [Test] + public void FindClass_Utf8_ThrowsOnNotFound () + { +#if __ANDROID__ + Assert.Throws (() => JniEnvironment.Types.FindClass ("does/not/Exist"u8)); +#else // __ANDROID__ + Assert.Throws (() => JniEnvironment.Types.FindClass ("does/not/Exist"u8)); +#endif // __ANDROID__ + } + + [Test] + public void TryFindClass_Utf8 () + { + Assert.IsTrue (JniEnvironment.Types.TryFindClass ("java/lang/Object"u8, out var found)); + try { + Assert.IsTrue (found.IsValid); + } finally { + JniObjectReference.Dispose (ref found); + } + + Assert.IsFalse (JniEnvironment.Types.TryFindClass ("does/not/Exist"u8, out var notFound)); + Assert.IsFalse (notFound.IsValid); + } + + [Test] + public void TryFindClass_Utf8_DoesNotLeakGlobalRefs () + { + int grefsBefore = JniEnvironment.Runtime.GlobalReferenceCount; + JniEnvironment.Types.TryFindClass ("does/not/Exist"u8, out _); + int grefsAfter = JniEnvironment.Runtime.GlobalReferenceCount; + Assert.AreEqual (grefsBefore, grefsAfter, + "TryFindClass for non-existent classes should not leak global references"); + } + + [Test] + public void TryFindClass_String_DoesNotLeakGlobalRefs () + { + int grefsBefore = JniEnvironment.Runtime.GlobalReferenceCount; + JniEnvironment.Types.TryFindClass ("does/not/Exist", out _); + int grefsAfter = JniEnvironment.Runtime.GlobalReferenceCount; + Assert.AreEqual (grefsBefore, grefsAfter, + "TryFindClass for non-existent classes should not leak global references"); + } + + [Test] + public void GetMethodID_Utf8_MatchesStringOverload () + { + using (var Object_class = new JniType ("java/lang/Object"u8)) { + var fromString = JniEnvironment.InstanceMethods.GetMethodID (Object_class.PeerReference, "hashCode", "()I"); + var fromUtf8 = JniEnvironment.InstanceMethods.GetMethodID (Object_class.PeerReference, "hashCode"u8, "()I"u8); + Assert.AreEqual (fromString.ID, fromUtf8.ID); + } + } + + [Test] + public void GetStaticMethodID_Utf8_MatchesStringOverload () + { + using (var System_class = new JniType ("java/lang/System"u8)) { + var fromString = JniEnvironment.StaticMethods.GetStaticMethodID (System_class.PeerReference, "currentTimeMillis", "()J"); + var fromUtf8 = JniEnvironment.StaticMethods.GetStaticMethodID (System_class.PeerReference, "currentTimeMillis"u8, "()J"u8); + Assert.AreEqual (fromString.ID, fromUtf8.ID); + } + } + + [Test] + public void GetFieldID_Utf8_MatchesStringOverload () + { + // Integer.value is private and blocked by ART hidden API restrictions. + // StreamTokenizer.ttype is a public instance field available on both JVM and Android. + using (var StreamTokenizer_class = new JniType ("java/io/StreamTokenizer"u8)) { + var fromString = JniEnvironment.InstanceFields.GetFieldID (StreamTokenizer_class.PeerReference, "ttype", "I"); + var fromUtf8 = JniEnvironment.InstanceFields.GetFieldID (StreamTokenizer_class.PeerReference, "ttype"u8, "I"u8); + Assert.AreEqual (fromString.ID, fromUtf8.ID); + } + } + + [Test] + public void GetStaticFieldID_Utf8_MatchesStringOverload () + { + using (var System_class = new JniType ("java/lang/System"u8)) { + var fromString = JniEnvironment.StaticFields.GetStaticFieldID (System_class.PeerReference, "in", "Ljava/io/InputStream;"); + var fromUtf8 = JniEnvironment.StaticFields.GetStaticFieldID (System_class.PeerReference, "in"u8, "Ljava/io/InputStream;"u8); + Assert.AreEqual (fromString.ID, fromUtf8.ID); + } + } + + [Test] + public void GetStaticField_Utf8 () + { + using (var System_class = new JniType ("java/lang/System"u8)) { + var System_in = System_class.GetStaticField ("in"u8, "Ljava/io/InputStream;"u8); + Assert.IsNotNull (System_in); + Assert.IsTrue (System_in.ID != IntPtr.Zero); + } + } + + [Test] + public void GetStaticMethod_Utf8_Invocation () + { + using (var System_class = new JniType ("java/lang/System"u8)) { + var currentTimeMillis = System_class.GetStaticMethod ("currentTimeMillis"u8, "()J"u8); + long time = JniEnvironment.StaticMethods.CallStaticLongMethod (System_class.PeerReference, currentTimeMillis); + Assert.IsTrue (time > 0); + } + } + + [Test] + public void GetCachedInstanceMethod_Utf8_ReturnsSameInstance () + { + using (var Object_class = new JniType ("java/lang/Object"u8)) { + JniMethodInfo? cached = null; + var first = Object_class.GetCachedInstanceMethod (ref cached, "hashCode"u8, "()I"u8); + var second = Object_class.GetCachedInstanceMethod (ref cached, "hashCode"u8, "()I"u8); + Assert.AreSame (first, second); + } + } + + [Test] + public void GetCachedStaticMethod_Utf8_ReturnsSameInstance () + { + using (var System_class = new JniType ("java/lang/System"u8)) { + JniMethodInfo? cached = null; + var first = System_class.GetCachedStaticMethod (ref cached, "currentTimeMillis"u8, "()J"u8); + var second = System_class.GetCachedStaticMethod (ref cached, "currentTimeMillis"u8, "()J"u8); + Assert.AreSame (first, second); + } + } + + [Test] + public void Dispose_Exceptions_Utf8 () + { + var t = new JniType ("java/lang/Object"u8); + t.Dispose (); + + Assert.Throws (() => t.GetConstructor ("()V"u8)); + Assert.Throws (() => t.GetInstanceField ("value"u8, "I"u8)); + Assert.Throws (() => t.GetInstanceMethod ("hashCode"u8, "()I"u8)); + Assert.Throws (() => t.GetStaticField ("in"u8, "Ljava/io/InputStream;"u8)); + Assert.Throws (() => t.GetStaticMethod ("currentTimeMillis"u8, "()J"u8)); + + JniFieldInfo? jif = null; + Assert.Throws (() => t.GetCachedInstanceField (ref jif, "value"u8, "I"u8)); + JniMethodInfo? jim = null; + Assert.Throws (() => t.GetCachedConstructor (ref jim, "()V"u8)); + Assert.Throws (() => t.GetCachedInstanceMethod (ref jim, "hashCode"u8, "()I"u8)); + JniFieldInfo? jsf = null; + Assert.Throws (() => t.GetCachedStaticField (ref jsf, "in"u8, "Ljava/io/InputStream;"u8)); + JniMethodInfo? jsm = null; + Assert.Throws (() => t.GetCachedStaticMethod (ref jsm, "currentTimeMillis"u8, "()J"u8)); + } + + [Test] + public void InvalidSignature_Utf8_ThrowsJniException () + { + using (var Object_class = new JniType ("java/lang/Object"u8)) { +#if __ANDROID__ + Assert.Throws (() => Object_class.GetInstanceMethod ("bogus"u8, "(Z)V"u8)); +#else // __ANDROID__ + Assert.Throws (() => Object_class.GetInstanceMethod ("bogus"u8, "(Z)V"u8)); +#endif // __ANDROID__ + } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerAttributeTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerAttributeTests.cs new file mode 100644 index 00000000000..97397fc70a6 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerAttributeTests.cs @@ -0,0 +1,23 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests { + + [TestFixture] + public class JniValueMarshalerAttributeTests { + + [Test] + public void Constructor () + { + Assert.Throws (() => new JniValueMarshalerAttribute (null)); + Assert.Throws (() => new JniValueMarshalerAttribute (typeof(int))); + + var a = new JniValueMarshalerAttribute (typeof (DemoValueTypeValueMarshaler)); + Assert.AreEqual (a.MarshalerType, typeof (DemoValueTypeValueMarshaler)); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerContractTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerContractTests.cs new file mode 100644 index 00000000000..40a6440889d --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniValueMarshalerContractTests.cs @@ -0,0 +1,702 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +using Java.Interop; +using Java.Interop.Expressions; + +using Mono.Linq.Expressions; + +using NUnit.Framework; + +namespace Java.InteropTests { + + [Category ("TrimmableTypeMapUnsupported")] + public abstract class JniValueMarshalerContractTests< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + T + > : JavaVMFixture + { + + protected abstract T Value {get;} + + protected virtual bool IsJniValueType {get;} + protected virtual bool UsesProxy {get;} + + protected virtual bool Equals (T x, T y) + { + return EqualityComparer.Default.Equals (x, y); + } + + protected virtual void Dispose (T value) + { + } + + protected JniValueMarshaler marshaler; + + protected JniValueMarshalerContractTests (JniValueMarshaler marshaler = null) + { + this.marshaler = marshaler ?? JniRuntime.CurrentRuntime.ValueManager.GetValueMarshaler (); + } + + [Test] + public void TestIsJniValueType () + { + Assert.AreEqual (IsJniValueType, marshaler.IsJniValueType); + } + + [Test] + public void CreateArgumentState () + { + if (IsJniValueType) { + var s = marshaler.CreateArgumentState (Value); + + // Note: Only valid if `Value` isn't 0, so don't do that! + Assert.AreNotEqual (new JniArgumentValue (), s.JniArgumentValue); + + // JniValueMarshaler.CreateArgumentState() for value types only + // fills out the JniArgumentValue value, nothing else. + Assert.IsFalse (s.ReferenceValue.IsValid); + Assert.IsNull (s.PeerableValue); + Assert.IsNull (s.Extra); + + marshaler.DestroyArgumentState (Value, ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + else { + var s = marshaler.CreateArgumentState (Value); + + if (s.PeerableValue != null) { + Assert.AreEqual (s.PeerableValue.PeerReference, s.ReferenceValue); + } + Assert.IsTrue (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (s.ReferenceValue), s.JniArgumentValue); + + marshaler.DestroyArgumentState (Value, ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + } + + [Test] + public void CreateGenericArgumentState () + { + if (IsJniValueType) { + var s = marshaler.CreateGenericArgumentState (Value); + + // Note: Only valid if `Value` isn't 0, so don't do that! + Assert.AreNotEqual (new JniArgumentValue (), s.JniArgumentValue); + + // JniValueMarshaler.CreateArgumentState() for value types only + // fills out the JniArgumentValue value, nothing else. + Assert.IsFalse (s.ReferenceValue.IsValid); + Assert.IsNull (s.PeerableValue); + Assert.IsNull (s.Extra); + + marshaler.DestroyGenericArgumentState (Value, ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + else { + var s = marshaler.CreateGenericArgumentState (Value); + + if (s.PeerableValue != null) { + Assert.AreEqual (s.PeerableValue.PeerReference, s.ReferenceValue); + } + Assert.IsTrue (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (s.ReferenceValue), s.JniArgumentValue); + + marshaler.DestroyGenericArgumentState (Value, ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + } + + [Test] + public void CreateObjectReferenceArgumentState_DefaultValue () + { + var s = marshaler.CreateObjectReferenceArgumentState (default (T)); + + if (IsJniValueType) { + Assert.IsTrue (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (s.ReferenceValue), s.JniArgumentValue); + } else { + Assert.IsFalse (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (), s.JniArgumentValue); + } + Assert.IsNull (s.PeerableValue); + marshaler.DestroyArgumentState (default (T), ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + + [Test] + public void CreateObjectReferenceArgumentState () + { + var s = marshaler.CreateObjectReferenceArgumentState (Value); + if (s.PeerableValue != null) { + Assert.AreEqual (s.PeerableValue.PeerReference, s.ReferenceValue); + } + Assert.IsTrue (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (s.ReferenceValue), s.JniArgumentValue); + + marshaler.DestroyArgumentState (Value, ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + + [Test] + public void CreateGenericObjectReferenceArgumentState_DefaultValue () + { + var s = marshaler.CreateGenericObjectReferenceArgumentState (default (T)); + + if (IsJniValueType) { + Assert.IsTrue (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (s.ReferenceValue), s.JniArgumentValue); + } else { + Assert.IsFalse (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (), s.JniArgumentValue); + } + Assert.IsNull (s.PeerableValue); + marshaler.DestroyGenericArgumentState (default (T), ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + + [Test] + public void CreateGenericObjectReferenceArgumentState () + { + var s = marshaler.CreateGenericObjectReferenceArgumentState (Value); + if (s.PeerableValue != null) { + Assert.AreEqual (s.PeerableValue.PeerReference, s.ReferenceValue); + } + Assert.IsTrue (s.ReferenceValue.IsValid); + Assert.AreEqual (new JniArgumentValue (s.ReferenceValue), s.JniArgumentValue); + + marshaler.DestroyGenericArgumentState (Value, ref s); + Assert.AreEqual (new JniValueMarshalerState (), s); + } + + [Test] + public void CreateValue () + { + var s = marshaler.CreateObjectReferenceArgumentState (Value); + var r = s.ReferenceValue; + var o = marshaler.CreateValue (ref r, JniObjectReferenceOptions.Copy); + Assert.IsTrue (Equals (Value, (T) o)); + if (!UsesProxy && !typeof(T).IsValueType) + Assert.AreNotSame (Value, o); + marshaler.DestroyArgumentState (Value, ref s); + + Dispose ((T) o); + } + + [Test] + public void CreateGenericValue () + { + var s = marshaler.CreateGenericObjectReferenceArgumentState (Value); + var r = s.ReferenceValue; + var o = marshaler.CreateGenericValue (ref r, JniObjectReferenceOptions.Copy); + Assert.IsTrue (Equals (Value, o)); + if (!UsesProxy && !typeof(T).IsValueType) + Assert.AreNotSame (Value, o); + marshaler.DestroyGenericArgumentState (Value, ref s); + + Dispose (o); + } + + [Test] + public void DestroyArgumentState () + { + var s = new JniValueMarshalerState (); + marshaler.DestroyArgumentState (null, ref s); + } + + [Test] + public void DestroyGenericArgumentState () + { + var s = new JniValueMarshalerState (); + marshaler.DestroyGenericArgumentState (default (T), ref s); + } + + [Test] + [RequiresUnreferencedCode ("CreateReturnValueFromManagedExpression")] + [RequiresDynamicCode ("CreateReturnValueFromManagedExpression")] + public void CreateReturnValueFromManagedExpression () + { + var runtime = Expression.Variable (typeof (JniRuntime), "__jvm"); + var value = Expression.Variable (typeof (T), "__value"); + var context = new JniValueMarshalerContext (runtime) { + LocalVariables = { + runtime, + value, + }, + }; + var ret = marshaler.CreateReturnValueFromManagedExpression (context, value); + CheckExpression (context, GetExpectedReturnValueFromManagedExpression (runtime.Name, value.Name, ret), ret); + } + + protected virtual string GetExpectedReturnValueFromManagedExpression (string jvm, string value, Expression ret) + { + var valueType = GetTypeName (typeof (T)); + var marshalerType = GetTypeName (marshaler.GetType ()); + return $@"{{ + JniRuntime {jvm}; + {valueType} {value}; + {marshalerType} {value}_marshaler; + JniValueMarshalerState {value}_state; + IntPtr {value}_val; + IntPtr {value}_rtn; + + try + {{ + {value}_marshaler = new {marshalerType}(); + {value}_state = {value}_marshaler.CreateArgumentState((object){value}, ParameterAttributes.None); + {value}_val = {value}_state.ReferenceValue.Handle; + {value}_rtn = References.NewReturnToJniRef({value}_state.ReferenceValue); + return {value}_rtn; + }} + finally + {{ + {value}_marshaler.DestroyArgumentState((object){value}, {value}_state, ParameterAttributes.None); + }} +}}"; + } + + void CheckExpression (JniValueMarshalerContext context, string expected, Expression ret) + { + var body = Expression.Block (context.CreationStatements.Concat (new[]{ ret })); + var cleanup = context.CleanupStatements.Any () + ? (Expression) Expression.Block (context.CleanupStatements.Reverse ()) + : (Expression) Expression.Empty (); + var expr = Expression.TryFinally (body, cleanup); + var block = Expression.Block (context.LocalVariables, expr); + // Convert line endings to Unix style to support building and running on different OS types. + string blockCSharp = block.ToCSharpCode (); + blockCSharp = blockCSharp.Replace ("\r\n", "\n"); + expected = expected.Replace ("\r\n", "\n"); + Console.WriteLine ("# jonp: expected: {0}", GetType ().Name); + Console.WriteLine (blockCSharp); + Assert.AreEqual (expected, blockCSharp); + } + + protected static string GetTypeName (Type type) + { + switch (type.Name) { + case "Boolean": + return "bool"; + case "Char": + return "char"; + case "Double": + return "double"; + case "Int16": + return "short"; + case "Int32": + return "int"; + case "Int64": + return "long"; + case "Object": + return "object"; + case "SByte": + return "sbyte"; + case "Single": + return "float"; + } + if (type.IsArray) { + return GetTypeName (type.GetElementType ()) + "[]"; + } + if (!type.IsGenericType) { + return type.Name; + } + var n = new System.Text.StringBuilder (); + n.Append (type.Name); + var b = type.Name.IndexOf ('`'); + n.Remove (b, type.Name.Length - b); + n.Append ("<"); + n.Append (string.Join (", ", type.GenericTypeArguments.Select (tp => GetTypeName (tp)))); + n.Append (">"); + return n.ToString (); + } + } + + [TestFixture] + public class JniValueMarshaler_String_ContractTests : JniValueMarshalerContractTests { + protected override string Value {get {return "value";}} + + protected override string GetExpectedReturnValueFromManagedExpression (string jvm, string value, Expression ret) + { + var rname = ((ParameterExpression) ret).Name; + return $@"{{ + JniRuntime {jvm}; + string {value}; + JniObjectReference {value}_ref; + IntPtr {value}_rtn; + + try + {{ + {value}_ref = Strings.NewString({value}); + {value}_rtn = References.NewReturnToJniRef({value}_ref); + return {rname}; + }} + finally + {{ + JniObjectReference.Dispose(__value_ref); + }} +}}"; + } + } + + public abstract class JniValueMarshaler_BuiltinType_ContractTests< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + T + > : JniValueMarshalerContractTests + { + protected override bool IsJniValueType {get {return true;}} + + protected override string GetExpectedReturnValueFromManagedExpression (string jvm, string value, Expression ret) + { + var valueType = GetTypeName (typeof (T)); + var rname = ((ParameterExpression) ret).Name; + return $@"{{ + JniRuntime {jvm}; + {valueType} {value}; + + try + {{ + return {rname}; + }} + finally + {{ + default(void); + }} +}}"; + } + } + + [TestFixture] + public class JniValueMarshaler_Boolean_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override bool Value {get {return true;}} + } + + [TestFixture] + public class JniValueMarshaler_SByte_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override sbyte Value {get {return (sbyte) 2;}} + } + + [TestFixture] + public class JniValueMarshaler_Char_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override char Value {get {return '3';}} + } + + [TestFixture] + public class JniValueMarshaler_Int16_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override short Value {get {return (short) 4;}} + } + + [TestFixture] + public class JniValueMarshaler_Int32_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override int Value {get {return 5;}} + } + + [TestFixture] + public class JniValueMarshaler_Int64_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override long Value {get {return 6;}} + } + + [TestFixture] + public class JniValueMarshaler_Single_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override float Value {get {return 7F;}} + } + + [TestFixture] + public class JniValueMarshaler_Double_ContractTests : JniValueMarshaler_BuiltinType_ContractTests { + protected override double Value {get {return 8D;}} + } + + [TestFixture] + [Category("LLVMIgnore")] //FIXME: https://github.com/dotnet/runtime/issues/89190 + public class JniValueMarshaler_NullableBoolean_ContractTests : JniValueMarshalerContractTests { + protected override bool? Value {get {return true;}} + } + + [TestFixture] + [Category("LLVMIgnore")] //FIXME: https://github.com/dotnet/runtime/issues/89190 + public class JniValueMarshaler_NullableSByte_ContractTests : JniValueMarshalerContractTests { + protected override sbyte? Value {get {return (sbyte) 2;}} + } + + [TestFixture] + [Category("LLVMIgnore")] //FIXME: https://github.com/dotnet/runtime/issues/89190 + public class JniValueMarshaler_NullableChar_ContractTests : JniValueMarshalerContractTests { + protected override char? Value {get {return '3';}} + } + + [TestFixture] + [Category("LLVMIgnore")] //FIXME: https://github.com/dotnet/runtime/issues/89190 + public class JniValueMarshaler_NullableInt16_ContractTests : JniValueMarshalerContractTests { + protected override short? Value {get {return (short) 4;}} + } + + [TestFixture] + public class JniValueMarshaler_NullableInt32_ContractTests : JniValueMarshalerContractTests { + protected override int? Value {get {return 5;}} + } + + [TestFixture] + public class JniValueMarshaler_NullableInt64_ContractTests : JniValueMarshalerContractTests { + protected override long? Value {get {return 6;}} + } + + [TestFixture] + public class JniValueMarshaler_NullableSingle_ContractTests : JniValueMarshalerContractTests { + protected override float? Value {get {return 7F;}} + } + + [TestFixture] + public class JniValueMarshaler_NullableDouble_ContractTests : JniValueMarshalerContractTests { + protected override double? Value {get {return 8D;}} + } + + public abstract class JniInt32ArrayValueMarshalerContractTests< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + T + > : JniValueMarshalerContractTests + where T : IEnumerable + { + protected abstract T CreateArray (int[] values); + protected abstract string ValueMarshalerSourceType {get;} + + protected override T Value { + get {return CreateArray (new[]{ 1, 2, 3 });} + } + + protected override bool Equals (T x, T y) + { + return x.SequenceEqual (y); + } + + [Test] + public unsafe void DestroyGenericArgumentState_UpdatesSource () + { + var a = CreateArray (new[]{ 1 }); + var s = marshaler.CreateGenericObjectReferenceArgumentState (a); + fixed (int *p = new[]{3}) + JniEnvironment.Arrays.SetIntArrayRegion (s.ReferenceValue, 0, 1, p); + marshaler.DestroyGenericArgumentState (a, ref s); + Assert.AreEqual (3, a.First ()); + Dispose (a); + } + + protected override void Dispose (T value) + { + var d = value as IDisposable; + if (d != null) { + d.Dispose (); + } + } + + protected override string GetExpectedReturnValueFromManagedExpression (string jvm, string value, Expression ret) + { + return $@"{{ + JniRuntime __jvm; + {ValueMarshalerSourceType} __value; + ValueMarshaler __value_marshaler; + JniValueMarshalerState __value_state; + IntPtr __value_val; + IntPtr __value_rtn; + + try + {{ + __value_marshaler = new ValueMarshaler(); + __value_state = __value_marshaler.CreateArgumentState((object)__value, ParameterAttributes.None); + __value_val = __value_state.ReferenceValue.Handle; + __value_rtn = References.NewReturnToJniRef(__value_state.ReferenceValue); + return __value_rtn; + }} + finally + {{ + __value_marshaler.DestroyArgumentState((object)__value, __value_state, ParameterAttributes.None); + }} +}}"; + } + } + + [TestFixture] + public class JniValueMarshaler_Int32Array_ContractTests : JniInt32ArrayValueMarshalerContractTests { + protected override int[] CreateArray (int[] values) {return values;} + + protected override string ValueMarshalerSourceType {get {return "int[]";}} + + [Test] + public unsafe void CreateGenericObjectReferenceArgumentState_OutParameterDoesNotCopy () + { + var a = new[]{ 1 }; + var s = marshaler.CreateGenericObjectReferenceArgumentState (a, ParameterAttributes.Out); + int v; + JniEnvironment.Arrays.GetIntArrayRegion (s.ReferenceValue, 0, 1, &v); + Assert.AreEqual (0, v); + marshaler.DestroyGenericArgumentState (a, ref s); + } + + [Test] + public unsafe void DestroyGenericArgumentState_InParameterDoesNotUpdatesSource () + { + var a = CreateArray (new[]{ 1 }); + var s = marshaler.CreateGenericObjectReferenceArgumentState (a); + fixed (int *p = new[]{3}) + JniEnvironment.Arrays.SetIntArrayRegion (s.ReferenceValue, 0, 1, p); + marshaler.DestroyGenericArgumentState (a, ref s, ParameterAttributes.In); + Assert.AreEqual (1, a.First ()); + Dispose (a); + } + } + + [TestFixture] + public class JniValueMarshaler_ListOfInt32_ContractTests : JniInt32ArrayValueMarshalerContractTests> { + protected override IList CreateArray (int[] values) {return values;} + + protected override string ValueMarshalerSourceType {get {return "IList";}} + } + + [TestFixture] + public class JniValueMarshaler_JavaArray_Int32_ContractTests : JniInt32ArrayValueMarshalerContractTests> { + protected override JavaArray CreateArray (int[] values) {return new JavaInt32Array (values);} + + protected override string ValueMarshalerSourceType {get {return "JavaArray";}} + } + + [TestFixture] + public class JniValueMarshaler_JavaPrimitiveArray_Int32_ContractTests : JniInt32ArrayValueMarshalerContractTests> { + protected override JavaPrimitiveArray CreateArray (int[] values) {return new JavaInt32Array (values);} + + protected override string ValueMarshalerSourceType {get {return "JavaPrimitiveArray";}} + } + + [TestFixture] + public class JniValueMarshaler_JavaInt32Array_ContractTests : JniInt32ArrayValueMarshalerContractTests { + protected override JavaInt32Array CreateArray (int[] values) {return new JavaInt32Array (values);} + + protected override string ValueMarshalerSourceType {get {return "JavaInt32Array";}} + } + + [TestFixture] + public class JniValueMarshaler_object_ContractTests : JniValueMarshalerContractTests { + + readonly object value = new object (); + + protected override object Value {get {return value;}} + protected override bool UsesProxy {get {return true;}} + + [Test] + public void SpecificTypesAreUsed () + { + // As a "GREF optimization", the JniValueMarshaler implementation + // will use a "nested" JniValueMarshaler for the runtime type, + // e.g. a boxed int will use JniValueMarshaler + var s = marshaler.CreateGenericObjectReferenceArgumentState (42); + Assert.AreEqual ("java/lang/Integer", JniEnvironment.Types.GetJniTypeNameFromInstance (s.ReferenceValue)); + marshaler.DestroyGenericArgumentState (42, ref s); + + // Compare to the default proxy behavior... + s = marshaler.CreateGenericObjectReferenceArgumentState (value); + Assert.AreEqual ("net/dot/jni/internal/JavaProxyObject", JniEnvironment.Types.GetJniTypeNameFromInstance (s.ReferenceValue)); + marshaler.DestroyGenericArgumentState (value, ref s); + } + } + + [TestFixture] + public class JniValueMarshaler_IJavaPeerable_ContractTests : JniValueMarshalerContractTests { + readonly IJavaPeerable value = new JavaObject (); + + protected override IJavaPeerable Value {get {return value;}} + + protected override string GetExpectedReturnValueFromManagedExpression (string jvm, string value, Expression ret) + { + var pret = (ParameterExpression) ret; + return $@"{{ + JniRuntime {jvm}; + IJavaPeerable {value}; + JniObjectReference {value}_ref; + IntPtr {value}_rtn; + + try + {{ + if (null == {value}) + {{ + return {value}_ref = new JniObjectReference(); + }} + else + {{ + return {value}_ref = (IJavaPeerable){value}.PeerReference; + }} + {value}_rtn = References.NewReturnToJniRef({value}_ref); + return {pret.Name}; + }} + finally + {{ + default(void); + }} +}}"; + } + } + + [JniValueMarshaler (typeof (DemoValueTypeValueMarshaler))] + struct DemoValueType { + public int Value {get;} + + public DemoValueType (int value) + { + Value = value; + } + } + + class DemoValueTypeValueMarshaler : JniValueMarshaler { + + JniValueMarshaler Int32Marshaler; + + public override bool IsJniValueType { + get { + return Int32Marshaler.IsJniValueType; + } + } + + public DemoValueTypeValueMarshaler () + { + Int32Marshaler = JniRuntime.CurrentRuntime.ValueManager.GetValueMarshaler (); + } + + public override DemoValueType CreateGenericValue ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + Type targetType) + { + var v = Int32Marshaler.CreateGenericValue (ref reference, options, typeof (int)); + return new DemoValueType (v); + } + + public override JniValueMarshalerState CreateGenericArgumentState (DemoValueType value, ParameterAttributes synchronize) + { + return Int32Marshaler.CreateGenericArgumentState (value.Value, synchronize); + } + + public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState (DemoValueType value, ParameterAttributes synchronize) + { + return Int32Marshaler.CreateGenericObjectReferenceArgumentState (value.Value, synchronize); + } + + public override void DestroyArgumentState (object value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + Int32Marshaler.DestroyArgumentState ((value as DemoValueType?)?.Value, ref state, synchronize); + } + + public override void DestroyGenericArgumentState (DemoValueType value, ref JniValueMarshalerState state, ParameterAttributes synchronize) + { + Int32Marshaler.DestroyGenericArgumentState (value.Value, ref state, synchronize); + } + } + + [TestFixture] + [Category ("TrimmableTypeMapUnsupported")] + class JniValueMarshaler_DemoValueType_ContractTests : JniValueMarshalerContractTests { + + protected override DemoValueType Value {get {return new DemoValueType (42);}} + protected override bool IsJniValueType {get {return true;}} + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/MethodBindingTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/MethodBindingTests.cs new file mode 100644 index 00000000000..05e8156fa91 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/MethodBindingTests.cs @@ -0,0 +1,79 @@ +using System; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ + [TestFixture] + [Category ("TrimmableTypeMapUnsupported")] + public class MethodBindingTests : JavaVMFixture + { + // + // https://bugzilla.xamarin.com/show_bug.cgi?id=17630 + // https://bugzilla.xamarin.com/show_bug.cgi?id=17750#c6 + // https://code.google.com/p/android/issues/detail?id=65710 + // + // The scenario: Assume a class hiearchy three-deep: + // CallNonvirtualBase > CallNonvirtualDerived > CallNonvirtualDerived2 + // + // Historically, "normal" binding rules/convention within Xamarin.Android + // is that if a Java class' Derived method overrides a base method + // without changing anything (visibility, return type), then the Derived + // method is not emitted. + // + // Thus consider the java CallNonvirtualDerived.method() method, which + // overrides but doesn't otherwise change CallNonvirtualBase.method(). + // Consequently, it doesn't need to be emitted, saving on IL size. + // + // Which leads us to the problem: what should the body of the "common" + // CallNonvirtualBase.Method() binding do? It needs to do EITHER a + // virtual method dispatch (invocation on non-public types) OR a + // non-virtual method dispatch (e.g. `base.Method()` invocation). + // + // THEN there are concerns about efficiency and not doing too much extra + // work within the binding methods. + // + // Which brings us to THIS scenario: CallNonvirtualBase declares method(). + // CallNonvirtualDerived overrides method(), but the override isn't + // declared within the CallNonvirtualDerived binding. Finally we have + // CallNonvirtualDerived2, which inherits CallNonvirtualDerived and + // doesn't override anything. + // + // Logically then, if we have a CallNonvirtualDerived2 instance and we + // invoke method() upon it, then we SHOULD invoke + // CallNonvirtualDerived.method(). ASSERT that this is the case. + // Failure to do so possibly results in Bug #17630/#65710, or #17750. + // + // Aside: just to get to this point we're throwing in + // JavaObject.JniThresholdType and JavaObject.JniThresholdClass. + // These likely won't survive long. + // + // Aside: in Bug #17630 terms, CallNonvirtualBase is ContextWrapper, + // CallNonvirtualDerived is Activity, and CallNonvirtualDerived2 is + // an Android Callable Wrapper/user subclass + [Test] + public void VirtualMethodBinding () + { + using (var d = new CallNonvirtualDerived ()) { + d.Method (); + Assert.IsTrue (d.MethodInvoked); + } + using (var b = new CallNonvirtualBase ()) { + b.Method (); + Assert.IsTrue (b.MethodInvoked); + } + using (CallNonvirtualBase b = new CallNonvirtualDerived ()) { + b.Method (); + Assert.IsFalse (b.MethodInvoked); + Assert.IsTrue (((CallNonvirtualDerived) b).MethodInvoked); + } + using (var d2 = new CallNonvirtualDerived2 ()) { + d2.Method (); + Assert.IsTrue (((CallNonvirtualDerived) d2).MethodInvoked); + Assert.IsFalse (((CallNonvirtualBase) d2).MethodInvoked); + } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/SelfRegistration.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/SelfRegistration.cs new file mode 100644 index 00000000000..b4e4ed3e526 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/SelfRegistration.cs @@ -0,0 +1,12 @@ +using System; + +namespace Java.InteropTests +{ + public class SelfRegistration + { + public SelfRegistration () + { + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/SelfRegistrationTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/SelfRegistrationTests.cs new file mode 100644 index 00000000000..9fbc25568f8 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/SelfRegistrationTests.cs @@ -0,0 +1,15 @@ +using NUnit.Framework; +using System; + +namespace Java.InteropTests +{ + [TestFixture ()] + public class SelfRegistrationTests + { + [Test ()] + public void TestCase () + { + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/TestType.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/TestType.cs new file mode 100644 index 00000000000..2e2314053a5 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/TestType.cs @@ -0,0 +1,211 @@ +// This really should be auto-generated, but isn't for test purposes. +using System; + +using Java.Interop; +using NUnit.Framework; + +namespace Java.InteropTests +{ +#if !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + [JniTypeSignature (TestType.JniTypeName, GenerateJavaPeer=false)] + public partial class TestType : JavaObject + { + internal const string JniTypeName = "net/dot/jni/test/TestType"; + static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (TestType)); + + [JniAddNativeMethodRegistrationAttribute] + static void RegisterNativeMembers (JniNativeMethodRegistrationArguments args) + { + args.Registrations.Add (new JniNativeMethodRegistration ("equalsThis", "(Ljava/lang/Object;)Z", GetEqualsThisHandler ())); + args.Registrations.Add (new JniNativeMethodRegistration ("getInt32Value", "()I", GetInt32ValueHandler ())); + } + + [JniAddNativeMethodRegistrationAttribute] + static void RegisterNativeMembers2 (JniNativeMethodRegistrationArguments args) + { + args.Registrations.Add (new JniNativeMethodRegistration ("getStringValue", "(I)Ljava/lang/String;", _GetStringValueHandler ())); + args.Registrations.Add (new JniNativeMethodRegistration ("methodThrows", "()V", GetMethodThrowsHandler ())); + } + + public override JniPeerMembers JniPeerMembers { + get { + return _members; + } + } + + public bool ExecutedDefaultConstructor; + + public TestType () + { + ExecutedDefaultConstructor = true; + } + + public bool ExecutedActivationConstructor; + + public TestType (ref JniObjectReference reference, JniObjectReferenceOptions transfer) + : base (ref reference, transfer) + { + ExecutedActivationConstructor = true; + } + + public static unsafe TestType NewTestType () + { + var o = _members.StaticMethods.InvokeObjectMethod ("newTestType.()Lnet/dot/jni/test/TestType;", null); + return JniEnvironment.Runtime.ValueManager.GetValue (ref o, JniObjectReferenceOptions.CopyAndDispose); + } + + public static unsafe TestType NewTestTypeWithUnboundConstructor () + { + const string id = "newTestTypeWithUnboundConstructor.()Lnet/dot/jni/test/TestType;"; + var o = _members.StaticMethods.InvokeObjectMethod (id, null); + return JniEnvironment.Runtime.ValueManager.GetValue (ref o, JniObjectReferenceOptions.CopyAndDispose); + } + + public unsafe void RunTests () + { + _members.InstanceMethods.InvokeVirtualVoidMethod ("runTests.()V", this, null); + } + + public int UpdateInt32Array (int[] value) + { + return _members.InstanceMethods.InvokeGenericVirtualInt32Method ("updateInt32Array.([I)I", this, value); + } + + public int UpdateInt32ArrayArray (int[][] value) + { + return _members.InstanceMethods.InvokeGenericVirtualInt32Method ("updateInt32ArrayArray.([[I)I", this, value); + } + + public int UpdateInt32ArrayArrayArray (int[][][] value) + { + return _members.InstanceMethods.InvokeGenericVirtualInt32Method ("updateInt32ArrayArrayArray.([[[I)I", this, value); + } + + public int Identity (int value) + { + return _members.InstanceMethods.InvokeGenericVirtualInt32Method ("identity.(I)I", this, value); + } + + public static int StaticIdentity (int value) + { + return _members.StaticMethods.InvokeGenericInt32Method ("staticIdentity.(I)I", value); + } + + public void MethodThrows () + { + throw new InvalidOperationException ("jonp: bye!"); + } + + public unsafe void PropogateException () + { + _members.InstanceMethods.InvokeVirtualVoidMethod ("propogateException.()V", this, null); + } + + public bool PropogateFinallyBlockExecuted { + get {return _members.InstanceFields.GetBooleanValue ("propogateFinallyBlockExecuted.Z", this);} + } + + static Delegate GetEqualsThisHandler () + { + EqualsThisMarshalMethod h = _EqualsThis; + return h; + } + + delegate bool EqualsThisMarshalMethod (IntPtr jnienv, IntPtr n_self, IntPtr n_value); + static bool _EqualsThis (IntPtr jnienv, IntPtr n_self, IntPtr n_value) + { + var jvm = JniEnvironment.Runtime; + var r_self = new JniObjectReference (n_self); + var self = jvm.ValueManager.GetValue(ref r_self, JniObjectReferenceOptions.CopyAndDoNotRegister); + var r_value = new JniObjectReference (n_self); + var value = jvm.ValueManager.GetValue (ref r_value, JniObjectReferenceOptions.CopyAndDoNotRegister); + + try { + return self.EqualsThis (value); + } finally { + self.DisposeUnlessReferenced (); + value.DisposeUnlessReferenced (); + } + } + + static Delegate GetInt32ValueHandler () + { + GetInt32ValueMarshalMethod h = _GetInt32Value; + return h; + } + + delegate int GetInt32ValueMarshalMethod (IntPtr jnienv, IntPtr n_self); + static int _GetInt32Value (IntPtr jnienv, IntPtr n_self) + { + var r_self = new JniObjectReference (n_self); + var self = JniEnvironment.Runtime.ValueManager.GetValue(ref r_self, JniObjectReferenceOptions.CopyAndDoNotRegister); + try { + return self.GetInt32Value (); + } finally { + self.DisposeUnlessReferenced (); + } + } + + static Delegate _GetStringValueHandler () + { + GetStringValueMarshalMethod h = GetStringValueHandler; + return h; + } + + delegate IntPtr GetStringValueMarshalMethod (IntPtr jnienv, IntPtr n_self, int value); + static IntPtr GetStringValueHandler (IntPtr jnienv, IntPtr n_self, int value) + { + var r_self = new JniObjectReference (n_self); + var self = JniEnvironment.Runtime.ValueManager.GetValue(ref r_self, JniObjectReferenceOptions.CopyAndDoNotRegister); + try { + var s = self.GetStringValue (value); + var r = JniEnvironment.Strings.NewString (s); + try { + return JniEnvironment.References.NewReturnToJniRef (r); + } finally { + JniObjectReference.Dispose (ref r); + } + } finally { + self.DisposeUnlessReferenced (); + } + } + + static Delegate GetMethodThrowsHandler () + { + MethodThrowsMarshalMethod h = MethodThrowsHandler; + return h; + } + + delegate void MethodThrowsMarshalMethod (IntPtr jnienv, IntPtr n_self); + static void MethodThrowsHandler (IntPtr jnienv, IntPtr n_self) + { + var r_self = new JniObjectReference (n_self); + var self = JniEnvironment.Runtime.ValueManager.GetValue(ref r_self, JniObjectReferenceOptions.CopyAndDoNotRegister); + try { + self.MethodThrows (); + } finally { + self.DisposeUnlessReferenced (); + } + } + + public bool EqualsThis (IJavaPeerable value) + { + Assert.IsNotNull (value); + Assert.AreNotSame (this, value); + Assert.IsTrue (JniEnvironment.Types.IsSameObject (PeerReference, value.PeerReference)); + return value != null && !object.ReferenceEquals (value, this) && + JniEnvironment.Types.IsSameObject (PeerReference, value.PeerReference); + } + + public int GetInt32Value () + { + return 42; + } + + public string GetStringValue (int value) + { + return value.ToString (); + } + } +#endif // !NO_MARSHAL_MEMBER_BUILDER_SUPPORT +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/TestTypeTests.cs b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/TestTypeTests.cs new file mode 100644 index 00000000000..b65e6f08412 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/TestTypeTests.cs @@ -0,0 +1,157 @@ +using System; +using System.Linq; + +using Java.Interop; + +using NUnit.Framework; + +namespace Java.InteropTests +{ +#if !NO_MARSHAL_MEMBER_BUILDER_SUPPORT + [TestFixture] + [Category ("TrimmableTypeMapUnsupported")] + public class TestTypeTests : JavaVMFixture + { + int lrefStartCount; + + [OneTimeSetUp] + public void StartArrayTests () + { + lrefStartCount = JniEnvironment.LocalReferenceCount; + } + + [OneTimeTearDown] + public void EndArrayTests () + { + int lref = JniEnvironment.LocalReferenceCount; + Assert.AreEqual (lrefStartCount, lref, "JNI local references"); + } + + [Test] + public void Constructor () + { + using (var t = TestType.NewTestType ()) { + Assert.IsTrue (t.ExecutedDefaultConstructor); + Assert.IsFalse (t.ExecutedActivationConstructor); + } + } + + [Test] + public void UnboundConstructor () + { + var e = Assert.Throws (() => TestType.NewTestTypeWithUnboundConstructor ()); + var ctorPrototype = + typeof (TestType).FullName + "(" + typeof (TestType).FullName + ", System.Int32)"; + Assert.IsTrue (e.Message.Contains (ctorPrototype)); + } + + [Test] + public void TestCase () + { + using (var t = new TestType ()) { + t.UnregisterFromRuntime (); + t.RunTests (); + } + } + + [Test] + public void ObjectBinding () + { + using (var b = new TestType ()) { + Console.WriteLine ("# ObjectBinding: {0}", b.ToString ()); + } + } + + [Test] + public void UpdateInt32Array () + { + using (var t = new TestType ()) { + Assert.AreEqual (-1, t.UpdateInt32Array (null)); + int[] value = new [] { 0 }; + Assert.AreEqual (1, t.UpdateInt32Array (value)); + value = new[]{ 1, 2, 3 }; + Assert.AreEqual (0, t.UpdateInt32Array (value)); + Assert.IsTrue (new[]{ 2, 4, 6 }.SequenceEqual (value)); + } + } + + [Test] + public void UpdateInt32ArrayArray () + { + using (var t = new TestType ()) { + Assert.AreEqual (-1, t.UpdateInt32ArrayArray (null)); + int[][] value = new [] { + new []{0}, + }; + Assert.AreEqual (1, t.UpdateInt32ArrayArray (value)); + value = new int[][] { + new int[] {11, 12, 13}, + new int[] {21, 22, 23}, + }; + Assert.AreEqual (0, t.UpdateInt32ArrayArray (value)); + Assert.IsTrue (new[]{ 22, 24, 26 }.SequenceEqual (value [0])); + Assert.IsTrue (new[]{ 42, 44, 46 }.SequenceEqual (value [1])); + } + } + + [Test] + public void UpdateInt32ArrayArrayArray () + { + using (var t = new TestType ()) { + Assert.AreEqual (-1, t.UpdateInt32ArrayArrayArray (null)); + int[][][] value = new [] { + new []{new[]{1}}, + }; + Assert.AreEqual (1, t.UpdateInt32ArrayArrayArray (value)); + value = new int[][][] { + new int[][] { + new int[]{111, 112, 113}, + new int[]{121, 122, 123}, + }, + new int[][] { + new int[]{211, 212, 213}, + new int[]{221, 222, 223}, + }, + }; + Assert.AreEqual (0, t.UpdateInt32ArrayArrayArray (value)); + Assert.IsTrue (new[]{ 222, 224, 226 }.SequenceEqual (value [0][0])); + Assert.IsTrue (new[]{ 242, 244, 246 }.SequenceEqual (value [0][1])); + Assert.IsTrue (new[]{ 422, 424, 426 }.SequenceEqual (value [1][0])); + Assert.IsTrue (new[]{ 442, 444, 446 }.SequenceEqual (value [1][1])); + } + } + + [Test] + public void Identity () + { + using (var t = new TestType ()) { + for (int i = 0; i < 10; ++i) + Assert.AreEqual (i, t.Identity (i)); + } + } + + [Test] + public void StaticIdentity () + { + for (int i = 0; i < 10; ++i) + Assert.AreEqual (i, TestType.StaticIdentity (i)); + } + + [Test] + public void PropogateException () + { + using (var t = new TestType ()) { + try { + Assert.IsFalse (t.PropogateFinallyBlockExecuted); + t.PropogateException (); + } catch (InvalidOperationException e) { + Assert.AreEqual ("jonp: bye!", e.Message); + Assert.IsTrue (t.PropogateFinallyBlockExecuted); + } catch (Exception e) { + Assert.Fail ("Expected InvalidOperationException; got: " + e); + } + } + } + } +#endif // !NO_MARSHAL_MEMBER_BUILDER_SUPPORT +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/AndroidInterface.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/AndroidInterface.java new file mode 100644 index 00000000000..89341a37068 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/AndroidInterface.java @@ -0,0 +1,14 @@ +package net.dot.jni.test; + +// When Android Desugaring is enabled -- the default when targeting API-25 and earlier -- +// certain Java constructs result in Java bytecode rewriting. +// Interface static methods are *moved* into $-CC types. +public interface AndroidInterface { + + // When Desugaring is enabled, this is moved to `AndroidInterface$-CC.getClassName()`, + // and the original `AndroidInterface.getClassName()` *no longer exists*. + + // public static String getClassName() { + // return "AndroidInterface"; + // } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/AnotherJavaInterfaceImpl.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/AnotherJavaInterfaceImpl.java new file mode 100644 index 00000000000..02005c388b3 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/AnotherJavaInterfaceImpl.java @@ -0,0 +1,13 @@ +package net.dot.jni.test; + +public class AnotherJavaInterfaceImpl + implements JavaInterface, Cloneable +{ + public String getValue() { + return "Another hello from Java!"; + } + + public Object clone() { + return this; + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualBase.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualBase.java new file mode 100644 index 00000000000..70d8bf705c4 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualBase.java @@ -0,0 +1,38 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class CallNonvirtualBase implements GCUserPeerable { + + static final String assemblyQualifiedName = "Java.InteropTests.CallNonvirtualBase, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public CallNonvirtualBase () { + if (CallNonvirtualBase.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + boolean methodInvoked; + public void method () { + System.out.println ("CallNonvirtualBase.method() invoked!"); + methodInvoked = true; + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualDerived.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualDerived.java new file mode 100644 index 00000000000..ebb75399704 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualDerived.java @@ -0,0 +1,40 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class CallNonvirtualDerived + extends CallNonvirtualBase + implements GCUserPeerable +{ + static final String assemblyQualifiedName = "Java.InteropTests.CallNonvirtualDerived, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public CallNonvirtualDerived () { + if (CallNonvirtualDerived.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + boolean methodInvoked; + public void method () { + System.out.println ("CallNonvirtualDerived.method() invoked!"); + methodInvoked = true; + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualDerived2.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualDerived2.java new file mode 100644 index 00000000000..b2622799a26 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallNonvirtualDerived2.java @@ -0,0 +1,34 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class CallNonvirtualDerived2 + extends CallNonvirtualDerived + implements GCUserPeerable +{ + static final String assemblyQualifiedName = "Java.InteropTests.CallNonvirtualDerived2, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public CallNonvirtualDerived2 () { + if (CallNonvirtualDerived2.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallVirtualFromConstructorBase.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallVirtualFromConstructorBase.java new file mode 100644 index 00000000000..f4660d0cb87 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallVirtualFromConstructorBase.java @@ -0,0 +1,38 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class CallVirtualFromConstructorBase implements GCUserPeerable { + + static final String assemblyQualifiedName = "Java.InteropTests.CallVirtualFromConstructorBase, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public CallVirtualFromConstructorBase (int value) { + if (CallVirtualFromConstructorBase.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "System.Int32", + value + ); + } + calledFromConstructor (value); + } + + public void calledFromConstructor (int value) { + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallVirtualFromConstructorDerived.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallVirtualFromConstructorDerived.java new file mode 100644 index 00000000000..5ae143daf1c --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CallVirtualFromConstructorDerived.java @@ -0,0 +1,47 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class CallVirtualFromConstructorDerived + extends CallVirtualFromConstructorBase + implements GCUserPeerable +{ + static { + net.dot.jni.ManagedPeer.registerNativeMembers ( + CallVirtualFromConstructorDerived.class, + ""); + } + + ArrayList managedReferences = new ArrayList(); + + public CallVirtualFromConstructorDerived (int value) { + super (value); + if (CallVirtualFromConstructorDerived.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + "(I)V", + value + ); + } + } + + public static CallVirtualFromConstructorDerived newInstance (int value) + { + return new CallVirtualFromConstructorDerived (value); + } + + public native void calledFromConstructor (int value); + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} + diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CrossReferenceBridge.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CrossReferenceBridge.java new file mode 100644 index 00000000000..a2c915bfe77 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/CrossReferenceBridge.java @@ -0,0 +1,32 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class CrossReferenceBridge implements GCUserPeerable { + + static final String assemblyQualifiedName = "Java.InteropTests.CrossReferenceBridge, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public CrossReferenceBridge () { + if (CrossReferenceBridge.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/DesugarAndroidInterface$_CC.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/DesugarAndroidInterface$_CC.java new file mode 100644 index 00000000000..b60d3e26ce0 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/DesugarAndroidInterface$_CC.java @@ -0,0 +1,8 @@ +package net.dot.jni.test; + +public class DesugarAndroidInterface$_CC { + + public static String getClassName() { + return "DesugarAndroidInterface$-CC"; + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/GetThis.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/GetThis.java new file mode 100644 index 00000000000..f3a27d02568 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/GetThis.java @@ -0,0 +1,39 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class GetThis implements GCUserPeerable { + + static { + net.dot.jni.ManagedPeer.registerNativeMembers ( + GetThis.class, + ""); + } + + ArrayList managedReferences = new ArrayList(); + + public GetThis () { + if (GetThis.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + "()V" + ); + } + } + + public final GetThis getThis() { + return this; + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/JavaInterface.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/JavaInterface.java new file mode 100644 index 00000000000..c1e55895a19 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/JavaInterface.java @@ -0,0 +1,6 @@ +package net.dot.jni.test; + +public interface JavaInterface { + + String getValue(); +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/MyJavaInterfaceImpl.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/MyJavaInterfaceImpl.java new file mode 100644 index 00000000000..3667fa0b7d5 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/MyJavaInterfaceImpl.java @@ -0,0 +1,13 @@ +package net.dot.jni.test; + +public class MyJavaInterfaceImpl + implements JavaInterface, Cloneable +{ + public String getValue() { + return "Hello from Java!"; + } + + public Object clone() { + return this; + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/ObjectHelper.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/ObjectHelper.java new file mode 100644 index 00000000000..44365ef279c --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/ObjectHelper.java @@ -0,0 +1,11 @@ +package net.dot.jni.test; + +public class ObjectHelper { + private ObjectHelper() + { + } + + public static int getHashCodeHelper (Object o) { + return o.hashCode(); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RegisterNativesTestType.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RegisterNativesTestType.java new file mode 100644 index 00000000000..e4d51a2c73e --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RegisterNativesTestType.java @@ -0,0 +1,5 @@ +package net.dot.jni.test; + +public class RegisterNativesTestType { + public native int add (int a, int b); +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassBase1.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassBase1.java new file mode 100644 index 00000000000..d843e43a7c6 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassBase1.java @@ -0,0 +1,39 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class RenameClassBase1 + implements GCUserPeerable +{ + static final String assemblyQualifiedName = "Java.InteropTests.RenameClassBase, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public RenameClassBase1 () { + System.out.println("RenameClassBase.()"); + if (RenameClassBase1.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + public int hashCode () { + System.out.println("RenameClassBase1.hashCode()"); + return 16; + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassBase2.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassBase2.java new file mode 100644 index 00000000000..562e15bff04 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassBase2.java @@ -0,0 +1,45 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class RenameClassBase2 + extends RenameClassBase1 + implements GCUserPeerable +{ + static final String assemblyQualifiedName = "Java.InteropTests.RenameClassBase, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public RenameClassBase2 () { + System.out.println("RenameClassBase.()"); + if (RenameClassBase2.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + public int hashCode () { + System.out.println("RenameClassBase2.hashCode()"); + return 32; + } + + public int myNewHashCode() { + System.out.println("RenameClassBase2.myNewHashCode()"); + return 33; + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassDerived.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassDerived.java new file mode 100644 index 00000000000..cfbe173f005 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/RenameClassDerived.java @@ -0,0 +1,45 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class RenameClassDerived + extends RenameClassBase2 // Note: does NOT match C# binding! This is "post Bytecode rewriting" + implements GCUserPeerable +{ + static final String assemblyQualifiedName = "Java.InteropTests.RenameClassDerived, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public RenameClassDerived () { + System.out.println("RenameClassDerived.()"); + if (RenameClassDerived.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + // Note: while *at runtime* `RenameClassBase1` is replaced with `RenameClassBase2`, + // Java Callable Wrapper generator doesn't know about that (yet?), and thus the + // *original* method name will be present. + // Not sure if this is actually a problem; perhaps Bytecode rewriting happens *after* + // Java Callable Wrapper generation? + public int hashCode () { + System.out.println("RenameClassDerived.hashCode()"); + return 64; + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/SelfRegistration.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/SelfRegistration.java new file mode 100644 index 00000000000..0c1367a31d7 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/SelfRegistration.java @@ -0,0 +1,32 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class SelfRegistration implements GCUserPeerable { + + static final String assemblyQualifiedName = "Java.InteropTests.SelfRegistration, Java.Interop-Tests"; + + ArrayList managedReferences = new ArrayList(); + + public SelfRegistration () { + if (SelfRegistration.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + assemblyQualifiedName, + "" + ); + } + } + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/TestType.java b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/TestType.java new file mode 100644 index 00000000000..456bef7b55b --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop-Tests/java/net/dot/jni/test/TestType.java @@ -0,0 +1,141 @@ +package net.dot.jni.test; + +import java.util.ArrayList; + +import net.dot.jni.GCUserPeerable; + +public class TestType implements GCUserPeerable { + + static { + net.dot.jni.ManagedPeer.registerNativeMembers ( + TestType.class, + ""); + } + + ArrayList managedReferences = new ArrayList(); + + public TestType () { + if (TestType.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + "()V" + ); + } + } + + // For test purposes; DO NOT provide this constructor in the TestType.cs! + public TestType (TestType a, int b) { + if (TestType.class == getClass ()) { + net.dot.jni.ManagedPeer.construct ( + this, + "(Lnet/dot/jni/test/TestType;I)V", + a, b + ); + } + } + + public void runTests () { + int n = getInt32Value (); + if (getInt32Value() != 42) + throw new Error("Expected getInt32Value()==42; got " + n + "!"); + + String s = getStringValue(64); + if (s == null || !s.equals("64")) + throw new Error("Expected getStringValue(64)==\"64\"; got " + s + "!"); + + if (!equalsThis(this)) + throw new Error("Expected equalsThis(this)==true!"); + + try { + methodThrows (); + throw new Exception ("should not be reached"); + } catch (Throwable t) { + String expected = "System.InvalidOperationException: jonp: bye!"; + String actual = t.getMessage (); + if (actual == null || !actual.startsWith (expected)) + throw new Error ("Expected message to start with '" + expected + "'! Was: " + actual); + } + } + + public int updateInt32Array (int[] array) { + if (array == null) + return -1; + for (int i = 0; i < array.length; ++i) { + if (array [i] != (i+1)*1) + return 1; + array [i] *= 2; + } + return 0; + } + + public int updateInt32ArrayArray (int[][] array) { + if (array == null) + return -1; + for (int i = 0; i < array.length; ++i) { + for (int j = 0; j < array [i].length; ++j) { + if (array [i][j] != ((i+1)*10) + ((j+1)*1)) + return 1; + array [i][j] *= 2; + } + } + return 0; + } + + public int updateInt32ArrayArrayArray (int[][][] array) + { + if (array == null) + return -1; + for (int i = 0; i < array.length; ++i) { + for (int j = 0; j < array [i].length; ++j) { + for (int k = 0; k < array [i][j].length; ++k) { + if (array [i][j][k] != ((i+1)*100) + ((j+1)*10) + (k+1)) + return 1; + array [i][j][k] *= 2; + } + } + } + return 0; + } + + public int identity (int value) { + return value; + } + + public static int staticIdentity (int value) { + return value; + } + + public boolean propogateFinallyBlockExecuted; + public void propogateException () { + try { + methodThrows (); + } finally { + propogateFinallyBlockExecuted = true; + } + } + + public static TestType newTestType () + { + return new TestType (); + } + + public static TestType newTestTypeWithUnboundConstructor () + { + return new TestType (null, 42); + } + + public native boolean equalsThis (Object value); + public native int getInt32Value (); + public native String getStringValue (int value); + public native void methodThrows (); + + public void jiAddManagedReference (java.lang.Object obj) + { + managedReferences.add (obj); + } + + public void jiClearManagedReferences () + { + managedReferences.clear (); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Enumification/ConstantEntryTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Enumification/ConstantEntryTests.cs new file mode 100644 index 00000000000..49f544ecfa3 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Enumification/ConstantEntryTests.cs @@ -0,0 +1,124 @@ +using System; +using Java.Interop.Tools.Generator.Enumification; +using NUnit.Framework; + +namespace Java.Interop.Tools.Generator_Tests +{ + public class ConstantEntryTests + { + [Test] + public void ParseEnumMapV1 () + { + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var entry = ConstantEntry.FromString (csv); + + Assert.AreEqual (ConstantAction.Enumify, entry.Action); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); + Assert.AreEqual ("5", entry.Value); + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); + Assert.AreEqual ("Cdsect", entry.EnumMember); + Assert.AreEqual (FieldAction.Keep, entry.FieldAction); + Assert.False (entry.IsFlags); + } + + [Test] + public void ParseTransientEnumMapV1 () + { + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var entry = ConstantEntry.FromString (csv, true); + + Assert.AreEqual (ConstantAction.Enumify, entry.Action); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); + Assert.AreEqual ("5", entry.Value); + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); + Assert.AreEqual ("Cdsect", entry.EnumMember); + Assert.AreEqual (FieldAction.Remove, entry.FieldAction); + Assert.False (entry.IsFlags); + } + + [Test] + public void ParseAddEnumMapV1 () + { + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,,5"; + var entry = ConstantEntry.FromString (csv); + + Assert.AreEqual (ConstantAction.Add, entry.Action); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); + Assert.AreEqual (string.Empty, entry.JavaSignature); + Assert.AreEqual ("5", entry.Value); + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); + Assert.AreEqual ("Cdsect", entry.EnumMember); + Assert.AreEqual (FieldAction.None, entry.FieldAction); + Assert.False (entry.IsFlags); + } + + [Test] + public void ParseRemoveEnumMapV1 () + { + var csv = "10,,,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var entry = ConstantEntry.FromString (csv); + + Assert.AreEqual (ConstantAction.Remove, entry.Action); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); + Assert.AreEqual ("5", entry.Value); + Assert.AreEqual (string.Empty, entry.EnumFullType); + Assert.AreEqual (string.Empty, entry.EnumMember); + Assert.AreEqual (FieldAction.Remove, entry.FieldAction); + Assert.False (entry.IsFlags); + } + + [Test] + public void ParseEnumMapV2 () + { + var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect,keep"; + var entry = ConstantEntry.FromString (csv); + + Assert.AreEqual (ConstantAction.Enumify, entry.Action); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); + Assert.AreEqual ("5", entry.Value); + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); + Assert.AreEqual ("Cdsect", entry.EnumMember); + Assert.AreEqual (FieldAction.Keep, entry.FieldAction); + Assert.False (entry.IsFlags); + Assert.IsNull (entry.DeprecatedSince); + } + + [Test] + public void ParseAddEnumMapV2 () + { + var csv = "A,10,,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect"; + var entry = ConstantEntry.FromString (csv); + + Assert.AreEqual (ConstantAction.Add, entry.Action); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); + Assert.AreEqual (string.Empty, entry.JavaSignature); + Assert.AreEqual ("5", entry.Value); + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", entry.EnumFullType); + Assert.AreEqual ("Cdsect", entry.EnumMember); + Assert.AreEqual (FieldAction.None, entry.FieldAction); + Assert.IsNull (entry.DeprecatedSince); + Assert.False (entry.IsFlags); + } + + [Test] + public void ParseRemoveEnumMapV2 () + { + var csv = "R,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,,,remove,,33"; + var entry = ConstantEntry.FromString (csv); + + Assert.AreEqual (ConstantAction.Remove, entry.Action); + Assert.AreEqual (10, entry.ApiLevel.ApiLevel); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", entry.JavaSignature); + Assert.AreEqual ("5", entry.Value); + Assert.AreEqual (string.Empty, entry.EnumFullType); + Assert.AreEqual (string.Empty, entry.EnumMember); + Assert.AreEqual (FieldAction.Remove, entry.FieldAction); + Assert.False (entry.IsFlags); + Assert.AreEqual (33, entry.DeprecatedSince?.ApiLevel ?? 0); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Java.Interop.Tools.Generator-Tests.csproj b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Java.Interop.Tools.Generator-Tests.csproj new file mode 100644 index 00000000000..658dfeb5d5f --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Java.Interop.Tools.Generator-Tests.csproj @@ -0,0 +1,26 @@ + + + + $(DotNetTargetFramework) + Java.Interop.Tools.Common_Tests + false + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Metadata/NamespaceTransformTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Metadata/NamespaceTransformTests.cs new file mode 100644 index 00000000000..7da4b2cd0a5 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Metadata/NamespaceTransformTests.cs @@ -0,0 +1,107 @@ +using System; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using NUnit.Framework; + +namespace Java.Interop.Tools.Generator_Tests +{ + public class NamespaceTransformTests + { + [Test] + public void ParseNamespaceTransform () + { + var doc = XDocument.Parse (""); + var result = NamespaceTransform.TryParse (doc.Root.Element ("ns-replace"), out var nt); + + Assert.IsTrue (result); + Assert.IsNotNull (nt); + Assert.AreEqual ("com.example", nt.OldValue); + Assert.AreEqual ("Xamarin", nt.NewValue); + } + + [Test] + public void ParseNamespaceTransform2 () + { + var doc = XDocument.Parse (""); + var result = NamespaceTransform.TryParse (doc.Root.Element ("ns-replace"), out var nt); + + Assert.IsTrue (result); + Assert.IsNotNull (nt); + Assert.AreEqual ("com.example", nt.OldValue); + Assert.AreEqual ("", nt.NewValue); + } + + [Test] + public void ParseInvalidNamespaceTransform () + { + // Logs: warning BG8A07: Invalid namespace transform '' + var doc = XDocument.Parse (""); + var result = NamespaceTransform.TryParse (doc.Root.Element ("ns-replace"), out var nt); + + Assert.IsFalse (result); + Assert.IsNull (nt); + } + + [Test] + public void ParseInvalidNamespaceTransform2 () + { + // Logs: warning BG8A07: Invalid namespace transform '' + var doc = XDocument.Parse (""); + var result = NamespaceTransform.TryParse (doc.Root.Element ("ns-replace"), out var nt); + + Assert.IsFalse (result); + Assert.IsNull (nt); + } + + [Test] + public void GetTransformedNamespace () + { + // Normal and case-insensitive + AssertTransformedNamespace ("Androidx.Core", "AndroidX.Core", new NamespaceTransform ("Androidx", "AndroidX")); + AssertTransformedNamespace ("Androidx.Core", "AndroidX.Core", new NamespaceTransform ("androidx", "AndroidX")); + + // Replace 1 level with 2 + AssertTransformedNamespace ("Androidx.Core", "Xamarin.AndroidX.Core", new NamespaceTransform ("androidx", "Xamarin.AndroidX")); + + // Replace 2 levels with 1 + AssertTransformedNamespace ("Google.Androidx.Core", "AndroidX.Core", new NamespaceTransform ("Google.Androidx", "AndroidX")); + + // Replace 2 levels with 2 + AssertTransformedNamespace ("Google.Androidx.Core", "Xamarin.AndroidX.Core", new NamespaceTransform ("Google.Androidx", "Xamarin.AndroidX")); + + // Removing a match + AssertTransformedNamespace ("Androidx.Core.Test", "Androidx.Test", new NamespaceTransform ("core", "")); + AssertTransformedNamespace ("Androidx.Core.Test", "Androidx.Core", new NamespaceTransform ("test", "")); + AssertTransformedNamespace ("Androidx.Core.Test", "Core.Test", new NamespaceTransform ("androidx", "")); + + // Multiple matches + AssertTransformedNamespace ("Androidx.Androidx.Core", "AndroidX.AndroidX.Core", new NamespaceTransform ("androidx", "AndroidX")); + AssertTransformedNamespace ("google.androidx.Core", "Xamarin.AndroidX.Core", new NamespaceTransform ("androidx", "AndroidX"), new NamespaceTransform ("google", "Xamarin")); + + // Starts with and ends with + AssertTransformedNamespace ("example", "Transformed", new NamespaceTransform (".example.", "Transformed")); + AssertTransformedNamespace ("Androidx.Core", "Transformed", new NamespaceTransform (".Androidx.Core.", "Transformed")); + AssertTransformedNamespace ("Androidx.Core", "Androidx.Core", new NamespaceTransform (".Core.", "Transformed")); + AssertTransformedNamespace ("Androidx.Core", "Androidx.Core", new NamespaceTransform (".AndroidX.", "Transformed")); + + // Starts with + AssertTransformedNamespace ("Androidx.Androidx.Core", "AndroidX2.Androidx.Core", new NamespaceTransform ("AndroidX.", "AndroidX2")); + AssertTransformedNamespace ("Androidx.Androidx.Core", "Androidx.Core", new NamespaceTransform ("AndroidX.", "")); + + // Ends with + AssertTransformedNamespace ("Androidx.Core.Core", "Androidx.Core.Core2", new NamespaceTransform (".core", "Core2")); + AssertTransformedNamespace ("Androidx.Core.Core", "Androidx.Core", new NamespaceTransform (".core", "")); + + // Only matches full level + AssertTransformedNamespace ("AndroidX.Test.Tests", "AndroidX.NewTest.Tests", new NamespaceTransform ("Test", "NewTest")); + } + + void AssertTransformedNamespace (string value, string expected, params NamespaceTransform [] transforms) + { + foreach (var nt in transforms) + value = nt.Apply (value); + + Assert.AreEqual (expected, value); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Utilities/AndroidSdkVersionTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Utilities/AndroidSdkVersionTests.cs new file mode 100644 index 00000000000..dbe107168c6 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Utilities/AndroidSdkVersionTests.cs @@ -0,0 +1,63 @@ +using System; +using Java.Interop.Tools.Generator; +using NUnit.Framework; + +namespace Java.Interop.Tools.Generator_Tests; + +[TestFixture] +public class AndroidSdkVersionTests +{ + [Test] + public void CompareTo() + { + var a = new AndroidSdkVersion (1); + var b = new AndroidSdkVersion (1); + var c = new AndroidSdkVersion (36, 1); + Assert.AreEqual (0, a.CompareTo (b), $"1 == 1"); + Assert.AreEqual (1, ((IComparable)a).CompareTo (null), $"1 < null"); + Assert.IsTrue (a.CompareTo (c) < 0, $"1 < 36.1"); + Assert.IsTrue (c.CompareTo (a) > 0, $"36.1 > 1"); + } + + [Test] + public void Operators () + { + var a = new AndroidSdkVersion (1); + var b = new AndroidSdkVersion (1); + var c = new AndroidSdkVersion (36, 1); + + Assert.IsFalse (a < b); + Assert.IsTrue (a <= b); + Assert.IsTrue (a < c); + Assert.IsTrue (a <= c); + + Assert.IsFalse (a > b); + Assert.IsTrue (a >= b); + Assert.IsTrue (c > a); + Assert.IsTrue (c >= a); + } + + [Test] + public void TryParse () + { + AndroidSdkVersion v; + Assert.IsFalse (AndroidSdkVersion.TryParse (null, out v)); + Assert.IsFalse (AndroidSdkVersion.TryParse ("", out v)); + + Assert.IsTrue (AndroidSdkVersion.TryParse ("1", out v)); + Assert.AreEqual (1, v.ApiLevel); + Assert.AreEqual (0, v.MinorRelease); + + Assert.IsTrue (AndroidSdkVersion.TryParse ("36.1", out v)); + Assert.AreEqual (36, v.ApiLevel); + Assert.AreEqual (1, v.MinorRelease); + } + + [Test] + public new void ToString () + { + Assert.AreEqual ("0", new AndroidSdkVersion (0).ToString ()); + Assert.AreEqual ("36", new AndroidSdkVersion (36).ToString ()); + Assert.AreEqual ("36.1", new AndroidSdkVersion (36, 1).ToString ()); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Utilities/NamingConverterTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Utilities/NamingConverterTests.cs new file mode 100644 index 00000000000..53c57befd72 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Generator-Tests/Utilities/NamingConverterTests.cs @@ -0,0 +1,37 @@ +using System; +using Java.Interop.Tools.Generator; +using NUnit.Framework; + +namespace Java.Interop.Tools.Generator_Tests; + +[TestFixture] +public class NamingConverterTests +{ + [Test] + public void ParseApiLevel_Exceptions () + { + Assert.Throws (() => NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-CANARY.xml.in")); + } + + [Test] + public void ParseApiLevel () + { + AndroidSdkVersion v; + + v = NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-28.xml.in"); + Assert.AreEqual (28, v.ApiLevel); + Assert.AreEqual (0, v.MinorRelease); + + v = NamingConverter.ParseApiLevel (@"…\Xamarin-Work\…\bin\BuildDebug\api\api-36.1.xml.in"); + Assert.AreEqual (36, v.ApiLevel); + Assert.AreEqual (1, v.MinorRelease); + + v = NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-36.1.xml.in"); + Assert.AreEqual (36, v.ApiLevel); + Assert.AreEqual (1, v.MinorRelease); + + v = NamingConverter.ParseApiLevel (@"..\..\bin\BuildDebug\api\api-R.xml.in"); + Assert.AreEqual (30, v.ApiLevel); + Assert.AreEqual (0, v.MinorRelease); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ActivityAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ActivityAttribute.cs new file mode 100644 index 00000000000..bda5a52e8b8 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ActivityAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Android.App +{ + sealed partial class ActivityAttribute : Attribute, Java.Interop.IJniNameProviderAttribute { + public string Name {get; set;} + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ApplicationAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ApplicationAttribute.cs new file mode 100644 index 00000000000..0e2b6477dfd --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ApplicationAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace Android.App { + sealed partial class ApplicationAttribute : Attribute, Java.Interop.IJniNameProviderAttribute { + public string Name {get; set;} + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/InstrumentationAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/InstrumentationAttribute.cs new file mode 100644 index 00000000000..4f5cd828f06 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/InstrumentationAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Android.App { + sealed partial class InstrumentationAttribute : Attribute, Java.Interop.IJniNameProviderAttribute { + public string Name { get; set; } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ServiceAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ServiceAttribute.cs new file mode 100644 index 00000000000..494f7ec5f8f --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.App/ServiceAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace Android.App { + sealed partial class ServiceAttribute : Attribute, Java.Interop.IJniNameProviderAttribute { + public string Name {get; set;} + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.Content/BroadcastReceiverAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.Content/BroadcastReceiverAttribute.cs new file mode 100644 index 00000000000..5c5dac36e8b --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.Content/BroadcastReceiverAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Android.Content { + + partial class BroadcastReceiverAttribute : Attribute, Java.Interop.IJniNameProviderAttribute { + public string Name { get; set; } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.Content/ContentProviderAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.Content/ContentProviderAttribute.cs new file mode 100644 index 00000000000..3021f14d3ea --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Android.Content/ContentProviderAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Android.Content { + + partial class ContentProviderAttribute : Attribute, Java.Interop.IJniNameProviderAttribute { + public string Name { get; set; } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj new file mode 100644 index 00000000000..e19feea8f81 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj @@ -0,0 +1,37 @@ + + + + $(DotNetTargetFramework) + false + $(DefineConstants);HAVE_CECIL;JCW_ONLY_TYPE_NAMES + $(NoWarn);CA1019;CA1813 + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/Crc64Tests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/Crc64Tests.cs new file mode 100644 index 00000000000..4685141552c --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/Crc64Tests.cs @@ -0,0 +1,84 @@ +using System.Text; +using System.Security.Cryptography; +using Java.Interop.Tools.JavaCallableWrappers; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaCallableWrappersTests +{ + [TestFixture] + public class Crc64Tests + { + static string ToHash (string value) + { + return ToHash (Encoding.UTF8.GetBytes (value)); + } + + static string ToHash (byte[] data) + { + using (var crc = new Crc64 ()) { + var hash = crc.ComputeHash (data); + var buf = new StringBuilder (hash.Length * 2); + foreach (var b in hash) + buf.AppendFormat ("{0:x2}", b); + return buf.ToString (); + } + } + + [Test] + public void Hello () + { + var actual = ToHash ("hello"); + Assert.AreEqual ("ad3d04bd697eb3c5", actual); + } + + [Test] + public void XmlDocument () + { + var actual = ToHash ("System.Xml.XmlDocument, System.Xml"); + Assert.AreEqual ("348bbd9fecf1b865", actual); + } + + [Test] + public void Collision () + { + Assert.AreNotEqual (ToHash (""), ToHash (new byte [32])); + } + + [Test] + public void AllBytesAreProcessed () + { + // Slicing processes 8 bytes (a 64-bit word) at a time, and if any of the bytes are skipped we will have a + // collision here. + string[] inputs = { + "obj/Debug/lp/10/jl/bin/classes.jar", + "obj/Debug/lp/11/jl/bin/classes.jar", + "obj/Debug/lp/12/jl/bin/classes.jar", + }; + + string[] expected = { + "419a37c9bcfddf3c", + "6ea5e242b7cc24a7", + "74770a86f8b97020", + }; + + string[] outputs = new string[inputs.Length]; + + for (int i = 0; i < inputs.Length; i++) { + byte[] bytes = Encoding.UTF8.GetBytes (inputs [i]); + using (HashAlgorithm hashAlg = new Crc64 ()) { + byte [] hash = hashAlg.ComputeHash (bytes); + outputs[i] = ToHash (hash); + Assert.AreEqual (expected[i], outputs[i], $"hash {i} differs"); + } + } + + for (int i = 0; i < outputs.Length; i++) { + for (int j = 0; j < outputs.Length; j++) { + if (j == i) + continue; + Assert.AreNotEqual (outputs[i], outputs[j], $"Outputs {i} and {j} are identical"); + } + } + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/DirectoryAssemblyResolverTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/DirectoryAssemblyResolverTests.cs new file mode 100644 index 00000000000..c2d48837f01 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/DirectoryAssemblyResolverTests.cs @@ -0,0 +1,69 @@ +using System.Diagnostics; +using System.IO; +using Java.Interop.Tools.Cecil; +using Mono.Cecil; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaCallableWrappersTests +{ + [TestFixture] + public class DirectoryAssemblyResolverTests + { + static void Log (TraceLevel level, string message) + { + TestContext.Out.WriteLine ($"{level}: {message}"); + + if (level == TraceLevel.Error) + Assert.Fail (message); + } + + static string assembly_path; + static string symbol_path; + + [OneTimeSetUp] + public static void SetUp() + { + var assembly = typeof (DirectoryAssemblyResolverTests).Assembly; + assembly_path = Path.Combine (Path.GetTempPath (), Path.GetFileName (assembly.Location)); + symbol_path = Path.ChangeExtension (assembly_path, ".pdb"); + + File.Copy (assembly.Location, assembly_path, overwrite: true); + File.Copy (Path.ChangeExtension (assembly.Location, ".pdb"), symbol_path, overwrite: true); + } + + [OneTimeTearDown] + public static void TearDown () + { + File.Delete (assembly_path); + File.Delete (symbol_path); + } + + [Test] + public void LoadSymbols ([Values (true, false)] bool loadDebugSymbols, [Values (true, false)] bool readWrite) + { + using var resolver = new DirectoryAssemblyResolver (Log, loadDebugSymbols: loadDebugSymbols, new ReaderParameters { + ReadWrite = readWrite + }); + + var assembly = resolver.Load (assembly_path); + Assert.IsNotNull (assembly); + Assert.AreEqual (loadDebugSymbols, assembly.MainModule.HasSymbols); + } + + [Test] + public void LoadSymbols_LockedPdb ([Values (true, false)] bool readWrite) + { + // Lock the PDB file exclusively so LoadSymbols will fail with IOException + using var lockStream = new FileStream (symbol_path, FileMode.Open, FileAccess.ReadWrite, FileShare.None); + + using var resolver = new DirectoryAssemblyResolver (Log, loadDebugSymbols: true, new ReaderParameters { + ReadWrite = readWrite + }); + + // Should succeed by retrying without symbols instead of throwing + var assembly = resolver.Load (assembly_path); + Assert.IsNotNull (assembly); + Assert.IsFalse (assembly.MainModule.HasSymbols); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidatorTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidatorTests.cs new file mode 100644 index 00000000000..772383627a2 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/IdentifierValidatorTests.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Java.Interop.Tools.JavaCallableWrappers; +using Java.Interop.Tools.TypeNameMappings; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaCallableWrappersTests +{ + [TestFixture] + public class IdentifierValidatorTests + { + [Test] + public void CreateValidIdentifier_Simple () + { + Assert.AreEqual ("my_identifier_test", IdentifierValidator.CreateValidIdentifier ("my-identifier$test")); + } + + [Test] + public void CreateValidIdentifier_Encoded () + { + Assert.AreEqual ("my_x45_identifier_x36_test", IdentifierValidator.CreateValidIdentifier ("my-identifier$test", true)); + Assert.AreEqual ("myidentifier_x55357__x56842_test", IdentifierValidator.CreateValidIdentifier ("myidentifier😊test", true)); + } + + [Test] + public void IsValidIdentifier () + { + Assert.IsTrue (IdentifierValidator.IsValidIdentifier ("name")); + Assert.IsTrue (IdentifierValidator.IsValidIdentifier ("Name_With_Underscores")); + + // Yes, this is "wrong" -- keywords aren't identifiers -- but the keyword check is done elsewhere. + Assert.IsTrue (IdentifierValidator.IsValidIdentifier ("true")); + + Assert.IsFalse (IdentifierValidator.IsValidIdentifier ("name-with-hyphens and spaces")); + Assert.IsFalse (IdentifierValidator.IsValidIdentifier ("123")); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs new file mode 100644 index 00000000000..1f4fcd55886 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs @@ -0,0 +1,726 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +using Mono.Cecil; + +using NUnit.Framework; + +using Java.Interop.Tools.Diagnostics; +using Java.Interop.Tools.JavaCallableWrappers; +using Java.Interop.Tools.JavaCallableWrappersTests; +using Java.Interop.Tools.TypeNameMappings; + +using Xamarin.Android.ToolsTests; +using Java.Interop.Tools.JavaCallableWrappers.Adapters; +using Java.Interop.Tools.Cecil; + +namespace Java.Interop.Tools.JavaCallableWrappersTests +{ + [TestFixture] + public class JavaCallableWrapperGeneratorTests + { + [Test] + public void ConstructorExceptions () + { + Action logger = (f, o) => { }; + + // structs aren't supported + var td = SupportDeclarations.GetTypeDefinition (typeof (int)); + var e = Assert.Throws (() => CecilImporter.CreateType (td, new TypeDefinitionCache ())); + Assert.AreEqual (4200, e.Code); + } + + [Test] + public void KotlinInvalidImplRegisterName () + { + Action logger = (f, o) => { }; + + // Contains invalid [Register] name of "foo-impl" + var td = SupportDeclarations.GetTypeDefinition (typeof (KotlinInvalidImplRegisterName)); + var e = Assert.Throws (() => CecilImporter.CreateType (td, new TypeDefinitionCache ())); + Assert.AreEqual (4217, e.Code); + } + + [Test] + public void KotlinInvalidHashRegisterName () + { + Action logger = (f, o) => { }; + + // Contains invalid [Register] name of "foo-f8k2a13" + var td = SupportDeclarations.GetTypeDefinition (typeof (KotlinInvalidHashRegisterName)); + var e = Assert.Throws (() => CecilImporter.CreateType (td, new TypeDefinitionCache ())); + Assert.AreEqual (4217, e.Code); + } + + [Test] + public void GenerateApplication ( + [Values (null, "android.app.Application", "android.support.multidex.MultiDexApplication")] string applicationJavaClass + ) + { + var actual = Generate (typeof (ApplicationName), applicationJavaClass); + var expected = $@"package application; + + +public class Name + extends {applicationJavaClass ?? "android.app.Application"} + implements + mono.android.IGCUserPeer +{{ +/** @hide */ + public static final String __md_methods; + static {{ + __md_methods = + """"; + }} + + public Name () + {{ + mono.MonoPackageManager.setContext (this); + }} + + public void onCreate () + {{ + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ApplicationName, Java.Interop.Tools.JavaCallableWrappers-Tests"", Name.class, __md_methods); + super.onCreate (); + }} + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + {{ + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + }} + + public void monodroidClearReferences () + {{ + if (refList != null) + refList.clear (); + }} +}} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateTypeMentioningNestedInvoker () + { + var actual = Generate (typeof (ApplicationName.ActivityLifecycleCallbacks)); + var expected = """ +package application; + + +public class Name_ActivityLifecycleCallbacks + extends java.lang.Object + implements + mono.android.IGCUserPeer, + java.lang.Object +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + "n_onActivityCreated:(Landroid/app/Activity;Landroid/os/Bundle;)V:GetOnActivityCreated_Landroid_app_Activity_Landroid_os_Bundle_Handler:Android.App.Application+IActivityLifecycleCallbacksInvoker, Mono.Android\n" + + ""; + mono.android.Runtime.register ("Xamarin.Android.ToolsTests.ApplicationName+ActivityLifecycleCallbacks, Java.Interop.Tools.JavaCallableWrappers-Tests", Name_ActivityLifecycleCallbacks.class, __md_methods); + } + + public void onActivityCreated (android.app.Activity p0, android.os.Bundle p1) + { + n_onActivityCreated (p0, p1); + } + + private native void n_onActivityCreated (android.app.Activity p0, android.os.Bundle p1); + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} + +"""; + Assert.AreEqual (expected, actual); + } + + static string Generate (Type type, string applicationJavaClass = null, string monoRuntimeInit = null, JavaPeerStyle style = JavaPeerStyle.XAJavaInterop1) + { + var reader_options = new CallableWrapperReaderOptions { + DefaultApplicationJavaClass = applicationJavaClass, + DefaultGenerateOnCreateOverrides = true, + DefaultMonoRuntimeInitialization = monoRuntimeInit, + }; + + var td = SupportDeclarations.GetTypeDefinition (type); + var g = CecilImporter.CreateType (td, new TypeDefinitionCache (), reader_options); + + var o = new StringWriter (); + var dir = Path.GetDirectoryName (typeof (JavaCallableWrapperGeneratorTests).Assembly.Location); + var options = new CallableWrapperWriterOptions { + CodeGenerationTarget = style, + }; + + g.Generate (Path.Combine (dir, "__o"), options); + g.Generate (o, options); + + return o.ToString (); + } + + + [Test] + public void GenerateIndirectApplication ( + [Values (null, "android.app.Application", "android.support.multidex.MultiDexApplication")] string applicationJavaClass + ) + { + var actual = Generate (typeof (IndirectApplication), applicationJavaClass); + var expected = @"package crc64197ae30a36756915; + + +public class IndirectApplication + extends application.Name + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + ""n_onCreate:()V:Application.OnCreate\n"" + + """"; + } + + public IndirectApplication () + { + mono.MonoPackageManager.setContext (this); + } + + public void onCreate () + { + n_onCreate (); + } + + private native void n_onCreate (); + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateExportedMembers () + { + var actual = Generate (typeof (ExportsMembers)); + var expected = @"package crc64197ae30a36756915; + + +public class ExportsMembers + extends java.lang.Object + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + ""n_GetInstance:()Lcrc64197ae30a36756915/ExportsMembers;:__export__\n"" + + ""n_GetValue:()Ljava/lang/String;:__export__\n"" + + ""n_staticMethodNotMangled:()V:__export__\n"" + + ""n_methodNamesNotMangled:()V:__export__\n"" + + ""n_CompletelyDifferentName:(Ljava/lang/String;I)Ljava/lang/String;:__export__\n"" + + ""n_methodThatThrows:()V:__export__\n"" + + ""n_methodThatThrowsEmptyArray:()V:__export__\n"" + + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ExportsMembers, Java.Interop.Tools.JavaCallableWrappers-Tests"", ExportsMembers.class, __md_methods); + } + + public static crc64197ae30a36756915.ExportsMembers STATIC_INSTANCE = GetInstance (); + + public java.lang.String VALUE = GetValue (); + + public static crc64197ae30a36756915.ExportsMembers GetInstance () + { + return n_GetInstance (); + } + + private static native crc64197ae30a36756915.ExportsMembers n_GetInstance (); + + public java.lang.String GetValue () + { + return n_GetValue (); + } + + private native java.lang.String n_GetValue (); + + public static void staticMethodNotMangled () + { + n_staticMethodNotMangled (); + } + + private static native void n_staticMethodNotMangled (); + + public void methodNamesNotMangled () + { + n_methodNamesNotMangled (); + } + + private native void n_methodNamesNotMangled (); + + public java.lang.String attributeOverridesNames (java.lang.String p0, int p1) + { + return n_CompletelyDifferentName (p0, p1); + } + + private native java.lang.String n_CompletelyDifferentName (java.lang.String p0, int p1); + + public void methodThatThrows () throws java.lang.Throwable + { + n_methodThatThrows (); + } + + private native void n_methodThatThrows (); + + public void methodThatThrowsEmptyArray () + { + n_methodThatThrowsEmptyArray (); + } + + private native void n_methodThatThrowsEmptyArray (); + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateInnerClass () + { + var actual = Generate (typeof (ExampleOuterClass)); + var expected = @"package crc64197ae30a36756915; + + +public class ExampleOuterClass + extends register.NonStaticOuterClass + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static final String __md_1_methods; + static { + __md_methods = + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ExampleOuterClass, Java.Interop.Tools.JavaCallableWrappers-Tests"", ExampleOuterClass.class, __md_methods); + __md_1_methods = + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ExampleOuterClass+ExampleInnerClass, Java.Interop.Tools.JavaCallableWrappers-Tests"", ExampleOuterClass_ExampleInnerClass.class, __md_1_methods); + } + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } + +public class ExampleOuterClass_ExampleInnerClass + extends register.NonStaticOuterClass.NonStaticInnerClass + implements + mono.android.IGCUserPeer +{ + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateNestedClass_DefaultName () + { + var actual = Generate (typeof (RegisterName.DefaultNestedName)); + var expected = @"package register; + + +public class Name_DefaultNestedName + extends java.lang.Object + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.RegisterName+DefaultNestedName, Java.Interop.Tools.JavaCallableWrappers-Tests"", Name_DefaultNestedName.class, __md_methods); + } + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateNestedClass_OverrideName () + { + var actual = Generate (typeof (RegisterName.OverrideNestedName)); + var expected = @"package register; + + +public class Name$Override + extends java.lang.Object + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.RegisterName+OverrideNestedName, Java.Interop.Tools.JavaCallableWrappers-Tests"", Name$Override.class, __md_methods); + } + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateConstructors () + { + var actual = Generate (typeof (ExportsConstructors)); + var expected = @"package register; + + +public class ExportsConstructors + extends java.lang.Object + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ExportsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ExportsConstructors.class, __md_methods); + } + + public ExportsConstructors () + { + super (); + if (getClass () == ExportsConstructors.class) { + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", """", this, new java.lang.Object[] { }); + } + } + + public ExportsConstructors (int p0) + { + super (p0); + if (getClass () == ExportsConstructors.class) { + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ""System.Int32, System.Private.CoreLib"", this, new java.lang.Object[] { p0 }); + } + } + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateConstructors_WithThrows () + { + var actual = Generate (typeof (ExportsThrowsConstructors)); + var expected = @"package register; + + +public class ExportsThrowsConstructors + extends java.lang.Object + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ExportsThrowsConstructors.class, __md_methods); + } + + public ExportsThrowsConstructors () throws java.lang.Throwable + { + super (); + if (getClass () == ExportsThrowsConstructors.class) { + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", """", this, new java.lang.Object[] { }); + } + } + + public ExportsThrowsConstructors (int p0) throws java.lang.Throwable + { + super (p0); + if (getClass () == ExportsThrowsConstructors.class) { + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ""System.Int32, System.Private.CoreLib"", this, new java.lang.Object[] { p0 }); + } + } + + public ExportsThrowsConstructors (java.lang.String p0) + { + super (p0); + if (getClass () == ExportsThrowsConstructors.class) { + mono.android.TypeManager.Activate (""Xamarin.Android.ToolsTests.ExportsThrowsConstructors, Java.Interop.Tools.JavaCallableWrappers-Tests"", ""System.String, System.Private.CoreLib"", this, new java.lang.Object[] { p0 }); + } + } + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateActivity () + { + var actual = Generate (typeof (ExampleActivity)); + var expected = @"package my; + + +public class ExampleActivity + extends android.app.Activity + implements + mono.android.IGCUserPeer +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + """"; + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ExampleActivity, Java.Interop.Tools.JavaCallableWrappers-Tests"", ExampleActivity.class, __md_methods); + } + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void monodroidClearReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateInstrumentation () + { + var init = "mono.MonoPackageManager.LoadApplication (context, context.getApplicationInfo (), new String[]{context.getApplicationInfo ().sourceDir});"; + var actual = Generate (typeof (ExampleInstrumentation), monoRuntimeInit: init); + var expected = $@"package my; + + +public class ExampleInstrumentation + extends android.app.Instrumentation + implements + mono.android.IGCUserPeer +{{ +/** @hide */ + public static final String __md_methods; + static {{ + __md_methods = + """"; + }} + + public void onCreate (android.os.Bundle arguments) + {{ + android.content.Context context = getContext (); + +{init} + + mono.android.Runtime.register (""Xamarin.Android.ToolsTests.ExampleInstrumentation, Java.Interop.Tools.JavaCallableWrappers-Tests"", ExampleInstrumentation.class, __md_methods); + super.onCreate (arguments); + }} + + private java.util.ArrayList refList; + public void monodroidAddReference (java.lang.Object obj) + {{ + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + }} + + public void monodroidClearReferences () + {{ + if (refList != null) + refList.clear (); + }} +}} +"; + Assert.AreEqual (expected, actual); + } + + [Test] + public void GenerateJavaInteropExample () + { + var actual = Generate (typeof (JavaInteropExample), style: JavaPeerStyle.JavaInterop1); + var expected = @"package register; + + +public class JavaInteropExample + extends java.lang.Object + implements + net.dot.jni.GCUserPeerable +{ +/** @hide */ + public static final String __md_methods; + static { + __md_methods = + ""n_Example:()V:__export__\n"" + + """"; + net.dot.jni.ManagedPeer.registerNativeMembers (JavaInteropExample.class, __md_methods); + } + + public JavaInteropExample (int p0, int p1) + { + super (); + if (getClass () == JavaInteropExample.class) { + net.dot.jni.ManagedPeer.construct (this, ""(II)V"", new java.lang.Object[] { p0, p1 }); + } + } + + public void example () + { + n_Example (); + } + + private native void n_Example (); + + private java.util.ArrayList refList; + public void jiAddManagedReference (java.lang.Object obj) + { + if (refList == null) + refList = new java.util.ArrayList (); + refList.add (obj); + } + + public void jiClearManagedReferences () + { + if (refList != null) + refList.clear (); + } +} +"; + Assert.AreEqual (expected, actual); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaNativeTypeManagerTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaNativeTypeManagerTests.cs new file mode 100644 index 00000000000..6f38eaba6a9 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/JavaNativeTypeManagerTests.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Java.Interop.Tools.TypeNameMappings; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaCallableWrappersTests +{ + [TestFixture] + public class JavaNativeTypeManagerTests + { + PackageNamingPolicy existingValue; + + [SetUp] + public void SetUp () + { + existingValue = JavaNativeTypeManager.PackageNamingPolicy; + } + + [TearDown] + public void TearDown () + { + JavaNativeTypeManager.PackageNamingPolicy = existingValue; + } + + [Test] + public void Crc64 () + { + JavaNativeTypeManager.PackageNamingPolicy = PackageNamingPolicy.LowercaseCrc64; + // System.String moved assemblies in .NET + Assert.AreEqual ("crc64d04135c992393d83", JavaNativeTypeManager.GetPackageName (typeof (string))); + } + + [Test] + public void Lowercase () + { + JavaNativeTypeManager.PackageNamingPolicy = PackageNamingPolicy.Lowercase; + Assert.AreEqual ("system", JavaNativeTypeManager.GetPackageName (typeof (string))); + } + + [Test] + public void LowercaseWithAssemblyName () + { + JavaNativeTypeManager.PackageNamingPolicy = PackageNamingPolicy.LowercaseWithAssemblyName; + // System.String moved assemblies in .NET + Assert.AreEqual ("assembly_system_private_corelib.system", JavaNativeTypeManager.GetPackageName (typeof (string))); + } + + [Test] + [TestCase (typeof (string), "java/lang/String")] + [TestCase (typeof (Type), "java/lang/Object")] + public void ToJniName (Type type, string expected) + { + string actual = JavaNativeTypeManager.ToJniName (type); + Assert.AreEqual (expected, actual); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs new file mode 100644 index 00000000000..0e6307cf00b --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Mono.Cecil; + +using Java.Interop; +using Java.Interop.Tools.Cecil; + +using Android.App; +using Android.Content; +using Android.Runtime; + +using RegisterAttribute = Android.Runtime.RegisterAttribute; + +namespace Android.App { + + [Register ("android/app/Application", DoNotGenerateAcw = true)] + class Application : Java.Lang.Object + { + [Register ("onCreate", "()V", "Application.OnCreate")] + protected virtual void OnCreate () + { + } + + [Register ("android/app/Application$ActivityLifecycleCallbacks", DoNotGenerateAcw = true)] + public partial interface IActivityLifecycleCallbacks { + [Register ( + name: "onActivityCreated", + signature: "(Landroid/app/Activity;Landroid/os/Bundle;)V", + connector: "GetOnActivityCreated_Landroid_app_Activity_Landroid_os_Bundle_Handler:Android.App.Application/IActivityLifecycleCallbacksInvoker, Mono.Android")] + void OnActivityCreated (Android.App.Activity activity, global::Android.OS.Bundle savedInstanceState); + } + + internal class IActivityLifecycleCallbacksInvoker : Java.Lang.Object, IActivityLifecycleCallbacks { + static Delegate GetOnActivityCreated_Landroid_app_Activity_Landroid_os_Bundle_Handler () + { + return null; + } + + public void OnActivityCreated (Android.App.Activity activity, global::Android.OS.Bundle savedInstanceState) + { + } + } + } + + [Register ("android/app/Activity", DoNotGenerateAcw = true)] + class Activity : Java.Lang.Object + { + [Register ("onCreate", "(Ljava/lang/Object;)V", "Activity.OnCreate")] + public virtual void OnCreate (Java.Lang.Object savedInstanceState) + { + } + } + + [Register ("android/app/Instrumentation", DoNotGenerateAcw = true)] + class Instrumentation : Java.Lang.Object + { + [Register ("onCreate", "(Ljava/lang/Object;)V", "Instrumentation.OnCreate")] + public virtual void OnCreate (Java.Lang.Object arguments) + { + } + } +} + +namespace Android.OS { + + [Register ("android/os/Bundle", DoNotGenerateAcw = true)] + class Bundle : Java.Lang.Object + { + } +} + +namespace Android.Runtime { + + interface IJavaObject + { + } +} + +namespace Java.Lang { + + [Register ("java/lang/Object", DoNotGenerateAcw = true)] + class Object : Android.Runtime.IJavaObject + { + } + + [Register ("java/lang/Throwable", DoNotGenerateAcw = true)] + class Throwable : Exception, Android.Runtime.IJavaObject + { + } +} + +namespace Xamarin.Android.ToolsTests { + + static class SupportDeclarations + { + static readonly Type [] Types = new []{ + typeof (AbstractClassInvoker), + typeof (AbstractClass), + typeof (ActivityName), + typeof (ApplicationName), + typeof (ApplicationName.ActivityLifecycleCallbacks), + typeof (DefaultName), + typeof (DefaultName.A), + typeof (DefaultName.A.B), + typeof (DefaultName.C.D), + typeof (ExampleActivity), + typeof (ExampleInstrumentation), + typeof (ExampleOuterClass), + typeof (ExampleOuterClass.ExampleInnerClass), + typeof (GlobalClass), + typeof (InstrumentationName), + typeof (NonStaticOuterClass), + typeof (NonStaticOuterClass.NonStaticInnerClass), + typeof (ProviderName), + typeof (ReceiverName), + typeof (RegisterName), + typeof (RegisterName.DefaultNestedName), + typeof (RegisterName.OverrideNestedName), + typeof (ServiceName), + }; + + public static List GetTestTypeDefinitions () + { + var a = AssemblyDefinition.ReadAssembly (typeof (DefaultName).Assembly.Location); + var r = new List (); + foreach (var t in Types) { + r.Add (GetTypeDefinition (t, a)); + } + return r; + } + + public static TypeDefinition GetTypeDefinition (Type type, AssemblyDefinition assemblyDef = null) + { + assemblyDef = assemblyDef ?? AssemblyDefinition.ReadAssembly (type.Assembly.Location); + + if (!type.IsNested) { + return assemblyDef.MainModule.FindType (type.FullName); + } + var declTypes = new Stack (); + for (var d = type; d != null; d = d.DeclaringType) { + declTypes.Push (d); + } + var def = assemblyDef.MainModule.FindType (declTypes.Pop ().FullName); + while (declTypes.Count != 0) { + var n = declTypes.Pop (); + def = def.NestedTypes.Single (nt => nt.Name == n.Name); + } + return def; + } + } + + [Register ("my.AbstractClass")] + abstract class AbstractClass : Java.Lang.Object + { + } + + [Register ("my.AbstractClass")] + class AbstractClassInvoker : AbstractClass + { + } + + [Activity (Name = "activity.Name")] + class ActivityName : Java.Lang.Object + { + } + + [Application (Name = "application.Name")] + class ApplicationName : Application + { + public class ActivityLifecycleCallbacks : Java.Lang.Object, Application.IActivityLifecycleCallbacks + { + public void OnActivityCreated (Activity activity, global::Android.OS.Bundle savedInstanceState) + { + } + } + } + + class IndirectApplication : ApplicationName + { + protected override void OnCreate () + { + base.OnCreate (); + } + } + + class DefaultName : Java.Lang.Object + { + public class A : Java.Lang.Object + { + public class B : Java.Lang.Object + { + } + } + public class C + { + public class D : Java.Lang.Object + { + } + } + } + + [Instrumentation (Name = "instrumentation.Name")] + class InstrumentationName : Java.Lang.Object + { + } + + [ContentProvider (Name = "provider.Name")] + class ProviderName : Java.Lang.Object + { + } + + [Register ("register/NonStaticOuterClass", DoNotGenerateAcw = true)] + class NonStaticOuterClass : Java.Lang.Object + { + + [Register ("register/NonStaticOuterClass$NonStaticInnerClass", DoNotGenerateAcw = true)] + public class NonStaticInnerClass : Java.Lang.Object + { + public NonStaticInnerClass (NonStaticOuterClass __self) + { + } + } + } + + class ExampleOuterClass : NonStaticOuterClass + { + public class ExampleInnerClass : NonStaticInnerClass + { + public ExampleInnerClass (ExampleOuterClass outer) + : base (outer) + { + } + } + } + + [Activity (Name = "my.ExampleActivity")] + class ExampleActivity : Activity + { + } + + [Instrumentation (Name = "my.ExampleInstrumentation")] + class ExampleInstrumentation : Instrumentation + { + } + + [BroadcastReceiver (Name = "receiver.Name")] + class ReceiverName : Java.Lang.Object + { + } + + [Register ("register.Name")] + class RegisterName : Java.Lang.Object + { + public class DefaultNestedName : Java.Lang.Object + { + } + + [Register ("register.Name$Override")] + public class OverrideNestedName : Java.Lang.Object + { + } + } + + [Register ("Kotlin.InvalidRegisterName")] + class KotlinInvalidRegisterName : Java.Lang.Object + { + [Register ("foo-impl")] + public virtual void Foo () + { + } + + [Register ("foo-f8k2a13")] + public virtual void Bar () + { + } + } + + [Register ("Kotlin.InvalidRegisterNameSubclass")] + class KotlinInvalidImplRegisterName : KotlinInvalidRegisterName + { + [Register ("foo-impl")] + public override void Foo () => base.Foo (); + } + + [Register ("Kotlin.InvalidRegisterNameSubclass")] + class KotlinInvalidHashRegisterName : KotlinInvalidRegisterName + { + [Register ("foo-f8k2a13")] + public override void Bar () => base.Foo (); + } + + [Service (Name = "service.Name")] + class ServiceName : Java.Lang.Object + { + } + + class ExportsMembers : Java.Lang.Object + { + [ExportField ("STATIC_INSTANCE")] + public static ExportsMembers GetInstance () + { + return null; + } + + [ExportField ("VALUE")] + public string GetValue () + { + return "value"; + } + + [Export] + public static void staticMethodNotMangled () + { + } + + [Export] + public void methodNamesNotMangled () + { + } + + [Export ("attributeOverridesNames")] + public string CompletelyDifferentName (string value, int count) + { + return value; + } + + [Export (Throws = new [] { typeof (Java.Lang.Throwable) })] + public void methodThatThrows() + { + } + + [Export (Throws = new Type [0])] + public void methodThatThrowsEmptyArray () + { + } + } + + [Register ("register.ExportsConstructors")] + class ExportsConstructors : Java.Lang.Object + { + [Export] + public ExportsConstructors () { } + + [Export] + public ExportsConstructors (int value) { } + } + + [Register ("register.ExportsThrowsConstructors")] + class ExportsThrowsConstructors : Java.Lang.Object + { + [Export (Throws = new [] { typeof (Java.Lang.Throwable) })] + public ExportsThrowsConstructors () { } + + [Export (Throws = new [] { typeof (Java.Lang.Throwable) })] + public ExportsThrowsConstructors (int value) { } + + [Export (Throws = new Type [0])] + public ExportsThrowsConstructors (string value) { } + } + + [JniTypeSignature ("register/JavaInteropExample")] + class JavaInteropExample : Java.Lang.Object { + + + [JavaCallableConstructor(SuperConstructorExpression="")] + public JavaInteropExample (int a, int b) {} + + [JavaCallable ("example")] + public void Example () {} + } +} + +[Register (nameof (GlobalClass))] +class GlobalClass : Java.Lang.Object +{ +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGeneratorTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGeneratorTests.cs new file mode 100644 index 00000000000..1f6f764ec59 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGeneratorTests.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; + +using Mono.Cecil; + +using NUnit.Framework; + +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Diagnostics; +using Java.Interop.Tools.JavaCallableWrappers; + +using Android.App; +using Android.Runtime; +using Android.Content; + +namespace Xamarin.Android.ToolsTests +{ + [TestFixture] + public class TypeNameMapGeneratorTests + { + [Test] + public void ConstructorExceptions () + { + Action logger = (f, o) => { }; + Action nullLogger = null; + Action levelLogger = (l, v) => { }; + Action nullLevelLogger = null; +#pragma warning disable 0618 + Assert.Throws (() => new TypeNameMapGenerator ((string []) null, levelLogger)); + Assert.Throws (() => new TypeNameMapGenerator ((TypeDefinition []) null, levelLogger)); + Assert.Throws (() => new TypeNameMapGenerator (new string [0], nullLevelLogger)); + Assert.Throws (() => new TypeNameMapGenerator (new TypeDefinition [0], nullLevelLogger)); + Assert.Throws (() => new TypeNameMapGenerator ((string []) null, logger)); + Assert.Throws (() => new TypeNameMapGenerator ((TypeDefinition []) null, logger)); + Assert.Throws (() => new TypeNameMapGenerator (new string [0], nullLogger)); + Assert.Throws (() => new TypeNameMapGenerator (new TypeDefinition [0], nullLogger)); +#pragma warning restore 0618 + } + + [Test] + public void WriteJavaToManaged () + { + var types = SupportDeclarations.GetTestTypeDefinitions (); + var v = new TypeNameMapGenerator (types, logger: Diagnostic.CreateConsoleLogger (), cache: null); + var o = new MemoryStream (); + v.WriteJavaToManaged (o); + var a = ToArray (o); + Save (a, "__j2m"); + var length = 193; + var offset = 76; + var e = + "version=1\u0000" + + $"entry-count={types.Count - 1}\u0000" + + "entry-len=" + length + "\u0000" + + "value-offset=" + offset + "\u0000" + + GetJ2MEntryLine (typeof (GlobalClass), "GlobalClass", offset, length) + + GetJ2MEntryLine (typeof (ActivityName), "activity/Name", offset, length) + + GetJ2MEntryLine (typeof (ApplicationName), "application/Name", offset, length) + + GetJ2MEntryLine (typeof (ApplicationName.ActivityLifecycleCallbacks), "application/Name_ActivityLifecycleCallbacks", offset, length) + + GetJ2MEntryLine (typeof (DefaultName), "crc64197ae30a36756915/DefaultName", offset, length) + + GetJ2MEntryLine (typeof (DefaultName.A), "crc64197ae30a36756915/DefaultName_A", offset, length) + + GetJ2MEntryLine (typeof (DefaultName.A.B), "crc64197ae30a36756915/DefaultName_A_B", offset, length) + + GetJ2MEntryLine (typeof (DefaultName.C.D), "crc64197ae30a36756915/DefaultName_C_D", offset, length) + + GetJ2MEntryLine (typeof (ExampleOuterClass), "crc64197ae30a36756915/ExampleOuterClass", offset, length) + + GetJ2MEntryLine (typeof (ExampleOuterClass.ExampleInnerClass), "crc64197ae30a36756915/ExampleOuterClass$ExampleOuterClass_ExampleInnerClass", offset, length) + + GetJ2MEntryLine (typeof (InstrumentationName), "instrumentation/Name", offset, length) + + GetJ2MEntryLine (typeof (AbstractClass), "my/AbstractClass", offset, length) + + GetJ2MEntryLine (typeof (ExampleActivity), "my/ExampleActivity", offset, length) + + GetJ2MEntryLine (typeof (ExampleInstrumentation), "my/ExampleInstrumentation", offset, length) + + GetJ2MEntryLine (typeof (ProviderName), "provider/Name", offset, length) + + GetJ2MEntryLine (typeof (ReceiverName), "receiver/Name", offset, length) + + GetJ2MEntryLine (typeof (RegisterName), "register/Name", offset, length) + + GetJ2MEntryLine (typeof (RegisterName.OverrideNestedName), "register/Name$Override", offset, length) + + GetJ2MEntryLine (typeof (RegisterName.DefaultNestedName), "register/Name_DefaultNestedName", offset, length) + + GetJ2MEntryLine (typeof (NonStaticOuterClass), "register/NonStaticOuterClass", offset, length) + + GetJ2MEntryLine (typeof (NonStaticOuterClass.NonStaticInnerClass), "register/NonStaticOuterClass$NonStaticInnerClass", offset, length) + + GetJ2MEntryLine (typeof (ServiceName), "service/Name", offset, length) + + "\u0000"; + var ex = Encoding.UTF8.GetBytes (e); + Save (ex, "__j2m.ex"); + CollectionAssert.AreEqual (ex, a); + } + + static void Save (byte [] data, string path) + { + var dir = Path.GetDirectoryName (typeof (TypeNameMapGeneratorTests).Assembly.Location); + using (var o = File.OpenWrite (Path.Combine (dir, path))) { + o.Write (data, 0, data.Length); + } + } + + static byte [] ToArray (MemoryStream stream) + { + stream.Position = 0; + var r = new byte [stream.Length]; + Array.Copy (stream.GetBuffer (), r, r.Length); + return r; + } + + static string GetJ2MEntryLine (Type type, string jniName, int offset, int length) + { + return GetEntryPart (jniName, offset) + GetEntryPart (GetTypeName (type), length - offset); + } + + static string GetEntryPart (string value, int length) + { + return value + new string ('\u0000', length - value.Length); + } + + [Test] + public void WriteManagedToJavaWithNoTypes () + { + var v = new TypeNameMapGenerator (new string[0], logger: Diagnostic.CreateConsoleLogger (), cache: null); + var o = new MemoryStream (); + v.WriteManagedToJava (o); + var a = ToArray (o); + Assert.AreEqual (52, a.Length); + } + + [Test] + public void WriteManagedToJava () + { + var types = SupportDeclarations.GetTestTypeDefinitions (); + var v = new TypeNameMapGenerator (types, logger: Diagnostic.CreateConsoleLogger (), cache: null); + var o = new MemoryStream (); + v.WriteManagedToJava (o); + var a = ToArray (o); + Save (a, "__m2j"); + var length = 193; + var offset = 117; + var e = + "version=1\u0000" + + $"entry-count={types.Count}\u0000" + + "entry-len=" + length + "\u0000" + + "value-offset=" + offset + "\u0000" + + GetM2JEntryLine (typeof (GlobalClass), "GlobalClass", offset, length) + + GetM2JEntryLine (typeof (AbstractClass), "my/AbstractClass", offset, length) + + GetM2JEntryLine (typeof (AbstractClassInvoker), "my/AbstractClass", offset, length) + + GetM2JEntryLine (typeof (ActivityName), "activity/Name", offset, length) + + GetM2JEntryLine (typeof (ApplicationName.ActivityLifecycleCallbacks), "application/Name_ActivityLifecycleCallbacks", offset, length) + + GetM2JEntryLine (typeof (ApplicationName), "application/Name", offset, length) + + GetM2JEntryLine (typeof (DefaultName.A.B), "crc64197ae30a36756915/DefaultName_A_B", offset, length) + + GetM2JEntryLine (typeof (DefaultName.A), "crc64197ae30a36756915/DefaultName_A", offset, length) + + GetM2JEntryLine (typeof (DefaultName.C.D), "crc64197ae30a36756915/DefaultName_C_D", offset, length) + + GetM2JEntryLine (typeof (DefaultName), "crc64197ae30a36756915/DefaultName", offset, length) + + GetM2JEntryLine (typeof (ExampleActivity), "my/ExampleActivity", offset, length) + + GetM2JEntryLine (typeof (ExampleInstrumentation), "my/ExampleInstrumentation", offset, length) + + GetM2JEntryLine (typeof (ExampleOuterClass.ExampleInnerClass), "crc64197ae30a36756915/ExampleOuterClass$ExampleOuterClass_ExampleInnerClass", offset, length) + + GetM2JEntryLine (typeof (ExampleOuterClass), "crc64197ae30a36756915/ExampleOuterClass", offset, length) + + GetM2JEntryLine (typeof (InstrumentationName), "instrumentation/Name", offset, length) + + GetM2JEntryLine (typeof (NonStaticOuterClass.NonStaticInnerClass), "register/NonStaticOuterClass$NonStaticInnerClass", offset, length) + + GetM2JEntryLine (typeof (NonStaticOuterClass), "register/NonStaticOuterClass", offset, length) + + GetM2JEntryLine (typeof (ProviderName), "provider/Name", offset, length) + + GetM2JEntryLine (typeof (ReceiverName), "receiver/Name", offset, length) + + GetM2JEntryLine (typeof (RegisterName.DefaultNestedName), "register/Name_DefaultNestedName", offset, length) + + GetM2JEntryLine (typeof (RegisterName.OverrideNestedName), "register/Name$Override", offset, length) + + GetM2JEntryLine (typeof (RegisterName), "register/Name", offset, length) + + GetM2JEntryLine (typeof (ServiceName), "service/Name", offset, length) + + "\u0000"; + var ex = Encoding.UTF8.GetBytes (e); + Save (ex, "__m2j.ex"); + CollectionAssert.AreEqual (ex, a); + } + + static string GetM2JEntryLine (Type type, string jniName, int offset, int length) + { + return GetEntryPart (GetTypeName (type), offset) + GetEntryPart (jniName, length - offset); + } + + static string GetTypeName (Type type) + { + return type.FullName + ", " + type.Assembly.GetName ().Name; + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/XmlImporterTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/XmlImporterTests.cs new file mode 100644 index 00000000000..6486045ae7b --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers/XmlImporterTests.cs @@ -0,0 +1,144 @@ +using System.IO; +using System.Xml.Linq; +using Java.Interop.Tools.JavaCallableWrappers.Adapters; +using Java.Interop.Tools.TypeNameMappings; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaCallableWrappersTests +{ + [TestFixture] + public class XmlImporterTests + { + PackageNamingPolicy existingValue; + + [SetUp] + public void SetUp () + { + existingValue = JavaNativeTypeManager.PackageNamingPolicy; + JavaNativeTypeManager.PackageNamingPolicy = PackageNamingPolicy.LowercaseCrc64; + } + + [TearDown] + public void TearDown () + { + JavaNativeTypeManager.PackageNamingPolicy = existingValue; + } + + [Test] + public void ImportType_EmptyPackage_GeneratesCrc64Package () + { + // Simulate the case where [Register("CustomView")] is used without a package prefix + // The XML has an empty package attribute, and we expect XmlImporter to generate a crc64 package + var xml = XElement.Parse (@" + + + + "); + + var type = XmlImporter.ImportType (xml); + + // The generated package should be "crc64" + crc64hash of "MyApp.Views:MyApp.Android" + Assert.AreEqual ("crc64b8e52a012da2d805", type.Package); + Assert.AreEqual ("CustomView", type.Name); + } + + [Test] + public void ImportType_EmptyPackage_NestedType_GeneratesCrc64Package () + { + // Simulate the case with a nested type + var xml = XElement.Parse (@" + + + + "); + + var type = XmlImporter.ImportType (xml); + + // The generated package should be based on "MyApp.Views:MyApp.Android" (ignoring nested type part) + Assert.AreEqual ("crc64b8e52a012da2d805", type.Package); + Assert.AreEqual ("InnerView", type.Name); + } + + [Test] + public void ImportType_MissingPackageAttribute_GeneratesCrc64Package () + { + // Simulate the case where the package attribute is completely missing + var xml = XElement.Parse (@" + + + + "); + + var type = XmlImporter.ImportType (xml); + + // The generated package should be "crc64" + crc64hash of "MyApp.Views:MyApp.Android" + Assert.AreEqual ("crc64b8e52a012da2d805", type.Package); + } + + [Test] + public void ImportType_WithPackage_UsesProvidedPackage () + { + // Ensure that when a package is provided, it is used directly + var xml = XElement.Parse (@" + + + + "); + + var type = XmlImporter.ImportType (xml); + + Assert.AreEqual ("my.custom.package", type.Package); + } + + [Test] + public void ImportType_NoNamespace_ReturnsEmptyPackage () + { + // When there's no namespace in the type name, we can't generate a package + var xml = XElement.Parse (@" + + + + "); + + var type = XmlImporter.ImportType (xml); + + // Without a namespace, we can't generate a crc64 package, so it should remain empty + Assert.AreEqual ("", type.Package); + } + + [Test] + public void ImportType_XamarinAndroidToolsTests_MatchesExpectedCrc64 () + { + // This test verifies the crc64 generation matches what JavaNativeTypeManager would generate + // Based on the test data in JavaCallableWrapperGeneratorTests, namespace "Xamarin.Android.ToolsTests" + // with assembly "Java.Interop.Tools.JavaCallableWrappers-Tests" should produce crc64197ae30a36756915 + var xml = XElement.Parse (@" + + + + "); + + var type = XmlImporter.ImportType (xml); + + // This should match the expected crc64 from JavaCallableWrapperGeneratorTests + Assert.AreEqual ("crc64197ae30a36756915", type.Package); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.cs new file mode 100644 index 00000000000..8b8c7d0f676 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.cs @@ -0,0 +1,21 @@ +#nullable enable +using System; + +namespace Java.Interop { + + [AttributeUsage (AttributeTargets.Method, AllowMultiple=false)] + public sealed class JavaCallableAttribute : Attribute { + + public JavaCallableAttribute () + { + } + + public JavaCallableAttribute (string? name) + { + Name = name; + } + + public string? Name {get; private set;} + public string? Signature {get; set;} + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.cs new file mode 100644 index 00000000000..23370d4cb02 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.cs @@ -0,0 +1,16 @@ +#nullable enable +using System; + +namespace Java.Interop { + + [AttributeUsage (AttributeTargets.Constructor, AllowMultiple=false)] + public sealed class JavaCallableConstructorAttribute : Attribute { + + public JavaCallableConstructorAttribute () + { + } + + public string? SuperConstructorExpression {get; set;} + public string? Signature {get; set;} + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/Java.Interop.Tools.JavaSource-Tests.csproj b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/Java.Interop.Tools.JavaSource-Tests.csproj new file mode 100644 index 00000000000..82cd2ad3543 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/Java.Interop.Tools.JavaSource-Tests.csproj @@ -0,0 +1,25 @@ + + + + $(DotNetTargetFramework) + False + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/JavaStubParserTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/JavaStubParserTests.cs new file mode 100644 index 00000000000..92ea2b77934 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/JavaStubParserTests.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; + +using NUnit.Framework; + +using Java.Interop.Tools.JavaSource; +using Xamarin.Android.Tools.ApiXmlAdjuster; + +namespace Java.Interop.Tools.JavaSource.Tests +{ + [TestFixture] + public class JavaStubParserTests + { + [Test] + public void TryParse_EmptySource () + { + var parser = new JavaStubParser (); + var package = parser.TryParse (""); + Assert.IsNotNull (package); + Assert.AreEqual (null, package.Name); + Assert.AreEqual (0, package.Types.Count); + } + + [Test] + public void TryParse_SimpleClass () + { + var parser = new JavaStubParser (); + var package = parser.TryParse (@" +class Example { + public static void m (String text) { + } +} +"); + Assert.IsNotNull (package); + Assert.AreEqual (null, package.Name); + Assert.AreEqual (1, package.Types.Count); + + var Example_Type = package.AllTypes.First (); + Assert.AreEqual ("Example", Example_Type.FullName); + + Assert.AreEqual (1, Example_Type.Members.Count); + var Example_m = Example_Type.Members [0] as JavaMethod; + Assert.IsNotNull (Example_m); + Assert.AreEqual ("m", Example_m.Name); + Assert.AreEqual ("void", Example_m.Return); + Assert.AreEqual (1, Example_m.Parameters.Count); + Assert.AreEqual ("String", Example_m.Parameters [0].Type); + Assert.AreEqual ("text", Example_m.Parameters [0].Name); + } + } +} + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.BlockTagsBnfTermsTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.BlockTagsBnfTermsTests.cs new file mode 100644 index 00000000000..ae4f3af4be9 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.BlockTagsBnfTermsTests.cs @@ -0,0 +1,187 @@ +using System; +using System.Linq; +using System.Xml.Linq; + +using NUnit.Framework; + +using Java.Interop.Tools.JavaSource; + +using Irony; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource.Tests +{ + [TestFixture] + public class SourceJavadocToXmldocGrammarBlockTagsBnfTermsTests : SourceJavadocToXmldocGrammarFixture { + + [Test] + public void ApiSinceDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.ApiSinceDeclaration); + + var r = p.Parse ("@apiSince 3\n"); + Assert.IsFalse (r.HasErrors (), "@apiSince: " + DumpMessages (r, p)); + Assert.AreEqual ("Added in API level 3.", r.Root.AstNode.ToString ()); + } + + [Test] + public void DeprecatedDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.DeprecatedDeclaration); + + var r = p.Parse ("@deprecated Insert reason here.\n"); + Assert.IsFalse (r.HasErrors (), "@deprecated: " + DumpMessages (r, p)); + Assert.AreEqual ("This member is deprecated. Insert reason here.", r.Root.AstNode.ToString ()); + } + + [Test] + public void DeprecatedSinceDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.DeprecatedSinceDeclaration); + + var r = p.Parse ("@deprecatedSince 3\n"); + Assert.IsFalse (r.HasErrors (), "@deprecatedSince: " + DumpMessages (r, p)); + Assert.AreEqual ("This member was deprecated in API level 3.", r.Root.AstNode.ToString ()); + } + + [Test] + public void ExceptionDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.ExceptionDeclaration); + + var r = p.Parse ("@exception Throwable Just Because.\n"); + Assert.IsFalse (r.HasErrors (), "@exception: " + DumpMessages (r, p)); + Assert.IsNull (r.Root.AstNode, "@exception should be ignored, but node was not null."); + // TODO: Re-enable when we can generate valid crefs + //Assert.AreEqual ("Just Because.", r.Root.AstNode.ToString ()); + } + + [Test] + public void InheritDocDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.InheritDocDeclaration); + + var r = p.Parse ("@inheritDoc"); + Assert.IsFalse (r.HasErrors (), "@inheritDoc: " + DumpMessages (r, p)); + // TODO: Enable after adding support for @inheritDoc + Assert.IsNull (r.Root.AstNode, "@inheritDoc should be ignored, but node was not null."); + + r = p.Parse ("@inheritDoc With extra"); + Assert.IsFalse (r.HasErrors (), "@inheritDoc with trailing content " + DumpMessages (r, p)); + // TODO: Enable after adding support for @inheritDoc + Assert.IsNull (r.Root.AstNode, "@inheritDoc with trailing content should be ignored, but node was not null."); + } + + [Test] + public void HideDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.HideDeclaration); + + var r = p.Parse ("@hide"); + Assert.IsFalse (r.HasErrors (), "@hide: " + DumpMessages (r, p)); + Assert.IsNull (r.Root.AstNode, "@hide should be ignored, but node was not null."); + r = p.Parse ("@hide Method is broken"); + Assert.IsFalse (r.HasErrors (), "@hide with trailing content: " + DumpMessages (r, p)); + Assert.IsNull (r.Root.AstNode, "@hide with trailing content should be ignored, but node was not null."); + } + + [Test] + public void ParamDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.ParamDeclaration); + + var r = p.Parse ("@param a Insert description here\nand here."); + Assert.IsFalse (r.HasErrors (), "@param: " + DumpMessages (r, p)); + Assert.AreEqual ($"Insert description here{Environment.NewLine}and here.", r.Root.AstNode.ToString ()); + + r = p.Parse ("@param b"); + Assert.IsFalse (r.HasErrors (), "name only @param: " + DumpMessages (r, p)); + Assert.AreEqual ("b", r.Root.AstNode.ToString ()); + } + + [Test] + public void ReturnDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.ReturnDeclaration); + + var r = p.Parse ("@return insert description here"); + Assert.IsFalse (r.HasErrors (), "single-line @return: " + DumpMessages (r, p)); + Assert.AreEqual ("insert description here", r.Root.AstNode.ToString ()); + + r = p.Parse ("@return line 1\n\tline two"); + Assert.IsFalse (r.HasErrors (), "multi-line @return: " + DumpMessages (r, p)); + Assert.AreEqual ("line 1\n\tline two".Replace ("\n", Environment.NewLine), + r.Root.AstNode.ToString ()); + } + + [Test] + public void ReturnDeclaration_WithInlineTags () + { + var p = CreateParser (g => g.BlockTagsTerms.ReturnDeclaration); + + var r = p.Parse ("@return {@code text} here."); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("\n text here.".Replace ("\n", Environment.NewLine), + r.Root.AstNode.ToString ()); + } + + [Test] + public void SeeDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.SeeDeclaration); + + var r = p.Parse ("@see \"Insert Book Name Here\""); + Assert.IsFalse (r.HasErrors (), "@see: " + DumpMessages (r, p)); + Assert.IsNull (r.Root.AstNode, "@see should be ignored, but node was not null."); + // TODO: Re-enable when we can generate valid crefs + //Assert.AreEqual ("", r.Root.AstNode.ToString ()); + } + + [Test] + public void SinceDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.SinceDeclaration); + + var r = p.Parse ("@since Insert Version Here"); + Assert.IsFalse (r.HasErrors (), "@since: " + DumpMessages (r, p)); + Assert.AreEqual ("Added in Insert Version Here.", r.Root.AstNode.ToString ()); + } + + [Test] + public void ThrowsDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.ThrowsDeclaration); + + var r = p.Parse ("@throws Throwable the {@code Exception} raised by this method"); + Assert.IsFalse (r.HasErrors (), "{@code} @throws: " + DumpMessages (r, p)); + Assert.IsNull (r.Root.AstNode, "@throws should be ignored, but node with code block was not null."); + // TODO: Re-enable when we can generate valid crefs + //Assert.AreEqual ("the Exception raised by this method", r.Root.AstNode.ToString ()); + + r = p.Parse ("@throws Throwable something or other!"); + Assert.IsFalse (r.HasErrors (), " @throws: " + DumpMessages (r, p)); + Assert.IsNull (r.Root.AstNode, "@throws should be ignored, but node with was not null."); + // TODO: Re-enable when we can generate valid crefs + //Assert.AreEqual ("something or other!", r.Root.AstNode.ToString ()); + + r = p.Parse ("@throws android.content.ActivityNotFoundException"); + Assert.IsFalse (r.HasErrors (), "name only @throws: " + DumpMessages (r, p)); + // TODO: Re-enable when we can generate valid crefs + Assert.IsNull (r.Root.AstNode, "@throws should be ignored, but name only node was not null."); + } + + [Test] + public void UnknownTagDeclaration () + { + var p = CreateParser (g => g.BlockTagsTerms.UnknownTagDeclaration); + + var r = p.Parse ("@this-is-not-supported something {@code foo} else."); + Assert.IsFalse (r.HasErrors (), "@this-is-not-supported: " + DumpMessages (r, p)); + Assert.AreEqual (null, r.Root.AstNode); + + r = p.Parse ("@standalonetag"); + Assert.IsFalse (r.HasErrors (), "@standalonetag: " + DumpMessages (r, p)); + Assert.AreEqual (null, r.Root.AstNode); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.HtmlBnfTermsTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.HtmlBnfTermsTests.cs new file mode 100644 index 00000000000..5f5061f2daa --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.HtmlBnfTermsTests.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Text; + +using NUnit.Framework; + +using Java.Interop.Tools.JavaSource; + +using Irony; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource.Tests +{ + [TestFixture] + public class SourceJavadocToXmldocGrammarHtmlBnfTermsTests : SourceJavadocToXmldocGrammarFixture { + + [Test] + public void PBlockDeclaration () + { + var p = CreateParser (g => g.HtmlTerms.PBlockDeclaration); + + var r = p.Parse ("

paragraph text\nand more!"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("paragraph text\nand more!".Replace ("\n", Environment.NewLine), + r.Root.AstNode.ToString ()); + + r = p.Parse ("

r= {@code Object} and following {@literal AC} text

"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("r= Object and following A<B>C text", r.Root.AstNode.ToString ()); + + r = p.Parse("

r= unknown text"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("r= <em>unknown</em> text", r.Root.AstNode.ToString ()); + + r = p.Parse ("

For

  • A Device Owner"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("For <li>A Device Owner", r.Root.AstNode.ToString ()); + } + + [Test] + public void PreBlockDeclaration () + { + var p = CreateParser (g => g.HtmlTerms.PreBlockDeclaration); + + var r = p.Parse ("
    this @contains  text.
    "); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("this @contains <arbitrary/> text.", + r.Root.AstNode.ToString ()); + + r = p.Parse ("
    ColorSpace cs = ColorSpace.get(ColorSpace.Named.DCI_P3);");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ($"ColorSpace cs = ColorSpace.get(ColorSpace.Named.DCI_P3);",
    +					r.Root.AstNode.ToString ());
    +		}
    +
    +		[Test]
    +		public void HyperLinkDeclaration ()
    +		{
    +			var p = CreateParser (g => g.HtmlTerms.InlineHyperLinkDeclaration);
    +
    +			var r = p.Parse ("application");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("application",
    +					r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax",
    +					r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("field classification");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("field classification", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("here");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("here", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("libphonenumber");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("libphonenumber", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse (" broken");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual (" broken", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("nobody");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("nobody", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("\nProgress & activity");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ($"{Environment.NewLine}Progress & activity",
    +					r.Root.AstNode.ToString ());
    +		}
    +
    +		[Test]
    +		public void CodeElementDeclaration ()
    +		{
    +			var p = CreateParser (g => g.HtmlTerms.CodeElementDeclaration);
    +
    +			var r = p.Parse ("input.position()");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("input.position()", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("null");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("null", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("android:label=\"@string/resolve_title\"");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("android:label=\"@string/resolve_title\"", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("Activity.RESULT_OK");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("Activity.RESULT_OK", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse ("format.setString(MediaFormat.KEY_FRAME_RATE, null)");
    +			Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
    +			Assert.AreEqual ("format.setString(MediaFormat.KEY_FRAME_RATE, null)", r.Root.AstNode.ToString ());
    +
    +			r = p.Parse (@"
    +

    [ 0, 0, 0, 0, 0 ] +

    [ 0, 0, 0, 0, 0 ] +

    [ 0, 0, 1, 0, 0 ] +

    [ 0, 0, 0, 0, 0 ] +

    [ 0, 0, 0, 0, 0 ] +"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual (@" +<p> [ 0, 0, 0, 0, 0 ] +<p> [ 0, 0, 0, 0, 0 ] +<p> [ 0, 0, 1, 0, 0 ] +<p> [ 0, 0, 0, 0, 0 ] +<p> [ 0, 0, 0, 0, 0 ] +", r.Root.AstNode.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.InlineTagsBnfTermsTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.InlineTagsBnfTermsTests.cs new file mode 100644 index 00000000000..35076a3b69f --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.InlineTagsBnfTermsTests.cs @@ -0,0 +1,112 @@ +using System; +using System.Linq; +using System.Xml.Linq; + +using NUnit.Framework; + +using Java.Interop.Tools.JavaSource; + +using Irony; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource.Tests +{ + [TestFixture] + public class SourceJavadocToXmldocGrammarInlineTagsBnfTermsTests : SourceJavadocToXmldocGrammarFixture { + + [Test] + public void CodeDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.CodeDeclaration); + + var r = p.Parse ("{@code Object}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("Object", r.Root.AstNode.ToString ()); + } + + [Test] + public void DocRootDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.DocRootDeclaration); + + var r = p.Parse ("{@docRoot}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual (DocRootPrefixExpected, r.Root.AstNode.ToString ()); + } + + [Test] + public void InheritDocDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.InheritDocDeclaration); + + var r = p.Parse ("{@inheritDoc}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("To be added", r.Root.AstNode.ToString ()); + } + + [Test] + public void LinkDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.LinkDeclaration); + + var r = p.Parse ("{@link #ctor}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + var c = (XElement) r.Root.AstNode; + Assert.AreEqual ("#ctor", c.ToString (SaveOptions.DisableFormatting)); + } + + [Test] + public void LinkplainDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.LinkplainDeclaration); + + var r = p.Parse ("{@linkplain #ctor}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("#ctor", r.Root.AstNode.ToString ()); + } + + [Test] + public void LiteralDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.LiteralDeclaration); + + var r = p.Parse ("{@literal AC}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("A<B>C", r.Root.AstNode.ToString ()); + } + + [Test] + public void SeeDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.SeeDeclaration); + + var r = p.Parse ("{@see #cancelNotification(String, String, int)}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("#cancelNotification(String, String, int)", r.Root.AstNode.ToString ()); + } + + [Test] + public void ValueDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.ValueDeclaration); + + var r = p.Parse ("{@value}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("To be added", r.Root.AstNode.ToString ()); + + r = p.Parse ("{@value #field}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("#field", r.Root.AstNode.ToString ()); + } + + [Test] + public void InlineParamDeclaration () + { + var p = CreateParser (g => g.InlineTagsTerms.InlineParamDeclaration); + + var r = p.Parse ("{@param phoneNumberString}"); + Assert.IsFalse (r.HasErrors (), DumpMessages (r, p)); + Assert.AreEqual ("phoneNumberString", r.Root.AstNode.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammarFixture.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammarFixture.cs new file mode 100644 index 00000000000..3362db412f2 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammarFixture.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Text; + +using NUnit.Framework; + +using Java.Interop.Tools.JavaSource; + +using Irony; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource.Tests +{ + [TestFixture] + public class SourceJavadocToXmldocGrammarFixture { + + protected const string DocRootPrefixActual = "https://developer.android.com"; + protected const string DocRootPrefixExpected = DocRootPrefixActual + "/"; + + public static Parser CreateParser (Func root) + { + var g = new SourceJavadocToXmldocGrammar (new XmldocSettings { + Style = XmldocStyle.Full, + DocRootValue = DocRootPrefixActual, + }) + { + LanguageFlags = LanguageFlags.Default | LanguageFlags.CreateAst, + }; + g.Root = root (g); + return new Parser (g) { + Context = { + TracingEnabled = true, + } + }; + } + + public static string DumpMessages (ParseTree tree, Parser parser) + { + var lines = GetLines (tree.SourceText); + var message = new StringBuilder (); + message.AppendLine ("ParserMessages:"); + foreach (var m in tree.ParserMessages) { + message.AppendLine ($" {m.Level} {m.Location}: {m.Message}"); + message.AppendLine (lines [m.Location.Line]); + message.Append (" "); + message.Append (new string (' ', m.Location.Column)); + message.Append ("^"); + message.AppendLine (); + } + message.AppendLine ("ParserTrace:"); + foreach (var t in parser.Context.ParserTrace) { + message.AppendLine ($" input=`{t.Input}`; error? {t.IsError}; message={t.Message}"); + } + return message.ToString (); + } + + static List GetLines (string text) + { + var lines = new List(); + var reader = new StringReader (text); + string line; + while ((line = reader.ReadLine()) != null) { + lines.Add (line); + } + return lines; + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocParserTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocParserTests.cs new file mode 100644 index 00000000000..a586f744d4d --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocParserTests.cs @@ -0,0 +1,842 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Text; + +using NUnit.Framework; + +using Java.Interop.Tools.JavaSource; + +using Irony; +using Irony.Parsing; + +namespace Java.Interop.Tools.JavaSource.Tests +{ + [TestFixture] + public class SourceJavadocToXmldocParserTests : SourceJavadocToXmldocGrammarFixture { + + [Test, TestCaseSource (nameof (TryParse_Success))] + public void TryParse (ParseResult parseResult) + { + ParseTree parseTree; + var p = new SourceJavadocToXmldocParser (new XmldocSettings { + Style = XmldocStyle.Full, + DocRootValue = DocRootPrefixActual, + }); + var n = p.TryParse (parseResult.Javadoc, null, out parseTree); + Assert.IsFalse (parseTree.HasErrors (), DumpMessages (parseTree, p)); + Assert.AreEqual (parseResult.FullXml, GetMemberXml (n), $"while parsing input: ```{parseResult.Javadoc}```"); + + p = new SourceJavadocToXmldocParser (new XmldocSettings { + Style = XmldocStyle.IntelliSense, + DocRootValue = DocRootPrefixActual, + }); + n = p.TryParse (parseResult.Javadoc, null, out parseTree); + Assert.IsFalse (parseTree.HasErrors (), DumpMessages (parseTree, p)); + Assert.AreEqual (parseResult.IntelliSenseXml, GetMemberXml (n), $"while parsing input: ```{parseResult.Javadoc}```"); + } + + static string GetMemberXml (IEnumerable members) + { + var e = new XElement ("member", members); + return e.ToString (); + } + + public static readonly ParseResult[] TryParse_Success = new ParseResult[]{ + new ParseResult { + Javadoc = "Summary.\n\nP2.\n\n

    Hello!

    ", + FullXml = @" + Summary. + + Summary. + P2. + Hello! + +", + IntelliSenseXml = @" + Summary. +", + }, + new ParseResult { + Javadoc = "The inline {@code code} tag should work for summary info.", + FullXml = @" + The inline code tag should work for summary info. + + The inline code tag should work for summary info. + +", + IntelliSenseXml = @" + The inline code tag should work for summary info. +", + }, + new ParseResult { + Javadoc = "@return {@code true} if something\n or other; otherwise {@code false}.", + FullXml = @" + + true if something + or other; otherwise false. +", + IntelliSenseXml = @" + + true if something + or other; otherwise false. +", + }, + new ParseResult { + Javadoc = "@return {@code true} if something else @return {@code false}.", + FullXml = @" + + true if something else false. +", + IntelliSenseXml = @" + + true if something else false. +", + }, + new ParseResult { + Javadoc = @"This is the summary sentence. Insert +more description here. + +What about soft paragraphs? + +

    What about hard paragraphs? + +@param a something +@param b +@param c +@see #method() +@apiSince 1 +", + FullXml = @" + something + b + c +

    This is the summary sentence. + + This is the summary sentence. Insert +more description here. + What about soft paragraphs? + What about hard paragraphs? + Added in API level 1. + +", + IntelliSenseXml = @" + something + b + c + This is the summary sentence. +", + }, + new ParseResult { + Javadoc = "Summary.\n\n

    Paragraph.

    foo @bar baz
    ", + FullXml = @" + Summary. + + Summary. + Paragraph. + foo @bar baz + +", + IntelliSenseXml = @" + Summary. +", + }, + new ParseResult { + Javadoc = "Something {@link #method}: description, \"declaration\" or

    some content

    .\n\n@apiSince 1\n", + FullXml = @" + Something #method: description, ""declaration"" or <pre><p>some content</pre></p>. + + Something #method: description, ""declaration"" or <pre><p>some content</pre></p>. + Added in API level 1. + +", + IntelliSenseXml = @" + Something #method: description, ""declaration"" or <pre><p>some content</pre></p>. +", + }, + new ParseResult { + Javadoc = @"The result code will be Activity.RESULT_OK for success, + or one of these errors: + RESULT_ERROR_GENERIC_FAILURE", + FullXml = @" + The result code will be Activity.RESULT_OK for success, + or one of these errors: + RESULT_ERROR_GENERIC_FAILURE + + The result code will be Activity.RESULT_OK for success, + or one of these errors: + RESULT_ERROR_GENERIC_FAILURE + +", + IntelliSenseXml = @" + The result code will be Activity.RESULT_OK for success, + or one of these errors: + RESULT_ERROR_GENERIC_FAILURE +", + }, + new ParseResult { + // @jls is currently not supported; should be handled by @unknown-tag & ignored. + Javadoc = "Summary.\n\n@jls 1.2\n", + FullXml = @" + Summary. + + Summary. + +", + IntelliSenseXml = @" + Summary. +", + }, + new ParseResult { + // @jls is currently not supported; should be handled by @unknown-tag & ignored. + Javadoc = "Summary.\n\n@throws Throwable insert description here.\n", + FullXml = @" + Summary. + + Summary. + +", + IntelliSenseXml = @" + Summary. +", + }, + new ParseResult { + Javadoc = @"See accept(2). Insert +more description {e.g. something} here. Include @ character. +How about another link accept(2) +@param manifest The value of the {@code +android:versionCode} manifest attribute. See {@param empty}. +@param empty +@param options Additional options. +See {@link foo()} +bar()} for more details. +@return the return value +", + FullXml = $@" + The value of the android:versionCode manifest attribute. See empty. + empty + Additional options. +See foo() +bar()}} for more details. + See accept(2). + + See accept(2). Insert +more description {{e.g. something}} here. Include @ character. +How about another link accept(2) + + the return value +", + IntelliSenseXml = $@" + The value of the android:versionCode manifest attribute. See empty. + empty + Additional options. +See foo() +bar()}} for more details. + See accept(2). + the return value +", + }, + new ParseResult { + Javadoc = "Summary with broken {@link AccessibilityService#takeScreenshot(int, Executor, Consumer) link.", + FullXml = @" + Summary with broken AccessibilityService#takeScreenshot(int, Executor, Consumer) link. + + Summary with broken AccessibilityService#takeScreenshot(int, Executor, Consumer) link. + +", + IntelliSenseXml = @" + Summary with broken AccessibilityService#takeScreenshot(int, Executor, Consumer) link. +", + }, + }; + + public class ParseResult { + public string Javadoc; + public string FullXml; + public string IntelliSenseXml; + } + + [Test] + public void ParseActivityDoc () + { + ParseTree parseTree; + var p = new SourceJavadocToXmldocParser (new XmldocSettings { + Style = XmldocStyle.Full, + DocRootValue = DocRootPrefixActual, + }); + p.TryParse (activityJavaDoc, null, out parseTree); + Assert.IsFalse (parseTree.HasErrors (), DumpMessages (parseTree, p)); + } + + string activityJavaDoc = @"An activity is a single, focused thing that the user can do. Almost all + activities interact with the user, so the Activity class takes care of + creating a window for you in which you can place your UI with + {@link #setContentView}. While activities are often presented to the user + as full-screen windows, they can also be used in other ways: as floating + windows (via a theme with {@link android.R.attr#windowIsFloating} set), + + Multi-Window mode or embedded into other windows. + + There are two methods almost all subclasses of Activity will implement: + +
      +
    • {@link #onCreate} is where you initialize your activity. Most + importantly, here you will usually call {@link #setContentView(int)} + with a layout resource defining your UI, and using {@link #findViewById} + to retrieve the widgets in that UI that you need to interact with + programmatically. + +
    • {@link #onPause} is where you deal with the user pausing active + interaction with the activity. Any changes made by the user should at + this point be committed (usually to the + {@link android.content.ContentProvider} holding the data). In this + state the activity is still visible on screen. +
    + +

    To be of use with {@link android.content.Context#startActivity Context.startActivity()}, all + activity classes must have a corresponding + {@link android.R.styleable#AndroidManifestActivity <activity>} + declaration in their package's AndroidManifest.xml.

    + +

    Topics covered here: +

      +
    1. Fragments +
    2. Activity Lifecycle +
    3. Configuration Changes +
    4. Starting Activities and Getting Results +
    5. Saving Persistent State +
    6. Permissions +
    7. Process Lifecycle +
    + +
    +

    Developer Guides

    +

    The Activity class is an important part of an application's overall lifecycle, + and the way activities are launched and put together is a fundamental + part of the platform's application model. For a detailed perspective on the structure of an + Android application and how activities behave, please read the + Application Fundamentals and + Tasks and Back Stack + developer guides.

    + +

    You can also find a detailed discussion about how to create activities in the + Activities + developer guide.

    +
    + + +

    Fragments

    + +

    The {@link androidx.fragment.app.FragmentActivity} subclass + can make use of the {@link androidx.fragment.app.Fragment} class to better + modularize their code, build more sophisticated user interfaces for larger + screens, and help scale their application between small and large screens.

    + +

    For more information about using fragments, read the + Fragments developer guide.

    + + +

    Activity Lifecycle

    + +

    Activities in the system are managed as + + activity stacks. When a new activity is started, it is usually placed on the top of the + current stack and becomes the running activity -- the previous activity always remains + below it in the stack, and will not come to the foreground again until + the new activity exits. There can be one or multiple activity stacks visible + on screen.

    + +

    An activity has essentially four states:

    +
      +
    • If an activity is in the foreground of the screen (at the highest position of the topmost + stack), it is active or running. This is usually the activity that the + user is currently interacting with.
    • +
    • If an activity has lost focus but is still presented to the user, it is visible. + It is possible if a new non-full-sized or transparent activity has focus on top of your + activity, another activity has higher position in multi-window mode, or the activity + itself is not focusable in current windowing mode. Such activity is completely alive (it + maintains all state and member information and remains attached to the window manager). +
    • If an activity is completely obscured by another activity, + it is stopped or hidden. It still retains all state and member + information, however, it is no longer visible to the user so its window is hidden + and it will often be killed by the system when memory is needed elsewhere.
    • +
    • The system can drop the activity from memory by either asking it to finish, + or simply killing its process, making it destroyed. When it is displayed again + to the user, it must be completely restarted and restored to its previous state.
    • +
    + +

    The following diagram shows the important state paths of an Activity. + The square rectangles represent callback methods you can implement to + perform operations when the Activity moves between states. The colored + ovals are major states the Activity can be in.

    + +

    + +

    There are three key loops you may be interested in monitoring within your + activity: + +

      +
    • The entire lifetime of an activity happens between the first call + to {@link android.app.Activity#onCreate} through to a single final call + to {@link android.app.Activity#onDestroy}. An activity will do all setup + of ""global"" state in onCreate(), and release all remaining resources in + onDestroy(). For example, if it has a thread running in the background + to download data from the network, it may create that thread in onCreate() + and then stop the thread in onDestroy(). + +
    • The visible lifetime of an activity happens between a call to + {@link android.app.Activity#onStart} until a corresponding call to + {@link android.app.Activity#onStop}. During this time the user can see the + activity on-screen, though it may not be in the foreground and interacting + with the user. Between these two methods you can maintain resources that + are needed to show the activity to the user. For example, you can register + a {@link android.content.BroadcastReceiver} in onStart() to monitor for changes + that impact your UI, and unregister it in onStop() when the user no + longer sees what you are displaying. The onStart() and onStop() methods + can be called multiple times, as the activity becomes visible and hidden + to the user. + +
    • The foreground lifetime of an activity happens between a call to + {@link android.app.Activity#onResume} until a corresponding call to + {@link android.app.Activity#onPause}. During this time the activity is + in visible, active and interacting with the user. An activity + can frequently go between the resumed and paused states -- for example when + the device goes to sleep, when an activity result is delivered, when a new + intent is delivered -- so the code in these methods should be fairly + lightweight. +
    + +

    The entire lifecycle of an activity is defined by the following + Activity methods. All of these are hooks that you can override + to do appropriate work when the activity changes state. All + activities will implement {@link android.app.Activity#onCreate} + to do their initial setup; many will also implement + {@link android.app.Activity#onPause} to commit changes to data and + prepare to pause interacting with the user, and {@link android.app.Activity#onStop} + to handle no longer being visible on screen. You should always + call up to your superclass when implementing these methods.

    + +

    +
    +  public class Activity extends ApplicationContext {
    +      protected void onCreate(Bundle savedInstanceState);
    +  
    +      protected void onStart();
    +  
    +      protected void onRestart();
    +  
    +      protected void onResume();
    +  
    +      protected void onPause();
    +  
    +      protected void onStop();
    +  
    +      protected void onDestroy();
    +  }
    +  
    + +

    In general the movement through an activity's lifecycle looks like + this:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Method Description Killable? Next
    {@link android.app.Activity#onCreate onCreate()}Called when the activity is first created. + This is where you should do all of your normal static set up: + create views, bind data to lists, etc. This method also + provides you with a Bundle containing the activity's previously + frozen state, if there was one. +

    Always followed by onStart().

    NoonStart()
        {@link android.app.Activity#onRestart onRestart()}Called after your activity has been stopped, prior to it being + started again. +

    Always followed by onStart()

    NoonStart()
    {@link android.app.Activity#onStart onStart()}Called when the activity is becoming visible to the user. +

    Followed by onResume() if the activity comes + to the foreground, or onStop() if it becomes hidden.

    NoonResume() or onStop()
        {@link android.app.Activity#onResume onResume()}Called when the activity will start + interacting with the user. At this point your activity is at + the top of its activity stack, with user input going to it. +

    Always followed by onPause().

    NoonPause()
    {@link android.app.Activity#onPause onPause()}Called when the activity loses foreground state, is no longer focusable or before + transition to stopped/hidden or destroyed state. The activity is still visible to + user, so it's recommended to keep it visually active and continue updating the UI. + Implementations of this method must be very quick because + the next activity will not be resumed until this method returns. +

    Followed by either onResume() if the activity + returns back to the front, or onStop() if it becomes + invisible to the user.

    Pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB}onResume() or
    + onStop()
    {@link android.app.Activity#onStop onStop()}Called when the activity is no longer visible to the user. This may happen either + because a new activity is being started on top, an existing one is being brought in + front of this one, or this one is being destroyed. This is typically used to stop + animations and refreshing the UI, etc. +

    Followed by either onRestart() if + this activity is coming back to interact with the user, or + onDestroy() if this activity is going away.

    YesonRestart() or
    + onDestroy()
    {@link android.app.Activity#onDestroy onDestroy()}The final call you receive before your + activity is destroyed. This can happen either because the + activity is finishing (someone called {@link Activity#finish} on + it), or because the system is temporarily destroying this + instance of the activity to save space. You can distinguish + between these two scenarios with the {@link + Activity#isFinishing} method.Yesnothing
    + +

    Note the ""Killable"" column in the above table -- for those methods that + are marked as being killable, after that method returns the process hosting the + activity may be killed by the system at any time without another line + of its code being executed. Because of this, you should use the + {@link #onPause} method to write any persistent data (such as user edits) + to storage. In addition, the method + {@link #onSaveInstanceState(Bundle)} is called before placing the activity + in such a background state, allowing you to save away any dynamic instance + state in your activity into the given Bundle, to be later received in + {@link #onCreate} if the activity needs to be re-created. + See the Process Lifecycle + section for more information on how the lifecycle of a process is tied + to the activities it is hosting. Note that it is important to save + persistent data in {@link #onPause} instead of {@link #onSaveInstanceState} + because the latter is not part of the lifecycle callbacks, so will not + be called in every situation as described in its documentation.

    + +

    Be aware that these semantics will change slightly between + applications targeting platforms starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB} + vs. those targeting prior platforms. Starting with Honeycomb, an application + is not in the killable state until its {@link #onStop} has returned. This + impacts when {@link #onSaveInstanceState(Bundle)} may be called (it may be + safely called after {@link #onPause()}) and allows an application to safely + wait until {@link #onStop()} to save persistent state.

    + +

    For applications targeting platforms starting with + {@link android.os.Build.VERSION_CODES#P} {@link #onSaveInstanceState(Bundle)} + will always be called after {@link #onStop}, so an application may safely + perform fragment transactions in {@link #onStop} and will be able to save + persistent state later.

    + +

    For those methods that are not marked as being killable, the activity's + process will not be killed by the system starting from the time the method + is called and continuing after it returns. Thus an activity is in the killable + state, for example, between after onStop() to the start of + onResume(). Keep in mind that under extreme memory pressure the + system can kill the application process at any time.

    + + +

    Configuration Changes

    + +

    If the configuration of the device (as defined by the + {@link Configuration Resources.Configuration} class) changes, + then anything displaying a user interface will need to update to match that + configuration. Because Activity is the primary mechanism for interacting + with the user, it includes special support for handling configuration + changes.

    + +

    Unless you specify otherwise, a configuration change (such as a change + in screen orientation, language, input devices, etc) will cause your + current activity to be destroyed, going through the normal activity + lifecycle process of {@link #onPause}, + {@link #onStop}, and {@link #onDestroy} as appropriate. If the activity + had been in the foreground or visible to the user, once {@link #onDestroy} is + called in that instance then a new instance of the activity will be + created, with whatever savedInstanceState the previous instance had generated + from {@link #onSaveInstanceState}.

    + +

    This is done because any application resource, + including layout files, can change based on any configuration value. Thus + the only safe way to handle a configuration change is to re-retrieve all + resources, including layouts, drawables, and strings. Because activities + must already know how to save their state and re-create themselves from + that state, this is a convenient way to have an activity restart itself + with a new configuration.

    + +

    In some special cases, you may want to bypass restarting of your + activity based on one or more types of configuration changes. This is + done with the {@link android.R.attr#configChanges android:configChanges} + attribute in its manifest. For any types of configuration changes you say + that you handle there, you will receive a call to your current activity's + {@link #onConfigurationChanged} method instead of being restarted. If + a configuration change involves any that you do not handle, however, the + activity will still be restarted and {@link #onConfigurationChanged} + will not be called.

    + + +

    Starting Activities and Getting Results

    + +

    The {@link android.app.Activity#startActivity} + method is used to start a + new activity, which will be placed at the top of the activity stack. It + takes a single argument, an {@link android.content.Intent Intent}, + which describes the activity + to be executed.

    + +

    Sometimes you want to get a result back from an activity when it + ends. For example, you may start an activity that lets the user pick + a person in a list of contacts; when it ends, it returns the person + that was selected. To do this, you call the + {@link android.app.Activity#startActivityForResult(Intent, int)} + version with a second integer parameter identifying the call. The result + will come back through your {@link android.app.Activity#onActivityResult} + method.

    + +

    When an activity exits, it can call + {@link android.app.Activity#setResult(int)} + to return data back to its parent. It must always supply a result code, + which can be the standard results RESULT_CANCELED, RESULT_OK, or any + custom values starting at RESULT_FIRST_USER. In addition, it can optionally + return back an Intent containing any additional data it wants. All of this + information appears back on the + parent's Activity.onActivityResult(), along with the integer + identifier it originally supplied.

    + +

    If a child activity fails for any reason (such as crashing), the parent + activity will receive a result with the code RESULT_CANCELED.

    + +
    +  public class MyActivity extends Activity {
    +      ...
    +  
    +      static final int PICK_CONTACT_REQUEST = 0;
    +  
    +      public boolean onKeyDown(int keyCode, KeyEvent event) {
    +          if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
    +              // When the user center presses, let them pick a contact.
    +              startActivityForResult(
    +                  new Intent(Intent.ACTION_PICK,
    +                  new Uri(""content://contacts"")),
    +                  PICK_CONTACT_REQUEST);
    +             return true;
    +          }
    +          return false;
    +      }
    +  
    +      protected void onActivityResult(int requestCode, int resultCode,
    +              Intent data) {
    +          if (requestCode == PICK_CONTACT_REQUEST) {
    +              if (resultCode == RESULT_OK) {
    +                  // A contact was picked.  Here we will just display it
    +                  // to the user.
    +                  startActivity(new Intent(Intent.ACTION_VIEW, data));
    +              }
    +          }
    +      }
    +  }
    +  
    + + +

    Saving Persistent State

    + +

    There are generally two kinds of persistent state that an activity + will deal with: shared document-like data (typically stored in a SQLite + database using a {@linkplain android.content.ContentProvider content provider}) + and internal state such as user preferences.

    + +

    For content provider data, we suggest that activities use an + ""edit in place"" user model. That is, any edits a user makes are effectively + made immediately without requiring an additional confirmation step. + Supporting this model is generally a simple matter of following two rules:

    + +
      +
    • When creating a new document, the backing database entry or file for + it is created immediately. For example, if the user chooses to write + a new email, a new entry for that email is created as soon as they + start entering data, so that if they go to any other activity after + that point this email will now appear in the list of drafts.

      +
    • When an activity's onPause() method is called, it should + commit to the backing content provider or file any changes the user + has made. This ensures that those changes will be seen by any other + activity that is about to run. You will probably want to commit + your data even more aggressively at key times during your + activity's lifecycle: for example before starting a new + activity, before finishing your own activity, when the user + switches between input fields, etc.

      +
    + +

    This model is designed to prevent data loss when a user is navigating + between activities, and allows the system to safely kill an activity (because + system resources are needed somewhere else) at any time after it has been + stopped (or paused on platform versions before {@link android.os.Build.VERSION_CODES#HONEYCOMB}). + Note this implies that the user pressing BACK from your activity does not + mean ""cancel"" -- it means to leave the activity with its current contents + saved away. Canceling edits in an activity must be provided through + some other mechanism, such as an explicit ""revert"" or ""undo"" option.

    + +

    See the {@linkplain android.content.ContentProvider content package} for + more information about content providers. These are a key aspect of how + different activities invoke and propagate data between themselves.

    + +

    The Activity class also provides an API for managing internal persistent state + associated with an activity. This can be used, for example, to remember + the user's preferred initial display in a calendar (day view or week view) + or the user's default home page in a web browser.

    + +

    Activity persistent state is managed + with the method {@link #getPreferences}, + allowing you to retrieve and + modify a set of name/value pairs associated with the activity. To use + preferences that are shared across multiple application components + (activities, receivers, services, providers), you can use the underlying + {@link Context#getSharedPreferences Context.getSharedPreferences()} method + to retrieve a preferences + object stored under a specific name. + (Note that it is not possible to share settings data across application + packages -- for that you will need a content provider.)

    + +

    Here is an excerpt from a calendar activity that stores the user's + preferred view mode in its persistent settings:

    + +
    +  public class CalendarActivity extends Activity {
    +      ...
    +  
    +      static final int DAY_VIEW_MODE = 0;
    +      static final int WEEK_VIEW_MODE = 1;
    +  
    +      private SharedPreferences mPrefs;
    +      private int mCurViewMode;
    +  
    +      protected void onCreate(Bundle savedInstanceState) {
    +          super.onCreate(savedInstanceState);
    +  
    +          mPrefs = getSharedPreferences(getLocalClassName(), MODE_PRIVATE);
    +          mCurViewMode = mPrefs.getInt(""view_mode"", DAY_VIEW_MODE);
    +      }
    +  
    +      protected void onPause() {
    +          super.onPause();
    +  
    +          SharedPreferences.Editor ed = mPrefs.edit();
    +          ed.putInt(""view_mode"", mCurViewMode);
    +          ed.commit();
    +      }
    +  }
    +  
    + + +

    Permissions

    + +

    The ability to start a particular Activity can be enforced when it is + declared in its + manifest's {@link android.R.styleable#AndroidManifestActivity <activity>} + tag. By doing so, other applications will need to declare a corresponding + {@link android.R.styleable#AndroidManifestUsesPermission <uses-permission>} + element in their own manifest to be able to start that activity. + +

    When starting an Activity you can set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION + Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION + Intent.FLAG_GRANT_WRITE_URI_PERMISSION} on the Intent. This will grant the + Activity access to the specific URIs in the Intent. Access will remain + until the Activity has finished (it will remain across the hosting + process being killed and other temporary destruction). As of + {@link android.os.Build.VERSION_CODES#GINGERBREAD}, if the Activity + was already created and a new Intent is being delivered to + {@link #onNewIntent(Intent)}, any newly granted URI permissions will be added + to the existing ones it holds. + +

    See the Security and Permissions + document for more information on permissions and security in general. + + +

    Process Lifecycle

    + +

    The Android system attempts to keep an application process around for as + long as possible, but eventually will need to remove old processes when + memory runs low. As described in Activity + Lifecycle, the decision about which process to remove is intimately + tied to the state of the user's interaction with it. In general, there + are four states a process can be in based on the activities running in it, + listed here in order of importance. The system will kill less important + processes (the last ones) before it resorts to killing more important + processes (the first ones). + +

      +
    1. The foreground activity (the activity at the top of the screen + that the user is currently interacting with) is considered the most important. + Its process will only be killed as a last resort, if it uses more memory + than is available on the device. Generally at this point the device has + reached a memory paging state, so this is required in order to keep the user + interface responsive. +

    2. A visible activity (an activity that is visible to the user + but not in the foreground, such as one sitting behind a foreground dialog + or next to other activities in multi-window mode) + is considered extremely important and will not be killed unless that is + required to keep the foreground activity running. +

    3. A background activity (an activity that is not visible to + the user and has been stopped) is no longer critical, so the system may + safely kill its process to reclaim memory for other foreground or + visible processes. If its process needs to be killed, when the user navigates + back to the activity (making it visible on the screen again), its + {@link #onCreate} method will be called with the savedInstanceState it had previously + supplied in {@link #onSaveInstanceState} so that it can restart itself in the same + state as the user last left it. +

    4. An empty process is one hosting no activities or other + application components (such as {@link Service} or + {@link android.content.BroadcastReceiver} classes). These are killed very + quickly by the system as memory becomes low. For this reason, any + background operation you do outside of an activity must be executed in the + context of an activity BroadcastReceiver or Service to ensure that the system + knows it needs to keep your process around. +

    + +

    Sometimes an Activity may need to do a long-running operation that exists + independently of the activity lifecycle itself. An example may be a camera + application that allows you to upload a picture to a web site. The upload + may take a long time, and the application should allow the user to leave + the application while it is executing. To accomplish this, your Activity + should start a {@link Service} in which the upload takes place. This allows + the system to properly prioritize your process (considering it to be more + important than other non-visible applications) for the duration of the + upload, independent of whether the original activity is paused, stopped, + or finished. +"; + + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/BaseMethodTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/BaseMethodTests.cs new file mode 100644 index 00000000000..d9f7eb3c8a8 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/BaseMethodTests.cs @@ -0,0 +1,141 @@ +using System; +using System.Linq; +using System.Text; +using System.Xml; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class BaseMethodTests + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.ResolveCollection (); + } + + [Test] + public void InstantiatedGenericArgumentName () + { + var kls = api.FindType ("android.database.ContentObservable") as JavaClassModel; + var method = kls.Methods.First (m => m.Name == "registerObserver"); + Assert.IsNotNull (method, "registerObserver() not found."); + + var para = method.Parameters.FirstOrDefault (); + Assert.IsNotNull (para, "Expected parameter, not found."); + Assert.AreEqual (method.Parameters.First (), method.Parameters.Last (), "There should be only one parameter."); + Assert.AreEqual ("T", para.InstantiatedGenericArgumentName, "InstantiatedGenericArgumentName mismatch"); + } + + [Test] + public void AncestralOverrides () + { + string xml = @" + + + + + + + + + + +"; + + var xapi = JavaApiTestHelper.GetLoadedApi (); + JavaXmlApiImporter.ParseString (xml, xapi); + + xapi.ResolveCollection (); + + var t = xapi.Packages ["XXX"].Types.First (_ => _.Name == "SherlockExpandableListActivity"); + var m = t.Methods.First (_ => _.Name == "addContentView"); + + Assert.IsNotNull (m.BaseMethod, "base method not found"); + } + + [Test] + public void GenericConstructors () + { + string xml = @" + + + + + + + + + + + + "; + + var xapi = JavaApiTestHelper.GetLoadedApi (); + JavaXmlApiImporter.ParseString (xml, xapi); + + var results = xapi.ResolveCollection (); + + var t = xapi.Packages ["XXX"].Types.First (_ => _.Name == "GenericConstructors") as JavaClassModel; + var m = t.Constructors.FirstOrDefault (); + Assert.IsNotNull (m.TypeParameters, "constructor not found"); + } + + [Test] + public void PreferRealApi () + { + // Our base method is abstract, and our derived method is not. However their is also a "matching" non-abstract + // base method that is "synthetic, bridge". If this method is chosen as the base then we will not write the derived + // method because it is not "different" from the base. (They are both not-abstract.) In reality, we need to + // match to the "not-synthetic, not-bridge" method that *is* abstract, so that the derived method is different + // enough to get written to the output. + // See "JavaXmlApiExporter.SaveMethod ()" for what constitutes "different" enough to be written. + string xml = @" + + + + + + + + + + + + +"; + + var xapi = JavaApiTestHelper.GetLoadedApi (); + JavaXmlApiImporter.ParseString (xml, xapi); + + var results = xapi.ResolveCollection (); + + var t = xapi.Packages ["com.google.crypto.tink.streamingaead"].Types.First (_ => _.Name == "AesGcmHkdfStreamingKey") as JavaClassModel; + var m = t.Methods.FirstOrDefault (); + + // The non-synthetic, non-bridge, abstract base method should be chosen + Assert.IsFalse (m.BaseMethod.IsSynthetic); + Assert.IsFalse (m.BaseMethod.IsBridge); + Assert.IsTrue (m.BaseMethod.IsAbstract); + + var sb = new StringBuilder (); + + // Write the results out to XML + using (var xw = XmlWriter.Create (sb)) + JavaXmlApiExporter.Save (xapi, xw); + + // Read results back in to ensure AesGcmHkdfStreamingKey.getParameters was output + var new_collection = JavaXmlApiImporter.ParseString (sb.ToString ()); + + var t2 = new_collection.Packages ["com.google.crypto.tink.streamingaead"].Types.First (_ => _.Name == "AesGcmHkdfStreamingKey") as JavaClassModel; + var m2 = t.Methods.FirstOrDefault (); + + Assert.IsNotNull (m2); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTests.cs new file mode 100644 index 00000000000..4d1c742421e --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/GenericInheritanceMappingTests.cs @@ -0,0 +1,95 @@ +using System; +using System.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class GenericInheritanceMappingTests + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.ResolveCollection (); + } + + [Test] + public void GenericInheritanceMappings () + { + var obj = api.FindType ("java.lang.Object") as JavaClassModel; + Assert.IsNotNull (obj.GenericInheritanceMapping, "java.lang.Object mapping not found"); + Assert.AreEqual (0, obj.GenericInheritanceMapping.Count, "ContentObservable mapping not found"); + + var kls = api.FindType ("android.database.ContentObservable") as JavaClassModel; + var map = kls.GenericInheritanceMapping; + Assert.IsNotNull (map, "ContentObservable mapping not found"); + Assert.AreEqual (1, map.Count, "ContentObservable mapping count unexpected"); + + Assert.IsNotNull (map.Keys.First ().ReferencedTypeParameter, "key is not GenericTypeParameter"); + Assert.IsNotNull ("T", map.Keys.First ().ReferencedTypeParameter.Name, "key GenericTypeParameter has unexpected name"); + Assert.IsNotNull (map.Values.First ().ReferencedType, "value is not to JavaType"); + Assert.IsNotNull ("android.database.ContentObserver", map.Values.First ().ReferencedType.FullName, "value JavaType has unexpected name"); + + var pkg = new JavaPackage ("com.example", "com/example", null); + var dummyType = JavaApiTestHelper.CreateClass (pkg, "Dummy"); + var tps = new JavaTypeParameters (dummyType); + var gt = new JavaTypeParameter ("T", tps); + + Assert.IsTrue (map.TryGetValue (new JavaTypeReference (gt, null), out var mapped), + "Mapped type for generic parameter 'T' not found, or dictionary lookup failed."); + + Assert.AreEqual ("android.database.ContentObserver", mapped.ReferencedType.FullName, "unexpected resolved type"); + } + + [Test] + public void GenericDerivation () + { + var dic = api.FindType ("java.util.Dictionary") as JavaClassModel; + Assert.IsNotNull (dic, "Dictionary not found"); + Assert.AreEqual (0, dic.GenericInheritanceMapping.Count, "Dictionary should have no mapping."); + + var hashtable = api.FindType ("java.util.Hashtable") as JavaClassModel; + Assert.IsNotNull (hashtable, "Hashtable not found"); + Assert.AreEqual (0, hashtable.GenericInheritanceMapping.Count, "Hashtable should have no mapping."); + + var pkg = new JavaPackage ("com.example", "com/example", null); + var dummyType = JavaApiTestHelper.CreateClass (pkg, "Dummy"); + var tps = new JavaTypeParameters (dummyType); + + var props = api.FindType ("java.util.Properties") as JavaClassModel; + Assert.IsNotNull (props, "Properties not found"); + Assert.AreEqual (2, props.GenericInheritanceMapping.Count, "Properties should have no mapping."); + + var k = new JavaTypeReference (new JavaTypeParameter ("K", tps), null); + var v = new JavaTypeReference (new JavaTypeParameter ("V", tps), null); + + Assert.IsNotNull (props.GenericInheritanceMapping [k], "Properties: mapping for K not found."); + Assert.AreEqual ("java.lang.Object", props.GenericInheritanceMapping [k].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object."); + Assert.AreEqual ("java.lang.Object", props.GenericInheritanceMapping [v].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object."); + } + + [Test] + public void NonGenericDerivation () + { + var viewGroup = api.FindType ("android.view.ViewGroup") as JavaClassModel; + Assert.IsNotNull (viewGroup, "ViewGroup not found"); + Assert.AreEqual (0, viewGroup.GenericInheritanceMapping.Count, "ViewGroup should have no mapping."); + + var adapterView = api.FindType ("android.widget.AdapterView") as JavaClassModel; + Assert.IsNotNull (adapterView, "AdapterView not found"); + Assert.AreEqual (0, adapterView.GenericInheritanceMapping.Count, "AdapterView should have no mapping."); + + var absListView = api.FindType ("android.widget.AbsListView") as JavaClassModel; + Assert.IsNotNull (absListView, "AbsListView not found"); + Assert.AreEqual (1, absListView.GenericInheritanceMapping.Count, "AbsListView should have 1 mapping."); + + var listView = api.FindType ("android.widget.ListView") as JavaClassModel; + Assert.IsNotNull (listView, "ListView not found"); + Assert.AreEqual (0, listView.GenericInheritanceMapping.Count, "ListView should have no mapping."); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/Java.Interop.Tools.JavaTypeSystem-Tests.csproj b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/Java.Interop.Tools.JavaTypeSystem-Tests.csproj new file mode 100644 index 00000000000..c85d22fad3f --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/Java.Interop.Tools.JavaTypeSystem-Tests.csproj @@ -0,0 +1,29 @@ + + + + $(DotNetTargetFramework) + false + Java.Interop.Tools.JavaTypeSystem.Tests + + + + + + $(TestOutputFullPath) + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs new file mode 100644 index 00000000000..93697a6d46a --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaApiTestHelper.cs @@ -0,0 +1,40 @@ +using System; +using System.IO; +using Java.Interop.Tools.JavaTypeSystem.Models; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + public class JavaApiTestHelper + { + static readonly string TopDir = Path.Combine (Path.GetDirectoryName (typeof (JavaApiTestHelper).Assembly.Location), "..", ".."); + static readonly string ApiPath = Path.Combine (TopDir, "tests", "TestData", "api-24.xml.in"); + + public static JavaTypeCollection GetLoadedApi () + { + return JavaXmlApiImporter.Parse (ApiPath); + } + + public static JavaClassModel CreateClass (JavaPackage javaPackage, string javaNestedName, string javaVisibility = "public", bool javaAbstract = false, bool javaFinal = false, string javaBaseType = "java.lang.Object", string javaBaseTypeGeneric = "java.lang.Object", string javaDeprecated = "not deprecated", bool javaStatic = false, string jniSignature = "", string baseTypeJni = "java/lang/Object", string annotatedVisibility = "") + { + if (string.IsNullOrWhiteSpace (jniSignature)) + jniSignature = $"{(!string.IsNullOrWhiteSpace (javaPackage.Name) ? javaPackage.Name + "." : "")}{javaNestedName}".Replace ('.', '/'); + + var klass = new JavaClassModel ( + javaPackage: javaPackage, + javaNestedName: javaNestedName, + javaVisibility: javaVisibility, + javaAbstract: javaAbstract, + javaFinal: javaFinal, + javaBaseType: javaBaseType, + javaBaseTypeGeneric: javaBaseTypeGeneric, + javaDeprecated: javaDeprecated, + javaStatic: javaStatic, + jniSignature: jniSignature, + baseTypeJni: baseTypeJni, + annotatedVisibility: annotatedVisibility + ); + + return klass; + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs new file mode 100644 index 00000000000..06faf1eb259 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs @@ -0,0 +1,151 @@ +using System; +using System.Linq; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeCollectionTests + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.ResolveCollection (); + } + + [Test] + public void TestResolvedTypes () + { + var type = api.FindType ("android.database.ContentObservable"); + Assert.IsNotNull (type, "type not found"); + + var kls = type as JavaClassModel; + Assert.IsNotNull (kls, "type was not class"); + Assert.IsNotNull (kls.BaseTypeReference, "extends not resolved."); + Assert.IsNotNull (kls.BaseTypeReference.ReferencedType, "referenced type is not correctly resolved"); + } + + [Test] + public void ResolveGenericArguments () + { + var type = api.FindType ("java.util.concurrent.ConcurrentHashMap"); + Assert.IsNotNull (type, "type not found"); + + var kls = type as JavaClassModel; + Assert.IsNotNull (kls, "type was not class"); + + var method = kls.Methods.OfType ().First (m => m.Name == "searchEntries"); + Assert.IsNotNull (method, "method not found."); + + var para = method.Parameters [1]; + Assert.AreEqual ("java.util.function.Function, ? extends U>", + para.TypeModel.ToString (), + "referenced type is not correctly resolved"); + } + + [Test] + public void IntentServiceHack () + { + // https://github.com/dotnet/java-interop/issues/717 + var api = JavaApiTestHelper.GetLoadedApi (); + + // Create "mono.android.app" package + var mono_android_app = api.AddPackage ("mono.android.app", "mono/android/app"); + + // Remove "android.app.IntentService" type + var android_app = api.Packages["android.app"]; + var intent_service = android_app.Types.Single (t => t.Name == "IntentService"); + android_app.Types.Remove (intent_service); + api.RemoveType (intent_service); + + // Create new "mono.android.app.IntentService" type + var new_intent_service = JavaApiTestHelper.CreateClass (mono_android_app, "IntentService"); + + api.AddType (new_intent_service); + + api.ResolveCollection (); + + // Ensure we can resolve the type by either name + Assert.AreSame (new_intent_service, api.FindType ("mono.android.app.IntentService")); + Assert.AreSame (new_intent_service, api.FindType ("android.app.IntentService")); + } + + [Test] + public void InheritedGenericTypeParameters () + { + // Ensure we can resolve generic type parameters from parent types: + // public class MyClass + // { + // public class MyNestedClass + // { + // public void DoT (T value) { } + // public void DoU (U value) { } + // } + // } + var xml = @" + + + + + + + + + + + + + + + + + + + + + +"; + + var xapi = JavaApiTestHelper.GetLoadedApi (); + JavaXmlApiImporter.ParseString (xml, xapi); + + var results = xapi.ResolveCollection (); + + var t = xapi.Packages ["example"].Types.First (_ => _.Name == "MyClass").NestedTypes.First (_ => _.Name == "MyNestedClass") as JavaClassModel; + + Assert.AreEqual (2, t.Methods.Count); + + Assert.IsNotNull (t.Methods.SingleOrDefault (m => m.Name == "DoT"), "Method with generic T not found"); + Assert.IsNotNull (t.Methods.SingleOrDefault (m => m.Name == "DoU"), "Method with generic U not found"); + } + + [Test] + public void InvalidBaseTypeResolution () + { + var api = new JavaTypeCollection (); + + // Create "my.ns" package + var my_ns = api.AddPackage ("my.ns", "my/ns"); + + // Create new "my.ns.MyObject" type with "my.ns.MyObject" as base type + var jlo = JavaApiTestHelper.CreateClass (my_ns, "MyObject", javaBaseType: "my.ns.MyObject", javaBaseTypeGeneric: "my.ns.MyObject"); + + api.AddType (jlo); + + // Run the resolver + var results = api.ResolveCollection (); + + // Ensure we marked it as unresolvable + Assert.AreEqual (1, results.Count); + Assert.AreEqual (1, results [0].Unresolvables.Count); + Assert.AreEqual ("The class '[Class] my.ns.MyObject' was removed because the base type 'my.ns.MyObject' is invalid.", results [0].Unresolvables [0].GetDisplayMessage ()); + + // Ensure we removed the type from the collection + Assert.AreEqual (0, api.TypesFlattened.Count); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeModelsTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeModelsTests.cs new file mode 100644 index 00000000000..1ee28de00e4 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeModelsTests.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeModelsTests + { + JavaTypeCollection api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + } + + [Test] + public void TestToString () + { + var pkg = api.Packages["android.database"]; + Assert.AreEqual ("[Package] android.database", pkg.ToString ()); + + var kls = pkg.Types.First (t => t.FullName == "android.database.ContentObservable"); + Assert.AreEqual ("[Class] android.database.ContentObservable", kls.ToString ()); + } + + [Test] + public void AnnotatedVisibility () + { + // Ensure the 'annotated-visibility' attribute gets passed through + using var sw = new StringWriter (); + + using (var xml = XmlWriter.Create (sw)) + JavaXmlApiExporter.Save (api, xml); + + var doc = new XmlDocument { XmlResolver = null }; + using var sreader = new StringReader (sw.ToString ()); + using var reader = XmlReader.Create (sreader, new XmlReaderSettings { XmlResolver = null }); + doc.Load (reader); + + var annotated_class = doc.SelectSingleNode ("/api/package/class[@name='StateListAnimator']"); + Assert.AreEqual ("TESTS", annotated_class.Attributes ["annotated-visibility"].InnerText); + + var annotated_ctor = annotated_class ["constructor"]; + Assert.AreEqual ("TESTS", annotated_ctor.Attributes ["annotated-visibility"].InnerText); + + var annotated_method = annotated_class ["method"]; + Assert.AreEqual ("TESTS", annotated_method.Attributes ["annotated-visibility"].InnerText); + + var annotated_interface = doc.SelectSingleNode ("/api/package/interface[@name='DrmStore.ConstraintsColumns']"); + Assert.AreEqual ("TESTS", annotated_interface.Attributes ["annotated-visibility"].InnerText); + + var annotated_field = annotated_interface ["field"]; + Assert.AreEqual ("TESTS", annotated_field.Attributes ["annotated-visibility"].InnerText); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeNameTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeNameTests.cs new file mode 100644 index 00000000000..e052dc52f38 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeNameTests.cs @@ -0,0 +1,49 @@ +using System; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeNameTests + { + [Test] + public void ParseName () + { + var tn = JavaTypeName.Parse ("java.util.Function, ? extends U>"); + Assert.AreEqual ("java.util.Function", tn.FullNameNonGeneric, "top failed to parse name"); + Assert.AreEqual (2, tn.GenericArguments.Count, "top incorrect number of parsed generic arguments"); + + var ga1 = tn.GenericArguments [0]; + Assert.AreEqual ("java.util.Map.Entry", ga1.FullNameNonGeneric, "genarg#0 name mismatch"); + Assert.AreEqual (2, ga1.GenericArguments.Count, "genarg#0 incorrect number of parsed generic arguments"); + Assert.AreEqual ("K", ga1.GenericArguments [0].FullNameNonGeneric, "genarg#0.1 name mismatch"); + Assert.AreEqual ("V", ga1.GenericArguments [1].FullNameNonGeneric, "genarg#0.2 name mismatch"); + + var ga2 = tn.GenericArguments [1]; + Assert.AreEqual ("?", ga2.FullNameNonGeneric, "genarg#1 name mismatch"); + Assert.AreEqual (" extends ", ga2.BoundsType, "genarg#1 incorrect bounds type"); + Assert.AreEqual (1, ga2.GenericConstraints.Count, "genarg#1 incorrect number of parsed generic constraints"); + Assert.AreEqual ("U", ga2.GenericConstraints [0].FullNameNonGeneric, "genarg#1.1 constraint name mismatch"); + } + + [Test] + public void ParseName2 () + { + var name = "com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a.b"; + var tn = JavaTypeName.Parse (name); + + Assert.IsTrue (tn.GenericParent != null, "result has generic parent"); + Assert.AreEqual ("b", tn.DottedName, "result name mismatch"); + Assert.AreEqual ("com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a.b", tn.FullNameNonGeneric, "failed to parse name"); + Assert.AreEqual (1, tn.GenericArguments.Count, "result genparams count mismatch"); + Assert.AreEqual ("com.good.gd.ndkproxy.auth.d.a", tn.GenericArguments [0].FullNameNonGeneric, "result genarg name mismatch"); + + var p = tn.GenericParent; + Assert.AreEqual (1, p.GenericArguments.Count, "top genparams count"); + + var ga1 = p.GenericArguments [0]; + Assert.AreEqual ("com.good.gd.ndkproxy.auth.c.a", ga1.FullNameNonGeneric, "top genarg name mismatch"); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeReferenceTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeReferenceTests.cs new file mode 100644 index 00000000000..90ae8d5b36e --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeReferenceTests.cs @@ -0,0 +1,36 @@ +using System; +using Java.Interop.Tools.JavaTypeSystem.Models; +using NUnit.Framework; + +namespace Java.Interop.Tools.JavaTypeSystem.Tests +{ + [TestFixture] + public class JavaTypeReferenceTests + { + [Test] + public void TypeReferenceEquals () + { + var int_ref = JavaTypeReference.Int; + Assert.AreEqual (JavaTypeReference.Int, int_ref, "primitive types 2"); + + var pkg = new JavaPackage ("com.example", "com/example", null); + var dummyType = JavaApiTestHelper.CreateClass (pkg, "Dummy"); + var tps = new JavaTypeParameters (dummyType); + var gt = new JavaTypeParameter ("T", tps); + + Assert.AreEqual (new JavaTypeReference (gt, null), new JavaTypeReference (new JavaTypeParameter ("T", tps), null), "type parameters"); + Assert.AreNotEqual (new JavaTypeReference (gt, null), new JavaTypeReference (new JavaTypeParameter ("U", tps), null), "type parameters 2"); + Assert.AreNotEqual (new JavaTypeReference (gt, null), new JavaTypeReference (gt, "[]"), "type parameters: array vs. non-array"); + Assert.AreEqual (new JavaTypeReference (gt, "[]"), new JavaTypeReference (gt, "[]"), "type parameters: array vs. array"); + + var type = JavaApiTestHelper.CreateClass (pkg, "T"); + Assert.AreEqual (new JavaTypeReference (type, null, null), new JavaTypeReference (type, null, null), "type vs. type"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, null), "type: array vs. non array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, "[][]"), "type: array vs. array of array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, null), new JavaTypeReference (new JavaTypeParameter ("T", tps), null), "type vs. type parameters"); + + Assert.AreNotEqual (new JavaTypeReference (gt, "[]"), new JavaTypeReference (type, null, null), "type: array vs. non array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, "[][]"), "type: array vs. array of array"); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/ArtifactTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/ArtifactTests.cs new file mode 100644 index 00000000000..186b25650e5 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/ArtifactTests.cs @@ -0,0 +1,125 @@ +using System; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven_Tests; + +public class ArtifactTests +{ + [TestCase ("com.google.guava:guava:31.1-jre", "com.google.guava", "guava", "31.1-jre")] + [TestCase ("androidx.core:core:1.9.0", "androidx.core", "core", "1.9.0")] + [TestCase ("a:b:1", "a", "b", "1")] + [TestCase ("group_1-x.y:artifact-id_2:1.0.0-SNAPSHOT", "group_1-x.y", "artifact-id_2", "1.0.0-SNAPSHOT")] + public void TryParse_Valid (string value, string groupId, string artifactId, string version) + { + Assert.IsTrue (Artifact.TryParse (value, out var artifact)); + Assert.AreEqual (groupId, artifact!.GroupId); + Assert.AreEqual (artifactId, artifact.Id); + Assert.AreEqual (version, artifact.Version); + Assert.AreEqual ($"{groupId}:{artifactId}", artifact.ArtifactString); + Assert.AreEqual (value, artifact.VersionedArtifactString); + Assert.AreEqual (value, artifact.ToString ()); + } + + [TestCase ("com.google.guava:guava:31.1-jre", "com.google.guava", "guava", "31.1-jre")] + public void Parse_Valid (string value, string groupId, string artifactId, string version) + { + var artifact = Artifact.Parse (value); + Assert.AreEqual (groupId, artifact.GroupId); + Assert.AreEqual (artifactId, artifact.Id); + Assert.AreEqual (version, artifact.Version); + } + + [TestCase ("")] + [TestCase ("foo")] + [TestCase ("foo:bar")] + [TestCase ("a:b:c:d")] + [TestCase ("::")] + [TestCase ("a::1")] + [TestCase (":b:1")] + [TestCase ("a:b:")] + [TestCase (" :b:1")] + [TestCase ("a b:c:1")] + [TestCase ("a:b c:1")] + [TestCase ("a:b:1 0")] + [TestCase ("a/b:c:1")] + [TestCase ("a:b@c:1")] + [TestCase ("a:b!:1")] + [TestCase ("a:b:c:d:e:f:g")] + [TestCase ("../a:b:1")] + [TestCase ("a:../b:1")] + [TestCase ("a:b:../1")] + [TestCase ("a:b:1.0/../")] + [TestCase ("a/../b:c:1")] + [TestCase ("..\\a:b:1")] + [TestCase ("a:b:..\\1.0")] + public void TryParse_Invalid (string value) + { + Assert.IsFalse (Artifact.TryParse (value, out var artifact)); + Assert.IsNull (artifact); + } + + [Test] + public void TryParse_Null () + { + Assert.IsFalse (Artifact.TryParse (null!, out var artifact)); + Assert.IsNull (artifact); + } + + [TestCase ("")] + [TestCase ("foo")] + [TestCase ("a:b c:1")] + public void Parse_Invalid_Throws (string value) + { + Assert.Throws (() => Artifact.Parse (value)); + } + + [Test] + public void Ctor_Valid () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + Assert.AreEqual ("com.example", artifact.GroupId); + Assert.AreEqual ("lib", artifact.Id); + Assert.AreEqual ("1.0.0", artifact.Version); + } + + [TestCase (null, "lib", "1.0")] + [TestCase ("com.example", null, "1.0")] + [TestCase ("com.example", "lib", null)] + public void Ctor_Null_Throws (string? groupId, string? artifactId, string? version) + { + Assert.Throws (() => new Artifact (groupId!, artifactId!, version!)); + } + + [TestCase ("", "lib", "1.0")] + [TestCase (" ", "lib", "1.0")] + [TestCase ("a b", "lib", "1.0")] + [TestCase ("a/b", "lib", "1.0")] + [TestCase ("a@b", "lib", "1.0")] + [TestCase ("com.example", "", "1.0")] + [TestCase ("com.example", " ", "1.0")] + [TestCase ("com.example", "li b", "1.0")] + [TestCase ("com.example", "lib!", "1.0")] + [TestCase ("com.example", "lib", " ")] + [TestCase ("com.example", "lib", "1 0")] + [TestCase ("com.example", "lib", "1:0")] + [TestCase ("../com.example", "lib", "1.0")] + [TestCase ("com.example", "../lib", "1.0")] + [TestCase ("com.example", "lib", "../1.0")] + [TestCase ("com.example", "lib", "1.0/../")] + [TestCase ("com.example", "lib", "..\\1.0")] + [TestCase ("com/example", "lib", "1.0")] + public void Ctor_Invalid_Throws (string groupId, string artifactId, string version) + { + Assert.Throws (() => new Artifact (groupId, artifactId, version)); + } + + [Test] + public void Ctor_AllowsEmptyVersion () + { + // Empty version is permitted in the constructor to support partial + // coordinates produced from POM XML where is omitted and + // inherited from a parent POM. + var artifact = new Artifact ("com.example", "lib", ""); + Assert.AreEqual ("", artifact.Version); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/CachedMavenRepositoryTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/CachedMavenRepositoryTests.cs new file mode 100644 index 00000000000..277466fad2b --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/CachedMavenRepositoryTests.cs @@ -0,0 +1,185 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Java.Interop.Tools.Maven.Models; +using Java.Interop.Tools.Maven.Repositories; + +namespace Java.Interop.Tools.Maven_Tests; + +public class CachedMavenRepositoryTests +{ + string cache_dir = ""; + + [SetUp] + public void SetUp () + { + cache_dir = Path.Combine (Path.GetTempPath (), "Java.Interop.Tools.Maven-Tests", Path.GetRandomFileName ()); + Directory.CreateDirectory (cache_dir); + } + + [TearDown] + public void TearDown () + { + if (Directory.Exists (cache_dir)) + Directory.Delete (cache_dir, recursive: true); + } + + [Test] + public void GetArtifactFilePath_HappyPath_ReturnsExpectedLayout () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var inner = new StubRepository ("central", artifact, "lib-1.0.0.jar", new byte [] { 1, 2, 3 }); + var cache = new CachedMavenRepository (cache_dir, inner); + + var expected = Path.GetFullPath (Path.Combine (cache_dir, "central", "com.example", "lib", "1.0.0", "lib-1.0.0.jar")); + var actual = cache.GetArtifactFilePath (artifact, "lib-1.0.0.jar"); + + Assert.AreEqual (expected, actual); + Assert.IsFalse (File.Exists (actual), "GetArtifactFilePath must not create/download the file."); + } + + [Test] + public void TryGetFilePath_HappyPath_DownloadsAndReturnsExpectedPath () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var content = new byte [] { 1, 2, 3 }; + var inner = new StubRepository ("central", artifact, "lib-1.0.0.jar", content); + var cache = new CachedMavenRepository (cache_dir, inner); + + var expected = Path.GetFullPath (Path.Combine (cache_dir, "central", "com.example", "lib", "1.0.0", "lib-1.0.0.jar")); + + Assert.IsTrue (cache.TryGetFilePath (artifact, "lib-1.0.0.jar", out var path)); + Assert.AreEqual (expected, path); + Assert.IsTrue (File.Exists (path)); + CollectionAssert.AreEqual (content, File.ReadAllBytes (path!)); + } + + [Test] + public void GetArtifactFilePath_RelativeFilename_Throws () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var inner = new ThrowingRepository ("central"); + var cache = new CachedMavenRepository (cache_dir, inner); + + var artifact_dir = Path.GetDirectoryName (cache.GetArtifactFilePath (artifact, "anchor.jar"))!; + var outside = Path.Combine (Path.GetDirectoryName (cache_dir)!, Path.GetFileName (cache_dir) + "-sibling", "relative.jar"); + var malicious = Path.GetRelativePath (artifact_dir, outside); + + Assert.Throws (() => cache.GetArtifactFilePath (artifact, malicious)); + } + + [Test] + public void TryGetFilePath_RelativeFilename_Throws () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var inner = new ThrowingRepository ("central"); + var cache = new CachedMavenRepository (cache_dir, inner); + + var artifact_dir = Path.GetDirectoryName (cache.GetArtifactFilePath (artifact, "anchor.jar"))!; + var outside = Path.Combine (Path.GetDirectoryName (cache_dir)!, Path.GetFileName (cache_dir) + "-sibling", "relative.jar"); + var malicious = Path.GetRelativePath (artifact_dir, outside); + + Assert.Throws (() => cache.TryGetFilePath (artifact, malicious, out _)); + Assert.AreEqual (0, inner.CallCount, "Inner repository must not be consulted for an escaping path."); + } + + [Test] + public void TryGetFile_RelativeFilename_Throws () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var inner = new ThrowingRepository ("central"); + var cache = new CachedMavenRepository (cache_dir, inner); + + var artifact_dir = Path.GetDirectoryName (cache.GetArtifactFilePath (artifact, "anchor.jar"))!; + var outside = Path.Combine (Path.GetDirectoryName (cache_dir)!, Path.GetFileName (cache_dir) + "-sibling", "relative.jar"); + var malicious = Path.GetRelativePath (artifact_dir, outside); + + Assert.Throws (() => cache.TryGetFile (artifact, malicious, out _)); + Assert.AreEqual (0, inner.CallCount, "Inner repository must not be consulted for an escaping path."); + } + + [Test] + public void GetFilePathAsync_RelativeFilename_Throws () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var inner = new ThrowingRepository ("central"); + var cache = new CachedMavenRepository (cache_dir, inner); + + var artifact_dir = Path.GetDirectoryName (cache.GetArtifactFilePath (artifact, "anchor.jar"))!; + var outside = Path.Combine (Path.GetDirectoryName (cache_dir)!, Path.GetFileName (cache_dir) + "-sibling", "relative.jar"); + var malicious = Path.GetRelativePath (artifact_dir, outside); + + Assert.ThrowsAsync (async () => + await cache.GetFilePathAsync (artifact, malicious, CancellationToken.None)); + Assert.AreEqual (0, inner.CallCount, "Inner repository must not be consulted for an escaping path."); + } + + [Test] + public void GetArtifactFilePath_RelativeRepositoryName_Throws () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var inner = new ThrowingRepository (Path.Combine ("..", Path.GetFileName (cache_dir) + "-sibling")); + var cache = new CachedMavenRepository (cache_dir, inner); + + Assert.Throws (() => cache.GetArtifactFilePath (artifact, "lib-1.0.0.jar")); + } + + [Test] + public void GetArtifactFilePath_SiblingPrefixCacheDirectory_Throws () + { + var artifact = new Artifact ("com.example", "lib", "1.0.0"); + var sibling = cache_dir + "-sibling"; + var repo_name = Path.GetRelativePath (cache_dir, sibling); + var inner = new ThrowingRepository (repo_name); + var cache = new CachedMavenRepository (cache_dir, inner); + + Assert.Throws (() => cache.GetArtifactFilePath (artifact, "lib-1.0.0.jar")); + } + + sealed class StubRepository : IMavenRepository + { + readonly Artifact expected; + readonly string expected_filename; + readonly byte [] content; + + public StubRepository (string name, Artifact expected, string filename, byte [] content) + { + Name = name; + this.expected = expected; + this.expected_filename = filename; + this.content = content; + } + + public string Name { get; } + + public bool TryGetFile (Artifact artifact, string filename, [NotNullWhen (true)] out Stream? stream) + { + if (artifact.GroupId == expected.GroupId && artifact.Id == expected.Id && artifact.Version == expected.Version && filename == expected_filename) { + stream = new MemoryStream (content); + return true; + } + stream = null; + return false; + } + } + + sealed class ThrowingRepository : IMavenRepository + { + public ThrowingRepository (string name) + { + Name = name; + } + + public string Name { get; } + + public int CallCount { get; private set; } + + public bool TryGetFile (Artifact artifact, string filename, [NotNullWhen (true)] out Stream? stream) + { + CallCount++; + throw new InvalidOperationException ("Inner repository should not be consulted when the resolved path escapes the cache directory."); + } + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/DependenciesTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/DependenciesTests.cs new file mode 100644 index 00000000000..90377134920 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/DependenciesTests.cs @@ -0,0 +1,57 @@ +using System; +using System.Linq; +using Java.Interop.Tools.Maven.Models; +using Java.Interop.Tools.Maven_Tests.Extensions; + +namespace Java.Interop.Tools.Maven_Tests; + +public class DependenciesTests +{ + [Test] + [TestCase ("dev.chrisbanes.snapper:snapper:0.3.0", "androidx.compose.foundation:foundation:1.2.1 - compile;org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 - compile")] + [TestCase ("com.squareup.wire:wire-runtime:4.4.3", "com.squareup.okio:okio:3.0.0 - runtime;org.jetbrains.kotlin:kotlin-stdlib-common:1.6.10 - runtime")] + [TestCase ("org.jboss:jboss-vfs:3.2.17.Final", "org.jboss.logging:jboss-logging:3.1.4.GA - compile")] + [TestCase ("com.squareup.okio:okio:1.17.4", "org.codehaus.mojo:animal-sniffer-annotations:1.10 - compile")] + [TestCase ("org.jetbrains.kotlin:kotlin-stdlib:1.6.20", "org.jetbrains:annotations:13.0 - compile;org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20 - compile")] + [TestCase ("com.github.bumptech.glide:glide:4.13.2", "androidx.exifinterface:exifinterface:1.2.0 - compile;androidx.fragment:fragment:1.3.1 - compile;androidx.tracing:tracing:1.0.0 - compile;androidx.vectordrawable:vectordrawable-animated:1.0.0 - compile;com.github.bumptech.glide:annotations:4.13.2 - compile;com.github.bumptech.glide:disklrucache:4.13.2 - compile;com.github.bumptech.glide:gifdecoder:4.13.2 - compile")] + [TestCase ("io.reactivex.rxjava3:rxandroid:3.0.0", "io.reactivex.rxjava3:rxjava:3.0.0 - compile")] + [TestCase ("com.jakewharton.timber:timber:5.0.1", "org.jetbrains:annotations:20.1.0 - runtime;org.jetbrains.kotlin:kotlin-stdlib:1.5.21 - compile")] + [TestCase ("org.greenrobot:eventbus:3.3.1", "org.greenrobot:eventbus-java:3.3.1 - compile")] + [TestCase ("com.squareup.picasso:picasso:2.8", "androidx.annotation:annotation:1.0.0 - compile;androidx.exifinterface:exifinterface:1.0.0 - compile;com.squareup.okhttp3:okhttp:3.10.0 - compile")] + [TestCase ("pub.devrel:easypermissions:3.0.0", "androidx.annotation:annotation:1.1.0 - compile;androidx.appcompat:appcompat:1.1.0 - compile;androidx.core:core:1.3.0 - compile;androidx.fragment:fragment:1.2.5 - compile")] + [TestCase ("com.squareup.okio:samples:1.17.6", "com.squareup.okio:okio:1.17.6 - compile")] + [TestCase ("com.android.volley:volley:1.2.1", "")] + [TestCase ("as.leap:LAS-cloudcode-sdk:2.3.6", "com.fasterxml.jackson.core:jackson-core:2.5.3 - compile;com.fasterxml.jackson.core:jackson-databind:2.5.3 - compile")] + [TestCase ("ai.grakn:grakn-dist:1.4.1", "ai.grakn:grakn-engine:1.4.1 - compile;ai.grakn:grakn-factory:1.4.1 - compile;ai.grakn:grakn-graql-shell:1.4.1 - compile;ai.grakn:migration-csv:1.4.1 - compile;ai.grakn:migration-export:1.4.1 - compile;ai.grakn:migration-json:1.4.1 - compile;ai.grakn:migration-sql:1.4.1 - compile;ai.grakn:migration-xml:1.4.1 - compile;ch.qos.logback:logback-classic:1.2.3 - compile;ch.qos.logback:logback-core:1.2.3 - compile;io.airlift:airline:0.6 - compile;org.codehaus.janino:janino:2.7.8 - compile;org.slf4j:slf4j-api:1.7.20 - compile")] + [TestCase ("at.crea-doo.homer:shell.data:1.0.11", "at.crea-doo.homer:processing.data:1.0.11 - compile;joda-time:joda-time:2.9.9 - compile;org.apache.karaf.shell:org.apache.karaf.shell.core:4.0.9 - compile")] + [TestCase ("at.crea-doo.homer:connector.ifttt.maker:1.0.11", "at.ac.ait.hbs.homer:at.ac.ait.hbs.homer.core.common:1.2.51 - compile;com.google.code.gson:gson:2.8.1 - compile;commons-codec:commons-codec:1.10 - compile;commons-logging:commons-logging:1.2 - compile;org.apache.httpcomponents:httpclient:4.5.3 - compile;org.apache.httpcomponents:httpcore:4.4.6 - compile")] + [TestCase ("at.reilaender.asciidoctorj.bootconfig2adoc:bootconfig2adoc-adoc:0.1.3", "at.reilaender.asciidoctorj.bootconfig2adoc:bootconfig2adoc-core:0.1.3 - compile")] + [TestCase ("at.researchstudio.sat:won-bot:0.9", "at.researchstudio.sat:won-core:0.9 - compile;at.researchstudio.sat:won-cryptography:0.9 - compile;at.researchstudio.sat:won-matcher:0.9 - compile;at.researchstudio.sat:won-owner:0.9 - compile;at.researchstudio.sat:won-sockets-tx:0.9 - compile;at.researchstudio.sat:won-utils-conversation:0.9 - compile;at.researchstudio.sat:won-utils-goals:0.9 - compile;ch.qos.logback:logback-classic:1.0.13 - compile;ch.qos.logback:logback-core:1.0.13 - compile;commons-io:commons-io:2.4 - compile;org.apache.commons:commons-email:1.3.1 - compile;org.apache.commons:commons-lang3:3.4 - compile;org.apache.httpcomponents:httpclient:4.5 - compile;org.apache.jena:jena-arq:3.5.0 - compile;org.apache.jena:jena-core:3.5.0 - compile;org.aspectj:aspectjweaver:1.5.4 - compile;org.bouncycastle:bcpkix-jdk15on:1.64 - compile;org.bouncycastle:bcprov-jdk15on:1.64 - compile;org.javasimon:javasimon-core:3.4.0 - compile;org.javasimon:javasimon-spring:3.4.0 - compile;org.jsoup:jsoup:1.7.3 - compile;org.quartz-scheduler:quartz:2.2.1 - compile;org.slf4j:slf4j-api:1.6.6 - compile;org.springframework:spring-core:4.3.18.RELEASE - compile;org.springframework.boot:spring-boot:1.5.17.RELEASE - compile;org.springframework.data:spring-data-commons:1.13.16.RELEASE - compile;org.springframework.data:spring-data-mongodb:1.10.3.RELEASE - compile")] + [TestCase ("au.csiro:elk-distribution-owlapi4:0.5.0", "au.csiro:elk-owlapi4:0.5.0 - compile;org.liveontologies:owlapi-proof:0.1.0 - compile;org.liveontologies:puli:0.1.0 - compile")] + [TestCase ("au.csiro:elk-distribution-owlapi5:0.5.0", "au.csiro:elk-distribution-owlapi4:0.5.0 - compile;au.csiro:elk-distribution-owlapi4:0.5.0 - compile;au.csiro:elk-owlapi5:0.5.0 - compile;org.liveontologies:owlapi-proof:0.1.0 - compile;org.liveontologies:puli:0.1.0 - compile")] + [TestCase ("au.gov.amsa.risky:ais:0.6.17", "au.gov.amsa.risky:formats:0.6.17 - compile;au.gov.amsa.risky:formats:0.6.17 - compile;au.gov.amsa.risky:streams:0.6.17 - compile;com.github.davidmoten:rxjava-extras:0.8.0.20 - compile;com.github.davidmoten:rxjava-slf4j:0.7.0 - compile;com.google.guava:guava:32.1.3-jre - compile;io.reactivex:rxjava-string:1.1.1 - compile;io.reactivex:rxjava:1.3.8 - compile;org.slf4j:slf4j-api:2.0.9 - compile")] + [TestCase ("am.ik.springmvc:new-controller:0.2.0", "me.geso:routes:0.6.0 - compile;org.slf4j:slf4j-api:1.7.8 - compile;org.springframework:spring-webmvc:4.1.4.RELEASE - compile")] + [TestCase ("me.drakeet.multitype:multitype:3.5.0", "androidx.annotation:annotation:1.0.0 - compile;androidx.recyclerview:recyclerview:1.0.0 - compile")] + [TestCase ("com.facebook.fresco:fresco:2.6.0", "com.facebook.fresco:drawee:2.6.0 - compile;com.facebook.fresco:fbcore:2.6.0 - compile;com.facebook.fresco:imagepipeline-native:2.6.0 - compile;com.facebook.fresco:imagepipeline:2.6.0 - compile;com.facebook.fresco:memory-type-ashmem:2.6.0 - compile;com.facebook.fresco:memory-type-java:2.6.0 - compile;com.facebook.fresco:memory-type-native:2.6.0 - compile;com.facebook.fresco:nativeimagefilters:2.6.0 - compile;com.facebook.fresco:nativeimagetranscoder:2.6.0 - compile;com.facebook.fresco:soloader:2.6.0 - runtime;com.facebook.fresco:ui-common:2.6.0 - runtime;com.facebook.soloader:nativeloader:0.10.1 - runtime")] + [TestCase ("com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0", "")] + [TestCase ("com.facebook.android:facebook-android-sdk:14.1.1", "com.facebook.android:facebook-applinks:14.1.1 - compile;com.facebook.android:facebook-common:14.1.1 - compile;com.facebook.android:facebook-core:14.1.1 - compile;com.facebook.android:facebook-gamingservices:14.1.1 - compile;com.facebook.android:facebook-login:14.1.1 - compile;com.facebook.android:facebook-messenger:14.1.1 - compile;com.facebook.android:facebook-share:14.1.1 - compile;org.jetbrains.kotlin:kotlin-stdlib:1.5.10 - compile")] + [TestCase ("com.airbnb.android:lottie:5.2.0", "androidx.appcompat:appcompat:1.3.1 - runtime;com.squareup.okio:okio:1.17.4 - runtime")] + public void TestMavenCentralResolvedDependencies (string artifact, string expected) + => TestResolvedDependencies (MavenProjectResolver.Central, artifact, expected); + + void TestResolvedDependencies (MavenProjectResolver resolver, string artifact, string expected) + { + var art = Artifact.Parse (artifact); + var project = ResolvedProject.FromArtifact (art, resolver); + var dependencies = project.Dependencies.Where (d => d.Scope == "compile" || d.Scope == "runtime").OrderBy (d => d.ToString ()).ToList (); + + if (dependencies.FirstOrDefault (d => string.IsNullOrEmpty (d.Version)) is ResolvedDependency rd) + throw new Exception ($"Missing version - {rd}"); + + if (dependencies.FirstOrDefault (d => d.Version.Contains ('$')) is ResolvedDependency rd2) + throw new Exception ("Unresolved variable in version"); + + Console.WriteLine (string.Join (';', dependencies)); + Assert.AreEqual (expected, string.Join (';', dependencies)); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Extensions/MavenProjectResolver.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Extensions/MavenProjectResolver.cs new file mode 100644 index 00000000000..1d208c32716 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Extensions/MavenProjectResolver.cs @@ -0,0 +1,40 @@ +using System; +using System.IO; +using Java.Interop.Tools.Maven; +using Java.Interop.Tools.Maven.Models; +using Java.Interop.Tools.Maven.Repositories; + +namespace Java.Interop.Tools.Maven_Tests.Extensions; + +class MavenProjectResolver : IProjectResolver +{ + readonly IMavenRepository repository; + + public MavenProjectResolver (IMavenRepository repository) + { + this.repository = repository; + } + + static MavenProjectResolver () + { + var cache_path = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), "dotnet-android", "MavenCacheDirectory"); + + Central = new MavenProjectResolver (new CachedMavenRepository (cache_path, MavenRepository.Central)); + Google = new MavenProjectResolver (new CachedMavenRepository (cache_path, MavenRepository.Google)); + } + + public Project Resolve (Artifact artifact) + { + if (repository.TryGetFile (artifact, $"{artifact.Id}-{artifact.Version}.pom", out var stream)) { + using (stream) { + return Project.Load (stream) ?? throw new InvalidOperationException ($"Could not deserialize POM for {artifact}"); + } + } + + throw new InvalidOperationException ($"No POM found for {artifact}"); + } + + public static MavenProjectResolver Google { get; } + + public static MavenProjectResolver Central { get; } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Extensions/TestDataExtensions.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Extensions/TestDataExtensions.cs new file mode 100644 index 00000000000..cbee3834881 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Extensions/TestDataExtensions.cs @@ -0,0 +1,39 @@ +using System.Xml.Linq; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven_Tests.Extensions; + +static class TestDataExtensions +{ + public static Project CreateProject (Artifact artifact, Project? parent = null) + { + var xml = new XDocument ( + new XElement ("project", + new XElement ("modelVersion", "4.0.0"), + new XElement ("groupId", artifact.GroupId), + new XElement ("artifactId", artifact.Id), + new XElement ("version", artifact.Version) + ) + ); + + if (parent is not null) { + var parent_xml = new XElement ("parent", + new XElement ("groupId", parent.GroupId), + new XElement ("artifactId", parent.ArtifactId), + new XElement ("version", parent.Version) + ); + + xml.Root!.Add (parent_xml); + } + + return Project.Parse (xml.ToString ()); + } + + public static void AddProperty (this Project project, string key, string value) + { + var xml = new XElement (key, value); + + project.Properties ??= new ModelProperties (); + project.Properties.Any.Add (xml); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Java.Interop.Tools.Maven-Tests.csproj b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Java.Interop.Tools.Maven-Tests.csproj new file mode 100644 index 00000000000..3856610c084 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/Java.Interop.Tools.Maven-Tests.csproj @@ -0,0 +1,31 @@ + + + + $(DotNetTargetFramework) + enable + false + true + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/MavenVersionRangeTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/MavenVersionRangeTests.cs new file mode 100644 index 00000000000..02575bb7fdd --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/MavenVersionRangeTests.cs @@ -0,0 +1,61 @@ +using System.Linq; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven_Tests; + +public class MavenVersionRangeTests +{ + [Test] + public void ParseTest () + { + TestSingleRange ("1.0", "1.0", null, true, false, true, false); + TestSingleRange ("(,1.0]", null, "1.0", false, true, false, true); + TestSingleRange ("[1.0]", "1.0", "1.0", true, true, true, true); + TestSingleRange ("[1.2,1.3]", "1.2", "1.3", true, true, true, true); + TestSingleRange ("[1.0,2.0)", "1.0", "2.0", true, true, true, false); + TestSingleRange ("[1.5,)", "1.5", null, true, false, true, false); + + var multi_range_1 = MavenVersionRange.Parse ("(,1.0],[1.2,)").ToArray (); + TestSingleRange (multi_range_1 [0], null, "1.0", false, true, false, true); + TestSingleRange (multi_range_1 [1], "1.2", null, true, false, true, false); + + var multi_range_2 = MavenVersionRange.Parse ("(,1.1),(1.1,)").ToArray (); + TestSingleRange (multi_range_2 [0], null, "1.1", false, true, false, false); + TestSingleRange (multi_range_2 [1], "1.1", null, true, false, false, false); + } + + [Test] + public void ContainsVersionTest () + { + TestContainsVersion ("1.0", false, true, true, true, true); + TestContainsVersion ("(,1.0]", true, true, false, false, false); + TestContainsVersion ("[1.0]", false, true, false, false, false); + TestContainsVersion ("[1.0,2.0]", false, true, true, true, false); + TestContainsVersion ("(1.0,2.0)", false, false, true, false, false); + TestContainsVersion ("[1.5,)", false, false, true, true, true); + } + + static void TestSingleRange (string value, string? minVersion, string? maxVersion, bool hasLowerBound, bool hasUpperBound, bool isMinInclusive, bool isMaxInclusive) + => TestSingleRange (MavenVersionRange.Parse (value).Single (), minVersion, maxVersion, hasLowerBound, hasUpperBound, isMinInclusive, isMaxInclusive); + + static void TestSingleRange (MavenVersionRange range, string? minVersion, string? maxVersion, bool hasLowerBound, bool hasUpperBound, bool isMinInclusive, bool isMaxInclusive) + { + Assert.AreEqual (hasLowerBound, range.HasLowerBound); + Assert.AreEqual (hasUpperBound, range.HasUpperBound); + Assert.AreEqual (minVersion, range.MinVersion); + Assert.AreEqual (maxVersion, range.MaxVersion); + Assert.AreEqual (isMinInclusive, range.IsMinInclusive); + Assert.AreEqual (isMaxInclusive, range.IsMaxInclusive); + } + + static void TestContainsVersion (string value, bool contains0_8, bool contains1_0, bool contains1_5, bool contains2_0, bool contains2_5) + { + var range = MavenVersionRange.Parse (value).Single (); + + Assert.AreEqual (contains0_8, range.ContainsVersion (MavenVersion.Parse ("0.8"))); + Assert.AreEqual (contains1_0, range.ContainsVersion (MavenVersion.Parse ("1.0"))); + Assert.AreEqual (contains1_5, range.ContainsVersion (MavenVersion.Parse ("1.5"))); + Assert.AreEqual (contains2_0, range.ContainsVersion (MavenVersion.Parse ("2.0"))); + Assert.AreEqual (contains2_5, range.ContainsVersion (MavenVersion.Parse ("2.5"))); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/MavenVersionTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/MavenVersionTests.cs new file mode 100644 index 00000000000..3140d7dcb0c --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/MavenVersionTests.cs @@ -0,0 +1,72 @@ +using System.Linq; +using Java.Interop.Tools.Maven.Models; + +namespace Java.Interop.Tools.Maven_Tests; + +public class MavenVersionTests +{ + [Test] + public void ParseTest () + { + TestParse ("", null, null, null, false); + TestParse ("1", "1", null, null, true); + TestParse ("1.2", "1", "2", null, true); + TestParse ("1.2.3", "1", "2", "3", true); + + TestParse ("1-BETA", "1-BETA", null, null, true); + TestParse ("1-ALPHA.2-BETA", "1-ALPHA", "2-BETA", null, true); + TestParse ("1-ALPHA.2-BETA.3-GAMMA", "1-ALPHA", "2-BETA", "3-GAMMA", true); + + TestParse ("1-ALPHA-RC3.2.3", "1-ALPHA-RC3", "2", "3", true); + + // 4th part isn't valid + TestParse ("1.2.3.4", "1", "2", "3", false); + + // Versions must be numeric + TestParse ("A.B.C", "A", "B", "C", false); + TestParse ("A-B.2.3", "A-B", "2", "3", false); + } + + [Test] + public void SortTest () + { + // Normal versions + TestSort ("1,2", "1", "2"); + TestSort ("1,2", "2", "1"); + TestSort ("1.1,1.2", "1.2", "1.1"); + TestSort ("1.1.1,1.1.2", "1.1.2", "1.1.1"); + + // Qualifiers are always "before" "release" versions when version numbers are equal + TestSort ("1.2-beta-2,1.2", "1.2", "1.2-beta-2"); + TestSort ("1-beta-2,1", "1", "1-beta-2"); + TestSort ("1.1.1-beta-2,1.1.1", "1.1.1", "1.1.1-beta-2"); + + // Qualifiers don't matter if the versions don't match + TestSort ("1-RC,2", "1-RC", "2"); + TestSort ("1,2-RC", "1", "2-RC"); + + // Qualifiers are sorted with simple string sort + TestSort ("1.2-alpha-6,1.2-beta-2", "1.2-alpha-6", "1.2-beta-2"); + + // If any version is "nonstandard", a simple string sort is used + TestSort ("1.0.1.0,1.0.10.1,1.0.10.2,1.0.9.3", "1.0.9.3", "1.0.10.1", "1.0.1.0", "1.0.10.2"); + } + + static void TestParse (string input, string? major, string? minor, string? patch, bool isValid) + { + var v = MavenVersion.Parse (input); + + Assert.AreEqual (major, v.Major); + Assert.AreEqual (minor, v.Minor); + Assert.AreEqual (patch, v.Patch); + Assert.AreEqual (isValid, v.IsValid); + } + + static void TestSort (string expected, params string [] values) + { + var sorted = values.Select (v => MavenVersion.Parse (v)).Order (); + var formatted = string.Join (',', sorted.Select (v => v.RawVersion)); + + Assert.AreEqual (expected, formatted); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/ProjectResolverTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/ProjectResolverTests.cs new file mode 100644 index 00000000000..716e7ebdcde --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/ProjectResolverTests.cs @@ -0,0 +1,76 @@ +using System; +using Java.Interop.Tools.Maven; +using Java.Interop.Tools.Maven.Models; +using Java.Interop.Tools.Maven_Tests.Extensions; + +namespace Java.Interop.Tools.Maven_Tests; + +public class ProjectResolverTests +{ + [Test] + public void ResolveRawProject_Success () + { + var artifact = new Artifact ("bar", "foo", "1.0"); + var project = TestDataExtensions.CreateProject (artifact); + var resolver = new DefaultProjectResolver (); + + resolver.Register (project); + + var result = resolver.Resolve (artifact); + + Assert.AreEqual (project, result); + } + + [Test] + public void ResolveRawProject_PomNotFound () + { + var resolver = new DefaultProjectResolver (); + + Assert.Throws (() => resolver.Resolve (new Artifact ("bar", "foo", "1.0"))); + } + + [Test] + public void Resolve_Success () + { + var artifact = new Artifact ("bar", "foo", "1.0"); + var parent_artifact = new Artifact ("bar-parent", "foo", "1.0"); + + var parent_project = TestDataExtensions.CreateProject (parent_artifact); + var project = TestDataExtensions.CreateProject (artifact, parent_project); + + var resolver = new DefaultProjectResolver (); + + resolver.Register (project); + resolver.Register (parent_project); + + var result = ResolvedProject.FromArtifact (artifact, resolver); + + Assert.AreEqual (project, result.Raw); + Assert.AreEqual (parent_project, result.Parent.Raw); + } + + [Test] + public void Resolve_ParentPomNotFound () + { + var artifact = new Artifact ("bar", "foo", "1.0"); + var parent_artifact = new Artifact ("bar-parent", "foo", "1.0"); + + var parent_project = TestDataExtensions.CreateProject (parent_artifact); + var project = TestDataExtensions.CreateProject (artifact, parent_project); + + var resolver = new DefaultProjectResolver (); + + // Note we are not adding the parent project to the resolver, so it will not be found + resolver.Register (project); + + Assert.Throws (() => ResolvedProject.FromArtifact (artifact, resolver)); + } + + [Test] + public void Resolve_PomNotFound () + { + var resolver = new DefaultProjectResolver (); + + Assert.Throws (() => resolver.Resolve (new Artifact ("bar", "foo", "1.0"))); + } +} diff --git a/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/PropertySubstitutionTests.cs b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/PropertySubstitutionTests.cs new file mode 100644 index 00000000000..ac6110c2ba9 --- /dev/null +++ b/external/Java.Interop/tests/Java.Interop.Tools.Maven-Tests/PropertySubstitutionTests.cs @@ -0,0 +1,161 @@ +using Java.Interop.Tools.Maven; +using Java.Interop.Tools.Maven.Models; +using Java.Interop.Tools.Maven_Tests.Extensions; + +namespace Java.Interop.Tools.Maven_Tests; + +public class PropertySubstitutionTests +{ + [Test] + public void Resolve_ExplicitProperty () + { + // This POM: + // ${mavenVersion} + // + // 3.0 + // + var artifact = new Artifact ("bar", "foo", "${mavenVersion}"); + + var project = TestDataExtensions.CreateProject (artifact); + project.AddProperty ("mavenVersion", "2.0.6"); + + var resolver = new DefaultProjectResolver (); + resolver.Register (project); + + var result = ResolvedProject.FromArtifact (artifact, resolver); + + Assert.AreEqual ("2.0.6", result.Version); + } + + [Test] + public void Resolve_ExplicitPropertyFromParent () + { + // This POM: + // ${mavenVersion} + // Parent POM: + // + // 3.0 + // + var artifact = new Artifact ("bar", "foo", "${mavenVersion}"); + var parent_artifact = new Artifact ("bar-parent", "foo", "1.0"); + + var parent_project = TestDataExtensions.CreateProject (parent_artifact); + var project = TestDataExtensions.CreateProject (artifact, parent_project); + + parent_project.AddProperty ("mavenVersion", "2.0.6"); + + var resolver = new DefaultProjectResolver (); + resolver.Register (parent_project); + resolver.Register (project); + + var result = ResolvedProject.FromArtifact (artifact, resolver); + + Assert.AreEqual ("2.0.6", result.Version); + } + + [Test] + public void Resolve_ProjectProperty () + { + // This POM: + // bar + // foo + // 2.0 + // ${project.groupId}:${project.artifactId}:${project.version} + var artifact = new Artifact ("bar", "foo", "2.0"); + + var project = TestDataExtensions.CreateProject (artifact); + project.Name = "${project.groupId}:${project.artifactId}:${project.version}"; + + var resolver = new DefaultProjectResolver (); + resolver.Register (project); + + var result = ResolvedProject.FromArtifact (artifact, resolver); + + Assert.AreEqual ("bar:foo:2.0", result.Name); + } + + [Test] + public void Resolve_ProjectPropertyFromParent () + { + // This POM: + // bar + // foo + // ${project.groupId}:${project.artifactId}:${project.version} + // Parent POM: + // 2.0 + var artifact = new Artifact ("bar", "foo", ""); + var parent_artifact = new Artifact ("bar-parent", "foo", "2.0"); + + var parent_project = TestDataExtensions.CreateProject (parent_artifact); + var project = TestDataExtensions.CreateProject (artifact, parent_project); + + project.Name = "${project.groupId}:${project.artifactId}:${project.version}"; + + var resolver = new DefaultProjectResolver (); + resolver.Register (parent_project); + resolver.Register (project); + + var result = ResolvedProject.FromArtifact (artifact, resolver); + + Assert.AreEqual ("bar:foo:2.0", result.Name); + } + + [Test] + public void Resolve_RecursiveProperties () + { + // This POM: + // bar + // foo + // ${mavenVersion} + // Parent POM: + // 2.0 + // + // ${project.version} + // + var artifact = new Artifact ("bar", "foo", "${mavenVersion}"); + var parent_artifact = new Artifact ("bar-parent", "foo", "2.0"); + + var parent_project = TestDataExtensions.CreateProject (parent_artifact); + var project = TestDataExtensions.CreateProject (artifact, parent_project); + + parent_project.AddProperty ("mavenVersion", "${project.version}"); + + var resolver = new DefaultProjectResolver (); + resolver.Register (parent_project); + resolver.Register (project); + + var result = ResolvedProject.FromArtifact (artifact, resolver); + + Assert.AreEqual ("2.0", result.Version); + } + + [Test] + public void Resolve_ChildPropertiesTakePrecedenceOverParentProperties () + { + // This POM: + // + // 2.0 + // + // Parent POM: + // ${mavenVersion} + // + // 1.0 + // + var artifact = new Artifact ("bar", "foo", ""); + var parent_artifact = new Artifact ("bar-parent", "foo", "${mavenVersion}"); + + var parent_project = TestDataExtensions.CreateProject (parent_artifact); + var project = TestDataExtensions.CreateProject (artifact, parent_project); + + project.AddProperty ("mavenVersion", "2.0"); + parent_project.AddProperty ("mavenVersion", "1.0"); + + var resolver = new DefaultProjectResolver (); + resolver.Register (parent_project); + resolver.Register (project); + + var result = ResolvedProject.FromArtifact (artifact, resolver); + + Assert.AreEqual ("2.0", result.Version); + } +} diff --git a/external/Java.Interop/tests/NativeTiming/CMakeLists.txt b/external/Java.Interop/tests/NativeTiming/CMakeLists.txt new file mode 100644 index 00000000000..0d4e50d8f71 --- /dev/null +++ b/external/Java.Interop/tests/NativeTiming/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.10.2) + +set(CMAKE_OSX_ARCHITECTURES x86_64 arm64) + +project(NativeTiming C) + +foreach(dir in ${JDK_INCLUDE_LIST}) + include_directories(${dir}) +endforeach() + +add_library(NativeTiming SHARED timing.c) diff --git a/external/Java.Interop/tests/NativeTiming/NativeTiming.csproj b/external/Java.Interop/tests/NativeTiming/NativeTiming.csproj new file mode 100644 index 00000000000..524d49c9e63 --- /dev/null +++ b/external/Java.Interop/tests/NativeTiming/NativeTiming.csproj @@ -0,0 +1,16 @@ + + + + $(DotNetTargetFramework) + false + + + + + + $(TestOutputFullPath) + + + + + diff --git a/external/Java.Interop/tests/NativeTiming/NativeTiming.targets b/external/Java.Interop/tests/NativeTiming/NativeTiming.targets new file mode 100644 index 00000000000..b393bdb5b74 --- /dev/null +++ b/external/Java.Interop/tests/NativeTiming/NativeTiming.targets @@ -0,0 +1,83 @@ + + + + + + <_NativeTimingLibName Condition=" $([MSBuild]::IsOSPlatform ('osx')) ">libNativeTiming.dylib + <_NativeTimingLibName Condition=" $([MSBuild]::IsOSPlatform ('linux')) ">libNativeTiming.so + <_NativeTimingLibName Condition=" $([MSBuild]::IsOSPlatform ('windows')) ">NativeTiming.dll + + + + <_NativeTimingLib Include="CMakeLists.txt"> + x86_amd64 +

    win-x64\ + + <_NativeTimingLib Include="CMakeLists.txt"> + x86 + win-x86\ + + + + + <_NativeTimingLib Include="CMakeLists.txt" /> + + + + + PreserveNewest + %(Dir)$(_NativeTimingLibName) + + + + + + + + + + + + + + + + <_JdkDirs>"-DJDK_INCLUDE_LIST=@(JdkIncludePath, ';')" + + + <_Cmake + Condition=" '$(PrepareNativeToolchain)' != '' " + Include="PrepareNativeToolchain=$(PrepareNativeToolchain) %(_NativeTimingLib.Arch)" + /> + <_Cmake Include="CmakePath=$(CmakePath)" /> + <_Cmake Include="CmakeGenerator=$(CmakeGenerator)" /> + <_Cmake Include="CmakeSourceDir=$(MSBuildThisFileDirectory)" /> + <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)%(_NativeTimingLib.Dir)" /> + <_Cmake Include="CmakeExtraArgs=$(_JdkDirs)" /> + + + + <_Libs Include="$(IntermediateOutputPath)%(_NativeTimingLib.Dir)$(_NativeTimingLibName)*" /> + + + + + + + + + + diff --git a/external/Java.Interop/tests/NativeTiming/timing.c b/external/Java.Interop/tests/NativeTiming/timing.c new file mode 100644 index 00000000000..b72b0bdbefb --- /dev/null +++ b/external/Java.Interop/tests/NativeTiming/timing.c @@ -0,0 +1,409 @@ +#include +#include + +#if WIN32 +#include +#else /* !def WIN32 */ +#include +#endif /* def WIN32 */ + +#ifdef PLATFORM_ANDROID +#include +#endif /* def PLATFORM_ANDROID */ + +static void +_log (const char *format, ...) +{ + va_list args; + va_start (args, format); +#ifdef PLATFORM_ANDROID + __android_log_vprint (ANDROID_LOG_INFO, "*Java.Interop*", format, args); +#else /* def PLATFORM_ANDROID */ + vprintf (format, args); +#endif /* !def PLATFORM_ANDROID */ + va_end (args); +} + +void +foo_void_timing (void) +{ +} + +int +foo_int_timing (void) +{ + return 0; +} + +void* +foo_ptr_timing (void) +{ + return 0; +} + +void +foo_void_a1_timing (void *obj1) +{ +} + +void +foo_void_a2_timing (void *obj1, void *obj2) +{ +} + +void +foo_void_a3_timing (void *obj1, void *obj2, void *obj3) +{ +} + +void +foo_void_ai1_timing (int i1) +{ +} + +void +foo_void_ai2_timing (int i1, int i2) +{ +} + +void +foo_void_ai3_timing (int i1, int i2, int i3) +{ +} + +struct FooMethods { + void (*instance_void)(void); + int (*instance_int)(void); + void* (*instance_ptr)(void); + + void (*void_1_args)(void *); + void (*void_2_args)(void *, void *); + void (*void_3_args)(void *, void *, void *); + + void (*void_1_iargs)(int); + void (*void_2_iargs)(int, int); + void (*void_3_iargs)(int, int, int); +}; + +void +foo_get_methods (struct FooMethods* methods) +{ + methods->instance_void = foo_void_timing; + methods->instance_int = foo_int_timing; + methods->instance_ptr = foo_ptr_timing; + + methods->void_1_args = foo_void_a1_timing; + methods->void_2_args = foo_void_a2_timing; + methods->void_3_args = foo_void_a3_timing; + + methods->void_1_iargs = foo_void_ai1_timing; + methods->void_2_iargs = foo_void_ai2_timing; + methods->void_3_iargs = foo_void_ai3_timing; +} + +static jmethodID Timing_StaticVoidMethod; +static jmethodID Timing_StaticIntMethod; +static jmethodID Timing_StaticObjectMethod; + +static jmethodID Timing_VirtualVoidMethod; +static jmethodID Timing_VirtualIntMethod; +static jmethodID Timing_VirtualObjectMethod; + +static jmethodID Timing_FinalVoidMethod; +static jmethodID Timing_FinalIntMethod; +static jmethodID Timing_FinalObjectMethod; + +static jmethodID Timing_StaticVoidMethod1Args; +static jmethodID Timing_StaticVoidMethod2Args; +static jmethodID Timing_StaticVoidMethod3Args; + +static jmethodID Timing_StaticVoidMethod1IArgs; +static jmethodID Timing_StaticVoidMethod2IArgs; +static jmethodID Timing_StaticVoidMethod3IArgs; + +static jclass Object_class; +static jmethodID Object_init; + +#if 0 +static void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...); +static int (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...); +static jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...); + +static void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); +static int (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); +static jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); + +static void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); +static int (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); +static jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); +#endif + +void +foo_init (JNIEnv *env) +{ + jclass Timing, Object; + + _log ("# NativeTiming: foo_init; env=%p\n", env); + + /* libbar.so loading test */ + if (!env) + return; + + Timing = (*env)->FindClass (env, "com/xamarin/interop/performance/JavaTiming"); + if (!Timing) + return; + + Object = (*env)->FindClass (env, "java/lang/Object"); + if (!Object) + return; + Object_class = (*env)->NewGlobalRef (env, Object); + (*env)->DeleteLocalRef (env, Object); + + Object_init = (*env)->GetMethodID (env, Object_class, "", "()V"); + + #if 0 + CallStaticVoidMethod = (*env)->CallStaticVoidMethod; + CallStaticIntMethod = (*env)->CallStaticIntMethod; + CallStaticObjectMethod = (*env)->CallStaticObjectMethod; + + CallVoidMethod = (*env)->CallVoidMethod; + CallIntMethod = (*env)->CallIntMethod; + CallObjectMethod = (*env)->CallObjectMethod; + + CallNonvirtualVoidMethod = (*env)->CallNonvirtualVoidMethod; + CallNonvirtualIntMethod = (*env)->CallNonvirtualIntMethod; + CallNonvirtualObjectMethod = (*env)->CallNonvirtualObjectMethod; + #endif + + Timing_StaticVoidMethod = (*env)->GetStaticMethodID (env, Timing, + "StaticVoidMethod", "()V"); + Timing_StaticIntMethod = (*env)->GetStaticMethodID (env, Timing, + "StaticIntMethod", "()I"); + Timing_StaticObjectMethod = (*env)->GetStaticMethodID (env, Timing, + "StaticObjectMethod", "()Ljava/lang/Object;"); + + Timing_VirtualVoidMethod = (*env)->GetMethodID (env, Timing, + "VirtualVoidMethod", "()V"); + Timing_VirtualIntMethod = (*env)->GetMethodID (env, Timing, + "VirtualIntMethod", "()I"); + Timing_VirtualObjectMethod = (*env)->GetMethodID (env, Timing, + "VirtualObjectMethod", "()Ljava/lang/Object;"); + + Timing_FinalVoidMethod = (*env)->GetMethodID (env, Timing, + "FinalVoidMethod", "()V"); + Timing_FinalIntMethod = (*env)->GetMethodID (env, Timing, + "FinalIntMethod", "()I"); + Timing_FinalObjectMethod = (*env)->GetMethodID (env, Timing, + "FinalObjectMethod", "()Ljava/lang/Object;"); + + Timing_StaticVoidMethod1Args = (*env)->GetStaticMethodID (env, Timing, + "StaticVoidMethod1Args", "(Ljava/lang/Object;)V"); + Timing_StaticVoidMethod2Args = (*env)->GetStaticMethodID (env, Timing, + "StaticVoidMethod2Args", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + Timing_StaticVoidMethod3Args = (*env)->GetStaticMethodID (env, Timing, + "StaticVoidMethod3Args", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); + + Timing_StaticVoidMethod1IArgs = (*env)->GetStaticMethodID (env, Timing, + "StaticVoidMethod1IArgs", "(I)V"); + Timing_StaticVoidMethod2IArgs = (*env)->GetStaticMethodID (env, Timing, + "StaticVoidMethod2IArgs", "(II)V"); + Timing_StaticVoidMethod3IArgs = (*env)->GetStaticMethodID (env, Timing, + "StaticVoidMethod3IArgs", "(III)V"); + + (*env)->DeleteLocalRef (env, Timing); +} + +static long long +current_time_millis (void) +{ +#if defined (WIN32) + return (long long) GetTickCount64 (); +#else /* !def WIN32 */ + struct timeval tv; + + gettimeofday(&tv, (struct timezone *) NULL); + long long when = tv.tv_sec * 1000LL + tv.tv_usec / 1000; + return when; +#endif /* def WIN32 */ +} + +void +foo_get_native_jni_timings (JNIEnv *env, int count, jclass klass, jobject self, long long *jniTimes) +{ + int i; + long long start, end; + + jobject obj1 = (*env)->NewObject(env, Object_class, Object_init), + obj2 = (*env)->NewObject(env, Object_class, Object_init), + obj3 = (*env)->NewObject(env, Object_class, Object_init); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticVoidMethod (env, klass, Timing_StaticVoidMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [0] = end - start; + _log ("# NativeTiming: foo/timing: static void method invoke: %10lli ms | average: %10f ms\n", + jniTimes [0], jniTimes [0] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticIntMethod (env, klass, Timing_StaticIntMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [1] = end - start; + _log ("# NativeTiming: foo/timing: static int method invoke: %10lli ms | average: %10f ms\n", + jniTimes [1], jniTimes [1] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticObjectMethod (env, klass, Timing_StaticObjectMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [2] = end - start; + _log ("# NativeTiming: foo/timing: static Object method invoke: %10lli ms | average: %10f ms\n", + jniTimes [2], jniTimes [2] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallVoidMethod (env, self, Timing_VirtualVoidMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [3] = end - start; + _log ("# NativeTiming: foo/timing: virtual void method invoke: %10lli ms | average: %10f ms\n", + jniTimes [3], jniTimes [3] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallIntMethod (env, self, Timing_VirtualIntMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [4] = end - start; + _log ("# NativeTiming: foo/timing: virtual int method invoke: %10lli ms | average: %10f ms\n", + jniTimes [4], jniTimes [4] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallObjectMethod (env, self, Timing_VirtualObjectMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [5] = end - start; + _log ("# NativeTiming: foo/timing: virtual Object method invoke: %10lli ms | average: %10f ms\n", + jniTimes [5], jniTimes [5] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallNonvirtualVoidMethod (env, self, klass, Timing_FinalVoidMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [6] = end - start; + _log ("# NativeTiming: foo/timing: final void method invoke: %10lli ms | average: %10f ms\n", + jniTimes [6], jniTimes [6] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallNonvirtualIntMethod (env, self, klass, Timing_FinalIntMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [7] = end - start; + _log ("# NativeTiming: foo/timing: final int method invoke: %10lli ms | average: %10f ms\n", + jniTimes [7], jniTimes [7] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallNonvirtualObjectMethod (env, self, klass, Timing_FinalObjectMethod); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [8] = end - start; + _log ("# NativeTiming: foo/timing: final Object method invoke: %10lli ms | average: %10f ms\n", + jniTimes [8], jniTimes [8] / (double) count); + + + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticVoidMethod (env, klass, Timing_StaticVoidMethod1Args, obj1); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [9] = end - start; + _log ("# NativeTiming: foo/timing: static void o1 method invoke: %10lli ms | average: %10f ms\n", + jniTimes [9], jniTimes [9] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticVoidMethod (env, klass, Timing_StaticVoidMethod2Args, obj1, obj2); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [10] = end - start; + _log ("# NativeTiming: foo/timing: static void o2 method invoke: %10lli ms | average: %10f ms\n", + jniTimes [10], jniTimes [10] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticVoidMethod (env, klass, Timing_StaticVoidMethod3Args, obj1, obj2, obj3); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [11] = end - start; + _log ("# NativeTiming: foo/timing: static void o3 method invoke: %10lli ms | average: %10f ms\n", + jniTimes [11], jniTimes [11] / (double) count); + + + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticVoidMethod (env, klass, Timing_StaticVoidMethod1IArgs, 42); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [12] = end - start; + _log ("# NativeTiming: foo/timing: static void i1 method invoke: %10lli ms | average: %10f ms\n", + jniTimes [12], jniTimes [12] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticVoidMethod (env, klass, Timing_StaticVoidMethod2IArgs, 42, 42); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [13] = end - start; + _log ("# NativeTiming: foo/timing: static void i2 method invoke: %10lli ms | average: %10f ms\n", + jniTimes [13], jniTimes [13] / (double) count); + + start = current_time_millis (); + for (i = 0; i < count; i++) { + (*env)->CallStaticVoidMethod (env, klass, Timing_StaticVoidMethod3IArgs, 42, 42, 42); + (*env)->ExceptionClear (env); + } + end = current_time_millis (); + + jniTimes [14] = end - start; + _log ("# NativeTiming: foo/timing: static void i3 method invoke: %10lli ms | average: %10f ms\n", + jniTimes [14], jniTimes [14] / (double) count); +} + diff --git a/external/Java.Interop/tests/TestData/api-24.xml.in b/external/Java.Interop/tests/TestData/api-24.xml.in new file mode 100644 index 00000000000..24a86328d50 --- /dev/null +++ b/external/Java.Interop/tests/TestData/api-24.xml.in @@ -0,0 +1,2628 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/TestJVM/TestJVM.cs b/external/Java.Interop/tests/TestJVM/TestJVM.cs new file mode 100644 index 00000000000..581584701e7 --- /dev/null +++ b/external/Java.Interop/tests/TestJVM/TestJVM.cs @@ -0,0 +1,571 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using System.Xml.Linq; + +using Xamarin.Android.Tools; + +namespace Java.Interop { + + struct JavaVMInitArgs { + public JniVersion version; + public int nOptions; + public IntPtr options; + public byte ignoreUnrecognized; + } + + struct JavaVMOption { + public IntPtr optionString; + public IntPtr extraInfo; + } + + public class TestJVMOptions : JniRuntime.CreationOptions { + + internal List Options {get;} = new List (); + internal Dictionary? typeMappings; + internal NativeLibraryJvmLibraryHandler? LibraryHandler; + + public ICollection JarFilePaths {get;} = new List (); + public IDictionary TypeMappings => typeMappings ??= new Dictionary (); + + internal List ClassPath {get;} = new List (); + internal JdkInfo? JdkInfo {get; set;} + + public TestJVMOptions () + { + JniVersion = JniVersion.v1_2; + } + + public TestJVMOptions AddOption (string option) + { + if (option == null) + throw new ArgumentNullException (nameof (option)); + Options.Add (option); + return this; + } + } + + public class TestJVM : JniRuntime { + + NativeLibraryJvmLibraryHandler? LibraryHandler; + +#if !__ANDROID__ + public JdkInfo? JdkInfo { get; private set; } +#endif // !__ANDROID__ + + public TestJVM (TestJVMOptions options) + : base (CreateJVM (options)) + { + LibraryHandler = options.LibraryHandler; +#if !__ANDROID__ + JdkInfo = options.JdkInfo; +#endif // !__ANDROID__ + } + + static unsafe TestJVMOptions CreateJVM (TestJVMOptions options) + { + if (options == null) + throw new ArgumentNullException (nameof (options)); + + options.TypeManager ??= new TestJvmTypeManager (options.typeMappings); + options.ValueManager ??= new ManagedValueManager (); + options.ObjectReferenceManager ??= new ManagedObjectReferenceManager (); + + if (options.InvocationPointer != IntPtr.Zero || options.EnvironmentPointer != IntPtr.Zero) + return options; + + var dir = GetOutputDirectoryName (); + var info = GetJdkInfo (); + + options.JvmLibraryPath ??= info.JdkJvmPath; + options.JdkInfo = info.JdkInfo; + + if (string.IsNullOrEmpty (options.JvmLibraryPath)) + throw new InvalidOperationException ($"Member `{nameof (TestJVMOptions)}.{nameof (TestJVMOptions.JvmLibraryPath)}` must be set."); + + foreach (var jar in options.JarFilePaths) + options.ClassPath.Add (Path.Combine (dir, jar)); + options.AddOption ("-Xcheck:jni"); + + var handler = new NativeLibraryJvmLibraryHandler (); + options.LibraryHandler = handler; + try { + handler.LoadJvmLibrary (options.JvmLibraryPath); + EnsureJavaInteropJar (options); + + var args = new JavaVMInitArgs { + version = options.JniVersion, + nOptions = options.Options.Count + 1, + ignoreUnrecognized = 0, + }; + var jvmOptions = new JavaVMOption [options.Options.Count + 1]; + try { + for (int i = 0; i < options.Options.Count; ++i) + jvmOptions [i].optionString = Marshal.StringToHGlobalAnsi (options.Options [i]); + jvmOptions [options.Options.Count].optionString = Marshal.StringToHGlobalAnsi ( + string.Format ("-Djava.class.path={0}", string.Join (Path.PathSeparator.ToString (), options.ClassPath))); + + fixed (JavaVMOption* popts = jvmOptions) { + args.options = (IntPtr) popts; + int r = handler.CreateJavaVM (out var javavm, out var jnienv, ref args); + if (r != 0) { + handler.Dispose (); + options.LibraryHandler = null; + throw new NotSupportedException ( + string.Format ( + "The JDK supports creating at most one JVM per process, ever; " + + "do you have a JVM running already, or have you already created (and destroyed?) one? " + + "(JNI_CreateJavaVM returned {0}).", + r)); + } + options.InvocationPointer = javavm; + options.EnvironmentPointer = jnienv; + } + } finally { + for (int i = 0; i < jvmOptions.Length; ++i) + Marshal.FreeHGlobal (jvmOptions [i].optionString); + } + return options; + } catch { + if (options.LibraryHandler != null) { + options.LibraryHandler.Dispose (); + options.LibraryHandler = null; + } + throw; + } + } + + static void EnsureJavaInteropJar (TestJVMOptions options) + { + if (options.ClassPath.Any (p => p.EndsWith ("java-interop.jar", StringComparison.OrdinalIgnoreCase))) + return; + + var dir = GetOutputDirectoryName (); + var jar = Path.Combine (dir, "java-interop.jar"); + if (!File.Exists (jar)) { + throw new FileNotFoundException ($"`java-interop.jar` is required. Please add to `TestJVMOptions.ClassPath`. Tried to find it in `{jar}`."); + } + options.ClassPath.Add (jar); + } + + static string GetOutputDirectoryName () + { + return Path.GetDirectoryName (typeof (TestJVM).Assembly.Location) ?? + Environment.CurrentDirectory; + } + + public static string? GetJvmLibraryPath (Action? logger = null) => GetJdkInfo (logger).JdkJvmPath; + + static (JdkInfo? JdkInfo, string? JdkJvmPath) GetJdkInfo (Action? logger = null) + { + var info = ReadJavaSdkDirectoryFromJdkInfoProps (logger); + if (info.JdkJvmPath != null) + return (JdkInfo: info.JavaSdkDirectory == null ? null : new JdkInfo (info.JavaSdkDirectory), JdkJvmPath: info.JdkJvmPath); + + var jdk = JdkInfo.GetKnownSystemJdkInfos (logger).FirstOrDefault (); + return (jdk, jdk?.JdkJvmPath); + } + + static (string? JavaSdkDirectory, string? JdkJvmPath) ReadJavaSdkDirectoryFromJdkInfoProps (Action? logger) + { + var jdkPropFile = TryProbeForJdkInfoProps (logger); + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: jdkPropFile? {jdkPropFile}"); + if (!File.Exists (jdkPropFile)) + return (null, null); + + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: Extracting $(JdkJvmPath) from: {jdkPropFile}"); + var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); + + var jdkProps = XDocument.Load (jdkPropFile); + var jdkJvmPath = jdkProps.Elements () + .Elements (msbuild + "Choose") + .Elements (msbuild + "When") + .Elements (msbuild + "PropertyGroup") + .Elements (msbuild + "JdkJvmPath") + .FirstOrDefault (); + if (jdkJvmPath == null) + return (null, null); + + var jdkPath = jdkProps.Elements () + .Elements (msbuild + "PropertyGroup") + .Elements (msbuild + "JavaSdkDirectory") + .FirstOrDefault (); + + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: $(JavaSdkDirectory)={jdkPath?.Value}; $(JdkJvmPath)={jdkJvmPath.Value}"); + return (JavaSdkDirectory: jdkPath?.Value, JdkJvmPath: jdkJvmPath.Value); + } + + static string? TryProbeForJdkInfoProps (Action? logger) + { + for (var probing = Path.GetDirectoryName (typeof (TestJVM).Assembly.Location); probing != null; probing = Path.GetDirectoryName (probing)) { + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: probing for JdkInfo.props around {probing}"); + if (File.Exists (Path.Combine (probing, "Java.Interop.sln"))) + return ProbeFromRootDir (probing); + + var dirName = Path.GetFileName (probing); + if (dirName.StartsWith ("Test", StringComparison.OrdinalIgnoreCase)) { + var buildName = dirName.Replace ("Test", "Build"); + if (buildName.Contains ('-')) + buildName = buildName.Substring (0, buildName.IndexOf ('-')); + return Path.Combine (Path.GetDirectoryName (probing)!, buildName, "JdkInfo.props"); + } + } + return null; + + static string ProbeFromRootDir (string location) + { + var buildDebug = Path.Combine (location, "bin", "BuildDebug"); + var buildRelease = Path.Combine (location, "bin", "BuildRelease"); + if (Directory.Exists (buildDebug) && !Directory.Exists (buildRelease)) + return Path.Combine (buildDebug, "JdkInfo.props"); + if (Directory.Exists (buildRelease) && !Directory.Exists (buildDebug)) + return Path.Combine (buildRelease, "JdkInfo.props"); + var dir = Directory.GetLastWriteTime (buildDebug) > Directory.GetLastWriteTime (buildRelease) + ? buildDebug + : buildRelease; + return Path.Combine (dir, "JdkInfo.props"); + } + } + + public TestJVM (string[]? jars = null, Dictionary? typeMappings = null) + : this (CreateOptions (jars, typeMappings)) + { + } + + static TestJVMOptions CreateOptions (string[]? jarFiles, Dictionary? typeMappings) + { + var options = new TestJVMOptions (); + if (typeMappings != null) { + foreach (var e in typeMappings) + options.TypeMappings.Add (e.Key, e.Value); + } + if (jarFiles != null) { + foreach (var jar in jarFiles) + options.JarFilePaths.Add (jar); + } + return options; + } + + public override string? GetCurrentManagedThreadName () + { + return Thread.CurrentThread.Name; + } + + public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool fNeedFileInfo) + { + return new StackTrace (skipFrames, fNeedFileInfo).ToString (); + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + LibraryHandler?.Dispose (); + LibraryHandler = null; + } + } + + internal sealed class NativeLibraryJvmLibraryHandler : IDisposable { + + IntPtr handle; + IntPtr create; + + public void LoadJvmLibrary (string path) + { + handle = NativeLibrary.Load (path); + if (!NativeLibrary.TryGetExport (handle, "JNI_CreateJavaVM", out create) || + !NativeLibrary.TryGetExport (handle, "JNI_GetCreatedJavaVMs", out _)) { + Dispose (); + throw new NotSupportedException ($"Library `{path}` does not export the required symbols `JNI_CreateJavaVM` or `JNI_GetCreatedJavaVMs`!"); + } + } + + public unsafe int CreateJavaVM (out IntPtr javavm, out IntPtr jnienv, ref JavaVMInitArgs args) + { + var createJavaVM = (delegate* unmanaged) create; + return createJavaVM (out javavm, out jnienv, ref args); + } + + public void Dispose () + { + if (handle != IntPtr.Zero) + NativeLibrary.Free (handle); + handle = IntPtr.Zero; + create = IntPtr.Zero; + } + } + + class ManagedObjectReferenceManager : JniRuntime.JniObjectReferenceManager { + + int grefCount; + int wgrefCount; + + public override int GlobalReferenceCount => grefCount; + public override int WeakGlobalReferenceCount => wgrefCount; + + public override JniObjectReference CreateGlobalReference (JniObjectReference reference) + { + var r = base.CreateGlobalReference (reference); + if (r.IsValid) + Interlocked.Increment (ref grefCount); + return r; + } + + public override void DeleteGlobalReference (ref JniObjectReference reference) + { + if (reference.IsValid) + Interlocked.Decrement (ref grefCount); + base.DeleteGlobalReference (ref reference); + } + + public override JniObjectReference CreateWeakGlobalReference (JniObjectReference reference) + { + var r = base.CreateWeakGlobalReference (reference); + if (r.IsValid) + Interlocked.Increment (ref wgrefCount); + return r; + } + + public override void DeleteWeakGlobalReference (ref JniObjectReference reference) + { + if (reference.IsValid) + Interlocked.Decrement (ref wgrefCount); + base.DeleteWeakGlobalReference (ref reference); + } + } + + public class ManagedValueManager : JniRuntime.ReflectionJniValueManager { + + Dictionary>? RegisteredInstances = new Dictionary> (); + + public override void WaitForGCBridgeProcessing () + { + } + + public override void CollectPeers () + { + var registered = RegisteredInstances ?? throw new ObjectDisposedException (nameof (ManagedValueManager)); + var peers = new List (); + + lock (registered) { + foreach (var ps in registered.Values) + peers.AddRange (ps); + registered.Clear (); + } + + List? exceptions = null; + foreach (var peer in peers) { + try { + peer.Dispose (); + } catch (Exception e) { + exceptions ??= new List (); + exceptions.Add (e); + } + } + if (exceptions != null) + throw new AggregateException ("Exceptions while collecting peers.", exceptions); + } + + public override void AddPeer (IJavaPeerable value) + { + var registered = RegisteredInstances ?? throw new ObjectDisposedException (nameof (ManagedValueManager)); + var r = value.PeerReference; + if (!r.IsValid) + throw new ObjectDisposedException (value.GetType ().FullName); + + if (r.Type != JniObjectReferenceType.Global) { + value.SetPeerReference (r.NewGlobalRef ()); + JniObjectReference.Dispose (ref r, JniObjectReferenceOptions.CopyAndDispose); + } + + int key = value.JniIdentityHashCode; + lock (registered) { + if (!registered.TryGetValue (key, out var peers)) { + registered.Add (key, new List { value }); + return; + } + + for (int i = peers.Count - 1; i >= 0; i--) { + var peer = peers [i]; + if (!JniEnvironment.Types.IsSameObject (peer.PeerReference, value.PeerReference)) + continue; + if (Replaceable (peer, value)) { + peers [i] = value; + } else { + WarnNotReplacing (key, value, peer); + } + return; + } + peers.Add (value); + } + } + + static bool Replaceable (IJavaPeerable peer, IJavaPeerable value) + { + return peer.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable) && + !value.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable); + } + + void WarnNotReplacing (int key, IJavaPeerable ignoreValue, IJavaPeerable keepValue) + { + Runtime.ObjectReferenceManager.WriteGlobalReferenceLine ( + "Warning: Not registering PeerReference={0} IdentityHashCode=0x{1} Instance={2} Instance.Type={3} Java.Type={4}; " + + "keeping previously registered PeerReference={5} Instance={6} Instance.Type={7} Java.Type={8}.", + ignoreValue.PeerReference.ToString (), + key.ToString ("x"), + RuntimeHelpers.GetHashCode (ignoreValue).ToString ("x"), + ignoreValue.GetType ().FullName, + JniEnvironment.Types.GetJniTypeNameFromInstance (ignoreValue.PeerReference), + keepValue.PeerReference.ToString (), + RuntimeHelpers.GetHashCode (keepValue).ToString ("x"), + keepValue.GetType ().FullName, + JniEnvironment.Types.GetJniTypeNameFromInstance (keepValue.PeerReference)); + } + + public override IJavaPeerable? PeekPeer (JniObjectReference reference) + { + var registered = RegisteredInstances ?? throw new ObjectDisposedException (nameof (ManagedValueManager)); + if (!reference.IsValid) + return null; + + int key = GetJniIdentityHashCode (reference); + lock (registered) { + if (!registered.TryGetValue (key, out var peers)) + return null; + + for (int i = peers.Count - 1; i >= 0; i--) { + var peer = peers [i]; + if (JniEnvironment.Types.IsSameObject (reference, peer.PeerReference)) + return peer; + } + if (peers.Count == 0) + registered.Remove (key); + } + return null; + } + + public override void RemovePeer (IJavaPeerable value) + { + var registered = RegisteredInstances ?? throw new ObjectDisposedException (nameof (ManagedValueManager)); + if (value == null) + throw new ArgumentNullException (nameof (value)); + + int key = value.JniIdentityHashCode; + lock (registered) { + if (!registered.TryGetValue (key, out var peers)) + return; + + for (int i = peers.Count - 1; i >= 0; i--) { + if (object.ReferenceEquals (value, peers [i])) + peers.RemoveAt (i); + } + if (peers.Count == 0) + registered.Remove (key); + } + } + + public override void FinalizePeer (IJavaPeerable value) + { + var h = value.PeerReference; + var o = Runtime.ObjectReferenceManager; + // MUST NOT use SafeHandle.ReferenceType: local refs are tied to a JniEnvironment + // and the JniEnvironment's corresponding thread; it's a thread-local value. + // Accessing SafeHandle.ReferenceType won't kill anything (so far...), but + // instead it always returns JniReferenceType.Invalid. + if (!h.IsValid || h.Type == JniObjectReferenceType.Local) { + RemovePeer (value); + value.SetPeerReference (new JniObjectReference ()); + value.Finalized (); + return; + } + + RemovePeer (value); + if (o.LogGlobalReferenceMessages) { + o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}", + h.ToString (), + value.JniIdentityHashCode.ToString ("x"), + RuntimeHelpers.GetHashCode (value).ToString ("x"), + value.GetType ().ToString ()); + } + value.SetPeerReference (new JniObjectReference ()); + JniObjectReference.Dispose (ref h); + value.Finalized (); + } + + public override List GetSurfacedPeers () + { + var registered = RegisteredInstances ?? throw new ObjectDisposedException (nameof (ManagedValueManager)); + lock (registered) { + var peers = new List (registered.Count); + foreach (var e in registered) { + foreach (var peer in e.Value) + peers.Add (new JniSurfacedPeerInfo (e.Key, new WeakReference (peer))); + } + return peers; + } + } + + protected override void Dispose (bool disposing) + { + RegisteredInstances = null; + base.Dispose (disposing); + } + } + + public class TestJvmTypeManager : JniRuntime.ReflectionJniTypeManager { + + const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; + + IDictionary? typeMappings; + + public TestJvmTypeManager (IDictionary? typeMappings) + { + this.typeMappings = typeMappings; + } + + protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) + { + foreach (var type in base.GetTypesForSimpleReference (jniSimpleReference)) + yield return type; + if (typeMappings != null && typeMappings.TryGetValue (jniSimpleReference, out var target)) + yield return target; + } + + protected override IEnumerable GetSimpleReferences (Type type) + { + return base.GetSimpleReferences (type) + .Concat (CreateSimpleReferencesEnumerator (type)); + } + + IEnumerable CreateSimpleReferencesEnumerator (Type type) + { + if (typeMappings == null) + yield break; + foreach (var e in typeMappings) { + if (e.Value == type) + yield return e.Key; + } + } + + public override void RegisterNativeMembers ( + JniType nativeClass, + [DynamicallyAccessedMembers (MethodsAndPrivateNested)] + Type type, + ReadOnlySpan methods) + { + if (TryRegisterNativeMembers (nativeClass, type, methods) || methods.IsEmpty) + return; + + throw new NotSupportedException ( + $"Could not register native members for type '{type.FullName}'. " + + "Ensure that the type has the appropriate [JniAddNativeMethodRegistration] attribute and static registration method."); + } + } +} diff --git a/external/Java.Interop/tests/TestJVM/TestJVM.csproj b/external/Java.Interop/tests/TestJVM/TestJVM.csproj new file mode 100644 index 00000000000..bccab73e1ee --- /dev/null +++ b/external/Java.Interop/tests/TestJVM/TestJVM.csproj @@ -0,0 +1,31 @@ + + + + $(DotNetTargetFramework) + enable + false + true + ..\..\product.snk + true + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/GenericInheritanceMappingTest.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/GenericInheritanceMappingTest.cs new file mode 100644 index 00000000000..6c02cfaeb3b --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/GenericInheritanceMappingTest.cs @@ -0,0 +1,89 @@ +using System; +using System.Linq; +using NUnit.Framework; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster.Tests +{ + [TestFixture] + public class GenericInheritanceMappingTest + { + JavaApi api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.Resolve (); + api.CreateGenericInheritanceMapping (); + } + + [Test] + public void GenericInheritanceMappings () + { + var obj = api.FindNonGenericType ("java.lang.Object") as JavaClass; + Assert.IsNotNull (obj.GenericInheritanceMapping, "java.lang.Object mapping not found"); + Assert.AreEqual (0, obj.GenericInheritanceMapping.Count, "ContentObservable mapping not found"); + + var kls = api.FindNonGenericType ("android.database.ContentObservable") as JavaClass; + var map = kls.GenericInheritanceMapping; + Assert.IsNotNull (map, "ContentObservable mapping not found"); + Assert.AreEqual (1, map.Count, "ContentObservable mapping count unexpected"); + + Assert.IsNotNull (map.Keys.First ().ReferencedTypeParameter, "key is not GenericTypeParameter"); + Assert.IsNotNull ("T", map.Keys.First ().ReferencedTypeParameter.Name, "key GenericTypeParameter has unexpected name"); + Assert.IsNotNull (map.Values.First ().ReferencedType, "value is not to JavaType"); + Assert.IsNotNull ("android.database.ContentObserver", map.Values.First ().ReferencedType.FullName, "value JavaType has unexpected name"); + + var dummyType = new JavaClass (new JavaPackage (api) { Name = string.Empty }) { Name = "Dummy" }; + var tps = new JavaTypeParameters (dummyType); + JavaTypeReference mapped; + Assert.IsTrue (map.TryGetValue (new JavaTypeReference (new JavaTypeParameter (tps) { Name = "T" }, null), out mapped), + "Mapped type for generic parameter 'T' not found, or dictionary lookup failed."); + Assert.AreEqual ("android.database.ContentObserver", mapped.ReferencedType.FullName, "unexpected resolved type"); + } + + [Test] + public void GenericDerivation () + { + var dic = api.FindNonGenericType ("java.util.Dictionary") as JavaClass; + Assert.IsNotNull (dic, "Dictionary not found"); + Assert.AreEqual (0, dic.GenericInheritanceMapping.Count, "Dictionary should have no mapping."); + + var hashtable = api.FindNonGenericType ("java.util.Hashtable") as JavaClass; + Assert.IsNotNull (hashtable, "Hashtable not found"); + Assert.AreEqual (0, hashtable.GenericInheritanceMapping.Count, "Hashtable should have no mapping."); + + var dummyType = new JavaClass (new JavaPackage (api) { Name = string.Empty }) { Name = "Dummy" }; + var tps = new JavaTypeParameters (dummyType); + var props = api.FindNonGenericType ("java.util.Properties") as JavaClass; + Assert.IsNotNull (props, "Properties not found"); + Assert.AreEqual (2, props.GenericInheritanceMapping.Count, "Properties should have no mapping."); + var k = new JavaTypeReference (new JavaTypeParameter (tps) { Name = "K" }, null); + var v = new JavaTypeReference (new JavaTypeParameter (tps) { Name = "V" }, null); + Assert.IsNotNull (props.GenericInheritanceMapping [k], "Properties: mapping for K not found."); + Assert.AreEqual ("java.lang.Object", props.GenericInheritanceMapping [k].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object."); + Assert.AreEqual ("java.lang.Object", props.GenericInheritanceMapping [v].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object."); + } + + [Test] + public void NonGenericDerivation () + { + var viewGroup = api.FindNonGenericType ("android.view.ViewGroup") as JavaClass; + Assert.IsNotNull (viewGroup, "ViewGroup not found"); + Assert.AreEqual (0, viewGroup.GenericInheritanceMapping.Count, "ViewGroup should have no mapping."); + + var adapterView = api.FindNonGenericType ("android.widget.AdapterView") as JavaClass; + Assert.IsNotNull (adapterView, "AdapterView not found"); + Assert.AreEqual (0, adapterView.GenericInheritanceMapping.Count, "AdapterView should have no mapping."); + + var absListView = api.FindNonGenericType ("android.widget.AbsListView") as JavaClass; + Assert.IsNotNull (absListView, "AbsListView not found"); + Assert.AreEqual (1, absListView.GenericInheritanceMapping.Count, "AbsListView should have 1 mapping."); + + var listView = api.FindNonGenericType ("android.widget.ListView") as JavaClass; + Assert.IsNotNull (listView, "ListView not found"); + Assert.AreEqual (0, listView.GenericInheritanceMapping.Count, "ListView should have no mapping."); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/JavaApiTest.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/JavaApiTest.cs new file mode 100644 index 00000000000..727bffe6278 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/JavaApiTest.cs @@ -0,0 +1,63 @@ +using NUnit.Framework; +using System; +using System.Xml; +using System.Linq; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster.Tests +{ + [TestFixture] + public class JavaApiTest + { + JavaApi api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + } + + [Test] + public void TestToString () + { + var pkg = api.AllPackages.First (p => p.Name == "android.database"); + Assert.AreEqual ("[Package] android.database", pkg.ToString ()); + var kls = pkg.AllTypes.First (t => t.FullName == "android.database.ContentObservable"); + Assert.AreEqual ("[Class] android.database.ContentObservable", kls.ToString ()); + } + + [Test] + public void ParseName () + { + var tn = JavaTypeName.Parse ("java.util.Function, ? extends U>"); + Assert.AreEqual ("java.util.Function", tn.FullNameNonGeneric, "top failed to parse name"); + Assert.AreEqual (2, tn.GenericArguments.Count, "top incorrect number of parsed generic arguments"); + var ga1 = tn.GenericArguments [0]; + Assert.AreEqual ("java.util.Map.Entry", ga1.FullNameNonGeneric, "genarg#0 name mismatch"); + Assert.AreEqual (2, ga1.GenericArguments.Count, "genarg#0 incorrect number of parsed generic arguments"); + Assert.AreEqual ("K", ga1.GenericArguments [0].FullNameNonGeneric, "genarg#0.1 name mismatch"); + Assert.AreEqual ("V", ga1.GenericArguments [1].FullNameNonGeneric, "genarg#0.2 name mismatch"); + var ga2 = tn.GenericArguments [1]; + Assert.AreEqual ("?", ga2.FullNameNonGeneric, "genarg#1 name mismatch"); + Assert.AreEqual (" extends ", ga2.BoundsType, "genarg#1 incorrect bounds type"); + Assert.AreEqual (1, ga2.GenericConstraints.Count, "genarg#1 incorrect number of parsed generic constraints"); + Assert.AreEqual ("U", ga2.GenericConstraints [0].FullNameNonGeneric, "genarg#1.1 constraint name mismatch"); + } + + [Test] + public void ParseName2 () + { + string name = "com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a.b"; + var tn = JavaTypeName.Parse (name); + Assert.IsTrue (tn.GenericParent != null, "result has generic parent"); + Assert.AreEqual ("b", tn.DottedName, "result name mismatch"); + Assert.AreEqual ("com.good.gd.ndkproxy.auth.GDFingerprintAuthenticationManager.a.b", tn.FullNameNonGeneric, "failed to parse name"); + Assert.AreEqual (1, tn.GenericArguments.Count, "result genparams count mismatch"); + Assert.AreEqual ("com.good.gd.ndkproxy.auth.d.a", tn.GenericArguments [0].FullNameNonGeneric, "result genarg name mismatch"); + var p = tn.GenericParent; + Assert.AreEqual (1, p.GenericArguments.Count, "top genparams count"); + var ga1 = p.GenericArguments [0]; + Assert.AreEqual ("com.good.gd.ndkproxy.auth.c.a", ga1.FullNameNonGeneric, "top genarg name mismatch"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/JavaApiTestHelper.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/JavaApiTestHelper.cs new file mode 100644 index 00000000000..df127d2bafb --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/JavaApiTestHelper.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using System.Xml; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster.Tests +{ + public class JavaApiTestHelper + { + static readonly string TopDir = Path.Combine ( + Path.GetDirectoryName (typeof (JavaApiTestHelper).Assembly.Location), + "..", + ".."); + + public static readonly string ApiPath = Path.Combine ( + TopDir, + "tests", + "TestData", + "api-24.xml.in"); + + public static JavaApi GetLoadedApi () + { + // The shared api-24.xml.in contains a handful of `annotated-visibility="TESTS"` + // markers used by Java.Interop.Tools.JavaTypeSystem-Tests. ApiXmlAdjuster's loader + // does not understand that attribute, so strip it before parsing. + var text = File.ReadAllText (ApiPath).Replace (" annotated-visibility=\"TESTS\"", ""); + var api = new JavaApi (); + using (var sr = new StringReader (text)) + using (var xr = XmlReader.Create (sr, new XmlReaderSettings { XmlResolver = null })) + api.Load (xr, false); + return api; + } + } +} + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/OverrideMarkerTest.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/OverrideMarkerTest.cs new file mode 100644 index 00000000000..085d0ddbeff --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/OverrideMarkerTest.cs @@ -0,0 +1,97 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml; +using NUnit.Framework; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster.Tests +{ + [TestFixture] + public class OverrideMarkerTest + { + JavaApi api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.Resolve (); + api.CreateGenericInheritanceMapping (); + api.MarkOverrides (); + } + + [Test] + public void InstantiatedGenericArgumentName () + { + var kls = api.FindNonGenericType ("android.database.ContentObservable") as JavaClass; + var method = kls.Members.OfType ().First (m => m.Name == "registerObserver"); + Assert.IsNotNull (method, "registerObserver() not found."); + var para = method.Parameters.FirstOrDefault (); + Assert.IsNotNull (para, "Expected parameter, not found."); + Assert.AreEqual (method.Parameters.First (), method.Parameters.Last (), "There should be only one parameter."); + Assert.AreEqual ("T", para.InstantiatedGenericArgumentName, "InstantiatedGenericArgumentName mismatch"); + } + + [Test] + public void AncestralOverrides () + { + string xml = @" + + + + + + + + + + +"; + var xapi = JavaApiTestHelper.GetLoadedApi (); + using (var xr = XmlReader.Create (new StringReader (xml))) + xapi.Load (xr, false); + xapi.Resolve (); + xapi.CreateGenericInheritanceMapping (); + xapi.MarkOverrides (); + var t = xapi.AllPackages.First (_ => _.Name == "XXX").AllTypes.First (_ => _.Name == "SherlockExpandableListActivity"); + var m = t.Members.OfType ().First (_ => _.Name == "addContentView"); + Assert.IsNotNull (m.BaseMethod, "base method not found"); + } + + [Test] + public void GenericConstructors () + { + string xml = @" + + + + + + + + + + + +"; + var xapi = new JavaApi (); + using (var xr = XmlReader.Create (new StringReader (xml))) + xapi.Load (xr, false); + xapi.StripNonBindables (); + xapi.Resolve (); + xapi.CreateGenericInheritanceMapping (); + xapi.MarkOverrides (); + xapi.FindDefects (); + var sw = new StringWriter (); + using (var xw = XmlWriter.Create (sw)) + xapi.Save (xw); + xapi = new JavaApi (); + using (var xr = XmlReader.Create (new StringReader (sw.ToString ()))) + xapi.Load (xr, true); + var t = xapi.AllPackages.First (_ => _.Name == "XXX").AllTypes.First (_ => _.Name == "GenericConstructors"); + var m = t.Members.OfType ().FirstOrDefault (); + Assert.IsNotNull (m.TypeParameters, "constructor not found"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/TypeResolverTest.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/TypeResolverTest.cs new file mode 100644 index 00000000000..479d29c9ea5 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/TypeResolverTest.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using NUnit.Framework; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster.Tests +{ + [TestFixture] + public class TypeResolverTest + { + JavaApi api; + + [OneTimeSetUp] + public void SetupFixture () + { + api = JavaApiTestHelper.GetLoadedApi (); + api.Resolve (); + } + + [Test] + public void TypeReferenceEquals () + { + var intRef = JavaTypeReference.Int; + Assert.AreEqual (JavaTypeReference.Int, intRef, "primitive types 2"); + + var dummyType = new JavaClass (new JavaPackage (api) { Name = string.Empty }) { Name = "Dummy" }; + var tps = new JavaTypeParameters (dummyType); + var gt = new JavaTypeParameter (tps) { Name = "T" }; + Assert.AreEqual (new JavaTypeReference (gt, null), new JavaTypeReference (new JavaTypeParameter (tps) { Name = "T"}, null), "type parameters"); + Assert.AreNotEqual (new JavaTypeReference (gt, null), new JavaTypeReference (new JavaTypeParameter (tps) { Name = "U"}, null), "type parameters 2"); + Assert.AreNotEqual (new JavaTypeReference (gt, null), new JavaTypeReference (gt, "[]"), "type parameters: array vs. non-array"); + Assert.AreEqual (new JavaTypeReference (gt, "[]"), new JavaTypeReference (gt, "[]"), "type parameters: array vs. array"); + + var type = new JavaClass (new JavaPackage (api) { Name = string.Empty }) { Name = "T" }; + Assert.AreEqual (new JavaTypeReference (type, null, null), new JavaTypeReference (type, null, null), "type vs. type"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, null), "type: array vs. non array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, "[][]"), "type: array vs. array of array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, null), new JavaTypeReference (new JavaTypeParameter (tps) { Name = "T"}, null), "type vs. type parameters"); + + Assert.AreNotEqual (new JavaTypeReference (gt, "[]"), new JavaTypeReference (type, null, null), "type: array vs. non array"); + Assert.AreNotEqual (new JavaTypeReference (type, null, "[]"), new JavaTypeReference (type, null, "[][]"), "type: array vs. array of array"); + } + + [Test] + public void TestResolvedTypes () + { + var type = api.FindNonGenericType ("android.database.ContentObservable"); + Assert.IsNotNull (type, "type not found"); + var kls = type as JavaClass; + Assert.IsNotNull (kls, "type was not class"); + Assert.IsNotNull (kls.ResolvedExtends, "extends not resolved."); + Assert.IsNotNull (kls.ResolvedExtends.ReferencedType, "referenced type is not correctly resolved"); + } + + [Test] + public void ResolveGenericArguments () + { + var type = api.FindNonGenericType ("java.util.concurrent.ConcurrentHashMap"); + Assert.IsNotNull (type, "type not found"); + var kls = type as JavaClass; + Assert.IsNotNull (kls, "type was not class"); + var method = kls.Members.OfType ().First (m => m.Name == "searchEntries"); + Assert.IsNotNull (method, "method not found."); + var para = method.Parameters [1]; + Assert.AreEqual ("java.util.function.Function, ? extends U>", + para.ResolvedType.ToString (), + "referenced type is not correctly resolved"); + } + + [Test] + public void IntentServiceHack () + { + // https://github.com/xamarin/java.interop/issues/717 + var api = JavaApiTestHelper.GetLoadedApi (); + + // Create "mono.android.app" package + var mono_android_app = new JavaPackage (api) { Name = "mono.android.app", JniName = "mono/android/app" }; + api.Packages.Add (mono_android_app.Name, mono_android_app); + + // Remove "android.app.IntentService" type + var android_app = api.AllPackages.Single (p => p.Name == "android.app"); + var intent_service = android_app.AllTypes.Single (t => t.Name == "IntentService"); + android_app.RemoveType (intent_service); + + // Create new "mono.android.app.IntentService" type + var new_intent_service = new JavaClass (mono_android_app) { + Name = intent_service.Name, + }; + + mono_android_app.AddType (new_intent_service); + + api.Resolve (); + + // Ensure we can resolve the type by either name + Assert.AreSame (new_intent_service, api.FindNonGenericType ("android.app.IntentService")); + Assert.AreSame (new_intent_service, api.FindNonGenericType ("mono.android.app.IntentService")); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests.csproj b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests.csproj new file mode 100644 index 00000000000..a823dc72ebf --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests/Xamarin.Android.Tools.ApiXmlAdjuster-Tests.csproj @@ -0,0 +1,25 @@ + + + + $(DotNetTargetFramework) + false + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ClassFileFixture.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ClassFileFixture.cs new file mode 100644 index 00000000000..51795a60cbf --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ClassFileFixture.cs @@ -0,0 +1,159 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + public class ClassFileFixture { + + static void OnLog (TraceLevel level, int verbosity, string format, object[] args) + { + var message = string.Format (format, args); + + // No "debug" messages from `Methods.cs` should be generated when parsing `.class` files. + if (message.StartsWith ("class-parse: method", StringComparison.OrdinalIgnoreCase)) { + Assert.Fail ($"TraceLevel={level}, Verbosity={verbosity}, Message={message}"); + } + } + + [SetUp] + public void CreateLogger () + { + Log.OnLog = OnLog; + } + + [TearDown] + public void DestroyLogger () + { + Log.OnLog = null; + } + + protected static ClassFile LoadClassFile (string resource) + { + using (var stream = GetResourceStream (resource)) { + if (stream == null) { + throw new InvalidOperationException ($"Could not find resource `{resource}`!"); + } + return new ClassFile (stream); + } + } + + protected static string LoadString (string resource) + { + var s = GetResourceStream (resource); + if (s == null) { + throw new InvalidOperationException ($"Could not find resource `{resource}`!"); + } + using (s) + using (var r = new StreamReader (s)) + return r.ReadToEnd (); + } + + protected static string LoadToTempFile (string resource) + { + var tempFilePath = Path.GetTempFileName (); + + using (var w = File.Create (tempFilePath)) + using (var s = GetResourceStream (resource)) + s.CopyTo (w); + + return tempFilePath; + } + + protected static void AssertXmlDeclaration (string classResource, string xmlResource, string documentationPath = null) + { + var classPathBuilder = new ClassPath () { + ApiSource = "class-parse", + DocumentationPaths = new string[] { + documentationPath, + }, + }; + classPathBuilder.Add (LoadClassFile (classResource)); + + var actual = new StringWriter (); + classPathBuilder.ApiSource = "class-parse"; + classPathBuilder.SaveXmlDescription (actual); + + var expected = LoadString (xmlResource); + + Assert.AreEqual (expected, actual.ToString ()); + } + + protected static void AssertXmlDeclaration (string[] classResources, string xmlResource, string documentationPath = null) + { + var classPathBuilder = new ClassPath () { + ApiSource = "class-parse", + DocumentationPaths = new string[] { + documentationPath, + }, + AutoRename = true + }; + foreach(var classFile in classResources.Select(s => LoadClassFile (s))) + classPathBuilder.Add (classFile); + + var actual = new StringWriter (); + classPathBuilder.SaveXmlDescription (actual); + + var expected = LoadString (xmlResource); + + Assert.AreEqual (expected, actual.ToString ()); + } + + protected static KotlinMetadata GetMetadataForClass (ClassFile klass) + { + var attr = klass.Attributes.OfType ().FirstOrDefault (); + var kotlin = attr?.Annotations.FirstOrDefault (a => a.Type == "Lkotlin/Metadata;"); + + Assert.NotNull (kotlin); + + var meta = KotlinMetadata.FromAnnotation (kotlin); + + return meta; + } + + protected static KotlinClass GetClassMetadataForClass (ClassFile klass) + { + var meta = GetMetadataForClass (klass); + Assert.AreEqual (KotlinMetadataKind.Class, meta.Kind); + + return meta.AsClassMetadata (); + } + + protected static KotlinFile GetFileMetadataForClass (ClassFile klass) + { + var meta = GetMetadataForClass (klass); + Assert.AreEqual (KotlinMetadataKind.File, meta.Kind); + + return meta.AsFileMetadata (); + } + + protected static KotlinMetadata GetMetadataForClassFile (string file) + { + var c = LoadClassFile (file); + return GetMetadataForClass (c); + } + + protected static KotlinClass GetClassMetadata (string file) + { + var c = LoadClassFile (file); + return GetClassMetadataForClass (c); + } + + static Stream GetResourceStream (string resource) + { + // Look for resources that end with our name, this allows us to + // avoid the LogicalName stuff + var assembly = Assembly.GetExecutingAssembly (); + var name = assembly.GetManifestResourceNames ().FirstOrDefault (n => n.EndsWith ("." + resource, StringComparison.OrdinalIgnoreCase)) ?? resource; + + return assembly.GetManifestResourceStream (name); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ClassFileTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ClassFileTests.cs new file mode 100644 index 00000000000..465b64ba06d --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ClassFileTests.cs @@ -0,0 +1,20 @@ +using System; +using System.Reflection; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class ClassFileTests { + + [Test] + public void Constructor_Exceptions () + { + Assert.Throws (() => new ClassFile (null)); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ConfiguredJdkInfo.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ConfiguredJdkInfo.cs new file mode 100644 index 00000000000..9126fbeaa54 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ConfiguredJdkInfo.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +using Xamarin.Android.Tools; + +namespace Xamarin.Android.Tools.BytecodeTests { + + static class ConfiguredJdkInfo { + + static JdkInfo info; + + static ConfiguredJdkInfo () + { + var jdkPath = ReadJavaSdkDirectoryFromJdkInfoProps (); + if (jdkPath == null) + return; + info = new JdkInfo (jdkPath); + } + + public static Version Version => info?.Version; + + static string ReadJavaSdkDirectoryFromJdkInfoProps () + { + var location = typeof (ConfiguredJdkInfo).Assembly.Location; + var binDir = Path.GetDirectoryName (Path.GetDirectoryName (location)); + var testDir = Path.GetFileName (Path.GetDirectoryName (location)); + if (!testDir.StartsWith ("Test", StringComparison.OrdinalIgnoreCase)) { + return null; + } + var buildName = testDir.Replace ("Test", "Build"); + if (buildName.IndexOf ("-", StringComparison.Ordinal) >= 0) { + buildName = buildName.Substring (0, buildName.IndexOf ('-')); + } + var jdkPropFile = Path.Combine (binDir, buildName, "JdkInfo.props"); + if (!File.Exists (jdkPropFile)) { + return null; + } + + var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); + + var jdkProps = XDocument.Load (jdkPropFile); + var jdkPath = jdkProps.Elements () + .Elements (msbuild + "PropertyGroup") + .Elements (msbuild + "JavaSdkDirectory") + .FirstOrDefault (); + if (jdkPath == null) { + return null; + } + return jdkPath.Value; + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedFieldDeclaration.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedFieldDeclaration.cs new file mode 100644 index 00000000000..10d49adc417 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedFieldDeclaration.cs @@ -0,0 +1,36 @@ +using System; +using System.Linq; + +using Xamarin.Android.Tools.Bytecode; + +using NAssert = NUnit.Framework.Assert; + +namespace Xamarin.Android.Tools.BytecodeTests { + + class ExpectedFieldDeclaration { + + public string Name; + public string Descriptor; + public string GenericDescriptor; + public string ConstantValue; + public bool Deprecated; + public FieldAccessFlags AccessFlags; + + public void Assert (FieldInfo field) + { + NAssert.AreEqual (AccessFlags, field.AccessFlags, string.Format ("Access flags for field '{0}' ({1}) doesn't match expected ({2})!", Name, field.AccessFlags, AccessFlags)); + NAssert.AreEqual (Name, field.Name, string.Format ("Field name '{0}' doesn't match expected '{1}'!", Name, field.Name)); + NAssert.AreEqual (Descriptor, field.Descriptor, string.Format ("Descriptor for field '{0}' ({1}) doesn't match expected ({2})!", Name, field.Descriptor, Descriptor)); + NAssert.AreEqual (GenericDescriptor, field.GetSignature (), string.Format ("GenericDescriptor for field '{0}' ({1}) doesn't match expected ({2})!", Name, field.GetSignature (), GenericDescriptor)); + NAssert.AreEqual (Deprecated, field.Attributes.Get() != null, + string.Format ("Deprecated for field '{0}' ({1}) doesn't match expected ({2})!", Name, !Deprecated, Deprecated)); + if (ConstantValue != null) { + ConstantValueAttribute cvalue = (ConstantValueAttribute) field.Attributes.FirstOrDefault (a => a.Name == "ConstantValue"); + NAssert.IsNotNull (cvalue, string.Format ("No constant found for field '{0}'!", Name)); + NAssert.AreEqual (ConstantValue, cvalue.Constant.ToString (), + string.Format ("ConstantValue for field '{0}' ({1}) doesn't match expected ({2})!", Name, cvalue.Constant.ToString (), ConstantValue)); + } + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedInnerClassInfo.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedInnerClassInfo.cs new file mode 100644 index 00000000000..4775edabf3e --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedInnerClassInfo.cs @@ -0,0 +1,25 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NAssert = NUnit.Framework.Assert; + +namespace Xamarin.Android.Tools.BytecodeTests { + + class ExpectedInnerClassInfo { + + public string InnerClassName; + public string OuterClassName; + public string InnerName; + public ClassAccessFlags AccessFlags; + + public void Assert (InnerClassInfo info) + { + NAssert.AreEqual (InnerClassName, info.InnerClass?.Name?.Value, $"InnerClassName"); + NAssert.AreEqual (OuterClassName, info.OuterClass?.Name?.Value, $"OuterClassName"); + NAssert.AreEqual (InnerName, info.InnerName, $"InnerName"); + NAssert.AreEqual (AccessFlags, info.InnerClassAccessFlags, $"InnerClassAccessFlags"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedMethodDeclaration.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedMethodDeclaration.cs new file mode 100644 index 00000000000..440c90507d2 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedMethodDeclaration.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Xamarin.Android.Tools.Bytecode; + +using NAssert = NUnit.Framework.Assert; + +namespace Xamarin.Android.Tools.BytecodeTests { + + class ExpectedMethodDeclaration { + + public string Name; + public MethodAccessFlags AccessFlags; + public bool Deprecated; + public List TypeParameters = new List (); + public string ReturnDescriptor; + public string ReturnGenericDescriptor; + public List Parameters = new List (); + public List Throws = new List (); + + public void Assert (MethodInfo method) + { + string message = Name + + "(" + string.Join ("", Parameters.Select (p => p.Type.TypeSignature ?? p.Type.BinaryName)) + ")" + + ReturnDescriptor; + + NAssert.AreEqual (AccessFlags, method.AccessFlags, message); + NAssert.AreEqual (Name, method.Name, message); + NAssert.AreEqual (ReturnDescriptor, method.ReturnType.BinaryName, message); + if (ReturnGenericDescriptor != null) { + NAssert.AreEqual (ReturnGenericDescriptor, method.ReturnType.TypeSignature, message); + } + + NAssert.AreEqual (Deprecated, method.Attributes.Get() != null, message); + + var signature = method.GetSignature (); + if (signature != null) { + NAssert.AreEqual (TypeParameters.Count, signature.TypeParameters.Count, message); + for (int i = 0; i < TypeParameters.Count; ++i) { + NAssert.AreEqual (TypeParameters [i].ToString (), signature.TypeParameters [i].ToString (), message); + } + } + + var parameters = method.GetParameters (); + NAssert.AreEqual (Parameters.Count, parameters.Length, $"Method {Name} Parameter Count\n" + + $"Expected signature: {string.Join (", ", Parameters.Select (p => $"{p.Type.TypeSignature}: {p.Name}"))}\n" + + $" Actual signature: {string.Join (", ", parameters.Select (p => $"{p.Type.TypeSignature}: {p.Name}"))}"); + for (int i = 0; i < Parameters.Count; ++i) { + NAssert.AreEqual (Parameters [i].Name, parameters [i].Name, message + $": parameter {i} name"); + NAssert.AreEqual (i, parameters [i].Position, message + $": parameter {i} position"); + NAssert.AreEqual (Parameters [i].Type.BinaryName, parameters [i].Type.BinaryName, message + $": parameter {i} binary name"); + NAssert.AreEqual (Parameters [i].Type.TypeSignature, parameters [i].Type.TypeSignature, message + $": parameter {i} type signature"); + } + + var exceptions = method.GetThrows (); + NAssert.AreEqual (Throws.Count, exceptions.Count); + for (int i = 0; i < Throws.Count; ++i) { + NAssert.AreEqual (Throws [i].BinaryName, exceptions [i].BinaryName, message + $": throws {i} binary name"); + NAssert.AreEqual (Throws [i].TypeSignature, exceptions [i].TypeSignature, message + $": throws {i} type signature"); + } + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedTypeDeclaration.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedTypeDeclaration.cs new file mode 100644 index 00000000000..d45cf6d4bf9 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ExpectedTypeDeclaration.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; + +using Xamarin.Android.Tools.Bytecode; + +using NAssert = NUnit.Framework.Assert; + +namespace Xamarin.Android.Tools.BytecodeTests { + + class ExpectedTypeDeclaration { + + public ushort MajorVersion; + public ushort MinorVersion; + public int ConstantPoolCount; + public ClassAccessFlags AccessFlags; + public string FullName; + public TypeInfo Superclass; + public bool Deprecated; + public List Interfaces = new List (); + public List InnerClasses = new List (); + public List TypeParameters = new List (); + public List Fields = new List (); + public List Methods = new List (); + + public void Assert (ClassFile classDeclaration) + { + NAssert.AreEqual (MajorVersion, classDeclaration.MajorVersion, FullName + " Major Version"); + NAssert.AreEqual (MinorVersion, classDeclaration.MinorVersion, FullName + " Minor Version"); + NAssert.AreEqual (ConstantPoolCount, classDeclaration.ConstantPool.Count, FullName + " ConstantPool Count"); + NAssert.AreEqual (AccessFlags, classDeclaration.AccessFlags, FullName + " AccessFlags"); + NAssert.AreEqual (FullName, classDeclaration.ThisClass.Name.Value, FullName + " Name"); + NAssert.AreEqual (Superclass?.BinaryName, classDeclaration?.SuperClass?.Name?.Value, FullName + " SuperClass Name"); + + NAssert.AreEqual (Deprecated, classDeclaration.Attributes.Get () != null, FullName + " Deprecated"); + + NAssert.AreEqual (Interfaces.Count, classDeclaration.Interfaces.Count, $"{FullName} Interfaces Count"); + for (int i = 0; i < Interfaces.Count; ++i) { + NAssert.AreEqual (Interfaces [i].BinaryName, classDeclaration.Interfaces [i].Name.Value, $"{FullName} Interface {i}"); + } + + var innerClasses = classDeclaration.InnerClasses; + NAssert.AreEqual (InnerClasses.Count, innerClasses.Count, FullName + " Inner Classes"); + for (int i = 0; i < InnerClasses.Count; ++i) + InnerClasses [i].Assert (innerClasses [i]); + + var interfaces = classDeclaration.GetInterfaces (); + for (int i = 0; i < Interfaces.Count; ++i) { + NAssert.AreEqual (Interfaces [i].BinaryName, interfaces [i].BinaryName, FullName + " Interfaces BinaryName"); + NAssert.AreEqual (Interfaces [i].TypeSignature, interfaces [i].TypeSignature, FullName + " Interfaces TypeSignature"); + } + + var signature = classDeclaration.GetSignature (); + if (signature != null) { + NAssert.AreEqual (Superclass.TypeSignature, signature.SuperclassSignature, FullName + " SuperclassSignature"); + NAssert.AreEqual (TypeParameters.Count, signature.TypeParameters.Count, FullName + " TypeParameters count"); + for (int i = 0; i < TypeParameters.Count; ++i) { + NAssert.AreEqual (TypeParameters [i].ToString (), signature.TypeParameters [i].ToString (), FullName + " Type Parameter"); + } + } + + NAssert.AreEqual (Fields.Count, classDeclaration.Fields.Count, FullName + " Fields Count"); + for (int i = 0; i < Fields.Count; ++i) { + Fields [i].Assert (classDeclaration.Fields [i]); + } + + NAssert.AreEqual (Methods.Count, classDeclaration.Methods.Count, FullName + " Methods Count"); + for (int i = 0; i < Methods.Count; ++i) { + Methods [i].Assert (classDeclaration.Methods [i]); + } + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/IJavaInterfaceTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/IJavaInterfaceTests.cs new file mode 100644 index 00000000000..1f4a210ad75 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/IJavaInterfaceTests.cs @@ -0,0 +1,75 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class IJavaInterfaceTests : ClassFileFixture { + + const string JavaType = "IJavaInterface"; + + [Test] + public void ClassFile_WithIJavaInterface_class () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 23, + AccessFlags = ClassAccessFlags.Interface | ClassAccessFlags.Abstract, + FullName = "com/xamarin/IJavaInterface", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + TypeParameters = { + new TypeParameterInfo ("TString") { + InterfaceBounds = { + "Ljava/lang/CharSequence;", + "Ljava/lang/Appendable;", + }, + }, + new TypeParameterInfo ("TStringList") { + ClassBound = "Ljava/util/ArrayList;", + InterfaceBounds = { + "Ljava/util/List;", + }, + }, + new TypeParameterInfo ("TReturn") { + ClassBound = "Ljava/lang/Object;", + }, + }, + Interfaces = { + new TypeInfo ("java/lang/Runnable", "Ljava/lang/Runnable;"), + }, + Fields = { + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_INT", + Descriptor = "I", + ConstantValue = "Integer(1)", + Deprecated = true, + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "func", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Abstract, + ReturnDescriptor = "Ljava/lang/Object;", + ReturnGenericDescriptor = "TTReturn;", + Parameters = { + new ParameterInfo ("value", "Ljava/lang/CharSequence;", "TTString;"), + }, + }, + } + }.Assert (c); + } + + [Test] + public void XmlDeclaration_WithIJavaInterface_class () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JSpecifyAnnotationTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JSpecifyAnnotationTests.cs new file mode 100644 index 00000000000..f5f0bb5e550 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JSpecifyAnnotationTests.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +#nullable enable + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests +{ + [TestFixture] + public class JSpecifyAnnotationTests : ClassFileFixture + { + static XElement BuildXml (string classResource, string? packageInfoResource = null) + { + var classPath = new ClassPath (); + if (packageInfoResource != null) + classPath.Add (LoadClassFile (packageInfoResource)); + var c = LoadClassFile (classResource); + classPath.Add (c); + + var packageInfo = packageInfoResource != null + ? classPath.GetPackageInfo (c.PackageName) + : null; + return new XmlClassDeclarationBuilder (c, packageInfo).ToXElement (); + } + + static XElement Method (XElement classXml, string name) + => classXml.Elements ().First (e => (e.Name.LocalName == "method" || e.Name.LocalName == "constructor") + && e.Attribute ("name")?.Value == name); + + static XElement Field (XElement classXml, string name) + => classXml.Elements ("field").First (f => f.Attribute ("name")?.Value == name); + + static XElement FirstParameter (XElement method) + { + return method.Element ("parameter") + ?? throw new AssertionException ($"method '{method.Attribute ("name")?.Value}' has no "); + } + + static string? Attr (XElement e, string name) => e.Attribute (name)?.Value; + + [Test] + public void PackageMarked_DefaultReferenceMembers_AreNotNull () + { + var xml = BuildXml ("JSpecifyPackageMarked.class", "package-info.class"); + + var m = Method (xml, "defaultReturn"); + Assert.AreEqual ("true", Attr (m, "return-not-null"), + "unannotated reference return in @NullMarked package must be not-null"); + + Assert.AreEqual ("true", Attr (FirstParameter (m), "not-null"), + "unannotated reference parameter in @NullMarked package must be not-null"); + + var f = Field (xml, "defaultField"); + Assert.AreEqual ("true", Attr (f, "not-null"), + "unannotated reference field in @NullMarked package must be not-null"); + } + + [Test] + public void PackageMarked_PrimitiveMembers_HaveNoNotNullAttribute () + { + var xml = BuildXml ("JSpecifyPackageMarked.class", "package-info.class"); + + var m = Method (xml, "primitiveReturn"); + Assert.IsNull (Attr (m, "return-not-null"), + "primitive return must not get a not-null attribute"); + + var f = Field (xml, "primitiveField"); + Assert.IsNull (Attr (f, "not-null"), + "primitive field must not get a not-null attribute"); + } + + [Test] + public void PackageMarked_NullableAnnotationOverridesScope () + { + var xml = BuildXml ("JSpecifyPackageMarked.class", "package-info.class"); + + var m = Method (xml, "nullableReturn"); + Assert.IsNull (Attr (m, "return-not-null"), + "@Nullable return must override the @NullMarked default"); + + Assert.IsNull (Attr (FirstParameter (m), "not-null"), + "@Nullable parameter must override the @NullMarked default"); + + var f = Field (xml, "nullableField"); + Assert.IsNull (Attr (f, "not-null"), + "@Nullable field must override the @NullMarked default"); + } + + // `@NullUnmarked` on a method is intentionally not honored yet + // (only class- and package-level scope are). This test pins the + // current behavior so the limitation is visible. + [Test] + public void PackageMarked_MethodLevelNullUnmarked_IsNotYetHonored () + { + var xml = BuildXml ("JSpecifyPackageMarked.class", "package-info.class"); + + var m = Method (xml, "unmarkedReturn"); + Assert.AreEqual ("true", Attr (m, "return-not-null"), + "method-level @NullUnmarked is not yet honored; the package-level @NullMarked scope still applies"); + } + + [Test] + public void PackageMarked_TypeVariableUsage_HasParametricNullness () + { + var xml = BuildXml ("JSpecifyPackageMarked.class", "package-info.class"); + + var m = Method (xml, "typeVariableReturn"); + Assert.IsNull (Attr (m, "return-not-null"), + "unannotated type-variable return must not gain not-null from the scope default"); + + Assert.IsNull (Attr (FirstParameter (m), "not-null"), + "unannotated type-variable parameter must not gain not-null from the scope default"); + } + + [Test] + public void ClassMarked_DefaultReferenceMembers_AreNotNull () + { + var xml = BuildXml ("JSpecifyClassMarked.class"); + + var m = Method (xml, "defaultReturn"); + Assert.AreEqual ("true", Attr (m, "return-not-null"), + "unannotated reference return in @NullMarked class must be not-null"); + + Assert.AreEqual ("true", Attr (FirstParameter (m), "not-null"), + "unannotated reference parameter in @NullMarked class must be not-null"); + + var f = Field (xml, "defaultField"); + Assert.AreEqual ("true", Attr (f, "not-null"), + "unannotated reference field in @NullMarked class must be not-null"); + } + + [Test] + public void ClassMarked_NullableOverrides () + { + var xml = BuildXml ("JSpecifyClassMarked.class"); + + var m = Method (xml, "nullableReturn"); + Assert.IsNull (Attr (m, "return-not-null"), + "@Nullable return must override the class-level @NullMarked default"); + + Assert.IsNull (Attr (FirstParameter (m), "not-null"), + "@Nullable parameter must override the class-level @NullMarked default"); + + var f = Field (xml, "nullableField"); + Assert.IsNull (Attr (f, "not-null"), + "@Nullable field must override the class-level @NullMarked default"); + } + + [Test] + public void Unmarked_NoScope_NoDefaultNotNull () + { + var xml = BuildXml ("JSpecifyUnmarked.class"); + + var m = Method (xml, "defaultReturn"); + Assert.IsNull (Attr (m, "return-not-null"), + "outside a @NullMarked scope, unannotated reference returns must not gain not-null"); + + Assert.IsNull (Attr (FirstParameter (m), "not-null"), + "outside a @NullMarked scope, unannotated reference parameters must not gain not-null"); + + var f = Field (xml, "defaultField"); + Assert.IsNull (Attr (f, "not-null"), + "outside a @NullMarked scope, unannotated reference fields must not gain not-null"); + } + + [Test] + public void Unmarked_ExplicitNonNullAnnotation_IsHonored () + { + var xml = BuildXml ("JSpecifyUnmarked.class"); + + var m = Method (xml, "nonNullReturn"); + Assert.AreEqual ("true", Attr (m, "return-not-null"), + "explicit @NonNull return must produce not-null even outside a @NullMarked scope"); + + Assert.AreEqual ("true", Attr (FirstParameter (m), "not-null"), + "explicit @NonNull parameter must produce not-null even outside a @NullMarked scope"); + + var f = Field (xml, "nonNullField"); + Assert.AreEqual ("true", Attr (f, "not-null"), + "explicit @NonNull field must produce not-null even outside a @NullMarked scope"); + } + + [Test] + public void PackageMarked_DeclarationNullable_OverridesScope () + { + var xml = BuildXml ("JSpecifyPackageMarked.class", "package-info.class"); + + var m = Method (xml, "declarationNullableReturn"); + Assert.IsNull (Attr (m, "return-not-null"), + "declaration-level @Nullable return must override the @NullMarked default"); + + Assert.IsNull (Attr (FirstParameter (m), "not-null"), + "declaration-level @Nullable parameter must override the @NullMarked default"); + + var f = Field (xml, "declarationNullableField"); + Assert.IsNull (Attr (f, "not-null"), + "declaration-level @Nullable field must override the @NullMarked default"); + } + + [Test] + public void PackageMarked_NestedNullable_DoesNotLeakToContainer () + { + var xml = BuildXml ("JSpecifyPackageMarked.class", "package-info.class"); + + var f = Field (xml, "nestedNullableField"); + Assert.AreEqual ("true", Attr (f, "not-null"), + "nested @Nullable on an inner type argument must not affect the container's nullness; " + + "the field's List type is non-null in a @NullMarked scope"); + } + + [Test] + public void TypeAnnotationsAttribute_IsParsed () + { + var c = LoadClassFile ("JSpecifyPackageMarked.class"); + var method = c.Methods.First (m => m.Name == "nullableReturn"); + var typeAnn = method.Attributes + .OfType () + .FirstOrDefault () + ?? throw new AssertionException ("javac must emit a RuntimeInvisibleTypeAnnotations attribute for @Nullable members"); + Assert.IsTrue (typeAnn.Annotations.Any (a => + a.Annotation.Type == "Lorg/jspecify/annotations/Nullable;" + && a.TargetType == TypeAnnotationTargetType.MethodReturn), + "@Nullable return type annotation must be parsed with MethodReturn target"); + Assert.IsTrue (typeAnn.Annotations.Any (a => + a.Annotation.Type == "Lorg/jspecify/annotations/Nullable;" + && a.TargetType == TypeAnnotationTargetType.MethodFormalParameter + && a.FormalParameterIndex == 0), + "@Nullable parameter type annotation must be parsed with MethodFormalParameter target"); + } + + [Test] + public void PackageInfo_IsRecognized () + { + var c = LoadClassFile ("package-info.class"); + Assert.IsTrue (c.IsPackageInfo, + "package-info.class must be flagged via IsPackageInfo"); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaAnnotationTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaAnnotationTests.cs new file mode 100644 index 00000000000..5309a7b515f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaAnnotationTests.cs @@ -0,0 +1,45 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaAnnotationTests : ClassFileFixture { + + const string JavaType = "JavaAnnotation"; + + [Test] + public void ClassFile_WithJavaAnnotation_class () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 23, + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Interface | ClassAccessFlags.Abstract | ClassAccessFlags.Annotation, + FullName = "com/xamarin/JavaAnnotation", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + Interfaces = { + new TypeInfo ("java/lang/annotation/Annotation"), + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "value", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Abstract, + ReturnDescriptor = "[Ljava/lang/String;", + }, + } + }.Assert (c); + } + + [Test] + public void XmlDeclaration_WithJavaAnnotation_class () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaEnumTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaEnumTests.cs new file mode 100644 index 00000000000..50ee71e255b --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaEnumTests.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +using Assembly = System.Reflection.Assembly; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaEnumTests : ClassFileFixture { + + const string JavaType = "JavaEnum"; + + [Test] + public void ClassFileDescription () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 55, + AccessFlags = ClassAccessFlags.Final | ClassAccessFlags.Super | ClassAccessFlags.Enum, + FullName = "com/xamarin/JavaEnum", + Superclass = new TypeInfo ("java/lang/Enum", "Ljava/lang/Enum;"), + Fields = { + new ExpectedFieldDeclaration { + Name = "FIRST", + Descriptor = "Lcom/xamarin/JavaEnum;", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final | FieldAccessFlags.Enum, + }, + new ExpectedFieldDeclaration { + Name = "SECOND", + Descriptor = "Lcom/xamarin/JavaEnum;", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final | FieldAccessFlags.Enum, + }, + new ExpectedFieldDeclaration { + Name = "$VALUES", + Descriptor = "[Lcom/xamarin/JavaEnum;", + AccessFlags = FieldAccessFlags.Private | FieldAccessFlags.Static | FieldAccessFlags.Final | FieldAccessFlags.Synthetic, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "values", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Static, + ReturnDescriptor = "[Lcom/xamarin/JavaEnum;", + }, + new ExpectedMethodDeclaration { + Name = "valueOf", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Static, + ReturnDescriptor = "Lcom/xamarin/JavaEnum;", + Parameters = { + new ParameterInfo ("name", "Ljava/lang/String;", "Ljava/lang/String;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Private, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("$enum$name", "Ljava/lang/String;", "Ljava/lang/String;"), + new ParameterInfo ("$enum$ordinal", "I", "I"), + }, + }, + new ExpectedMethodDeclaration { + Name = "switchValue", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "I", + }, + new ExpectedMethodDeclaration { + Name = "$values", + AccessFlags = MethodAccessFlags.Private | MethodAccessFlags.Static | MethodAccessFlags.Synthetic, + ReturnDescriptor = "[Lcom/xamarin/JavaEnum;", + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Static, + ReturnDescriptor = "V", + }, + } + }.Assert (c); + } + + [Test] + public void XmlDescription () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.1MyStringListTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.1MyStringListTests.cs new file mode 100644 index 00000000000..661b33852a7 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.1MyStringListTests.cs @@ -0,0 +1,138 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaType_1MyStringListTests : ClassFileFixture { + + const string JavaType = "JavaType$1MyStringList"; + + static readonly bool Jdk8 = ConfiguredJdkInfo.Version == null + ? false + : ConfiguredJdkInfo.Version < new Version (1, 9); + + [Test] + public void ClassFileDescription () + { + var vallist = Jdk8 + ? new ParameterInfo ("val$value1", "Ljava/util/List;", "Ljava/util/List;") + : new ParameterInfo ("val$unboundedList", "Ljava/util/List;", "Ljava/util/List;"); + var valobj = Jdk8 + ? new ParameterInfo ("val$unboundedList", "Ljava/lang/Object;", "Ljava/lang/Object;") + : new ParameterInfo ("val$value1", "Ljava/lang/Object;", "Ljava/lang/Object;"); + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 74, + AccessFlags = ClassAccessFlags.Super, + FullName = "com/xamarin/JavaType$1MyStringList", + Superclass = new TypeInfo ("java/util/ArrayList", "Ljava/util/ArrayList;"), + InnerClasses = { + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$1MyStringList", + OuterClassName = null, + InnerName = "MyStringList", + AccessFlags = 0, + }, + }, + Fields = { + new ExpectedFieldDeclaration { + Name = "val$unboundedList", + Descriptor = "Ljava/util/List;", + AccessFlags = FieldAccessFlags.Final | FieldAccessFlags.Synthetic, + }, + new ExpectedFieldDeclaration { + Name = "val$value1", + Descriptor = "Ljava/lang/Object;", + AccessFlags = FieldAccessFlags.Final | FieldAccessFlags.Synthetic, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + // "actual" parameters: + new ParameterInfo ("a", "Ljava/lang/String;", "Ljava/lang/String;"), + new ParameterInfo ("b", "I", "I"), + // declaring method parameters: + vallist, + valobj, + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + // "actual" parameters: + new ParameterInfo ("value1", "Ljava/lang/Object;", "TT;"), + new ParameterInfo ("a", "Ljava/lang/String;", "Ljava/lang/String;"), + new ParameterInfo ("b", "I", "I"), + // declaring method parameters: + vallist, + valobj, + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + // "actual" parameters: + new ParameterInfo ("a", "Ljava/lang/String;", "Ljava/lang/String;"), + new ParameterInfo ("value2", "Ljava/lang/Number;", "TTExtendsNumber;"), + new ParameterInfo ("b", "I", "I"), + // declaring method parameters: + vallist, + valobj, + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + // "actual" parameters: + new ParameterInfo ("a", "Ljava/lang/String;", "Ljava/lang/String;"), + new ParameterInfo ("b", "I", "I"), + new ParameterInfo ("unboundedList", "Ljava/util/List;", "Ljava/util/List<*>;"), + // declaring method parameters: + vallist, + valobj, + }, + }, + new ExpectedMethodDeclaration { + Name = "get", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "Ljava/lang/String;", + Parameters = { + new ParameterInfo ("index", "I", "I"), + }, + }, + new ExpectedMethodDeclaration { + Name = "get", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Bridge | MethodAccessFlags.Synthetic, + ReturnDescriptor = "Ljava/lang/Object;", + Parameters = { + new ParameterInfo ("index", "I", "I"), + }, + }, + } + }.Assert (c); + } + + [Test] + public void XmlDescription () + { + var resourceName = JavaType + (Jdk8 ? "-1.8" : "") + ".xml"; + AssertXmlDeclaration (JavaType + ".class", resourceName); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.1Tests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.1Tests.cs new file mode 100644 index 00000000000..c8bcb0e44fb --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.1Tests.cs @@ -0,0 +1,64 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaType_1Tests : ClassFileFixture { + + const string JavaType = "JavaType$1"; + + [Test] + public void ClassFileDescription () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 48, + AccessFlags = ClassAccessFlags.Super, + FullName = "com/xamarin/JavaType$1", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + InnerClasses = { + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$1", + OuterClassName = null, + InnerName = null, + AccessFlags = 0, + }, + }, + Interfaces = { + new TypeInfo ("java/lang/Runnable"), + }, + Fields = { + new ExpectedFieldDeclaration { + Name = "this$0", + Descriptor = "Lcom/xamarin/JavaType;", + AccessFlags = FieldAccessFlags.Final | FieldAccessFlags.Synthetic, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = 0, + ReturnDescriptor = "V", + }, + new ExpectedMethodDeclaration { + Name = "run", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + }, + } + }.Assert (c); + } + + [Test] + public void XmlDescription () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.ASCTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.ASCTests.cs new file mode 100644 index 00000000000..c8bc6d01c3e --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.ASCTests.cs @@ -0,0 +1,50 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaType_ASCTests : ClassFileFixture { + + const string JavaType = "JavaType$ASC"; + + [Test] + public void ClassFileDescription () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 24, + Deprecated = true, + AccessFlags = ClassAccessFlags.Super, + FullName = "com/xamarin/JavaType$ASC", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + InnerClasses = { + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$ASC", + OuterClassName = "com/xamarin/JavaType", + InnerName = "ASC", + AccessFlags = ClassAccessFlags.Static, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = 0, + ReturnDescriptor = "V", + }, + } + }.Assert (c); + } + + [Test] + public void XmlDescription () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.PSCTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.PSCTests.cs new file mode 100644 index 00000000000..e7c2977a056 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.PSCTests.cs @@ -0,0 +1,66 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaType_PSCTests : ClassFileFixture { + + const string JavaType = "JavaType$PSC"; + + [Test] + public void ClassFileDescription () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 21, + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Super | ClassAccessFlags.Abstract, + FullName = "com/xamarin/JavaType$PSC", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + TypeParameters = { + new TypeParameterInfo ("TString") { + InterfaceBounds = { + "Ljava/lang/CharSequence;", + "Ljava/lang/Appendable;", + }, + }, + new TypeParameterInfo ("TStringList") { + ClassBound = "Ljava/util/ArrayList;", + InterfaceBounds = { + "Ljava/util/List;", + }, + }, + new TypeParameterInfo ("TReturn") { + ClassBound = "Ljava/lang/Object;", + }, + }, + InnerClasses = { + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$PSC", + OuterClassName = "com/xamarin/JavaType", + InnerName = "PSC", + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Static | ClassAccessFlags.Abstract, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + }, + } + }.Assert (c); + } + + [Test] + public void XmlDescription () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNC.RPNCTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNC.RPNCTests.cs new file mode 100644 index 00000000000..9957bf876d2 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNC.RPNCTests.cs @@ -0,0 +1,86 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaType_RNC_RPNCTests : ClassFileFixture { + + const string JavaType = "JavaType$RNC$RPNC"; + + [Test] + public void ClassFileDescription () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 47, + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Super | ClassAccessFlags.Abstract, + FullName = "com/xamarin/JavaType$RNC$RPNC", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + TypeParameters = { + new TypeParameterInfo ("E3") { + ClassBound = "Ljava/lang/Object;", + }, + }, + InnerClasses = { + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$RNC", + OuterClassName = "com/xamarin/JavaType", + InnerName = "RNC", + AccessFlags = ClassAccessFlags.Protected | ClassAccessFlags.Abstract, + }, + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$RNC$RPNC", + OuterClassName = "com/xamarin/JavaType$RNC", + InnerName = "RPNC", + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Abstract, + }, + }, + Fields = { + new ExpectedFieldDeclaration { + Name = "this$1", + Descriptor = "Lcom/xamarin/JavaType$RNC;", + AccessFlags = FieldAccessFlags.Final | FieldAccessFlags.Synthetic, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("value1", "Ljava/lang/Object;", "TE;"), + new ParameterInfo ("value2", "Ljava/lang/Object;", "TE2;"), + new ParameterInfo ("value3", "Ljava/lang/Object;", "TE3;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "fromE2", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Abstract, + ReturnDescriptor = "Ljava/lang/Object;", + ReturnGenericDescriptor = "TE3;", + Parameters = { + new ParameterInfo ("value", "Ljava/lang/Object;", "TE2;"), + }, + }, + } + }.Assert (c); + } + + [Test] + public void XmlDescription () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNCTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNCTests.cs new file mode 100644 index 00000000000..92e8f1d0258 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaType.RNCTests.cs @@ -0,0 +1,85 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaType_RNCTests : ClassFileFixture { + + const string JavaType = "JavaType$RNC"; + + [Test] + public void ClassFileDescription () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 45, + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Super | ClassAccessFlags.Abstract, + FullName = "com/xamarin/JavaType$RNC", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + TypeParameters = { + new TypeParameterInfo ("E2") { + ClassBound = "Ljava/lang/Object;", + }, + }, + InnerClasses = { + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$RNC", + OuterClassName = "com/xamarin/JavaType", + InnerName = "RNC", + AccessFlags = ClassAccessFlags.Protected | ClassAccessFlags.Abstract, + }, + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$RNC$RPNC", + OuterClassName = "com/xamarin/JavaType$RNC", + InnerName = "RPNC", + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Abstract, + }, + }, + Fields = { + new ExpectedFieldDeclaration { + Name = "this$0", + Descriptor = "Lcom/xamarin/JavaType;", + AccessFlags = FieldAccessFlags.Final | FieldAccessFlags.Synthetic, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Protected, + ReturnDescriptor = "V", + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Protected, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("value1", "Ljava/lang/Object;", "TE;"), + new ParameterInfo ("value2", "Ljava/lang/Object;", "TE2;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "fromE", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Abstract, + ReturnDescriptor = "Ljava/lang/Object;", + ReturnGenericDescriptor = "TE2;", + Parameters = { + new ParameterInfo ("value", "Ljava/lang/Object;", "TE;"), + }, + }, + } + }.Assert (c); + } + + [Test] + public void XmlDescription () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeNoParametersTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeNoParametersTests.cs new file mode 100644 index 00000000000..13c33b06367 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeNoParametersTests.cs @@ -0,0 +1,45 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaTypeNoParametersTests : ClassFileFixture { + + const string JavaType = "JavaTypeNoParameters"; + + [Test] + public void ClassFile_WithNonGenericGlobalType_class () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 18, + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Super, + FullName = "com/xamarin/JavaTypeNoParameters", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("copy", "Lcom/xamarin/JavaTypeNoParameters;", "Lcom/xamarin/JavaTypeNoParameters;"), + }, + }, + } + }.Assert (c); + } + + [Test] + public void XmlDeclaration_WithNonGenericGlobalType_class () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeTests.cs new file mode 100644 index 00000000000..4ec9dbe3d4d --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JavaTypeTests.cs @@ -0,0 +1,356 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +using Assembly = System.Reflection.Assembly; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JavaTypeTests : ClassFileFixture { + + [Test] + public void ClassFile_WithJavaType_class () + { + var c = LoadClassFile ("JavaType.class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 202, + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Super, + FullName = "com/xamarin/JavaType", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + TypeParameters = { + new TypeParameterInfo ("E") { + ClassBound = "Ljava/lang/Object;", + }, + }, + Interfaces = { + new TypeInfo ("java/lang/Cloneable", "Ljava/lang/Cloneable;"), + new TypeInfo ("java/lang/Comparable", "Ljava/lang/Comparable;>;"), + new TypeInfo ("com/xamarin/IJavaInterface", "Lcom/xamarin/IJavaInterface;Ljava/util/List;>;"), + }, + InnerClasses = { + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$1", + OuterClassName = null, + InnerName = null, + AccessFlags = 0, + }, + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$ASC", + OuterClassName = "com/xamarin/JavaType", + InnerName = "ASC", + AccessFlags = ClassAccessFlags.Static, + }, + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$RNC", + OuterClassName = "com/xamarin/JavaType", + InnerName = "RNC", + AccessFlags = ClassAccessFlags.Protected | ClassAccessFlags.Abstract, + }, + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$PSC", + OuterClassName = "com/xamarin/JavaType", + InnerName = "PSC", + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Static | ClassAccessFlags.Abstract, + }, + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$1MyStringList", + OuterClassName = null, + InnerName = "MyStringList", + AccessFlags = 0, + }, + new ExpectedInnerClassInfo { + InnerClassName = "com/xamarin/JavaType$RNC$RPNC", + OuterClassName = "com/xamarin/JavaType$RNC", + InnerName = "RPNC", + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Abstract, + }, + }, + Fields = { + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_OBJECT", + Descriptor = "Ljava/lang/Object;", + Deprecated = true, + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_INT32", + Descriptor = "I", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Integer(42)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_INT32_MIN", + Descriptor = "I", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Integer(-2147483648)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_INT32_MAX", + Descriptor = "I", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Integer(2147483647)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_CHAR_MIN", + Descriptor = "C", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Integer(0)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_CHAR_MAX", + Descriptor = "C", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Integer(65535)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_INT64_MIN", + Descriptor = "J", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Long(-9223372036854775808)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_INT64_MAX", + Descriptor = "J", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Long(9223372036854775807)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_SINGLE_MIN", + Descriptor = "F", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Float(1.40129846E-45)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_SINGLE_MAX", + Descriptor = "F", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Float(3.40282347E+38)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_DOUBLE_MIN", + Descriptor = "D", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Double(4.9406564584124654E-324)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_DOUBLE_MAX", + Descriptor = "D", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Double(1.7976931348623157E+308)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_STRING", + Descriptor = "Ljava/lang/String;", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "String(stringIndex=101 Utf8=\"Hello, \\\"embedded\0Nulls\" and \ud83d\udca9!\")", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_BOOL_FALSE", + Descriptor = "Z", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Integer(0)", + }, + new ExpectedFieldDeclaration { + Name = "STATIC_FINAL_BOOL_TRUE", + Descriptor = "Z", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Integer(1)", + }, + new ExpectedFieldDeclaration { + Name = "POSITIVE_INFINITY", + Descriptor = "D", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Double(Infinity)", + }, + new ExpectedFieldDeclaration { + Name = "NEGATIVE_INFINITY", + Descriptor = "D", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Double(-Infinity)", + }, + new ExpectedFieldDeclaration { + Name = "NaN", + Descriptor = "D", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Static | FieldAccessFlags.Final, + ConstantValue = "Double(NaN)", + }, + new ExpectedFieldDeclaration { + Name = "INSTANCE_FINAL_OBJECT", + Descriptor = "Ljava/lang/Object;", + Deprecated = true, + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Final, + }, + new ExpectedFieldDeclaration { + Name = "INSTANCE_FINAL_E", + Descriptor = "Ljava/lang/Object;", + GenericDescriptor = "TE;", + AccessFlags = FieldAccessFlags.Public | FieldAccessFlags.Final, + }, + new ExpectedFieldDeclaration { + Name = "packageInstanceEArray", + Descriptor = "[Ljava/lang/Object;", + GenericDescriptor = "[TE;", + AccessFlags = 0, + }, + new ExpectedFieldDeclaration { + Name = "protectedInstanceEList", + Descriptor = "Ljava/util/List;", + GenericDescriptor = "Ljava/util/List;", + AccessFlags = FieldAccessFlags.Protected, + }, + new ExpectedFieldDeclaration { + Name = "privateInstanceArrayOfListOfIntArrayArray", + Descriptor = "[Ljava/util/List;", + GenericDescriptor = "[Ljava/util/List<[[I>;", + AccessFlags = FieldAccessFlags.Private, + }, + }, + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("value", "Ljava/lang/String;", "Ljava/lang/String;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "compareTo", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "I", + Parameters = { + new ParameterInfo ("value", "Lcom/xamarin/JavaType;", "Lcom/xamarin/JavaType;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "func", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "Ljava/util/List;", + ReturnGenericDescriptor = "Ljava/util/List;", + Parameters = { + new ParameterInfo ("value", "Ljava/lang/StringBuilder;", "Ljava/lang/StringBuilder;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "run", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + }, + new ExpectedMethodDeclaration { + Name = "action", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Deprecated = true, + Parameters = { + new ParameterInfo ("value", "Ljava/lang/Object;", "Ljava/lang/Object;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "func", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "Ljava/lang/Integer;", + Parameters = { + new ParameterInfo ("values", "[Ljava/lang/String;", "[Ljava/lang/String;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "staticActionWithGenerics", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Static, + ReturnDescriptor = "V", + TypeParameters = { + new TypeParameterInfo ("T", "Ljava/lang/Object;"), + new TypeParameterInfo ("TExtendsNumber", "Ljava/lang/Number;", new [] { "Ljava/lang/Comparable;" }), + new TypeParameterInfo ("TThrowable", "Ljava/lang/Throwable;"), + }, + Parameters = { + new ParameterInfo ("value1", "Ljava/lang/Object;", "TT;"), + new ParameterInfo ("value2", "Ljava/lang/Number;", "TTExtendsNumber;"), + new ParameterInfo ("unboundedList", "Ljava/util/List;", "Ljava/util/List<*>;"), + new ParameterInfo ("extendsList", "Ljava/util/List;", "Ljava/util/List<+Ljava/lang/Number;>;"), + new ParameterInfo ("superList", "Ljava/util/List;", "Ljava/util/List<-Ljava/lang/Throwable;>;"), + }, + Throws = { + new TypeInfo ("java/lang/IllegalArgumentException", "Ljava/lang/IllegalArgumentException;"), + new TypeInfo ("java/lang/NumberFormatException", "Ljava/lang/NumberFormatException;"), + new TypeInfo ("java/lang/Throwable", "TTThrowable;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "instanceActionWithGenerics", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + TypeParameters = { + new TypeParameterInfo ("T", "Ljava/lang/Object;"), + }, + Parameters = { + new ParameterInfo ("value1", "Ljava/lang/Object;", "TT;"), + new ParameterInfo ("value2", "Ljava/lang/Object;", "TE;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "sum", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Static | MethodAccessFlags.Varargs, + ReturnDescriptor = "I", + Parameters = { + new ParameterInfo ("first", "I", "I"), + new ParameterInfo ("remaining", "[I", "[I"), + }, + }, + new ExpectedMethodDeclaration { + Name = "finalize", + AccessFlags = MethodAccessFlags.Protected, + ReturnDescriptor = "V", + }, + new ExpectedMethodDeclaration { + Name = "finalize", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Static, + ReturnDescriptor = "I", + Parameters = { + new ParameterInfo ("value", "I", "I"), + }, + }, + new ExpectedMethodDeclaration { + Name = "compareTo", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Bridge | MethodAccessFlags.Synthetic, + ReturnDescriptor = "I", + Parameters = { + new ParameterInfo ("value", "Ljava/lang/Object;", "Ljava/lang/Object;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "func", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Bridge | MethodAccessFlags.Synthetic, + ReturnDescriptor = "Ljava/lang/Object;", + Parameters = { + new ParameterInfo ("value", "Ljava/lang/CharSequence;", "Ljava/lang/CharSequence;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Static, + ReturnDescriptor = "V", + }, + }, + }.Assert (c); + } + + [Test] + public void XmlDeclaration_WithJavaType_class () + { + AssertXmlDeclaration ("JavaType.class", "JavaType.xml"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JvmOverloadsConstructorTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JvmOverloadsConstructorTests.cs new file mode 100644 index 00000000000..f9fd5cec78c --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/JvmOverloadsConstructorTests.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +using Assembly = System.Reflection.Assembly; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class JvmOverloadsConstructorTests : ClassFileFixture { + + const string ClassFile = "JvmOverloadsConstructor.class"; + const string XmlFile = "JvmOverloadsConstructor.xml"; + + [Test] + public void ClassFile_WithJavaType_class () + { + var c = LoadClassFile (ClassFile); + new ExpectedTypeDeclaration { + MajorVersion = 0x32, + MinorVersion = 0, + ConstantPoolCount = 59, + AccessFlags = ClassAccessFlags.Public | ClassAccessFlags.Final | ClassAccessFlags.Super, + FullName = "JvmOverloadsConstructor", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("something", "LJvmOverloadsConstructor;", "LJvmOverloadsConstructor;"), + new ParameterInfo ("id", "I", "I"), + new ParameterInfo ("imageId", "I", "I"), + new ParameterInfo ("title", "Ljava/lang/String;", "Ljava/lang/String;"), + new ParameterInfo ("useDivider", "Z", "Z"), + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public | MethodAccessFlags.Synthetic, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("p0", "LJvmOverloadsConstructor;", "LJvmOverloadsConstructor;"), + new ParameterInfo ("p1", "I", "I"), + new ParameterInfo ("p2", "I", "I"), + new ParameterInfo ("p3", "Ljava/lang/String;", "Ljava/lang/String;"), + new ParameterInfo ("p4", "Z", "Z"), + new ParameterInfo ("p5", "I", "I"), + new ParameterInfo ("p6", "Lkotlin/jvm/internal/DefaultConstructorMarker;", "Lkotlin/jvm/internal/DefaultConstructorMarker;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("something", "LJvmOverloadsConstructor;", "LJvmOverloadsConstructor;"), + new ParameterInfo ("id", "I", "I"), + new ParameterInfo ("imageId", "I", "I"), + new ParameterInfo ("title", "Ljava/lang/String;", "Ljava/lang/String;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("something", "LJvmOverloadsConstructor;", "LJvmOverloadsConstructor;"), + new ParameterInfo ("id", "I", "I"), + new ParameterInfo ("title", "Ljava/lang/String;", "Ljava/lang/String;"), + }, + }, + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = MethodAccessFlags.Public, + ReturnDescriptor = "V", + Parameters = { + new ParameterInfo ("something", "LJvmOverloadsConstructor;", "LJvmOverloadsConstructor;"), + new ParameterInfo ("title", "Ljava/lang/String;", "Ljava/lang/String;"), + }, + }, + }, + }.Assert (c); + } + + [Test] + public void XmlDeclaration_WithJavaType_class () + { + AssertXmlDeclaration (ClassFile, XmlFile); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs new file mode 100644 index 00000000000..e92deeb9569 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using Xamarin.Android.Tools.Bytecode; + +namespace Xamarin.Android.Tools.BytecodeTests +{ + [TestFixture] + public class KotlinFixupsTests : ClassFileFixture + { + [Test] + public void HideInternalClass () + { + var klass = LoadClassFile ("InternalClass.class"); + var inner_class = klass.InnerClasses.First (); + + Assert.True (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.True (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); + + var output = new XmlClassDeclarationBuilder (klass).ToXElement ().ToString (); + Assert.True (output.Contains ("visibility=\"private\"")); + } + + [Test] + public void MakeInternalInterfacePackagePrivate () + { + var klass = LoadClassFile ("InternalInterface.class"); + var inner_class = klass.InnerClasses.First (); + + Assert.True (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.True (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + // "package-private" is denoted as no visibility flags + Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Protected)); + Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Private)); + + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Protected)); + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Private)); + } + + [Test] + public void HideInternalConstructor () + { + var klass = LoadClassFile ("InternalConstructor.class"); + var ctor = klass.Methods.First (m => m.Name == ""); + + Assert.True (ctor.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.False (ctor.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + var output = new XmlClassDeclarationBuilder (klass).ToXElement ().ToString (); + Assert.True (output.Contains ("visibility=\"kotlin-internal\"")); + } + + [Test] + public void HideDefaultConstructorMarker () + { + var klass = LoadClassFile ("DefaultConstructor.class"); + + // init () + var ctor_0p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 0); + + // init (string name) + var ctor_1p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 1); + + // init (string p0, int p1, DefaultConstructorMarker p2) + var ctor_3p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 3); + + Assert.True (ctor_3p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + // Assert that the normal constructors are still public + Assert.True (ctor_0p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (ctor_1p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Assert that the synthetic "DefaultConstructorMarker" constructor has been marked private + Assert.False (ctor_3p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + } + + [Test] + public void HidePrivateDefaultConstructorMarker () + { + var klass = LoadClassFile ("PrivateDefaultConstructor.class"); + + // init (int isFoo) + var ctor_1p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 1); + + // init (int isFoo, DefaultConstructorMarker p1) + var ctor_2p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 2); + + Assert.True (ctor_2p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + KotlinFixups.Fixup ([klass]); + + // Assert that the normal constructor is still public + Assert.False (ctor_1p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Assert that the synthetic "DefaultConstructorMarker" constructor has been marked private + Assert.False (ctor_2p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + } + + [Test] + public void HideImplementationMethod () + { + var klass = LoadClassFile ("MethodImplementation.class"); + var method = klass.Methods.First (m => m.Name == "toString-impl"); + + Assert.True (method.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.False (method.AccessFlags.HasFlag (MethodAccessFlags.Public)); + } + + [Test] + public void RenameExtensionParameter () + { + var klass = LoadClassFile ("RenameExtensionParameterKt.class"); + var method = klass.Methods.First (m => m.Name == "toUtf8String"); + var p = method.GetParameters () [0]; + + Assert.AreEqual ("$this$toUtf8String", p.Name); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.AreEqual ("obj", p.Name); + } + + [Test] + public void HideInternalMethod () + { + var klass = LoadClassFile ("InternalMethod.class"); + var method = klass.Methods.First (m => m.Name == "take$main"); + + Assert.True (method.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.False (method.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + var output = new XmlClassDeclarationBuilder (klass).ToXElement ().ToString (); + Assert.True (output.Contains ("visibility=\"kotlin-internal\"")); + } + + [Test] + public void HideInternalField () + { + var klass = LoadClassFile ("InternalField.class"); + var field = klass.Fields.First (m => m.Name == "city"); + + Assert.True (field.AccessFlags.HasFlag (FieldAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.False (field.AccessFlags.HasFlag (FieldAccessFlags.Public)); + + var output = new XmlClassDeclarationBuilder (klass).ToXElement ().ToString (); + Assert.True (output.Contains ("visibility=\"kotlin-internal\"")); + } + + [Test] + public void ParameterName () + { + var klass = LoadClassFile ("ParameterName.class"); + var method = klass.Methods.First (m => m.Name == "take"); + var p = method.GetParameters () [0]; + + Assert.AreEqual ("p0", p.Name); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.AreEqual ("count", p.Name); + } + + [Test] + public void HideInternalProperty () + { + var klass = LoadClassFile ("InternalProperty.class"); + var getter = klass.Methods.First (m => m.Name == "getCity$main"); + var setter = klass.Methods.First (m => m.Name == "setCity$main"); + + Assert.True (getter.AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (setter.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.False (getter.AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.False (setter.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + var output = new XmlClassDeclarationBuilder (klass).ToXElement ().ToString (); + Assert.True (output.Contains ("visibility=\"kotlin-internal\"")); + } + + [Test] + public void RenameSetterParameter () + { + var klass = LoadClassFile ("SetterParameterName.class"); + var setter = klass.Methods.First (m => m.Name == "setCity"); + var p = setter.GetParameters () [0]; + + Assert.AreEqual ("p0", p.Name); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.AreEqual ("value", p.Name); + } + + [Test] + public void UnsignedMethods () + { + var klass = LoadClassFile ("UnsignedTypes.class"); + + var uint_method = klass.Methods.Single (m => m.Name.Contains ("foo_uint-")); + var ushort_method = klass.Methods.Single (m => m.Name.Contains ("foo_ushort-")); + var ulong_method = klass.Methods.Single (m => m.Name.Contains ("foo_ulong-")); + var ubyte_method = klass.Methods.Single (m => m.Name.Contains ("foo_ubyte-")); + var uintarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_uintarray-")); + var ushortarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_ushortarray-")); + var ulongarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_ulongarray-")); + var ubytearray_method = klass.Methods.Single (m => m.Name.Contains ("foo_ubytearray-")); + var uintarrayarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_uintarrayarray")); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.AreEqual ("uint", uint_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("uint", uint_method.KotlinReturnType); + + Assert.AreEqual ("ushort", ushort_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ushort", ushort_method.KotlinReturnType); + + Assert.AreEqual ("ulong", ulong_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ulong", ulong_method.KotlinReturnType); + + Assert.AreEqual ("ubyte", ubyte_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ubyte", ubyte_method.KotlinReturnType); + + Assert.AreEqual ("uint[]", uintarray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("uint[]", uintarray_method.KotlinReturnType); + + Assert.AreEqual ("ushort[]", ushortarray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ushort[]", ushortarray_method.KotlinReturnType); + + Assert.AreEqual ("ulong[]", ulongarray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ulong[]", ulongarray_method.KotlinReturnType); + + Assert.AreEqual ("ubyte[]", ubytearray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ubyte[]", ubytearray_method.KotlinReturnType); + + // Kotlin's Array does not trigger this code because it is not + // encoded as Java's "[[I", instead it is exposed as "UIntArray[]", so + // we treat it as a normal class array. + Assert.Null (uintarrayarray_method.GetParameters () [0].KotlinType); + Assert.Null (uintarrayarray_method.KotlinReturnType); + } + + [Test] + public void UnsignedFields () + { + var klass = LoadClassFile ("UnsignedTypesKt.class"); + + var uint_field = klass.Fields.Single (m => m.Name == "UINT_CONST"); + var ushort_field = klass.Fields.Single (m => m.Name == "USHORT_CONST"); + var ulong_field = klass.Fields.Single (m => m.Name == "ULONG_CONST"); + var ubyte_field = klass.Fields.Single (m => m.Name == "UBYTE_CONST"); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.AreEqual ("uint", uint_field.KotlinType); + Assert.AreEqual ("ushort", ushort_field.KotlinType); + Assert.AreEqual ("ulong", ulong_field.KotlinType); + Assert.AreEqual ("ubyte", ubyte_field.KotlinType); + } + + [Test] + public void UnsignedFieldsXml () + { + // Ensure Kotlin unsigned types end up in the xml + var klass = LoadClassFile ("UnsignedTypesKt.class"); + + KotlinFixups.Fixup (new [] { klass }); + + var xml = new XmlClassDeclarationBuilder (klass).ToXElement (); + + Assert.AreEqual ("uint", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "UINT_CONST").Attribute ("type").Value); + Assert.AreEqual ("ushort", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "USHORT_CONST").Attribute ("type").Value); + Assert.AreEqual ("ulong", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "ULONG_CONST").Attribute ("type").Value); + Assert.AreEqual ("ubyte", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "UBYTE_CONST").Attribute ("type").Value); + } + + [Test] + public void UnsignedMethodsXml () + { + // Ensure Kotlin unsigned types end up in the xml + var klass = LoadClassFile ("UnsignedTypes.class"); + + KotlinFixups.Fixup (new [] { klass }); + + var xml = new XmlClassDeclarationBuilder (klass).ToXElement (); + + Assert.AreEqual ("uint", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uint-WZ4Q5Ns").Attribute ("return").Value); + Assert.AreEqual ("uint", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uint-WZ4Q5Ns").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ushort", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushort-xj2QHRw").Attribute ("return").Value); + Assert.AreEqual ("ushort", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushort-xj2QHRw").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ulong", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulong-VKZWuLQ").Attribute ("return").Value); + Assert.AreEqual ("ulong", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulong-VKZWuLQ").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ubyte", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubyte-7apg3OU").Attribute ("return").Value); + Assert.AreEqual ("ubyte", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubyte-7apg3OU").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("uint[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uintarray--ajY-9A").Attribute ("return").Value); + Assert.AreEqual ("uint[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uintarray--ajY-9A").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ushort[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushortarray-rL5Bavg").Attribute ("return").Value); + Assert.AreEqual ("ushort[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushortarray-rL5Bavg").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ulong[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulongarray-QwZRm1k").Attribute ("return").Value); + Assert.AreEqual ("ulong[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulongarray-QwZRm1k").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ubyte[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubytearray-GBYM_sE").Attribute ("return").Value); + Assert.AreEqual ("ubyte[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubytearray-GBYM_sE").Element ("parameter").Attribute ("type").Value); + } + + [Test] + public void HandleKotlinNameShadowing () + { + var klass = LoadClassFile ("NameShadowing.class"); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.True (klass.Methods.Single (m => m.Name == "count").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (klass.Methods.Single (m => m.Name == "hitCount").AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Private property and explicit getter/setter + // There is no generated getter/setter, and explicit ones should be public + Assert.True (klass.Methods.Single (m => m.Name == "getType").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (klass.Methods.Single (m => m.Name == "setType").AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Private immutable property and explicit getter/setter + // There is no generated getter/setter, and explicit ones should be public + Assert.True (klass.Methods.Single (m => m.Name == "getType2").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (klass.Methods.Single (m => m.Name == "setType2").AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Internal property and explicit getter/setter + // Generated getter/setter should not be public, and explicit ones should be public + Assert.False (klass.Methods.Single (m => m.Name == "getItype$main").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.False (klass.Methods.Single (m => m.Name == "setItype$main").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (klass.Methods.Single (m => m.Name == "getItype").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (klass.Methods.Single (m => m.Name == "setItype").AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Internal immutable property and explicit getter/setter + // Generated getter should not be public, and explicit ones should be public + Assert.False (klass.Methods.Single (m => m.Name == "getItype2$main").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (klass.Methods.Single (m => m.Name == "getItype2").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (klass.Methods.Single (m => m.Name == "setItype2").AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Internal property with unsigned type + // Generated getter/setter should not be public + Assert.False (klass.Methods.Single (m => m.Name == "getUnsignedInternalProperty-pVg5ArA$main").AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.False (klass.Methods.Single (m => m.Name == "setUnsignedInternalProperty-WZ4Q5Ns$main").AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Public property with unsigned type + // We want to check that KotlinType/KotlinReturnType are filled it as it proves our FindJavaProperty[Getter|Setter] functions are matching + // (We aren't changing the visibility of the getter/setter, so we can't just check the access flags) + Assert.AreEqual ("uint", klass.Methods.Single (m => m.Name == "getUnsignedPublicProperty-pVg5ArA").KotlinReturnType); + Assert.AreEqual ("uint", klass.Methods.Single (m => m.Name == "setUnsignedPublicProperty-WZ4Q5Ns").GetParameters () [0].KotlinType); + } + + [Test] + public void MatchParametersWithReceiver () + { + var klass = LoadClassFile ("DeepRecursiveKt.class"); + var meta = GetFileMetadataForClass (klass); + + var java_method = klass.Methods.Single (m => m.Name == "invoke"); + var kotlin_function = meta.Functions.Single (m => m.Name == "invoke"); + + (var start, var end) = KotlinFixups.CreateParameterMap (java_method, kotlin_function, null); + + // Start is 1 instead of 0 to skip the receiver + Assert.AreEqual (1, start); + Assert.AreEqual (2, end); + } + + [Test] + public void MatchParametersWithContinuation () + { + var klass = LoadClassFile ("DeepRecursiveScope.class"); + var meta = GetClassMetadataForClass (klass); + + var java_method = klass.Methods.Single (m => m.Name == "callRecursive" && m.GetParameters ().Count () == 2); + var kotlin_function = meta.Functions.Single (m => m.Name == "callRecursive" && m.JvmSignature.Count (c => c == ';') == 3); + + (var start, var end) = KotlinFixups.CreateParameterMap (java_method, kotlin_function, null); + + // End is 1 instead of 2 to skip the trailing continuation + Assert.AreEqual (0, start); + Assert.AreEqual (1, end); + } + + [Test] + public void MatchParametersWithStaticThis () + { + var klass = LoadClassFile ("UByteArray.class"); + var meta = GetClassMetadataForClass (klass); + + var java_method = klass.Methods.Single (m => m.Name == "contains-7apg3OU" && m.GetParameters ().Count () == 2); + var kotlin_function = meta.Functions.Single (m => m.Name == "contains"); + + (var start, var end) = KotlinFixups.CreateParameterMap (java_method, kotlin_function, null); + + // Start is 1 instead of 0 to skip the static 'this' + Assert.AreEqual (1, start); + Assert.AreEqual (2, end); + } + + [Test] + public void MatchMetadataToMultipleMethodsWithSameMangledName () + { + var klass = LoadClassFile ("UByteArray.class"); + var meta = GetClassMetadataForClass (klass); + + // There is only one Kotlin metadata for Java method "contains-7apg3OU" + var kotlin_function = meta.Functions.Single (m => m.Name == "contains"); + + // However there are 2 Java methods named "contains-7apg3OU" + // - public boolean contains-7apg3OU (byte element) + // - public static boolean contains-7apg3OU (byte[] arg0, byte element) + var java_methods = klass.Methods.Where (m => m.Name == "contains-7apg3OU"); + Assert.AreEqual (2, java_methods.Count ()); + + KotlinFixups.Fixup (new [] { klass }); + + // Ensure the fixup "fixed" the parameter "element" type to "ubyte" + Assert.AreEqual ("ubyte", java_methods.ElementAt (0).GetParameters ().Single (p => p.Name == "element").KotlinType); + Assert.AreEqual ("ubyte", java_methods.ElementAt (1).GetParameters ().Single (p => p.Name == "element").KotlinType); + } + + [Test] + public void GetMethodNameWithoutUnsignedSuffix () + { + // Just a few quick tests to ensure the various cases are covered + Assert.AreEqual ("setFoo", KotlinUtilities.GetMethodNameWithoutUnsignedSuffix ("setFoo")); + Assert.AreEqual ("setFoo", KotlinUtilities.GetMethodNameWithoutUnsignedSuffix ("setFoo-7apg3OU")); + Assert.AreEqual ("setFoo$main", KotlinUtilities.GetMethodNameWithoutUnsignedSuffix ("setFoo-7apg3OU$main")); + Assert.AreEqual ("setFoo$main", KotlinUtilities.GetMethodNameWithoutUnsignedSuffix ("setFoo$main")); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinInlineClassCollisionTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinInlineClassCollisionTests.cs new file mode 100644 index 00000000000..854e78e3f45 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinInlineClassCollisionTests.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Xamarin.Android.Tools.Bytecode; + +namespace Xamarin.Android.Tools.BytecodeTests +{ + // Exercises the real Kotlin bytecode produced by the Gradle fixture under + // kotlin-gradle/ to confirm that the JVM-level mangling we expect (and that + // the generator's KotlinFixups must now de-collide) is actually what kotlinc + // emits for @JvmInline value-class parameters. See dotnet/java-interop#1431. + [TestFixture] + public class KotlinInlineClassCollisionTests : ClassFileFixture + { + [Test] + public void Widgets_HasCollidingHashMangledSiblings () + { + var klass = LoadClassFile ("Widgets.class"); + + // Kotlin emits one mangled method per inline-class overload: + // tint-(J)V for MyColor (ULong-backed) + // tint-(J)V for MyAlpha (ULong-backed) — collides with MyColor + // tint-(F)V for MyDp (Float-backed) — unique + var tints = klass.Methods + .Where (m => m.Name.StartsWith ("tint-", StringComparison.Ordinal)) + .ToList (); + + Assert.AreEqual (3, tints.Count, "Expected three `tint-` overloads from the Gradle fixture."); + + var longTints = tints.Where (m => m.Descriptor == "(J)V").ToList (); + Assert.AreEqual (2, longTints.Count, + "Expected two `tint-(J)V` siblings (MyColor + MyAlpha) — this is the multi-sibling collision case from dotnet/java-interop#1431."); + + Assert.AreEqual (1, tints.Count (m => m.Descriptor == "(F)V"), + "Expected one unique `tint-(F)V` (MyDp) that should survive deduplication."); + } + + [Test] + public void Widgets_HasNonCollidingHashMangledOverloads () + { + var klass = LoadClassFile ("Widgets.class"); + + var pads = klass.Methods + .Where (m => m.Name.StartsWith ("pad-", StringComparison.Ordinal)) + .ToList (); + + Assert.AreEqual (2, pads.Count); + CollectionAssert.AreEquivalent ( + new [] { "(F)F", "(FF)F" }, + pads.Select (m => m.Descriptor).ToArray (), + "`pad` overloads have distinct JVM signatures and should both survive after rename."); + } + + [Test] + public void InlineClasses_AreEmittedAsValueClasses () + { + // Sanity check that @JvmInline really produced a JvmInline annotation on + // the inline-class type — this is what step (2) of #1431 will key on. + var myColor = LoadClassFile ("MyColor.class"); + + var annotations = myColor.Attributes + .OfType () + .SelectMany (a => a.Annotations) + .Select (a => a.Type) + .ToList (); + + Assert.Contains ("Lkotlin/jvm/JvmInline;", annotations); + } + + // dotnet/java-interop#1431 (Phase 2): KotlinFixups must surface the inline + // class's underlying primitive on each `@JvmInline value class` ClassFile so + // the generator can later emit a strongly-typed wrapper struct. + [Test] + public void Fixup_StampsKotlinInlineClassUnderlyingJniType () + { + var classes = LoadInlineClassFixture (); + + KotlinFixups.Fixup (classes); + + var byName = classes.ToDictionary (c => c.ThisClass.Name.Value); + + // MyColor and MyAlpha are both ULong-backed -> JNI primitive `J`. + Assert.AreEqual ("J", byName ["xat/bytecode/tests/MyColor"].KotlinInlineClassUnderlyingJniType); + Assert.AreEqual ("J", byName ["xat/bytecode/tests/MyAlpha"].KotlinInlineClassUnderlyingJniType); + + // MyDp is Float-backed -> JNI primitive `F`. + Assert.AreEqual ("F", byName ["xat/bytecode/tests/MyDp"].KotlinInlineClassUnderlyingJniType); + + // Non-inline classes must NOT be stamped. + Assert.IsNull (byName ["xat/bytecode/tests/Widgets"].KotlinInlineClassUnderlyingJniType); + } + + // dotnet/java-interop#1431 (Phase 2): for every Kotlin function whose + // source-level parameter type is a known inline class, KotlinFixups must + // stamp the `KotlinInlineClassJniType` on that parameter so the generator + // can swap the parameter's symbol for a wrapper-struct projection while + // keeping JNI marshaling on the underlying primitive. + [Test] + public void Fixup_StampsParameterInlineClassJniType () + { + var classes = LoadInlineClassFixture (); + KotlinFixups.Fixup (classes); + + var widgets = classes.Single (c => c.ThisClass.Name.Value == "xat/bytecode/tests/Widgets"); + + var tints = widgets.Methods + .Where (m => m.Name.StartsWith ("tint-", StringComparison.Ordinal)) + .ToList (); + + // Each tint() should have exactly one parameter, and that parameter + // should be stamped with the JNI signature of the inline class it + // originally came from in Kotlin source. + var stampedJniTypes = tints + .Select (m => m.GetParameters ().Single ().KotlinInlineClassJniType) + .Where (j => !string.IsNullOrEmpty (j)) + .OrderBy (j => j, StringComparer.Ordinal) + .ToList (); + + CollectionAssert.AreEquivalent ( + new [] { + "Lxat/bytecode/tests/MyAlpha;", + "Lxat/bytecode/tests/MyColor;", + "Lxat/bytecode/tests/MyDp;", + }, + stampedJniTypes, + "Each tint() parameter must be stamped with its inline-class JNI signature."); + } + + // dotnet/java-interop#1431 (Phase 2): when a method's Kotlin-source-level + // return type is a `@JvmInline value class`, KotlinFixups must stamp the + // method's `KotlinInlineClassReturnJniType` so the generator can project + // the return type to the wrapper struct. + [Test] + public void Fixup_StampsReturnInlineClassJniType () + { + var classes = LoadInlineClassFixture (); + KotlinFixups.Fixup (classes); + + var widgets = classes.Single (c => c.ThisClass.Name.Value == "xat/bytecode/tests/Widgets"); + + var pads = widgets.Methods + .Where (m => m.Name.StartsWith ("pad-", StringComparison.Ordinal)) + .ToList (); + + Assert.IsTrue (pads.Count > 0, "Expected `pad` overloads in fixture."); + Assert.IsTrue ( + pads.All (m => m.KotlinInlineClassReturnJniType == "Lxat/bytecode/tests/MyDp;"), + $"All `pad` overloads return MyDp; got: [{string.Join (", ", pads.Select (m => m.KotlinInlineClassReturnJniType ?? ""))}]"); + } + + // dotnet/java-interop#1431 (Phase 2): KotlinFixups.FixupProperty must also + // stamp inline-class JNI types on property getter return values and setter + // parameters, not just on function parameters/returns. + [Test] + public void Fixup_StampsPropertyInlineClassJniType () + { + var classes = LoadInlineClassFixture (); + KotlinFixups.Fixup (classes); + + var widgets = classes.Single (c => c.ThisClass.Name.Value == "xat/bytecode/tests/Widgets"); + + // `var tintColor: MyColor` emits a mangled getter/setter pair — + // the property finder must look past the inline-class mangled name + // suffix (`-`) AND past the erased primitive return/parameter + // to bind these to the Kotlin property. + var getter = widgets.Methods.Single (m => m.Name.StartsWith ("getTintColor-", StringComparison.Ordinal)); + var setter = widgets.Methods.Single (m => m.Name.StartsWith ("setTintColor-", StringComparison.Ordinal)); + + Assert.AreEqual ("Lxat/bytecode/tests/MyColor;", getter.KotlinInlineClassReturnJniType, + "Inline-class typed property getter must be stamped with the wrapper's JNI signature."); + Assert.AreEqual ("Lxat/bytecode/tests/MyColor;", setter.GetParameters ().Single ().KotlinInlineClassJniType, + "Inline-class typed property setter parameter must be stamped with the wrapper's JNI signature."); + } + + // dotnet/java-interop#1431 (Phase 2): the new fields must round-trip + // through XmlClassDeclarationBuilder onto the api.xml that the generator + // consumes. + [Test] + public void XmlOutput_ContainsKotlinInlineClassAttributes () + { + var classes = LoadInlineClassFixture (); + KotlinFixups.Fixup (classes); + + var classPath = new ClassPath { ApiSource = "class-parse" }; + foreach (var c in classes) + classPath.Add (c); + + var sw = new System.IO.StringWriter (); + classPath.SaveXmlDescription (sw); + var xml = sw.ToString (); + + StringAssert.Contains ("kotlin-inline-class=\"true\"", xml); + StringAssert.Contains ("kotlin-inline-class-underlying-jni-type=\"J\"", xml); + StringAssert.Contains ("kotlin-inline-class-underlying-jni-type=\"F\"", xml); + StringAssert.Contains ("kotlin-inline-class-jni-type=\"Lxat/bytecode/tests/MyColor;\"", xml); + StringAssert.Contains ("kotlin-inline-class-return-jni-type=\"Lxat/bytecode/tests/MyDp;\"", xml); + } + + static List LoadInlineClassFixture () => new List { + LoadClassFile ("MyColor.class"), + LoadClassFile ("MyAlpha.class"), + LoadClassFile ("MyDp.class"), + LoadClassFile ("Widgets.class"), + }; + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinMetadataTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinMetadataTests.cs new file mode 100644 index 00000000000..cf3e97ff142 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinMetadataTests.cs @@ -0,0 +1,206 @@ +using System; +using Xamarin.Android.Tools.Bytecode; +using NUnit.Framework; +using System.Linq; + +namespace Xamarin.Android.Tools.BytecodeTests +{ + [TestFixture] + public class KotlinMetadataTests : ClassFileFixture + { + [Test] + public void PublicKotlinClassFile () + { + var klass_meta = GetClassMetadata ("PublicClass.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + } + + [Test] + public void PrivateKotlinClassFile () + { + var klass_meta = GetClassMetadata ("PrivateClass.class"); + + Assert.AreEqual (KotlinClassVisibility.Private, klass_meta.Visibility); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + } + + [Test] + public void InternalKotlinClassFile () + { + var klass_meta = GetClassMetadata ("InternalClass.class"); + + Assert.AreEqual (KotlinClassVisibility.Internal, klass_meta.Visibility); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + } + + [Test] + public void ProtectedKotlinClassFile () + { + var klass_meta = GetClassMetadata ("PublicClass$ProtectedClass.class"); + + Assert.AreEqual (KotlinClassVisibility.Protected, klass_meta.Visibility); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + } + + [Test] + public void SealedClassFile () + { + var klass_meta = GetClassMetadata ("SealedClass.class"); + + Assert.AreEqual (KotlinClassInheritability.Sealed, klass_meta.Inheritability); + } + + [Test] + public void Interface () + { + var klass_meta = GetClassMetadata ("MyInterface.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.AreEqual (KotlinClassInheritability.Abstract, klass_meta.Inheritability); + Assert.AreEqual (KotlinClassType.Interface, klass_meta.ObjectType); + + Assert.AreEqual (2, klass_meta.Functions.Count); + Assert.AreEqual (2, klass_meta.Properties.Count); + } + + [Test] + public void InterfaceDefaultImpls () + { + var meta = GetMetadataForClassFile ("MyInterface$DefaultImpls.class"); + + Assert.AreEqual (KotlinMetadataKind.SyntheticClass, meta.Kind); + + // TODO: We don't support SyntheticClass yet + } + + [Test] + public void InterfaceInheritingInterface () + { + var klass_meta = GetClassMetadata ("MyInterface2.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.AreEqual (KotlinClassInheritability.Abstract, klass_meta.Inheritability); + Assert.AreEqual (KotlinClassType.Interface, klass_meta.ObjectType); + + Assert.AreEqual (0, klass_meta.Functions.Count); + Assert.AreEqual (2, klass_meta.Properties.Count); + Assert.AreEqual ("MyInterface;", klass_meta.SuperTypes [0].ClassName); + } + + [Test] + public void ClassInheritingInterface () + { + var klass_meta = GetClassMetadata ("MyInterfaceChild.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + + Assert.AreEqual (1, klass_meta.Functions.Count); + Assert.AreEqual (1, klass_meta.Properties.Count); + Assert.AreEqual ("MyInterface;", klass_meta.SuperTypes [0].ClassName); + } + + [Test] + public void DataClass () + { + var klass_meta = GetClassMetadata ("DataClass.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.IsData)); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + + Assert.AreEqual (1, klass_meta.Constructors.Count); + Assert.AreEqual (6, klass_meta.Functions.Count); + Assert.AreEqual (3, klass_meta.Properties.Count); + } + + [Test] + public void EnumClassFile () + { + var klass_meta = GetClassMetadata ("EnumClass.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.AreEqual (KotlinClassType.EnumClass, klass_meta.ObjectType); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + + Assert.AreEqual (1, klass_meta.Constructors.Count); + Assert.AreEqual (4, klass_meta.EnumEntries.Count); + } + + [Test] + public void EnumClassWithInterfaces () + { + var klass_meta = GetClassMetadata ("EnumClassWithInterfaces.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.AreEqual (KotlinClassType.EnumClass, klass_meta.ObjectType); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + + Assert.AreEqual (1, klass_meta.Constructors.Count); + Assert.AreEqual (1, klass_meta.Functions.Count); + Assert.AreEqual (2, klass_meta.EnumEntries.Count); + + Assert.AreEqual ("PLUS", klass_meta.EnumEntries [0]); + Assert.AreEqual ("TIMES", klass_meta.EnumEntries [1]); + + Assert.AreEqual (2, klass_meta.SuperTypes.Count); + + Assert.AreEqual ("kotlin/Enum", klass_meta.SuperTypes [0].ClassName); + Assert.AreEqual ("EnumClassWithInterfacesInterface;", klass_meta.SuperTypes [1].ClassName); + } + + [Test] + public void EnumClassWithFunction () + { + var klass_meta = GetClassMetadata ("EnumClassWithInterfaces$PLUS.class"); + + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + Assert.AreEqual (KotlinClassType.EnumEntry, klass_meta.ObjectType); + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + + Assert.AreEqual (1, klass_meta.Functions.Count); + Assert.AreEqual (1, klass_meta.SuperTypes.Count); + + Assert.AreEqual ("EnumClassWithInterfaces;", klass_meta.SuperTypes [0].ClassName); + } + + [Test] + public void InlineClass () + { + var klass_meta = GetClassMetadata ("InlineClass.class"); + + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.IsInlineClass)); + } + + [Test] + public void Object () + { + var klass_meta = GetClassMetadata ("Object.class"); + + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + Assert.AreEqual (KotlinClassType.Object, klass_meta.ObjectType); + } + + [Test] + public void CompanionObject () + { + var klass_meta = GetClassMetadata ("CompanionObject$Companion.class"); + + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + Assert.AreEqual (KotlinClassType.CompanionObject, klass_meta.ObjectType); + } + + [Test] + public void KotlinExtensionMethods () + { + var klass_meta = GetClassMetadata ("ExtensionMethods.class"); + + Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability); + Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ModuleInfoTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ModuleInfoTests.cs new file mode 100644 index 00000000000..035cc708352 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ModuleInfoTests.cs @@ -0,0 +1,45 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class ModuleInfoTests : ClassFileFixture { + + const string JavaType = "module-info"; + + [Test] + public void ClassFile () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 12, + AccessFlags = ClassAccessFlags.Module, + FullName = "module-info", + }.Assert (c); + + Assert.AreEqual (2, c.Attributes.Count); + + Assert.AreEqual ("SourceFile", c.Attributes [0].Name); + var sourceFileAttr = c.Attributes [0] as SourceFileAttribute; + Assert.IsTrue (sourceFileAttr != null); + Assert.AreEqual ("module-info.java", sourceFileAttr.FileName); + + Assert.AreEqual ("Module", c.Attributes [1].Name); + var moduleAttr = c.Attributes [1] as ModuleAttribute; + Assert.IsTrue (moduleAttr != null); + Assert.AreEqual ("com.xamarin", moduleAttr.ModuleName); + Assert.AreEqual (null, moduleAttr.ModuleVersion); + Assert.AreEqual (1, moduleAttr.Requires.Count); + Assert.AreEqual ("java.base", moduleAttr.Requires [0].Requires); + Assert.AreEqual (1, moduleAttr.Exports.Count); + Assert.AreEqual ("com/xamarin", moduleAttr.Exports [0].Exports); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/NonGenericGlobalTypeTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/NonGenericGlobalTypeTests.cs new file mode 100644 index 00000000000..706660a9f5a --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/NonGenericGlobalTypeTests.cs @@ -0,0 +1,42 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.BytecodeTests { + + [TestFixture] + public class NonGenericGlobalTypeTests : ClassFileFixture { + + const string JavaType = "NonGenericGlobalType"; + + [Test] + public void ClassFile_WithNonGenericGlobalType_class () + { + var c = LoadClassFile (JavaType + ".class"); + new ExpectedTypeDeclaration { + MajorVersion = 0x37, + MinorVersion = 0, + ConstantPoolCount = 16, + AccessFlags = ClassAccessFlags.Super, + FullName = "NonGenericGlobalType", + Superclass = new TypeInfo ("java/lang/Object", "Ljava/lang/Object;"), + Methods = { + new ExpectedMethodDeclaration { + Name = "", + AccessFlags = 0, + ReturnDescriptor = "V", + }, + } + }.Assert (c); + } + + [Test] + public void XmlDeclaration_WithNonGenericGlobalType_class () + { + AssertXmlDeclaration (JavaType + ".class", JavaType + ".xml"); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/NullableAnnotationTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/NullableAnnotationTests.cs new file mode 100644 index 00000000000..e1020792c15 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/NullableAnnotationTests.cs @@ -0,0 +1,68 @@ +using System; + +using Xamarin.Android.Tools.Bytecode; + +using NUnit.Framework; +using System.Linq; + +namespace Xamarin.Android.Tools.BytecodeTests +{ + [TestFixture] + public class NullableAnnotationTests : ClassFileFixture + { + [Test] + public void RuntimeInvisibleAnnotations () + { + var c = LoadClassFile ("NotNullClass.class"); + + // Method with no annotations + var null_method = c.Methods.First (m => m.Name == "nullFunc"); + + Assert.AreEqual (0, null_method.Attributes.OfType ().Count ()); + Assert.AreEqual (0, null_method.Attributes.OfType ().Count ()); + + // Method with not-null parameter and return value annotations + var notnull_method = c.Methods.First (m => m.Name == "notNullFunc"); + var return_ann = notnull_method.Attributes.OfType ().FirstOrDefault ()?.Annotations; + var param_ann = notnull_method.Attributes.OfType ().FirstOrDefault ()?.Annotations; + + Assert.NotNull (return_ann); + Assert.IsTrue (return_ann.Any (a => a.Type == "Landroid/annotation/NonNull;")); + + Assert.NotNull (param_ann); + Assert.IsTrue (param_ann.Any (a => a.ParameterIndex == 0 && a.Annotations[0].Type == "Landroid/annotation/NonNull;")); + + // Field with no annotations + var null_field = c.Fields.First (f => f.Name == "nullField"); + + Assert.AreEqual (0, null_field.Attributes.OfType ().Count ()); + Assert.AreEqual (0, null_field.Attributes.OfType ().Count ()); + + // Field with not-null annotation + var notnull_field = c.Fields.First (f => f.Name == "notNullField"); + + var field_ann = notnull_method.Attributes.OfType ().FirstOrDefault ()?.Annotations; + + Assert.NotNull (field_ann); + Assert.IsTrue (field_ann.Any (a => a.Type == "Landroid/annotation/NonNull;")); + } + + [Test] + public void NullableAnnotationOutput () + { + var c = LoadClassFile ("NotNullClass.class"); + var builder = new XmlClassDeclarationBuilder (c); + var xml = builder.ToXElement (); + + var method = xml.Elements ("method").First (m => m.Attribute ("name").Value == "notNullFunc"); + Assert.AreEqual ("true", method.Attribute ("return-not-null").Value); + + var parameter = method.Element ("parameter"); + Assert.AreEqual ("true", parameter.Attribute ("not-null").Value); + + var field = xml.Elements ("field").First (f => f.Attribute ("name").Value == "notNullField"); + Assert.AreEqual ("true", field.Attribute ("not-null").Value); + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ParameterFixupTests.cs b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ParameterFixupTests.cs new file mode 100644 index 00000000000..7ed2eb37268 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/ParameterFixupTests.cs @@ -0,0 +1,132 @@ +using System; +using System.IO; +using NUnit.Framework; +using Xamarin.Android.Tools.Bytecode; + +namespace Xamarin.Android.Tools.BytecodeTests +{ + [TestFixture] + public class ParameterFixupTests : ClassFileFixture { + + [Test] + public void XmlDeclaration_FixedUpFromOtherClasses () + { + AssertXmlDeclaration (new [] {"IParameterInterface.class","ParameterAbstractClass.class", "ParameterClass.class", "ParameterClass2.class"}, "ParameterFixup.xml"); + } + + [Test] + public void XmlDeclaration_FixedUpFromDocumentation() + { + var androidSdkPath = Environment.GetEnvironmentVariable ("ANDROID_SDK_PATH"); + if (string.IsNullOrEmpty (androidSdkPath)) { + Assert.Ignore ("The `ANDROID_SDK_PATH` environment variable isn't set; " + + "cannot test importing parameter names from HTML. Skipping..."); + return; + } + try { + AssertXmlDeclaration ("TypeEvaluator.class", "ParameterFixupFromDocs.xml", Path.Combine (Environment.GetEnvironmentVariable ("ANDROID_SDK_PATH"), "docs", "reference")); + } catch (Exception ex) { + Assert.Fail ("An unexpected exception was thrown : {0}", ex); + } + } + + [Test] + public void XmlDeclaration_FixedUpFromApiXmlDocumentation () + { + string tempFile = null; + + try { + tempFile = LoadToTempFile ("ParameterFixupApiXmlDocs.xml"); + + AssertXmlDeclaration ("TypeEvaluator.class", "ParameterFixupFromDocs.xml", tempFile); + } finally { + if (File.Exists (tempFile)) + File.Delete (tempFile); + } + } + + [Test] + public void XmlDeclaration_FixedUpFromUnresolvedApiXmlDocumentation () + { + string docsPath = null; + + try { + docsPath = LoadToTempFile ("ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml"); + + AssertXmlDeclaration ("JavaInterfaceNoParameters.class", "ParameterFixup_JavaInterfaceNoParameters.xml", docsPath); + } finally { + if (File.Exists (docsPath)) + File.Delete (docsPath); + } + } + + [Test] + public void XmlDeclaration_DoesNotThrowAnExceptionIfDocumentationNotFound () + { + try { + AssertXmlDeclaration (new [] {"IParameterInterface.class","ParameterAbstractClass.class", "ParameterClass.class", "ParameterClass2.class"}, "ParameterFixup.xml", "SomeNonExistantPath"); + } catch (Exception ex) { + Assert.Fail ("An unexpected exception was thrown : {0}", ex); + } + } + + [Test] + public void DocletType_ShouldDetectApiXml () + { + string tempFile = null; + + try { + tempFile = LoadToTempFile ("ParameterFixupApiXmlDocs.xml"); + + Assert.AreEqual (JavaDocletType._ApiXml, JavaMethodParameterNameProvider.GetDocletType (tempFile)); + } finally { + if (File.Exists (tempFile)) + File.Delete (tempFile); + } + } + + [Test] + public void DocletType_ShouldDetectDroidDocs () + { + var androidSdkPath = Environment.GetEnvironmentVariable ("ANDROID_SDK_PATH"); + if (string.IsNullOrEmpty (androidSdkPath)) { + Assert.Ignore("The `ANDROID_SDK_PATH` environment variable isn't set; " + + "cannot test importing parameter names from HTML. Skipping..."); + return; + } + + var droidDocsPath = Path.Combine (androidSdkPath, "docs", "reference"); + + if (!Directory.Exists (droidDocsPath)) + Assert.Fail("The Android SDK Documentation path `{0}` was not found.", droidDocsPath); + + Assert.AreEqual(JavaDocletType.DroidDoc2, JavaMethodParameterNameProvider.GetDocletType(droidDocsPath)); + } + + [Test] + public void XmlDeclaration_FixedUpFromParameterDescription () + { + string tempFile = null; + + try { + tempFile = LoadToTempFile ("ParameterDescription.txt"); + + AssertXmlDeclaration (new string [] { "TypeEvaluator.class" }, "ParameterFixupFromDocs.xml", tempFile); + } + finally { + if (File.Exists (tempFile)) + File.Delete (tempFile); + } + + try { + tempFile = LoadToTempFile ("ParameterDescription.txt"); + + AssertXmlDeclaration (new string [] { "NestedInterface$DnsSdTxtRecordListener.class" }, "ParameterFixupFromDescriptionText.xml", tempFile); + } finally { + if (File.Exists (tempFile)) + File.Delete (tempFile); + } + } + } +} + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/IJavaInterface.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/IJavaInterface.xml new file mode 100644 index 00000000000..0bee5c8a3c6 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/IJavaInterface.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaAnnotation.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaAnnotation.xml new file mode 100644 index 00000000000..1e45c17b820 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaAnnotation.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaEnum.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaEnum.xml new file mode 100644 index 00000000000..d4a233d1d4d --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaEnum.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1.xml new file mode 100644 index 00000000000..34a0fb86496 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1.xml @@ -0,0 +1,41 @@ + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1MyStringList-1.8.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1MyStringList-1.8.xml new file mode 100644 index 00000000000..ec90afd758f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1MyStringList-1.8.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1MyStringList.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1MyStringList.xml new file mode 100644 index 00000000000..f366b2233fb --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$1MyStringList.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$ASC.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$ASC.xml new file mode 100644 index 00000000000..c46d3168c6f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$ASC.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$PSC.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$PSC.xml new file mode 100644 index 00000000000..89f2cec4037 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$PSC.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$RNC$RPNC.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$RNC$RPNC.xml new file mode 100644 index 00000000000..4297eee5223 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$RNC$RPNC.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$RNC.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$RNC.xml new file mode 100644 index 00000000000..a9366418fa5 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType$RNC.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType.xml new file mode 100644 index 00000000000..b399864905d --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaType.xml @@ -0,0 +1,614 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaTypeNoParameters.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaTypeNoParameters.xml new file mode 100644 index 00000000000..da8a053127d --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JavaTypeNoParameters.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JvmOverloadsConstructor.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JvmOverloadsConstructor.xml new file mode 100644 index 00000000000..91dfbc19adb --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JvmOverloadsConstructor.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/NonGenericGlobalType.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/NonGenericGlobalType.xml new file mode 100644 index 00000000000..e785908f20c --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/NonGenericGlobalType.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterDescription.txt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterDescription.txt new file mode 100644 index 00000000000..469ed8f4959 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterDescription.txt @@ -0,0 +1,9 @@ + +; This is a comment line. +package android.animation ; Anything after semicolon is comment. + class TypeEvaluator + evaluate(float fraction, T startValue, T endValue) + +package com.xamarin + interface NestedInterface.DnsSdTxtRecordListener + onDnsSdTxtRecordAvailable(java.lang.String fullDomainName, java.util.Map txtRecordMap, java.lang.String srcDevice) diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup.xml new file mode 100644 index 00000000000..af03cb2ee99 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup.xml @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupApiXmlDocs.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupApiXmlDocs.xml new file mode 100644 index 00000000000..ab1f555e051 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupApiXmlDocs.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupFromDescriptionText.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupFromDescriptionText.xml new file mode 100644 index 00000000000..df774997c6e --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupFromDescriptionText.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupFromDocs.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupFromDocs.xml new file mode 100644 index 00000000000..66cdcc2f6a4 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixupFromDocs.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters.xml new file mode 100644 index 00000000000..27d8d50bfcc --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml new file mode 100644 index 00000000000..fd041241ff6 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj new file mode 100644 index 00000000000..ae5a8f9466f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj @@ -0,0 +1,67 @@ + + + + $(DotNetTargetFramework) + false + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.targets b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.targets new file mode 100644 index 00000000000..da2b4d7b121 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/Xamarin.Android.Tools.Bytecode-Tests.targets @@ -0,0 +1,50 @@ + + + + + + + + + + + <_BuildClassOutputs Include="@(TestJar->'$(IntermediateOutputPath)classes\%(RecursiveDir)%(Filename).class')" /> + <_BuildClassOutputs Include="@(TestJarNoParameters->'$(IntermediateOutputPath)classes\%(RecursiveDir)%(Filename).class')" /> + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/NonGenericGlobalType.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/NonGenericGlobalType.java new file mode 100644 index 00000000000..6eb91592913 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/NonGenericGlobalType.java @@ -0,0 +1,2 @@ +class NonGenericGlobalType { +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/android/animation/TypeEvaluator.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/android/animation/TypeEvaluator.java new file mode 100644 index 00000000000..07a1d7cae42 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/android/animation/TypeEvaluator.java @@ -0,0 +1,5 @@ +package android.animation; + +public interface TypeEvaluator { + T evaluate(float fraction, T startValue, T endValue); +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/android/annotation/NonNull.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/android/annotation/NonNull.java new file mode 100644 index 00000000000..96a318968b9 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/android/annotation/NonNull.java @@ -0,0 +1,7 @@ +package android.annotation; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +public @interface NonNull { +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/androidx/annotation/Nullable.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/androidx/annotation/Nullable.java new file mode 100644 index 00000000000..d9c55a87db8 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/androidx/annotation/Nullable.java @@ -0,0 +1,17 @@ +package androidx.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Test-only stub of the declaration-target `androidx.annotation.Nullable`. + * Unlike `org.jspecify.annotations.Nullable`, this is *not* `TYPE_USE`, so + * it lands in `Runtime(In)visibleAnnotations` and exercises the declaration- + * level nullable resolution path. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE }) +public @interface Nullable { +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/JSpecifyClassMarked.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/JSpecifyClassMarked.java new file mode 100644 index 00000000000..f2454a8ddfb --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/JSpecifyClassMarked.java @@ -0,0 +1,23 @@ +package com.jspecifytest; + +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Class-level `@NullMarked` inside an already-marked package, with a + * `@Nullable` opt-out, exercises the class-level scope code path. + */ +@NullMarked +public class JSpecifyClassMarked { + + public String defaultReturn (String value) { + return value; + } + + public @Nullable String nullableReturn (@Nullable String value) { + return value; + } + + public String defaultField; + public @Nullable String nullableField; +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/JSpecifyPackageMarked.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/JSpecifyPackageMarked.java new file mode 100644 index 00000000000..ee75a58a9f4 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/JSpecifyPackageMarked.java @@ -0,0 +1,63 @@ +package com.jspecifytest; + +import java.util.List; + +import androidx.annotation.Nullable; +import org.jspecify.annotations.NullUnmarked; + +/** + * Lives inside a `@NullMarked` package. Without any annotations, + * all reference-typed return values, parameters, and fields should + * be considered non-null. + */ +public class JSpecifyPackageMarked { + + // Reference return / param / field with no annotations -> non-null. + public String defaultReturn (String value) { + return value; + } + + public String defaultField; + + // Primitive return / field — never gets a `not-null` attribute. + public int primitiveReturn () { + return 0; + } + + public int primitiveField; + + // TYPE_USE `@Nullable` overrides scope default. + public @org.jspecify.annotations.Nullable String nullableReturn (@org.jspecify.annotations.Nullable String value) { + return value; + } + + public @org.jspecify.annotations.Nullable String nullableField; + + // Declaration-style `@Nullable` (lives in `Runtime(In)visibleAnnotations`, + // not the type-annotation table) must also override the scope default. + @Nullable + public String declarationNullableReturn (@Nullable String value) { + return value; + } + + @Nullable + public String declarationNullableField; + + @NullUnmarked + public String unmarkedReturn (String value) { + return value; + } + + // Type-variable usages have parametric nullness per JSpecify; + // they must not gain `not-null` from the scope default even + // though their erased descriptor is `Ljava/lang/Object;`. + public T typeVariableReturn (T value) { + return value; + } + + // Nested `@Nullable` on an inner type argument. The container + // (List) is still non-null in a `@NullMarked` scope; the inner + // annotation has a non-empty `type_path` and must be ignored + // at the top level. + public List<@org.jspecify.annotations.Nullable String> nestedNullableField; +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/package-info.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/package-info.java new file mode 100644 index 00000000000..6fc7ede5dfb --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifytest/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package com.jspecifytest; + +import org.jspecify.annotations.NullMarked; diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifyunmarked/JSpecifyUnmarked.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifyunmarked/JSpecifyUnmarked.java new file mode 100644 index 00000000000..94638c7417c --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/jspecifyunmarked/JSpecifyUnmarked.java @@ -0,0 +1,28 @@ +package com.jspecifyunmarked; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +/** + * Class in a package with no `package-info.class` and no class-level + * `@NullMarked`. Only explicit annotations should produce nullness + * output; the rest should be unknown (no attribute). + */ +public class JSpecifyUnmarked { + + public String defaultReturn (String value) { + return value; + } + + public @Nullable String nullableReturn (@Nullable String value) { + return value; + } + + public @NonNull String nonNullReturn (@NonNull String value) { + return value; + } + + public String defaultField; + + public @NonNull String nonNullField = ""; +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/IJavaInterface.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/IJavaInterface.java new file mode 100644 index 00000000000..63214ef328a --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/IJavaInterface.java @@ -0,0 +1,12 @@ +package com.xamarin; + +import java.util.List; +import java.util.ArrayList; + +interface IJavaInterface & List, TReturn> extends Runnable { + + @Deprecated + public static final int STATIC_FINAL_INT = 1; + + TReturn func (TString value); +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/IParameterInterface.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/IParameterInterface.java new file mode 100644 index 00000000000..8014a1ad46b --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/IParameterInterface.java @@ -0,0 +1,7 @@ +package com.xamarin; + +interface IParameterInterface { + void func (int value); + int test (int param1, int param2); + int test2 (int param1, int param2, int param3); +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaAnnotation.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaAnnotation.java new file mode 100644 index 00000000000..8c9f765f802 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaAnnotation.java @@ -0,0 +1,20 @@ +package com.xamarin; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ + ElementType.TYPE, + ElementType.FIELD, + ElementType.CONSTRUCTOR, + ElementType.METHOD, + ElementType.PARAMETER, + ElementType.LOCAL_VARIABLE +}) +@Retention(RetentionPolicy.SOURCE) +public @interface JavaAnnotation { + + public String[] value(); +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaInterfaceNoParameters.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaInterfaceNoParameters.java new file mode 100644 index 00000000000..56fe849ba03 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaInterfaceNoParameters.java @@ -0,0 +1,19 @@ +package com.xamarin; + +public interface JavaInterfaceNoParameters { + /** + * JNI sig: ([Ljava/lang/Object;)Ljava/util/List; + */ + java.util.List asList(T... a); + + /** + * JNI sig: ([Ljava/lang/Object;IILjava/lang/Object;)I + * + * @param a [Ljava/lang/Object; + * @param fromIndex int + * @param toIndex int + * @param key Ljava/lang/Object + * @return int + */ + int binarySearch(Object[] a, int fromIndex, int toIndex, Object key); +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaType.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaType.java new file mode 100644 index 00000000000..cb233ae3876 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaType.java @@ -0,0 +1,240 @@ +package com.xamarin; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * JNI sig: Lcom/xamarin/JavaEnum; + */ +// Disconnective comment? +enum JavaEnum { + /** FIRST; JNI sig: Lcom/xamarin/JavaEnum; */ + FIRST, + + /** SECOND; JNI sig: Lcom/xamarin/JavaEnum; */ + + SECOND; + + /** + * summary + * + *

    Paragraphs of text? + * + * @return some value + */ + public int switchValue() { + return 0; + } +} + +/** + * JNI sig: Lcom/xamarin/JavaType; + * + * @param + */ + +public class JavaType + implements Cloneable, Comparable>, + IJavaInterface, List> +{ + /** JNI sig: STATIC_FINAL_OBJECT.L/java/lang/Object; */ + + @Deprecated + public static final Object STATIC_FINAL_OBJECT = new Object (); + /** JNI sig: STATIC_FINAL_INT32.I */ + public static final int STATIC_FINAL_INT32 = 42; + /** JNI sig: STATIC_FINAL_INT32_MIN.I */ + public static final int STATIC_FINAL_INT32_MIN = Integer.MIN_VALUE; + /** JNI sig: STATIC_FINAL_INT32_MAX.I */ + public static final int STATIC_FINAL_INT32_MAX = Integer.MAX_VALUE; + /** JNI sig: STATIC_FINAL_CHAR_MIN.C */ + public static final char STATIC_FINAL_CHAR_MIN = Character.MIN_VALUE; + /** JNI sig: STATIC_FINAL_CHAR_MAX.C */ + public static final char STATIC_FINAL_CHAR_MAX = Character.MAX_VALUE; + /** JNI sig: STATIC_FINAL_INT64_MIN.J */ + public static final long STATIC_FINAL_INT64_MIN = Long.MIN_VALUE; + /** JNI sig: STATIC_FINAL_INT64_MAX.J */ + public static final long STATIC_FINAL_INT64_MAX = Long.MAX_VALUE; + /** JNI sig: STATIC_FINAL_SINGLE_MIN.F */ + public static final float STATIC_FINAL_SINGLE_MIN = Float.MIN_VALUE; + /** JNI sig: STATIC_FINAL_SINGLE_MAX.F */ + public static final float STATIC_FINAL_SINGLE_MAX = Float.MAX_VALUE; + /** JNI sig: STATIC_FINAL_DOUBLE_MIN.D */ + public static final double STATIC_FINAL_DOUBLE_MIN = Double.MIN_VALUE; + /** JNI sig: STATIC_FINAL_DOUBLE_MAX.D */ + public static final double STATIC_FINAL_DOUBLE_MAX = Double.MAX_VALUE; + /** JNI sig: STATIC_FINAL_STRING.Ljava/lang/String; */ + public static final String STATIC_FINAL_STRING = "Hello, \\\"embedded\u0000Nulls\" and \uD83D\uDCA9!"; + /** JNI sig: STATIC_FINAL_BOOL_FALSE.Z */ + public static final boolean STATIC_FINAL_BOOL_FALSE = false; + /** JNI sig: STATIC_FINAL_BOOL_TRUE.Z */ + public static final boolean STATIC_FINAL_BOOL_TRUE = true; + /** JNI sig: POSITIVE_INFINITY.D */ + public static final double POSITIVE_INFINITY = 1.0 / 0.0; + /** JNI sig: NEGATIVE_INFINITY.D */ + public static final double NEGATIVE_INFINITY = -1.0 / 0.0; + /** JNI sig: NaN.D */ + public static final double NaN = 0.0d / 0.0; + + + // The previous nested type naming convention generated names + // which were "too long" (230 chars is too long?!), resulting in + // build errors on *Linux* (of all places). (Wat) + // Consequently, we can't spell everything out. + // + // Naming Convention: + // P: Public visibility + // R: pRotected visibility + // A: pAckage visibiliity + // V: priVate visibility + // S: Static inner class + // N: Non-static inner class + // C: Class + // I: Interface + + /** JNI sig: Lcom/xamarin/JavaType$PSC; */ + + public static abstract class PSC { + } + + /** JNI sig: Lcom/xamarin/JavaType$RNC; */ + protected abstract class RNC { + + /** JNI sig: ()V */ + protected RNC () { + } + + /** JNI sig: (Ljava/lang/Object;Ljava/lang/Object;)V */ + protected RNC (E value1, E2 value2) { + } + + /** JNI sig: (Ljava/lang/Object;)Ljava/lang/Object; */ + + public abstract E2 fromE (E value); + + /** JNI sig: Lcom/xamarin/JavaType$RNC$RPNC; */ + public abstract class RPNC { + /** JNI sig: ()V */ + public RPNC () { + } + + /** JNI sig: (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V */ + public RPNC (E value1, E2 value2, E3 value3) { + } + + /** JNI sig: fromE2.(Ljava/lang/Object;)Ljava/lang/Object; */ + public abstract E3 fromE2 (E2 value); + } + } + + /** JNI sig: Lcom/xamarin/JavaType$ASC; */ + + @Deprecated + /* package */ static class ASC { + } + + /** JNI sig: ()V */ + public JavaType () { + } + + /** JNI sig: (Ljava/lang/String;)V */ + public JavaType (String value) { + } + + /** JNI sig: INSTANCE_FINAL_OBJECT.Ljava/lang/Object; */ + @Deprecated + public final Object INSTANCE_FINAL_OBJECT = new Object (); + + /** JNI sig: INSTANCE_FINAL_E.Ljava/lang/Object; */ + public final E INSTANCE_FINAL_E = null; + + /** JNI sig: packageInstanceEArray.[Ljava/lang/Object; */ + /* package */ E[] packageInstanceEArray; + + /** JNI sig: protectedInstanceEList.Ljava/util/List; */ + protected List protectedInstanceEList; + + private List[] privateInstanceArrayOfListOfIntArrayArray; + + /** JNI sig: compareTo.(Lcom/xamarin/JavaType;)I */ + public int compareTo (JavaType value) { + return 0; + } + + /** JNI sig: func.(Ljava/lang/StringBuilder;)Ljava/util/List; */ + // Comment to "disconnect" Javadoc from the member + public List func (StringBuilder value) { + return null; + } + + /** JNI sig: run.()V */ + public void run () { + } + + /** JNI sig: action.(Ljava/lang/Object;)V */ + @Deprecated + public void action (Object value) { + Object local = new Object (); + local.toString (); + int i = 42; + Runnable r = new Runnable () { + public void run() { + System.out.println ("foo"); + } + }; + r.run(); + } + + /** JNI sig: func.([Ljava/lang/String;)Ljava/lang/Integer; */ + public java.lang.Integer func (String[] values) { + return values.length; + } + + /** JNI sig: staticActionWithGenerics.(Ljava/lang/Object;Ljava/lang/Number;Ljava/util/List;Ljava/util/List;Ljava/util/List;)V */ + public static , TThrowable extends Throwable> + void staticActionWithGenerics ( + T value1, + TExtendsNumber value2, + List unboundedList, + List extendsList, + List superList) + throws IllegalArgumentException, NumberFormatException, TThrowable { + + class MyStringList extends ArrayList { + public MyStringList(String a, int b) { + } + public MyStringList(T value1, String a, int b) { + } + public MyStringList(String a, TExtendsNumber value2, int b) { + } + public MyStringList(String a, int b, List unboundedList) { + } + public String get(int index) { + unboundedList.add (null); + return value1.toString(); + } + } + } + + /** JNI sig: instanceActionWithGenerics.(Ljava/lang/Object;java/lang/Object;)V */ + public + void instanceActionWithGenerics ( + T value1, + E value2) { + } + + /** JNI sig: sum.(I[I)I */ + public static int sum (int first, int... remaining) { + return -1; + } + + /** JNI sig: finalize.()V */ + protected void finalize () { + } + + /** JNI sig: finalize.(I)I */ + public static int finalize (int value) { + return value; + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaTypeNoParameters.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaTypeNoParameters.java new file mode 100644 index 00000000000..6cda34be613 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaTypeNoParameters.java @@ -0,0 +1,9 @@ +package com.xamarin; + +public class JavaTypeNoParameters { + /** + * JNI sig: (Lcom/xamarin/JavaTypeNoParameters;)V + */ + public JavaTypeNoParameters (JavaTypeNoParameters copy) { + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/NestedInterface.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/NestedInterface.java new file mode 100644 index 00000000000..ecd8cdc4a4f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/NestedInterface.java @@ -0,0 +1,11 @@ +package com.xamarin; + +import java.util.Map; + +public class NestedInterface +{ + public interface DnsSdTxtRecordListener + { + void onDnsSdTxtRecordAvailable(String p1, Map p2, String p3); + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/NotNullClass.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/NotNullClass.java new file mode 100644 index 00000000000..f71a70ea65c --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/NotNullClass.java @@ -0,0 +1,18 @@ +package com.xamarin; + +import android.annotation.NonNull; + +public class NotNullClass { + + public void nullFunc (String value) { + } + + @NonNull + public void notNullFunc (@NonNull String value) { + } + + public String nullField; + + @NonNull + public String notNullField; +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterAbstractClass.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterAbstractClass.java new file mode 100644 index 00000000000..006e5aeb4db --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterAbstractClass.java @@ -0,0 +1,9 @@ +package com.xamarin; + +public abstract class ParameterAbstractClass + implements IParameterInterface { + + public abstract void func (int value); + public abstract int test (int param1, int param2); + public abstract int test2 (int p0, int p1, int p2); +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterClass.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterClass.java new file mode 100644 index 00000000000..ab175b53259 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterClass.java @@ -0,0 +1,13 @@ +package com.xamarin; + +public abstract class ParameterClass extends ParameterAbstractClass { + + @Override + public void func (int value) { + } + + @Override + public int test (int param1, int param2) { + return 0; + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterClass2.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterClass2.java new file mode 100644 index 00000000000..f80c04e2c7f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/ParameterClass2.java @@ -0,0 +1,9 @@ +package com.xamarin; + +public class ParameterClass2 extends ParameterClass { + + @Override + public int test2 (int param1, int param2, int param3) { + return 0; + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/internal/PublicClassNotInModuleExports.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/internal/PublicClassNotInModuleExports.java new file mode 100644 index 00000000000..e24c4ceba20 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/internal/PublicClassNotInModuleExports.java @@ -0,0 +1,4 @@ +package com.xamarin.internal; + +public class PublicClassNotInModuleExports { +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/module-info.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/module-info.java new file mode 100644 index 00000000000..48bc26c5b69 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/module-info.java @@ -0,0 +1,4 @@ +module com.xamarin { + requires java.base; + exports com.xamarin; +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NonNull.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NonNull.java new file mode 100644 index 00000000000..41e4bc461c6 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NonNull.java @@ -0,0 +1,8 @@ +package org.jspecify.annotations; + +import java.lang.annotation.*; + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.CLASS) +public @interface NonNull { +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NullMarked.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NullMarked.java new file mode 100644 index 00000000000..a2b88c37fd5 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NullMarked.java @@ -0,0 +1,15 @@ +package org.jspecify.annotations; + +import java.lang.annotation.*; + +@Target({ + ElementType.MODULE, + ElementType.PACKAGE, + ElementType.TYPE, + ElementType.METHOD, + ElementType.CONSTRUCTOR, + ElementType.FIELD, +}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NullMarked { +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NullUnmarked.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NullUnmarked.java new file mode 100644 index 00000000000..d3f5ea8c40f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/NullUnmarked.java @@ -0,0 +1,15 @@ +package org.jspecify.annotations; + +import java.lang.annotation.*; + +@Target({ + ElementType.MODULE, + ElementType.PACKAGE, + ElementType.TYPE, + ElementType.METHOD, + ElementType.CONSTRUCTOR, + ElementType.FIELD, +}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NullUnmarked { +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/Nullable.java b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/Nullable.java new file mode 100644 index 00000000000..8dfa3e99721 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/java/org/jspecify/annotations/Nullable.java @@ -0,0 +1,8 @@ +package org.jspecify.annotations; + +import java.lang.annotation.*; + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.CLASS) +public @interface Nullable { +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/DeepRecursiveKt.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/DeepRecursiveKt.class new file mode 100644 index 00000000000..e115f1336fb Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/DeepRecursiveKt.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/DeepRecursiveScope.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/DeepRecursiveScope.class new file mode 100644 index 00000000000..71b52736670 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/DeepRecursiveScope.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/UByteArray.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/UByteArray.class new file mode 100644 index 00000000000..15ba3575589 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-ThirdParty/UByteArray.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle.targets b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle.targets new file mode 100644 index 00000000000..5b8a7fd218c --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle.targets @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + <_KotlinGradleProjectDir>$(MSBuildThisFileDirectory)kotlin-gradle + <_TestKotlinGradleOutputDir>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\$(IntermediateOutputPath)kotlin-gradle\classes')) + + + + + + + diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/.gitignore b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/.gitignore new file mode 100644 index 00000000000..71ddeefe74a --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/.gitignore @@ -0,0 +1,4 @@ +# Gradle build outputs - rebuilt from source on every test build. +.gradle/ +build/ +classes/ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/build.gradle.kts b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/build.gradle.kts new file mode 100644 index 00000000000..cd214a3ac07 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + kotlin("jvm") version "2.0.21" +} + +repositories { + mavenCentral() +} + +// Don't pin a jvmToolchain -- it would force Gradle to auto-provision a +// matching JDK and fail in CI environments without download repositories +// configured. Use whatever JDK the caller already set in JAVA_HOME (the +// .NET build forwards $(JavaSdkDirectory) for consistency with the rest +// of the repo). Kotlin 2.0.21 targets JVM 11 by default, which is fine +// for the bytecode the tests inspect. + +// Emit compiled classes into a stable, predictable location so the +// .NET test harness can load them via ClassFileFixture without needing +// to know the Gradle build directory layout. +tasks.named("compileKotlin") { + destinationDirectory.set(file((findProperty("kotlinClassesDir") as String?) ?: "$rootDir/classes")) +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/gradle.properties b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/gradle.properties new file mode 100644 index 00000000000..019aab88f98 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/gradle.properties @@ -0,0 +1,5 @@ +# Compile Kotlin in-process to avoid the macOS CI flake where the +# external Kotlin compile daemon fails to start on attempt #1, emits an +# `e :` line to stderr (which dotnet/Exec treats as an error and exit -1) +# even though gradle reports BUILD SUCCESSFUL after the retry. +kotlin.compiler.execution.strategy=in-process diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/settings.gradle.kts b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/settings.gradle.kts new file mode 100644 index 00000000000..6517d1d3a54 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "kotlin-inline-class-fixtures" diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/src/main/kotlin/InlineClassCollisions.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/src/main/kotlin/InlineClassCollisions.kt new file mode 100644 index 00000000000..bc74ac290d3 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin-gradle/src/main/kotlin/InlineClassCollisions.kt @@ -0,0 +1,41 @@ +@file:JvmName("InlineClassCollisionsKt") + +package xat.bytecode.tests + +// Two distinct Kotlin inline classes that erase to the same JVM primitive (long). +// Both `tint(MyColor)` and `tint(MyAlpha)` mangle to `tint-(J)V`, so they +// collide once class-parse drops the hash suffix. This is the exact scenario +// that Jetpack Compose triggers with Color/TextUnit/etc. and is the case +// step (1) of dotnet/java-interop#1431 must handle. +@JvmInline +value class MyColor(val value: ULong) + +@JvmInline +value class MyAlpha(val value: ULong) + +// A second inline class with a different backing primitive, so we can verify +// that *non*-colliding hash siblings still survive. +@JvmInline +value class MyDp(val value: Float) + +object Widgets { + + // Colliding pair: both erase to `tint-XXXXXXX(J)V`. + fun tint(color: MyColor) { /* no-op */ } + fun tint(alpha: MyAlpha) { /* no-op */ } + + // Distinct hash-mangled sibling of the same source name — should survive + // alongside one of the `tint(long)` overloads. + fun tint(dp: MyDp) { /* no-op */ } + + // A non-colliding pair: different arity, both hash-mangled. + fun pad(dp: MyDp): MyDp = dp + fun pad(dp1: MyDp, dp2: MyDp): MyDp = dp1 + + // dotnet/java-interop#1431 (Phase 2): a mutable property typed as an + // inline class exercises the KotlinFixups.FixupProperty path — the + // getter's KotlinInlineClassReturnJniType and the setter's parameter + // KotlinInlineClassJniType must both be stamped so the generator emits + // `public static MyColor TintColor { get; set; }` instead of long. + var tintColor: MyColor = MyColor(0u) +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject$Companion.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject$Companion.class new file mode 100644 index 00000000000..d01d39fc631 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject$Companion.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject.class new file mode 100644 index 00000000000..c380cd78a90 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject.kt new file mode 100644 index 00000000000..69f88986171 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/CompanionObject.kt @@ -0,0 +1,3 @@ +class CompanionObject { + companion object { } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DataClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DataClass.class new file mode 100644 index 00000000000..84aafabbb8d Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DataClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DataClass.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DataClass.kt new file mode 100644 index 00000000000..c75507a7f40 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DataClass.kt @@ -0,0 +1,3 @@ +data class DataClass(val name: String = "", val age: Int = 0) { + var weight: Int = 0 +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.class new file mode 100644 index 00000000000..491cd197525 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.kt new file mode 100644 index 00000000000..ce8653b26fe --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.kt @@ -0,0 +1,2 @@ +class DefaultConstructor (name: String = "bob") { +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClass.class new file mode 100644 index 00000000000..2a2f4701f6d Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClass.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClass.kt new file mode 100644 index 00000000000..d8026e82857 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClass.kt @@ -0,0 +1,3 @@ +enum class EnumClass { + NORTH, SOUTH, WEST, EAST +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces$PLUS.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces$PLUS.class new file mode 100644 index 00000000000..16e36be4b01 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces$PLUS.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces$TIMES.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces$TIMES.class new file mode 100644 index 00000000000..571111d3a32 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces$TIMES.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces.class new file mode 100644 index 00000000000..da1b369c80c Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces.kt new file mode 100644 index 00000000000..5b2efc37613 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfaces.kt @@ -0,0 +1,15 @@ +interface EnumClassWithInterfacesInterface { + fun apply(t: Int, u: Int) : Int + fun applyAsInt(t: Int, u: Int) : Int +} + +enum class EnumClassWithInterfaces : EnumClassWithInterfacesInterface { + PLUS { + override fun apply(t: Int, u: Int): Int = t + u + }, + TIMES { + override fun apply(t: Int, u: Int): Int = t * u + }; + + override fun applyAsInt(t: Int, u: Int) = apply(t, u) +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfacesInterface.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfacesInterface.class new file mode 100644 index 00000000000..3b63f4fa4e5 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/EnumClassWithInterfacesInterface.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ExtensionMethods.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ExtensionMethods.class new file mode 100644 index 00000000000..4065ea2b810 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ExtensionMethods.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ExtensionMethods.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ExtensionMethods.kt new file mode 100644 index 00000000000..4c6ac694eea --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ExtensionMethods.kt @@ -0,0 +1,7 @@ +class ExtensionMethods { + fun MutableList.swap(index1: Int, index2: Int) { + val tmp = this[index1] // 'this' corresponds to the list + this[index1] = this[index2] + this[index2] = tmp + } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InlineClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InlineClass.class new file mode 100644 index 00000000000..c3c2b48ae90 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InlineClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InlineClass.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InlineClass.kt new file mode 100644 index 00000000000..c137def4e7f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InlineClass.kt @@ -0,0 +1 @@ +inline class InlineClass(val value: String) \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Interfaces.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Interfaces.kt new file mode 100644 index 00000000000..d4a01df59fe --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Interfaces.kt @@ -0,0 +1,26 @@ +interface MyInterface { + fun bar() + + val prop: Int // abstract + + val propertyWithImplementation: String + get() = "foo" + + fun foo() { + print(prop) + } +} + +class MyInterfaceChild : MyInterface { + override val prop: Int = 29 + + override fun bar() { + // body + } +} + +interface MyInterface2 : MyInterface { + val value2 : Int + + override val prop: Int get() = 30 +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.class new file mode 100644 index 00000000000..5708648aaf6 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.kt new file mode 100644 index 00000000000..3fbb917113f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.kt @@ -0,0 +1,3 @@ +internal class InternalClass { + enum class ChildEnum { VALUE1, VALUE2 } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalConstructor.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalConstructor.class new file mode 100644 index 00000000000..2e8406b540d Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalConstructor.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalConstructor.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalConstructor.kt new file mode 100644 index 00000000000..a1a474467a9 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalConstructor.kt @@ -0,0 +1 @@ +class InternalConstructor internal constructor (private var myInt : Int) \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalField.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalField.class new file mode 100644 index 00000000000..718a175cf85 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalField.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalField.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalField.kt new file mode 100644 index 00000000000..817c71d5b3f --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalField.kt @@ -0,0 +1,4 @@ +class InternalField { + @JvmField + internal val city: String = "London" +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.class new file mode 100644 index 00000000000..de140482e6f Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.kt new file mode 100644 index 00000000000..3a109d6addd --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.kt @@ -0,0 +1,3 @@ +internal interface InternalInterface { + enum class ChildEnum { VALUE1, VALUE2 } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalMethod.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalMethod.class new file mode 100644 index 00000000000..a4edaafc85d Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalMethod.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalMethod.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalMethod.kt new file mode 100644 index 00000000000..8ad206d1700 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalMethod.kt @@ -0,0 +1,5 @@ +class InternalMethod { + internal fun take() + { + } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalProperty.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalProperty.class new file mode 100644 index 00000000000..4b8dccef25e Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalProperty.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalProperty.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalProperty.kt new file mode 100644 index 00000000000..45b4922b0ba --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalProperty.kt @@ -0,0 +1,3 @@ +class InternalProperty { + internal var city: String = "London" +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/JvmOverloadsConstructor.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/JvmOverloadsConstructor.class new file mode 100644 index 00000000000..6a23a3a7d60 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/JvmOverloadsConstructor.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/JvmOverloadsConstructor.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/JvmOverloadsConstructor.kt new file mode 100644 index 00000000000..3e5c00f1332 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/JvmOverloadsConstructor.kt @@ -0,0 +1,11 @@ +class JvmOverloadsConstructor { + @JvmOverloads + constructor( + something : JvmOverloadsConstructor, + id: Int = 1, + imageId: Int = 2, + title: String, + useDivider: Boolean = false + ) { + } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/META-INF/main.kotlin_module b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/META-INF/main.kotlin_module new file mode 100644 index 00000000000..2983af70661 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/META-INF/main.kotlin_module differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MethodImplementation.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MethodImplementation.class new file mode 100644 index 00000000000..a046801a320 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MethodImplementation.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MethodImplementation.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MethodImplementation.kt new file mode 100644 index 00000000000..5e216da3801 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MethodImplementation.kt @@ -0,0 +1,7 @@ +public inline class MethodImplementation constructor(@PublishedApi internal val data: Short) : Comparable { + public override fun toString(): String = "woof" + + override operator fun compareTo(other: Short): Int { + return 0; + } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface$DefaultImpls.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface$DefaultImpls.class new file mode 100644 index 00000000000..e8c60b1dcd5 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface$DefaultImpls.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface.class new file mode 100644 index 00000000000..cecdbcd327c Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface2$DefaultImpls.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface2$DefaultImpls.class new file mode 100644 index 00000000000..66bbbb170e8 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface2$DefaultImpls.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface2.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface2.class new file mode 100644 index 00000000000..3f77774fc9c Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterface2.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterfaceChild.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterfaceChild.class new file mode 100644 index 00000000000..34521a36421 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/MyInterfaceChild.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/NameShadowing.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/NameShadowing.class new file mode 100644 index 00000000000..023c36e0609 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/NameShadowing.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/NameShadowing.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/NameShadowing.kt new file mode 100644 index 00000000000..93fcf3b3461 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/NameShadowing.kt @@ -0,0 +1,34 @@ +@Suppress("NAME_SHADOWING") +public class NameShadowing { + // Property and method + private val count: Int = 3 + fun count(): Int = count + + // Field and method + private var hitCount = 0 + fun hitCount(): Int = hitCount + + // Private property and explicit getter/setter + private var type = 0 + fun getType(): Int = type + fun setType(type: Int) { } + + // Private immutable property and explicit getter/setter + private val type2 = 0 + fun getType2(): Int = type2 + fun setType2(type: Int) { } + + // Internal property and explicit getter/setter + internal var itype = 0 + fun getItype(): Int = itype + fun setItype(type: Int) { } + + // Internal immutable property and explicit getter/setter + internal val itype2 = 0 + fun getItype2(): Int = itype2 + fun setItype2(type: Int) { } + + // Unsigned types properties + internal var unsignedInternalProperty: UInt = 3u + var unsignedPublicProperty: UInt = 3u +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Object.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Object.class new file mode 100644 index 00000000000..0fd44798674 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Object.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Object.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Object.kt new file mode 100644 index 00000000000..fe0184116bd --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/Object.kt @@ -0,0 +1 @@ +object Object { } \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ParameterName.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ParameterName.class new file mode 100644 index 00000000000..0927cd7dffe Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ParameterName.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ParameterName.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ParameterName.kt new file mode 100644 index 00000000000..43fbf79dcda --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/ParameterName.kt @@ -0,0 +1,3 @@ +interface ParameterName { + fun take(count: Int) +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateClass.class new file mode 100644 index 00000000000..c6721027c7b Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateClass.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateClass.kt new file mode 100644 index 00000000000..fdf66c40924 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateClass.kt @@ -0,0 +1 @@ +private class PrivateClass \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor$Default.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor$Default.class new file mode 100644 index 00000000000..26045198cb3 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor$Default.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor.class new file mode 100644 index 00000000000..a1588dfc607 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor.kt new file mode 100644 index 00000000000..15c0719cd8d --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PrivateDefaultConstructor.kt @@ -0,0 +1,5 @@ +public open class PrivateDefaultConstructor private constructor (internal val isFoo: Boolean) { + init { } + + public companion object Default : PrivateDefaultConstructor (isFoo = false) { } +} diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass$ProtectedClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass$ProtectedClass.class new file mode 100644 index 00000000000..d3ea5a8b404 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass$ProtectedClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass.class new file mode 100644 index 00000000000..a5bc823f5f6 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass.kt new file mode 100644 index 00000000000..e809d056bf9 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/PublicClass.kt @@ -0,0 +1,3 @@ +class PublicClass { + protected class ProtectedClass { } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/RenameExtensionParameter.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/RenameExtensionParameter.kt new file mode 100644 index 00000000000..70f80bd1dec --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/RenameExtensionParameter.kt @@ -0,0 +1 @@ +internal fun ByteArray.toUtf8String(): String = String(this, Charsets.UTF_8) \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/RenameExtensionParameterKt.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/RenameExtensionParameterKt.class new file mode 100644 index 00000000000..00542d8f571 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/RenameExtensionParameterKt.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SealedClass.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SealedClass.class new file mode 100644 index 00000000000..0a0ff078966 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SealedClass.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SealedClass.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SealedClass.kt new file mode 100644 index 00000000000..5fdb470d1b3 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SealedClass.kt @@ -0,0 +1 @@ +sealed class SealedClass \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SetterParameterName.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SetterParameterName.class new file mode 100644 index 00000000000..43822c9671e Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SetterParameterName.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SetterParameterName.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SetterParameterName.kt new file mode 100644 index 00000000000..7b261cd7b0c --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/SetterParameterName.kt @@ -0,0 +1,3 @@ +interface SetterParameterName { + var city: String +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.class new file mode 100644 index 00000000000..b55f4c2bd04 Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.class differ diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.kt b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.kt new file mode 100644 index 00000000000..269d9c43a2a --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.kt @@ -0,0 +1,28 @@ +@kotlin.ExperimentalUnsignedTypes +const val UINT_CONST: UInt = 3u + +@kotlin.ExperimentalUnsignedTypes +const val USHORT_CONST: UShort = 3u + +@kotlin.ExperimentalUnsignedTypes +const val ULONG_CONST: ULong = 3u + +@kotlin.ExperimentalUnsignedTypes +const val UBYTE_CONST: UByte = 3u + +@kotlin.ExperimentalUnsignedTypes +public class UnsignedTypes { + public fun foo_uint (value : Int) : Int { return value; } + public fun foo_uint (value : UInt) : UInt { return value; } + public fun foo_ushort (value : Short) : Short { return value; } + public fun foo_ushort (value : UShort) : UShort { return value; } + public fun foo_ulong (value : Long) : Long { return value; } + public fun foo_ulong (value : ULong) : ULong { return value; } + public fun foo_ubyte (value : Byte) : Byte { return value; } + public fun foo_ubyte (value : UByte) : UByte { return value; } + public fun foo_uintarray (value : UIntArray) : UIntArray { return value; } + public fun foo_ushortarray (value : UShortArray) : UShortArray { return value; } + public fun foo_ulongarray (value : ULongArray) : ULongArray { return value; } + public fun foo_ubytearray (value : UByteArray) : UByteArray { return value; } + public fun foo_uintarrayarray (value : Array) : Array { return value; } +} \ No newline at end of file diff --git a/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypesKt.class b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypesKt.class new file mode 100644 index 00000000000..4140b0fe40b Binary files /dev/null and b/external/Java.Interop/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypesKt.class differ diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/ClassWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/ClassWriterTests.cs new file mode 100644 index 00000000000..ad2e9a523c2 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/ClassWriterTests.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class ClassWriterTests + { + [Test] + public void Basics () + { + var klass = new ClassWriter { + IsPublic = true, + Inherits = "System.Object", + IsPartial = true, + Name = "MyClass", + UsePriorityOrder = true + }; + + klass.Fields.Add (new FieldWriter { IsPublic = true, Name = "my_field", Type = TypeReferenceWriter.Bool }); + klass.AddInlineComment ("// Test comment"); + + klass.Methods.Add (new MethodWriter { Name = "MyMethod", IsPublic = true, ReturnType = TypeReferenceWriter.Void }); + klass.Methods [0].Parameters.Add (new MethodParameterWriter ("test", TypeReferenceWriter.Bool)); + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + klass.Write (writer); + + var expected = +@"public partial class MyClass : System.Object { + public bool my_field; + + // Test comment + + public void MyMethod (bool test) + { + } + +} +"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/ConstructorWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/ConstructorWriterTests.cs new file mode 100644 index 00000000000..06bffefd43c --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/ConstructorWriterTests.cs @@ -0,0 +1,32 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class ConstructorWriterTests + { + [Test] + public void Basics () + { + var ctor = new ConstructorWriter { Name = "MyClass", IsPublic = true, BaseCall = "base ()" }; + ctor.Parameters.Add (new MethodParameterWriter ("test", TypeReferenceWriter.Bool)); + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + ctor.Write (writer); + + var expected = +@"public MyClass (bool test) : base () +{ +} +"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/DelegateWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/DelegateWriterTests.cs new file mode 100644 index 00000000000..f4352366bd6 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/DelegateWriterTests.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class DelegateWriterTests + { + [Test] + public void Basics () + { + var method = new DelegateWriter { Name = "MyDelegate", IsPublic = true, Type = TypeReferenceWriter.IntPtr }; + method.Parameters.Add (new MethodParameterWriter ("test", TypeReferenceWriter.Bool)); + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + method.Write (writer); + + var expected = "public delegate IntPtr MyDelegate (bool test);"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/EventWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/EventWriterTests.cs new file mode 100644 index 00000000000..17bb39495bf --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/EventWriterTests.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class EventWriterTests + { + [Test] + public void Basics () + { + var ev = new EventWriter { Name = "MyEvent", IsPublic = true, EventType = new TypeReferenceWriter ("EventHandler") }; + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + ev.Write (writer); + + var expected = @"public event EventHandler MyEvent; +"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/FieldWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/FieldWriterTests.cs new file mode 100644 index 00000000000..6f79df7d773 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/FieldWriterTests.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class FieldWriterTests + { + [Test] + public void Basics () + { + var field = new FieldWriter { Name = "MyField", IsPublic = true, Type = TypeReferenceWriter.IntPtr }; + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + field.Write (writer); + + var expected = @"public IntPtr MyField; +"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/InterfaceWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/InterfaceWriterTests.cs new file mode 100644 index 00000000000..f45b4c744a4 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/InterfaceWriterTests.cs @@ -0,0 +1,41 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class InterfaceWriterTests + { + [Test] + public void Basics () + { + var iface = new InterfaceWriter { + IsPublic = true, + Inherits = "IDisposable", + IsPartial = true, + Name = "IMyInterface", + UsePriorityOrder = true + }; + + iface.Methods.Add (new MethodWriter { Name = "MyMethod", IsDeclaration = true, ReturnType = TypeReferenceWriter.Void }); + iface.Methods [0].Parameters.Add (new MethodParameterWriter ("test", TypeReferenceWriter.Bool)); + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + iface.Write (writer); + + var expected = +@"public partial interface IMyInterface : IDisposable { + void MyMethod (bool test); + +} +"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/MethodWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/MethodWriterTests.cs new file mode 100644 index 00000000000..1507aea6f00 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/MethodWriterTests.cs @@ -0,0 +1,32 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class MethodWriterTests + { + [Test] + public void Basics () + { + var method = new MethodWriter { Name = "MyMethod", IsPublic = true, ReturnType = TypeReferenceWriter.Void }; + method.Parameters.Add (new MethodParameterWriter ("test", TypeReferenceWriter.Bool)); + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + method.Write (writer); + + var expected = +@"public void MyMethod (bool test) +{ +} +"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/PropertyWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/PropertyWriterTests.cs new file mode 100644 index 00000000000..5d2acf4063a --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/PropertyWriterTests.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class PropertyWriterTests + { + [Test] + public void Basics () + { + var property = new PropertyWriter { Name = "MyProperty", IsPublic = true, PropertyType = TypeReferenceWriter.IntPtr, HasGet = true, HasSet = true }; + + property.GetBody.Add ("return IntPtr.Zero;"); + property.SetBody.Add ("this.Handle = value;"); + + var sw = new StringWriter (); + var writer = new CodeWriter (sw); + + property.Write (writer); + + Console.WriteLine (sw.ToString ()); + + var expected = +@"public IntPtr MyProperty { + get { return IntPtr.Zero; } + set { this.Handle = value; } +} +"; + + Assert.AreEqual (expected, sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/TypeReferenceWriterTests.cs b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/TypeReferenceWriterTests.cs new file mode 100644 index 00000000000..548c9e042a3 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/TypeReferenceWriterTests.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Xamarin.SourceWriter.Tests +{ + [TestFixture] + public class TypeReferenceWriterTests + { + [Test] + public void Constructor () + { + var t = new TypeReferenceWriter ("String"); + + Assert.AreEqual (null, t.Namespace); + Assert.AreEqual ("String", t.Name); + + t = new TypeReferenceWriter ("System.String"); + + Assert.AreEqual ("System", t.Namespace); + Assert.AreEqual ("String", t.Name); + + t = new TypeReferenceWriter ("System.Internal.String"); + + Assert.AreEqual ("System.Internal", t.Namespace); + Assert.AreEqual ("String", t.Name); + } + + [Test] + public void NotNull () + { + var t = new TypeReferenceWriter ("string"); + + var sw = new StringWriter (); + var cw = new CodeWriter (sw); + + t.WriteTypeReference (cw); + + Assert.AreEqual ("string ", sw.ToString ()); + } + + [Test] + public void Nullable () + { + var t = new TypeReferenceWriter ("string") { Nullable = true }; + + var sw = new StringWriter (); + var cw = new CodeWriter (sw); + + t.WriteTypeReference (cw); + + Assert.AreEqual ("string? ", sw.ToString ()); + } + } +} diff --git a/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/Xamarin.SourceWriter-Tests.csproj b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/Xamarin.SourceWriter-Tests.csproj new file mode 100644 index 00000000000..fe26f93a9d4 --- /dev/null +++ b/external/Java.Interop/tests/Xamarin.SourceWriter-Tests/Xamarin.SourceWriter-Tests.csproj @@ -0,0 +1,25 @@ + + + + $(DotNetTargetFramework) + false + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/AccessModifiers.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/AccessModifiers.cs new file mode 100644 index 00000000000..1f0f8fb3316 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/AccessModifiers.cs @@ -0,0 +1,20 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class AccessModifiers : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "AccessModifiers", + apiDescriptionFile: "expected.ji/AccessModifiers/AccessModifiers.xml", + expectedRelativePath: "AccessModifiers", + additionalSupportPaths: null); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Adapters.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Adapters.cs new file mode 100644 index 00000000000..d10be6e40e9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Adapters.cs @@ -0,0 +1,22 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Adapters : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => true; + + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "Adapters", + apiDescriptionFile: "expected.ji/Adapters/Adapters.xml", + expectedRelativePath: "Adapters", + additionalSupportPaths: new[]{ "expected.ji/Adapters/SupportFiles" }); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Android_Graphics_Color.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Android_Graphics_Color.cs new file mode 100644 index 00000000000..b3645bb9bfb --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Android_Graphics_Color.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Android_Graphics_Color : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "Android.Graphics.Color", + apiDescriptionFile: "expected.ji/Android.Graphics.Color/Android.Graphics.Color.xml", + expectedRelativePath: "Android.Graphics.Color"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Arrays.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Arrays.cs new file mode 100644 index 00000000000..651c033977c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Arrays.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Arrays : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "Arrays", + apiDescriptionFile: "expected.ji/Arrays/Arrays.xml", + expectedRelativePath: "Arrays"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/BaseGeneratorTest.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/BaseGeneratorTest.cs new file mode 100644 index 00000000000..e399831d156 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/BaseGeneratorTest.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Java.Interop.Tools.JavaCallableWrappers; +using NUnit.Framework; +using Xamarin.Android.Binder; + +namespace generatortests +{ + public class BaseGeneratorTest + { + StringWriter sw = null; + + [SetUp] + public void Setup () + { + Options = new CodeGeneratorOptions (); + Options.ApiLevel = "4"; + Options.GlobalTypeNames = true; + Options.EnumFieldsMapFile = null; + Options.EnumMethodsMapFile = null; + Options.AssemblyQualifiedName = "Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; + Options.OnlyBindPublicTypes = true; + sw = new StringWriter (); + AdditionalSourceDirectories = new List (); + } + + protected CodeGeneratorOptions Options = null; + protected Assembly BuiltAssembly = null; + List AdditionalSourceDirectories; + protected bool AllowWarnings; + + protected virtual bool TryJavaInterop1 => true; + + public void Execute () + { + CodeGenerator.Run (Options); + var output = sw.ToString (); + if (output.Contains ("error")) { + Assert.Fail (output); + } + bool hasErrors; + string compilerOutput; + BuiltAssembly = Compiler.Compile (Options, FullPath ("Mono.Android.dll"), AdditionalSourceDirectories, + out hasErrors, out compilerOutput, AllowWarnings); + Assert.AreEqual (false, hasErrors, compilerOutput); + Assert.IsNotNull (BuiltAssembly); + } + + protected void CompareOutputs (string sourceDir, string destinationDir) + { + if (!Path.IsPathRooted (sourceDir)) + sourceDir = FullPath (sourceDir); + if (!Path.IsPathRooted (destinationDir)) + destinationDir = FullPath (destinationDir); + + var files = Directory.GetFiles (sourceDir); + foreach (var file in files) { + var extension = Path.GetExtension (file); + if (extension == ".xml" || extension == ".fixed") + continue; + var filename = Path.GetFileName (file); + var dest = Path.Combine (destinationDir, filename); + if (!File.Exists (dest)) { + Assert.Fail (string.Format ("Expected {0} but it was not generated.", dest)); + } else if (!FileCompare (file, dest)) { + var fullSource = Path.GetFullPath (file); + var fullDest = Path.GetFullPath (dest); + //Error message for diff in powershell vs bash + string message = Environment.OSVersion.Platform == PlatformID.Win32NT ? + $"File contents differ; run: diff (cat {fullSource}) `{Environment.NewLine}\t(cat {fullDest})" : + $"File contents differ; run: git diff --no-index {fullSource} \\{Environment.NewLine}\t{fullDest}"; + Assert.Fail (message); + } + } + } + + protected void Cleanup (string path) + { + if (!Path.IsPathRooted (path)) + path = FullPath (path); + if (Directory.Exists (path)) + Directory.Delete (path, true); + } + + protected bool FileCompare (string file1, string file2) + { + bool result = false; + + result = File.Exists (file1) && File.Exists (file2); + + if (result) { + byte[] f1 = ReadAllBytesIgnoringLineEndings (file1); + byte[] f2 = ReadAllBytesIgnoringLineEndings (file2); + + using (var hash = new Crc64 ()) { + var f1hash = Convert.ToBase64String (hash.ComputeHash (f1)); + var f2hash = Convert.ToBase64String (hash.ComputeHash (f2)); + result = string.Equals (f1hash, f2hash, StringComparison.Ordinal); + } + } + + return result; + } + + private byte[] ReadAllBytesIgnoringLineEndings (string path) + { + using (var memoryStream = new MemoryStream ()) { + using (var file = File.OpenRead (path)) { + int readByte; + while ((readByte = file.ReadByte()) != -1) { + byte b = (byte)readByte; + if (b != '\r' && b != '\n' && b != ' ' && b != '\t') { + memoryStream.WriteByte (b); + } + } + } + return memoryStream.ToArray (); + } + } + + protected void RunAllTargets (string outputRelativePath, string apiDescriptionFile, string expectedRelativePath, string[] additionalSupportPaths = null, string enumFieldsMapFile = null, string enumMethodMapFile = null, string metadataFile = null) + { + Run (CodeGenerationTarget.XAJavaInterop1, Path.Combine ("out.xaji", outputRelativePath), apiDescriptionFile, Path.Combine ("expected.xaji", expectedRelativePath), additionalSupportPaths, enumFieldsMapFile, enumMethodMapFile, metadataFile); + if (TryJavaInterop1) { + Run (CodeGenerationTarget.JavaInterop1, Path.Combine ("out.ji", outputRelativePath), apiDescriptionFile, Path.Combine ("expected.ji", expectedRelativePath), additionalSupportPaths, enumFieldsMapFile, enumMethodMapFile, metadataFile); + } + } + + protected string FullPath (string path) + { + var dir = Path.GetDirectoryName (GetType ().Assembly.Location); + return Path.Combine (dir, path.Replace ('/', Path.DirectorySeparatorChar)); + } + + protected void Run (CodeGenerationTarget target, string outputPath, string apiDescriptionFile, string expectedPath, string[] additionalSupportPaths = null, string enumFieldsMapFile = null, string enumMethodMapFile = null, string metadataFile = null) + { + Cleanup (outputPath); + AdditionalSourceDirectories.Clear (); + + Options.CodeGenerationTarget = target; + Options.EmitLegacyInterfaceInvokers = false; + Options.ApiDescriptionFile = FullPath (apiDescriptionFile); + Options.ManagedCallableWrapperSourceOutputDirectory = FullPath (outputPath); + + if (!string.IsNullOrWhiteSpace (enumFieldsMapFile)) + Options.EnumFieldsMapFile = FullPath (enumFieldsMapFile); + + if (!string.IsNullOrWhiteSpace (enumMethodMapFile)) + Options.EnumMethodsMapFile = FullPath (enumMethodMapFile); + + if (!string.IsNullOrWhiteSpace (metadataFile)) + Options.FixupFiles.Add (metadataFile); + + var adjuster_output = Path.Combine (Path.GetTempPath (), "generator-tests"); + Directory.CreateDirectory (adjuster_output); + + // Put this in a temp folder so it doesn't end up in "expected", which breaks the compare. + Options.ApiXmlAdjusterOutput = Path.Combine (adjuster_output, Path.GetFileName (apiDescriptionFile) + ".adjusted"); + + if (additionalSupportPaths != null) { + AdditionalSourceDirectories.AddRange (additionalSupportPaths.Select (p => FullPath (p))); + } + + Execute (); + + // Try to clean up after ourselves. + try { + Directory.Delete (adjuster_output, true); + } catch { } + + CompareOutputs (expectedPath, outputPath); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/CSharpKeywords.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/CSharpKeywords.cs new file mode 100644 index 00000000000..ab7333b54b6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/CSharpKeywords.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class CSharpKeywords : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "CSharpKeywords", + apiDescriptionFile: "expected.ji/CSharpKeywords/CSharpKeywords.xml", + expectedRelativePath: "CSharpKeywords"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Compiler.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Compiler.cs new file mode 100644 index 00000000000..d227479ea1d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Compiler.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using NUnit.Framework; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generatortests +{ + public static class Compiler + { + private static string supportFilePath = typeof (Compiler).Assembly.Location; + private static string unitTestFrameworkAssemblyPath = typeof (Assert).Assembly.Location; + + public static Assembly Compile (Xamarin.Android.Binder.CodeGeneratorOptions options, + string assemblyFileName, IEnumerable AdditionalSourceDirectories, + out bool hasErrors, out string output, bool allowWarnings) + { + // Gather all the files we need to compile + var generatedCodePath = options.ManagedCallableWrapperSourceOutputDirectory; + var sourceFiles = Directory.EnumerateFiles (generatedCodePath, "*.cs", + SearchOption.AllDirectories).ToList (); + sourceFiles = sourceFiles.Select (x => Path.GetFullPath (x)).ToList (); + + var supportFiles = Directory.EnumerateFiles (Path.Combine (Path.GetDirectoryName (supportFilePath), "SupportFiles"), + "*.cs", SearchOption.AllDirectories); + sourceFiles.AddRange (supportFiles); + + foreach (var dir in AdditionalSourceDirectories) { + var additonal = Directory.EnumerateFiles (dir, "*.cs", SearchOption.AllDirectories); + sourceFiles.AddRange (additonal); + } + + var preprocessorSymbols = new List (); + if (options.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + preprocessorSymbols.Add ("JAVA_INTEROP1"); + } + preprocessorSymbols.Add ("NET"); + + var parseOptions = new CSharpParseOptions (preprocessorSymbols:preprocessorSymbols); + + + // Parse the source files + var syntax_trees = sourceFiles.Distinct () + .Select (s => CSharpSyntaxTree.ParseText (File.ReadAllText (s), options:parseOptions)) + .ToArray (); + + // Set up the assemblies we need to reference + var binDir = Path.GetDirectoryName (typeof (BaseGeneratorTest).Assembly.Location); + var facDir = GetFacadesPath (); + + var referencePaths = new[]{ + unitTestFrameworkAssemblyPath, + typeof(object).Assembly.Location, + typeof(Enumerable).Assembly.Location, + typeof(Uri).Assembly.Location, + Path.Combine (binDir, "Java.Interop.dll"), + Path.Combine (facDir, "netstandard.dll"), + Path.Combine (facDir, "System.Runtime.dll"), + }; + + var references = referencePaths.Select (p => MetadataReference.CreateFromFile (p)).ToArray (); + + string testCommandLine = + $"csc -noconfig -nostdlib \"-out:{Path.GetFileName (assemblyFileName)}\" " + + $"-unsafe -t:library " + + string.Join (" ", preprocessorSymbols.Select (p => $"\"-define:{p}\"")) + " " + + string.Join (" ", referencePaths.Select (p => $"\"-r:{p}\"")) + " " + + string.Join (" ", sourceFiles) + ; + + Console.WriteLine ($"# Trying to compile: {testCommandLine}"); + + // Compile! + var compilation = CSharpCompilation.Create ( + Path.GetFileName (assemblyFileName), + syntaxTrees: syntax_trees, + references: references, + options: new CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true)); + + // Save assembly to a memory stream and load it with reflection + using (var ms = new MemoryStream ()) { + var result = compilation.Emit (ms); + var success = result.Success && (allowWarnings || !result.Diagnostics.Any (d => d.Severity == DiagnosticSeverity.Warning)); + + if (!success) { + var failures = result.Diagnostics.Where (diagnostic => + diagnostic.Severity == DiagnosticSeverity.Warning || + diagnostic.Severity == DiagnosticSeverity.Error); + + hasErrors = true; + output = OutputDiagnostics (failures); + } else { + ms.Seek (0, SeekOrigin.Begin); + + hasErrors = false; + output = null; + + return Assembly.Load (ms.ToArray ()); + } + } + + return null; + } + + static string GetFacadesPath () + { + var env = Environment.GetEnvironmentVariable ("FACADES_PATH"); + if (env != null) + return env; + + var dir = Path.GetDirectoryName (typeof (object).Assembly.Location); + var facades = Path.Combine (dir, "Facades"); + if (Directory.Exists (facades)) + return facades; + + return dir; + } + + static string OutputDiagnostics (IEnumerable diagnostics) + { + var sb = new StringBuilder (); + + foreach (var d in diagnostics) + sb.AppendLine ($"{d.Id}: {d.GetMessage ()} ({d.Location})"); + + return sb.ToString (); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Constructors.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Constructors.cs new file mode 100644 index 00000000000..4882f4720a7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Constructors.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Constructors : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "Constructors", + apiDescriptionFile: "expected.ji/Constructors/Constructors.xml", + expectedRelativePath: "Constructors"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Core_ClassParse.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Core_ClassParse.cs new file mode 100644 index 00000000000..8954c5649b6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Core_ClassParse.cs @@ -0,0 +1,22 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Core_ClassParse : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + AllowWarnings = true; + + RunAllTargets ( + outputRelativePath: "Core_ClassParse", + apiDescriptionFile: "expected.ji/Core_ClassParse/api.xml", + expectedRelativePath: "Core_ClassParse", + metadataFile: FullPath ("expected.ji/Core_ClassParse/metadata.xml")); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Core_Jar2Xml.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Core_Jar2Xml.cs new file mode 100644 index 00000000000..3ec77c2e6be --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Core_Jar2Xml.cs @@ -0,0 +1,26 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Core_Jar2Xml : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => false; + + [Test] + public void GeneratedOK () + { + AllowWarnings = true; + + RunAllTargets ( + outputRelativePath: "Core_Jar2Xml", + apiDescriptionFile: "expected.ji/Core_Jar2Xml/api.xml", + expectedRelativePath: "Core_Jar2Xml", + enumFieldsMapFile: "expected.ji/Core_Jar2Xml/fields.xml", + enumMethodMapFile: "expected.ji/Core_Jar2Xml/methods.xml" + ); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/GenericArguments.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/GenericArguments.cs new file mode 100644 index 00000000000..de97f10bfea --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/GenericArguments.cs @@ -0,0 +1,22 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class GenericArguments : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => false; + + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "GenericArguments", + apiDescriptionFile: "expected.ji/GenericArguments/GenericArguments.xml", + expectedRelativePath: "GenericArguments", + additionalSupportPaths: null); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/InterfaceMethodsConflict.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/InterfaceMethodsConflict.cs new file mode 100644 index 00000000000..c5dda391625 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/InterfaceMethodsConflict.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class InterfaceMethodsConflict : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "InterfaceMethodsConflict", + apiDescriptionFile: "expected.ji/InterfaceMethodsConflict/InterfaceMethodsConflict.xml", + expectedRelativePath: "InterfaceMethodsConflict"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Interfaces.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Interfaces.cs new file mode 100644 index 00000000000..82575d755f3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Interfaces.cs @@ -0,0 +1,28 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Interfaces : BaseGeneratorTest + { + public Interfaces () + { + // warning CS0108: 'IDeque.Add(Object)' hides inherited member 'IQueue.Add(Object)'. Use the new keyword if hiding was intended. + // warning CS0108: 'IQueue.Add(Object)' hides inherited member 'ICollection.Add(Object)'. Use the new keyword if hiding was intended. + AllowWarnings = true; + } + + protected override bool TryJavaInterop1 => true; + + [Test] + public void Generated_OK () + { + RunAllTargets ( + outputRelativePath: "TestInterface", + apiDescriptionFile: "expected.ji/TestInterface/TestInterface.xml", + expectedRelativePath: "TestInterface"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Lang_Enum.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Lang_Enum.cs new file mode 100644 index 00000000000..eb9451042cf --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Lang_Enum.cs @@ -0,0 +1,21 @@ +using NUnit.Framework; +using System; + +namespace generatortests +{ + [TestFixture] + public class Java_Lang_Enum : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => true; + + [Test] + public void Generated_OK () + { + RunAllTargets ( + outputRelativePath: "java.lang.Enum", + apiDescriptionFile: "expected.ji/java.lang.Enum/Java.Lang.Enum.xml", + expectedRelativePath: "java.lang.Enum"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Lang_Object.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Lang_Object.cs new file mode 100644 index 00000000000..7aeff7b15fd --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Lang_Object.cs @@ -0,0 +1,22 @@ +using System; +using System.Linq; +using NUnit.Framework; +using MonoDroid.Generation; +using System.Xml; + +namespace generatortests +{ + [TestFixture] + public class Java_Lang_Object : BaseGeneratorTest + { + [Test] + public void Generated_OK () + { + Run (target: Xamarin.Android.Binder.CodeGenerationTarget.JavaInterop1, + outputPath: "out.ji/java.lang.Object", + apiDescriptionFile: "expected.ji/java.lang.Object/java.lang.Object.xml", + expectedPath: "expected.ji/java.lang.Object"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Util_List.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Util_List.cs new file mode 100644 index 00000000000..19da2f51e9c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Java_Util_List.cs @@ -0,0 +1,21 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Java_Util_List : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => true; + + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "java.util.List", + apiDescriptionFile: "expected.ji/java.util.List/java.util.List.xml", + expectedRelativePath: "java.util.List"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/NestedTypes.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NestedTypes.cs new file mode 100644 index 00000000000..54085667a84 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NestedTypes.cs @@ -0,0 +1,20 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class NestedTypes : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => true; + + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "NestedTypes", + apiDescriptionFile: "expected.ji/NestedTypes/NestedTypes.xml", + expectedRelativePath: "NestedTypes"); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/NonStaticFields.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NonStaticFields.cs new file mode 100644 index 00000000000..bd56d4d4ce4 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NonStaticFields.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class NonStaticFields : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "NonStaticFields", + apiDescriptionFile: "expected.ji/NonStaticFields/NonStaticField.xml", + expectedRelativePath: "NonStaticFields"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/NormalMethods.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NormalMethods.cs new file mode 100644 index 00000000000..a30350685be --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NormalMethods.cs @@ -0,0 +1,21 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class NormalMethods : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => false; + + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "NormalMethods", + apiDescriptionFile: "expected.ji/NormalMethods/NormalMethods.xml", + expectedRelativePath: "NormalMethods"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/NormalProperties.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NormalProperties.cs new file mode 100644 index 00000000000..97e973b3f49 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/NormalProperties.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class NormalProperties : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "NormalProperties", + apiDescriptionFile: "expected.ji/NormalProperties/NormalProperties.xml", + expectedRelativePath: "NormalProperties"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/PamareterXPath.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/PamareterXPath.cs new file mode 100644 index 00000000000..229af5e6ef5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/PamareterXPath.cs @@ -0,0 +1,21 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class ParameterXPath : BaseGeneratorTest + { + protected override bool TryJavaInterop1 => true; + + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "ParameterXPath", + apiDescriptionFile: "expected.ji/ParameterXPath/ParameterXPath.xml", + expectedRelativePath: "ParameterXPath"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticFields.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticFields.cs new file mode 100644 index 00000000000..ecb22dac6e7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticFields.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class StaticFields : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "StaticFields", + apiDescriptionFile: "expected.ji/StaticFields/StaticField.xml", + expectedRelativePath: "StaticFields"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticMethods.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticMethods.cs new file mode 100644 index 00000000000..cb33ce955f6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticMethods.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class StaticMethods : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "StaticMethods", + apiDescriptionFile: "expected.ji/StaticMethods/StaticMethod.xml", + expectedRelativePath: "StaticMethods"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticProperties.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticProperties.cs new file mode 100644 index 00000000000..0e25b3fe4d8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/StaticProperties.cs @@ -0,0 +1,19 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class StaticProperties : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "StaticProperties", + apiDescriptionFile: "expected.ji/StaticProperties/StaticProperties.xml", + expectedRelativePath: "StaticProperties"); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Integration-Tests/Streams.cs b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Streams.cs new file mode 100644 index 00000000000..e27cfc3d6cd --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Integration-Tests/Streams.cs @@ -0,0 +1,20 @@ +using System; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class Streams : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + RunAllTargets ( + outputRelativePath: "Streams", + apiDescriptionFile: "expected.ji/Streams/Streams.xml", + expectedRelativePath: "Streams", + additionalSupportPaths: new[]{ "expected.ji/Streams/SupportFiles" }); + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/README.md b/external/Java.Interop/tests/generator-Tests/README.md new file mode 100644 index 00000000000..b2b22b9a388 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/README.md @@ -0,0 +1,43 @@ + +These tests are not intuitive at all. So we need some documentation here. + +These tests compare outcomes from generator to the "expected" outcomes. + +It does not work together with class-parse, so you cannot pass any jars +nor java sources, which is a pain point (but those who created these tests +didn't care). + +There are two "expected" set of files. One is "expected" and the other is +"expected.ji". They are different per Java.Interop output methods. + +The differences between "expected" and "expected.ji" are almost only +annoying, but this test blindly compares those differences. So if you are +going to add tests you will have to duplicate your work twice... + +Tests that use `BaseGeneratorTest` are organized as: + +./BaseGeneratorTest.cs - sets up generation and compilation options. +./Compiler.cs - implements C# compilation with `CodeDomProvider`. +./(others).cs - the actual `TestFixture`s. + +What those tests do are: + +- invoke class-parse (and perhaps jar2xml), to generate XML API inputs to generator. +- invoke generator, to generate comparable sources. +- optionally invoke csc to see if it builds. + +`BaseGeneratorTest` takes the arguments below, + +- outputRelativePath - path to generator output subdir +- apiDescriptionFile - path to the input API XML output. Sadly existing tests + are organized horribly and they reside in the "expected" directory. +- expectedRelativePath - path to the "expected" file generation. +- additionalSupportPaths - path to additional compilation items. + +The test outputs are generated to `out` and `out.ji` directories, per +the generator's output method. + +When you are creating a new test, it is easier to once generate results in +those `out` and `out.ji` directories, and copy them as "expected" and +"expected.ji" with required changes (so that they become really expected +contents). diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/Android.Text.SpanTypes.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/Android.Text.SpanTypes.cs new file mode 100644 index 00000000000..7ac45bf8862 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/Android.Text.SpanTypes.cs @@ -0,0 +1,12 @@ +#if !JAVA_INTEROP1 + +using System; + +namespace Android.Text { + + public enum SpanTypes { + None = 0 + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/Android_Runtime_CharSequence.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/Android_Runtime_CharSequence.cs new file mode 100644 index 00000000000..4db1ef23e47 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/Android_Runtime_CharSequence.cs @@ -0,0 +1,37 @@ +#if !JAVA_INTEROP1 + +using System; +using System.Collections.Generic; + +namespace Android.Runtime { + + public static class CharSequence + { + public static Java.Lang.ICharSequence [] ArrayFromStringArray (string [] val) + { + throw new NotImplementedException (); + } + + public static string [] ArrayToStringArray (Java.Lang.ICharSequence [] val) + { + throw new NotImplementedException (); + } + + public static IntPtr ToLocalJniHandle (string value) + { + throw new NotImplementedException (); + } + + public static IntPtr ToLocalJniHandle (Java.Lang.ICharSequence value) + { + throw new NotImplementedException (); + } + + public static IntPtr ToLocalJniHandle (IEnumerable value) + { + throw new NotImplementedException (); + } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/EventHelper.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/EventHelper.cs new file mode 100644 index 00000000000..ba1752a3d16 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/EventHelper.cs @@ -0,0 +1,43 @@ +using System; + +namespace Java.Interop { + + public static class EventHelper { + + public static void AddEventHandler ( + ref WeakReference implementor, + Func creator, + Action setListener, + Action add) + where TImplementor : Java.Lang.Object, TInterface + { + TImplementor impl = null; + if (implementor == null || (impl = (TImplementor) implementor.Target) == null) { + impl = creator (); + implementor = new WeakReference (impl, true); + setListener (impl); + } + add (impl); + } + + public static void RemoveEventHandler ( + ref WeakReference implementor, + Func empty, + Action unsetListener, + Action remove) + where TImplementor : Java.Lang.Object, TInterface + { + TImplementor impl = null; + if (implementor == null || (impl = (TImplementor) implementor.Target) == null) + return; + remove (impl); + if (empty (impl)) { + unsetListener (impl); + impl = null; + implementor.Target = null; + implementor = null; + } + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/GeneratedEnumAttribute.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/GeneratedEnumAttribute.cs new file mode 100644 index 00000000000..f3d37275562 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/GeneratedEnumAttribute.cs @@ -0,0 +1,11 @@ +#if !JAVA_INTEROP1 + +using System; + +namespace Android.Runtime +{ + [AttributeUsage (AttributeTargets.ReturnValue | AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public class GeneratedEnumAttribute : Attribute {} +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/IJavaObject.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/IJavaObject.cs new file mode 100644 index 00000000000..647664ab796 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/IJavaObject.cs @@ -0,0 +1,12 @@ +#if !JAVA_INTEROP1 + +using System; + +namespace Android.Runtime { + + public interface IJavaObject : IDisposable { + IntPtr Handle { get; } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/IntDefinitionAttribute.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/IntDefinitionAttribute.cs new file mode 100644 index 00000000000..8249751a3f3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/IntDefinitionAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace Android.Runtime +{ + [AttributeUsage (AttributeTargets.Field)] + public class IntDefinitionAttribute : Attribute + { + public IntDefinitionAttribute (string constantMember) + { + ConstantMember = constantMember; + } + + public string ConstantMember { get; set; } + public string JniField { get; set; } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JNIEnv.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JNIEnv.cs new file mode 100644 index 00000000000..d6a9b532dca --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JNIEnv.cs @@ -0,0 +1,596 @@ +#if !JAVA_INTEROP1 + +#pragma warning disable +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Threading; +using System.Text; + +namespace Android.Runtime { + + struct JnienvInitializeArgs { + public IntPtr javaVm; + public IntPtr env; + public IntPtr grefLoader; + public IntPtr Loader_loadClass; + public uint logCategories; + public IntPtr Class_getName; + public int version; + public int androidSdkVersion; + public int localRefsAreIndirect; + public int grefGcThreshold; + public IntPtr grefIGCUserPeer; + } + + public static partial class JNIEnv { + + static IntPtr java_class_loader; + static IntPtr java_vm; + static IntPtr load_class_id; + static JNIInvokeInterface invoke_iface; + static int version; + static int gref_gc_threshold; + static int androidSdkVersion; + + static bool AllocObjectSupported; + + static IntPtr cid_System; + static IntPtr mid_System_identityHashCode; + internal static IntPtr mid_Class_getName; + + internal static bool PropagateExceptions; + + [ThreadStatic] static IntPtr handle; + [ThreadStatic] static JniNativeInterfaceInvoker env; + + static JniNativeInterfaceInvoker Env { + get; + set; + } + + public static IntPtr Handle { + get; + set; + } + + static void SetEnv () + { + throw new NotImplementedException (); + } + + public static void CheckHandle (IntPtr jnienv) + { + throw new NotImplementedException (); + } + + [DllImport ("libc")] + static extern int gettid (); + + delegate Delegate GetCallbackHandler (); + + static MethodInfo dynamic_callback_gen; + + static Delegate CreateDynamicCallback (MethodInfo method) + { + throw new NotImplementedException (); + } + + static unsafe void RegisterJniNatives (IntPtr typeName_ptr, int typeName_len, IntPtr jniClass, IntPtr methods_ptr, int methods_len) + { + throw new NotImplementedException (); + } + + internal static unsafe void Initialize (JnienvInitializeArgs* args) + { + throw new NotImplementedException (); + } + + + static volatile bool BridgeProcessing; // = false + + public static void WaitForBridgeProcessing () + { + throw new NotImplementedException (); + } + + + internal static Func IdentityHash; + + public static IntPtr AllocObject (string jniClassName) + { + throw new NotImplementedException (); + } + + public static IntPtr AllocObject (Type type) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr StartCreateInstance (IntPtr jclass, IntPtr constructorId, JValue* constructorParameters) + { + throw new NotImplementedException (); + } + + public static IntPtr StartCreateInstance (IntPtr jclass, IntPtr constructorId, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static unsafe void FinishCreateInstance (IntPtr instance, IntPtr jclass, IntPtr constructorId, JValue* constructorParameters) + { + } + + public static void FinishCreateInstance (IntPtr instance, IntPtr jclass, IntPtr constructorId, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr StartCreateInstance (Type type, string jniCtorSignature, JValue* constructorParameters) + { + throw new NotImplementedException (); + } + + public static IntPtr StartCreateInstance (Type type, string jniCtorSignature, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr StartCreateInstance (string jniClassName, string jniCtorSignature, JValue* constructorParameters) + { + throw new NotImplementedException (); + } + + public static IntPtr StartCreateInstance (string jniClassName, string jniCtorSignature, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static unsafe void FinishCreateInstance (IntPtr instance, string jniCtorSignature, JValue* constructorParameters) + { + throw new NotImplementedException (); + } + + public static void FinishCreateInstance (IntPtr instance, string jniCtorSignature, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static void InvokeConstructor (IntPtr instance, string jniCtorSignature, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static IntPtr CreateInstance (IntPtr jniClass, string signature, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static IntPtr CreateInstance (string jniClassName, string signature, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + public static IntPtr CreateInstance (Type type, string signature, params JValue[] constructorParameters) + { + throw new NotImplementedException (); + } + + static unsafe JniNativeInterfaceInvoker CreateNativeInterface () + { + throw new NotImplementedException (); + } + + public static IntPtr FindClass (System.Type type) + { + throw new NotImplementedException (); + } + + static readonly int nameBufferLength = 1024; + [ThreadStatic] static char[] nameBuffer; + + static unsafe IntPtr BinaryName (string classname) + { + throw new NotImplementedException (); + } + + public static IntPtr FindClass (string classname) + { + throw new NotImplementedException (); + } + + public static IntPtr FindClass (string className, ref IntPtr cachedJniClassHandle) + { + throw new NotImplementedException (); + } + + public static void Throw (IntPtr obj) + { + throw new NotImplementedException (); + } + + public static void ThrowNew (IntPtr clazz, string message) + { + throw new NotImplementedException (); + } + + public static void PushLocalFrame (int capacity) + { + throw new NotImplementedException (); + } + + public static void EnsureLocalCapacity (int capacity) + { + throw new NotImplementedException (); + } + + internal static void DeleteRef (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + public static IntPtr NewGlobalRef (IntPtr jobject) + { + throw new NotImplementedException (); + } + + public static void DeleteGlobalRef (IntPtr jobject) + { + throw new NotImplementedException (); + } + + static IntPtr LogCreateLocalRef (IntPtr jobject) + { + throw new NotImplementedException (); + } + + public static IntPtr NewLocalRef (IntPtr jobject) + { + throw new NotImplementedException (); + } + + public static void DeleteLocalRef (IntPtr jobject) + { + throw new NotImplementedException (); + } + + public static void DeleteWeakGlobalRef (IntPtr jobject) + { + throw new NotImplementedException (); + } + + public static IntPtr NewObject (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static IntPtr NewObject (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static string GetClassNameFromInstance (IntPtr jobject) + { + throw new NotImplementedException (); + } + + public static string GetJniName (Type type) + { + throw new NotImplementedException (); + } + + public static IntPtr ToJniHandle (IJavaObject value) + { + throw new NotImplementedException (); + } + + public static IntPtr ToLocalJniHandle (IJavaObject value) + { + throw new NotImplementedException (); + } + + static JObjectRefType GetObjectRefType (IntPtr jobject) + { + throw new NotImplementedException (); + } + + static byte _GetObjectRefType (IntPtr jobject) + { + throw new NotImplementedException (); + } + + static IntPtr char_sequence_to_string_id; + + public static string GetCharSequence (IntPtr jobject, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + public static unsafe string GetString (IntPtr value, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr NewString (string text) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr NewString (char[] text, int length) + { + throw new NotImplementedException (); + } + + static void AssertCompatibleArrayTypes (Type sourceType, IntPtr destArray) + { + throw new NotImplementedException (); + } + + static void AssertCompatibleArrayTypes (IntPtr sourceArray, Type destType) + { + throw new NotImplementedException (); + } + + public static void CopyArray (IntPtr src, bool[] dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (IntPtr src, string[] dest) + { + throw new NotImplementedException (); + } + + static Dictionary> NativeArrayElementToManaged { + get; + set; + } + + static Dictionary> CreateNativeArrayElementToManaged () + { + throw new NotImplementedException (); + } + + static TValue GetConverter(Dictionary dict, Type elementType, IntPtr array) + { + throw new NotImplementedException (); + } + + public static void CopyArray (IntPtr src, Array dest, Type elementType = null) + { + throw new NotImplementedException (); + } + + static void AssertIsJavaObject (Type targetType) + { + throw new NotImplementedException (); + } + + public static void CopyArray (IntPtr src, T[] dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (bool[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (string[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (IJavaObject[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + static Dictionary> CopyManagedToNativeArray { + get; + set; + } + + static Dictionary> CreateCopyManagedToNativeArray () + { + throw new NotImplementedException (); + } + + public static void CopyArray (Array source, Type elementType, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (T[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static Array GetArray (IntPtr array_ptr, JniHandleOwnership transfer, Type element_type = null) + { + throw new NotImplementedException (); + } + + static Dictionary> NativeArrayToManaged { + get; + set; + } + + static Dictionary> CreateNativeArrayToManaged () + { + throw new NotImplementedException (); + } + + static Array _GetArray (IntPtr array_ptr, Type element_type) + { + throw new NotImplementedException (); + } + + public static object[] GetObjectArray (IntPtr array_ptr, Type[] element_types) + { + throw new NotImplementedException (); + } + + public static T[] GetArray (IntPtr array_ptr) + { + throw new NotImplementedException (); + } + + public static T[] GetArray (Java.Lang.Object[] array) + { + throw new NotImplementedException (); + } + + public static T GetArrayItem (IntPtr array_ptr, int index) + { + throw new NotImplementedException (); + } + + public static int GetArrayLength (IntPtr array_ptr) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (bool[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (string[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewObjectArray (int length, IntPtr elementClass) + { + throw new NotImplementedException (); + } + + public static IntPtr NewObjectArray (int length, IntPtr elementClass, IntPtr initialElement) + { + throw new NotImplementedException (); + } + + public static IntPtr NewObjectArray(params T[] values) + { + throw new NotImplementedException (); + } + + static IntPtr GetArrayElementClass(T[] values) + { + throw new NotImplementedException (); + } + + public static void CopyObjectArray(IntPtr source, T[] destination) + { + throw new NotImplementedException (); + } + + public static void CopyObjectArray(T[] source, IntPtr destination) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (IJavaObject[] array) + { + throw new NotImplementedException (); + } + + static Dictionary> CreateManagedToNativeArray { + get ; + set; + } + + static Dictionary> CreateCreateManagedToNativeArray () + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (Array value, Type elementType = null) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (T[] array) + { + throw new NotImplementedException (); + } + + static Dictionary> SetNativeArrayElement { + get; + set; + } + + static Dictionary> CreateSetNativeArrayElement () + { + throw new NotImplementedException (); + } + + public static void SetArrayItem (IntPtr array_ptr, int index, T value) + { + throw new NotImplementedException (); + } + + public static Java.Lang.Object[] ToObjectArray (T[] array) + { + throw new NotImplementedException (); + } + + delegate int GetEnvDelegate (IntPtr javavm, out IntPtr envptr, int version); + delegate int AttachCurrentThreadDelegate (IntPtr javavm, out IntPtr env, IntPtr args); + delegate int DetachCurrentThreadDelegate (IntPtr javavm); + + struct JNIInvokeInterface { + public IntPtr reserved0; + public IntPtr reserved1; + public IntPtr reserved2; + + public IntPtr DestroyJavaVM; // jint (*DestroyJavaVM)(JavaVM*); + public AttachCurrentThreadDelegate AttachCurrentThread; + public DetachCurrentThreadDelegate DetachCurrentThread; + public GetEnvDelegate GetEnv; + public IntPtr AttachCurrentThreadAsDaemon; //jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); + } + + internal struct JNINativeMethod { + + public string Name; + public string Sig; + public Delegate Func; + + public JNINativeMethod (string name, string sig, Delegate func) + { + throw new NotImplementedException (); + } + } + +#if ANDROID_8 + internal static int AndroidBitmap_getInfo (IntPtr jbitmap, out Android.Graphics.AndroidBitmapInfo info) + { + throw new NotImplementedException (); + } + + internal static int AndroidBitmap_lockPixels (IntPtr jbitmap, out IntPtr addrPtr) + { + throw new NotImplementedException (); + } + + internal static int AndroidBitmap_unlockPixels (IntPtr jbitmap) + { + throw new NotImplementedException (); + } +#endif // ANDROID_8 + } + + partial class JniNativeInterfaceInvoker { + } +} +#pragma warning restore + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JNIEnv.g.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JNIEnv.g.cs new file mode 100644 index 00000000000..e476e5733d9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JNIEnv.g.cs @@ -0,0 +1,2649 @@ +#if !JAVA_INTEROP1 + +// Generated file; DO NOT EDIT! +// +// To make changes, edit monodroid/tools/jnienv-gen and rerun +#pragma warning disable +using System; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Android.Runtime { + + public static partial class JNIEnv { + + internal delegate int IntPtr_int_Delegate (IntPtr env); + internal static int GetVersion () + { + throw new NotImplementedException (); + } + + internal delegate IntPtr IntPtr_string_IntPtr_IntPtr_int_IntPtr_Delegate (IntPtr env, string name, IntPtr loader, IntPtr buf, int bufLen); + + internal delegate IntPtr IntPtr_string_IntPtr_Delegate (IntPtr env, string classname); + internal static IntPtr _FindClass (string classname) + { + throw new NotImplementedException (); + } + + internal delegate IntPtr IntPtr_IntPtr_IntPtr_Delegate (IntPtr env, IntPtr method); + + + internal delegate IntPtr IntPtr_IntPtr_IntPtr_bool_IntPtr_Delegate (IntPtr env, IntPtr cls, IntPtr jmethod, bool isStatic); + + public static IntPtr GetSuperclass (IntPtr jclass) + { + throw new NotImplementedException (); + } + + internal delegate bool IntPtr_IntPtr_IntPtr_bool_Delegate (IntPtr env, IntPtr clazz1, IntPtr clazz2); + public static bool IsAssignableFrom (IntPtr clazz1, IntPtr clazz2) + { + throw new NotImplementedException (); + } + + + internal delegate int IntPtr_IntPtr_int_Delegate (IntPtr env, IntPtr obj); + + internal delegate int IntPtr_IntPtr_string_int_Delegate (IntPtr env, IntPtr clazz, string message); + + internal delegate IntPtr IntPtr_IntPtr_Delegate (IntPtr env); + public static IntPtr ExceptionOccurred () + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_void_Delegate (IntPtr env); + public static void ExceptionDescribe () + { + throw new NotImplementedException (); + } + + public static void ExceptionClear () + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_string_void_Delegate (IntPtr env, string msg); + + internal delegate int IntPtr_int_int_Delegate (IntPtr env, int capacity); + + public static IntPtr PopLocalFrame (IntPtr result) + { + throw new NotImplementedException (); + } + + + internal delegate void IntPtr_IntPtr_void_Delegate (IntPtr env, IntPtr jobject); + + + public static bool IsSameObject (IntPtr ref1, IntPtr ref2) + { + throw new NotImplementedException (); + } + + + + public static IntPtr AllocObject (IntPtr jclass) + { + throw new NotImplementedException (); + } + + internal delegate IntPtr IntPtr_IntPtr_IntPtr_IntPtr_Delegate (IntPtr env, IntPtr jclass, IntPtr jmethod); + + + internal delegate IntPtr IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate (IntPtr env, IntPtr jclass, IntPtr jmethod, JValue[] parms); + + public static IntPtr GetObjectClass (IntPtr jobject) + { + throw new NotImplementedException (); + } + + public static bool IsInstanceOf (IntPtr obj, IntPtr clazz) + { + throw new NotImplementedException (); + } + + internal delegate IntPtr IntPtr_IntPtr_string_string_IntPtr_Delegate (IntPtr env, IntPtr kls, string name, string signature); + public static IntPtr GetMethodID (IntPtr kls, string name, string signature) + { + throw new NotImplementedException (); + } + + public static IntPtr CallObjectMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr CallObjectMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static IntPtr CallObjectMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static bool CallBooleanMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe bool CallBooleanMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate bool IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static bool CallBooleanMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate sbyte IntPtr_IntPtr_IntPtr_sbyte_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static sbyte CallByteMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe sbyte CallByteMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate sbyte IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static sbyte CallByteMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate char IntPtr_IntPtr_IntPtr_char_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static char CallCharMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe char CallCharMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate char IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static char CallCharMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate short IntPtr_IntPtr_IntPtr_short_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static short CallShortMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe short CallShortMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate short IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static short CallShortMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate int IntPtr_IntPtr_IntPtr_int_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static int CallIntMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe int CallIntMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate int IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static int CallIntMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate long IntPtr_IntPtr_IntPtr_long_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static long CallLongMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe long CallLongMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate long IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static long CallLongMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate float IntPtr_IntPtr_IntPtr_float_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static float CallFloatMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe float CallFloatMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate float IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static float CallFloatMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate double IntPtr_IntPtr_IntPtr_double_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static double CallDoubleMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe double CallDoubleMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate double IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static double CallDoubleMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod); + public static void CallVoidMethod (IntPtr jobject, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe void CallVoidMethod (IntPtr jobject, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jmethod, JValue[] parms); + public static void CallVoidMethod (IntPtr jobject, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate IntPtr IntPtr_IntPtr_IntPtr_IntPtr_IntPtr_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static IntPtr CallNonvirtualObjectMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr CallNonvirtualObjectMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate IntPtr IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static IntPtr CallNonvirtualObjectMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate bool IntPtr_IntPtr_IntPtr_IntPtr_bool_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static bool CallNonvirtualBooleanMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe bool CallNonvirtualBooleanMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate bool IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static bool CallNonvirtualBooleanMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate sbyte IntPtr_IntPtr_IntPtr_IntPtr_sbyte_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static sbyte CallNonvirtualByteMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe sbyte CallNonvirtualByteMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate sbyte IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static sbyte CallNonvirtualByteMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate char IntPtr_IntPtr_IntPtr_IntPtr_char_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static char CallNonvirtualCharMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe char CallNonvirtualCharMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate char IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static char CallNonvirtualCharMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate short IntPtr_IntPtr_IntPtr_IntPtr_short_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static short CallNonvirtualShortMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe short CallNonvirtualShortMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate short IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static short CallNonvirtualShortMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate int IntPtr_IntPtr_IntPtr_IntPtr_int_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static int CallNonvirtualIntMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe int CallNonvirtualIntMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate int IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static int CallNonvirtualIntMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate long IntPtr_IntPtr_IntPtr_IntPtr_long_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static long CallNonvirtualLongMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe long CallNonvirtualLongMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate long IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static long CallNonvirtualLongMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate float IntPtr_IntPtr_IntPtr_IntPtr_float_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static float CallNonvirtualFloatMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe float CallNonvirtualFloatMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate float IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static float CallNonvirtualFloatMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate double IntPtr_IntPtr_IntPtr_IntPtr_double_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static double CallNonvirtualDoubleMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe double CallNonvirtualDoubleMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate double IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static double CallNonvirtualDoubleMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_IntPtr_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod); + public static void CallNonvirtualVoidMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe void CallNonvirtualVoidMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jclass, IntPtr jmethod, JValue[] parms); + public static void CallNonvirtualVoidMethod (IntPtr jobject, IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static IntPtr GetFieldID (IntPtr jclass, string name, string sig) + { + throw new NotImplementedException (); + } + + public static IntPtr GetObjectField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static bool GetBooleanField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static sbyte GetByteField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static char GetCharField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static short GetShortField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static int GetIntField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static long GetLongField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static float GetFloatField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static double GetDoubleField (IntPtr jobject, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static void SetField (IntPtr jobject, IntPtr jfieldID, IntPtr val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_bool_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, bool val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, bool val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_sbyte_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, sbyte val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, sbyte val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_char_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, char val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, char val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_short_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, short val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, short val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_int_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, int val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, int val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_long_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, long val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, long val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_float_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, float val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, float val) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_IntPtr_double_void_Delegate (IntPtr env, IntPtr jobject, IntPtr jfieldID, double val); + public static void SetField (IntPtr jobject, IntPtr jfieldID, double val) + { + throw new NotImplementedException (); + } + + public static IntPtr GetStaticMethodID (IntPtr jclass, string name, string sig) + { + throw new NotImplementedException (); + } + + public static IntPtr CallStaticObjectMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe IntPtr CallStaticObjectMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static IntPtr CallStaticObjectMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static bool CallStaticBooleanMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe bool CallStaticBooleanMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static bool CallStaticBooleanMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static sbyte CallStaticByteMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe sbyte CallStaticByteMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static sbyte CallStaticByteMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static char CallStaticCharMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe char CallStaticCharMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static char CallStaticCharMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static short CallStaticShortMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe short CallStaticShortMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static short CallStaticShortMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static int CallStaticIntMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe int CallStaticIntMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static int CallStaticIntMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static long CallStaticLongMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe long CallStaticLongMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static long CallStaticLongMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static float CallStaticFloatMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe float CallStaticFloatMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static float CallStaticFloatMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static double CallStaticDoubleMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe double CallStaticDoubleMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static double CallStaticDoubleMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static void CallStaticVoidMethod (IntPtr jclass, IntPtr jmethod) + { + throw new NotImplementedException (); + } + + public static unsafe void CallStaticVoidMethod (IntPtr jclass, IntPtr jmethod, JValue* parms) + { + throw new NotImplementedException (); + } + + public static void CallStaticVoidMethod (IntPtr jclass, IntPtr jmethod, params JValue[] parms) + { + throw new NotImplementedException (); + } + + public static IntPtr GetStaticFieldID (IntPtr jclass, string name, string sig) + { + throw new NotImplementedException (); + } + + public static IntPtr GetStaticObjectField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static bool GetStaticBooleanField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static sbyte GetStaticByteField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static char GetStaticCharField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static short GetStaticShortField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static int GetStaticIntField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static long GetStaticLongField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static float GetStaticFloatField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static double GetStaticDoubleField (IntPtr jclass, IntPtr jfieldID) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, IntPtr val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, bool val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, sbyte val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, char val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, short val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, int val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, long val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, float val) + { + throw new NotImplementedException (); + } + + public static void SetStaticField (IntPtr jclass, IntPtr jfieldID, double val) + { + throw new NotImplementedException (); + } + + [UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl, CharSet=CharSet.Unicode)] + internal delegate IntPtr IntPtr_IntPtr_int_IntPtr_Delegate (IntPtr env, IntPtr unicodeChars, int len); + + internal static int GetStringLength (IntPtr @string) + { + throw new NotImplementedException (); + } + + internal static IntPtr GetStringChars (IntPtr @string, IntPtr isCopy) + { + throw new NotImplementedException (); + } + + internal static void ReleaseStringChars (IntPtr @string, IntPtr chars) + { + throw new NotImplementedException (); + } + + + + internal delegate string IntPtr_IntPtr_IntPtr_string_Delegate (IntPtr env, IntPtr @string, IntPtr isCopy); + + internal delegate void IntPtr_IntPtr_string_void_Delegate (IntPtr env, IntPtr @string, string utf); + + + internal delegate IntPtr IntPtr_int_IntPtr_IntPtr_IntPtr_Delegate (IntPtr env, int length, IntPtr elementClass, IntPtr initialElement); + + public static IntPtr GetObjectArrayElement (IntPtr array, int index) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_IntPtr_void_Delegate (IntPtr env, IntPtr array, int index, IntPtr value); + public static void SetObjectArrayElement (IntPtr array, int index, IntPtr value) + { + throw new NotImplementedException (); + + } + + internal delegate IntPtr IntPtr_int_IntPtr_Delegate (IntPtr env, int length); + + public static IntPtr NewArray (byte[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (char[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (short[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (int[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (long[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (float[] array) + { + throw new NotImplementedException (); + } + + public static IntPtr NewArray (double[] array) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_int_byteArray_void_Delegate (IntPtr env, IntPtr array, int start, int len, byte[] buf); + internal static void GetBooleanArrayRegion (IntPtr array, int start, int len, byte[] buf) + { + throw new NotImplementedException (); + } + + public static void CopyArray (IntPtr src, byte[] dest) + { + throw new NotImplementedException (); + } + + [UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl, CharSet=CharSet.Unicode)] + internal delegate void IntPtr_IntPtr_int_int_charArray_void_Delegate (IntPtr env, IntPtr array, int start, int len, char[] buf); + public static void CopyArray (IntPtr src, char[] dest) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_int_shortArray_void_Delegate (IntPtr env, IntPtr array, int start, int len, short[] buf); + public static void CopyArray (IntPtr src, short[] dest) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_int_intArray_void_Delegate (IntPtr env, IntPtr array, int start, int len, int[] buf); + public static void CopyArray (IntPtr src, int[] dest) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_int_longArray_void_Delegate (IntPtr env, IntPtr array, int start, int len, long[] buf); + public static void CopyArray (IntPtr src, long[] dest) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_int_floatArray_void_Delegate (IntPtr env, IntPtr array, int start, int len, float[] buf); + public static void CopyArray (IntPtr src, float[] dest) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_int_doubleArray_void_Delegate (IntPtr env, IntPtr array, int start, int len, double[] buf); + public static void CopyArray (IntPtr src, double[] dest) + { + throw new NotImplementedException (); + } + + internal static void SetBooleanArrayRegion (IntPtr array, int start, int len, byte[] buf) + { + throw new NotImplementedException (); + } + + public static void CopyArray (byte[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (char[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (short[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (int[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (long[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (float[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + public static void CopyArray (double[] src, IntPtr dest) + { + throw new NotImplementedException (); + } + + internal delegate int IntPtr_IntPtr_JNINativeMethodArray_int_int_Delegate (IntPtr env, IntPtr jclass, JNINativeMethod [] methods, int nMethods); + internal static int RegisterNatives (IntPtr jclass, JNINativeMethod [] methods, int nMethods) + { + throw new NotImplementedException (); + } + + + + + internal delegate int IntPtr_outIntPtr_int_Delegate (IntPtr env, out IntPtr vm); + internal static int GetJavaVM (out IntPtr vm) + { + throw new NotImplementedException (); + } + + internal delegate void IntPtr_IntPtr_int_int_IntPtr_void_Delegate (IntPtr env, IntPtr str, int start, int len, IntPtr buf); + + internal delegate bool IntPtr_bool_Delegate (IntPtr env); + + internal delegate IntPtr IntPtr_IntPtr_long_IntPtr_Delegate (IntPtr env, IntPtr address, long capacity); + public static IntPtr NewDirectByteBuffer (IntPtr address, long capacity) + { + throw new NotImplementedException (); + } + + public static IntPtr GetDirectBufferAddress (IntPtr buf) + { + throw new NotImplementedException (); + } + + internal delegate long IntPtr_IntPtr_long_Delegate (IntPtr env, IntPtr buf); + public static long GetDirectBufferCapacity (IntPtr buf) + { + throw new NotImplementedException (); + } + + } + + [StructLayout (LayoutKind.Sequential)] + partial struct JniNativeInterfaceStruct { + + private IntPtr reserved0; // void* + private IntPtr reserved1; // void* + private IntPtr reserved2; // void* + private IntPtr reserved3; // void* + public IntPtr GetVersion; // jint (*GetVersion)(JNIEnv*); + public IntPtr DefineClass; // jclass (*DefineClass)(JNIEnv*, const char, jobject, const jbyte*, jsize); + public IntPtr _FindClass; // jclass (*FindClass)(JNIEnv*, const char*); + public IntPtr FromReflectedMethod; // jmethodID (*FromReflectedMethod)(JNIEnv*, jobject); + public IntPtr FromReflectedField; // jfieldID (*FromReflectedField)(JNIEnv*, jobject); + public IntPtr ToReflectedMethod; // jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean); + public IntPtr GetSuperclass; // jclass (*GetSuperclass)(JNIEnv*, jclass); + public IntPtr IsAssignableFrom; // jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass); + public IntPtr ToReflectedField; // jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean); + public IntPtr Throw; // jint (*Throw)(JNIEnv*, jthrowable); + public IntPtr ThrowNew; // jint (*ThrowNew)(JNIEnv*, jclass, const char*); + public IntPtr ExceptionOccurred; // jthrowable (*ExceptionOccurred)(JNIEnv*); + public IntPtr ExceptionDescribe; // void (*ExceptionDescribe)(JNIEnv*); + public IntPtr ExceptionClear; // void (*ExceptionClear)(JNIEnv*); + public IntPtr FatalError; // void (*FatalError)(JNIEnv*, const char*); + public IntPtr _PushLocalFrame; // jint (*PushLocalFrame)(JNIEnv*, jint); + public IntPtr PopLocalFrame; // jobject (*PopLocalFrame)(JNIEnv*, jobject); + public IntPtr NewGlobalRef; // jobject (*NewGlobalRef)(JNIEnv*, jobject); + public IntPtr DeleteGlobalRef; // void (*DeleteGlobalRef)(JNIEnv*, jobject); + public IntPtr DeleteLocalRef; // void (*DeleteLocalRef)(JNIEnv*, jobject); + public IntPtr IsSameObject; // jboolean (*IsSameObject)(JNIEnv*, jobject, jobject); + public IntPtr NewLocalRef; // jobject (*NewLocalRef)(JNIEnv*, jobject); + public IntPtr _EnsureLocalCapacity; // jint (*EnsureLocalCapacity)(JNIEnv*, jint); + public IntPtr AllocObject; // jobject (*AllocObject)(JNIEnv*, jclass); + public IntPtr NewObject; // jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr NewObjectV; // jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr NewObjectA; // jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr GetObjectClass; // jclass (*GetObjectClass)(JNIEnv*, jobject); + public IntPtr IsInstanceOf; // jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass); + public IntPtr GetMethodID; // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); + public IntPtr CallObjectMethod; // jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallObjectMethodV; // jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallObjectMethodA; // jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallBooleanMethod; // jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallBooleanMethodV; // jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallBooleanMethodA; // jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallByteMethod; // jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallByteMethodV; // jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallByteMethodA; // jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallCharMethod; // jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallCharMethodV; // jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallCharMethodA; // jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallShortMethod; // jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallShortMethodV; // jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallShortMethodA; // jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallIntMethod; // jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallIntMethodV; // jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallIntMethodA; // jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallLongMethod; // jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallLongMethodV; // jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallLongMethodA; // jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallFloatMethod; // jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallFloatMethodV; // jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallFloatMethodA; // jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallDoubleMethod; // jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallDoubleMethodV; // jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallDoubleMethodA; // jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallVoidMethod; // void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); + public IntPtr CallVoidMethodV; // void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); + public IntPtr CallVoidMethodA; // void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); + public IntPtr CallNonvirtualObjectMethod; // jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualObjectMethodV; // jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualObjectMethodA; // jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualBooleanMethod; // jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualBooleanMethodV; // jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualBooleanMethodA; // jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualByteMethod; // jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualByteMethodV; // jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualByteMethodA; // jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualCharMethod; // jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualCharMethodV; // jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualCharMethodA; // jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualShortMethod; // jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualShortMethodV; // jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualShortMethodA; // jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualIntMethod; // jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualIntMethodV; // jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualIntMethodA; // jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualLongMethod; // jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualLongMethodV; // jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualLongMethodA; // jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualFloatMethod; // jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualFloatMethodV; // jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualFloatMethodA; // jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualDoubleMethod; // jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualDoubleMethodV; // jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualDoubleMethodA; // jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr CallNonvirtualVoidMethod; // void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); + public IntPtr CallNonvirtualVoidMethodV; // void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); + public IntPtr CallNonvirtualVoidMethodA; // void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); + public IntPtr GetFieldID; // jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*); + public IntPtr GetObjectField; // jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetBooleanField; // jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetByteField; // jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetCharField; // jchar (*GetCharField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetShortField; // jshort (*GetShortField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetIntField; // jint (*GetIntField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetLongField; // jlong (*GetLongField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetFloatField; // jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID); + public IntPtr GetDoubleField; // jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID); + public IntPtr SetObjectField; // void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject); + public IntPtr SetBooleanField; // void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean); + public IntPtr SetByteField; // void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte); + public IntPtr SetCharField; // void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar); + public IntPtr SetShortField; // void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort); + public IntPtr SetIntField; // void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint); + public IntPtr SetLongField; // void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong); + public IntPtr SetFloatField; // void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat); + public IntPtr SetDoubleField; // void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble); + public IntPtr GetStaticMethodID; // jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*); + public IntPtr CallStaticObjectMethod; // jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticObjectMethodV; // jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticObjectMethodA; // jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticBooleanMethod; // jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticBooleanMethodV; // jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticBooleanMethodA; // jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticByteMethod; // jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticByteMethodV; // jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticByteMethodA; // jbyte (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticCharMethod; // jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticCharMethodV; // jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticCharMethodA; // jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticShortMethod; // jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticShortMethodV; // jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticShortMethodA; // jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticIntMethod; // jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticIntMethodV; // jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticIntMethodA; // jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticLongMethod; // jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticLongMethodV; // jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticLongMethodA; // jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticFloatMethod; // jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticFloatMethodV; // jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticFloatMethodA; // jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticDoubleMethod; // jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticDoubleMethodV; // jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticDoubleMethodA; // jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr CallStaticVoidMethod; // void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...); + public IntPtr CallStaticVoidMethodV; // void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list); + public IntPtr CallStaticVoidMethodA; // void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); + public IntPtr GetStaticFieldID; // jfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*, const char*); + public IntPtr GetStaticObjectField; // jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticBooleanField; // jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticByteField; // jbyte (*GetStaticByteField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticCharField; // jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticShortField; // jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticIntField; // jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticLongField; // jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticFloatField; // jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID); + public IntPtr GetStaticDoubleField; // jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID); + public IntPtr SetStaticObjectField; // void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject); + public IntPtr SetStaticBooleanField; // void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean); + public IntPtr SetStaticByteField; // void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte); + public IntPtr SetStaticCharField; // void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar); + public IntPtr SetStaticShortField; // void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort); + public IntPtr SetStaticIntField; // void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint); + public IntPtr SetStaticLongField; // void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong); + public IntPtr SetStaticFloatField; // void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat); + public IntPtr SetStaticDoubleField; // void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble); + public IntPtr NewString; // jstring (*NewString)(JNIEnv*, const jchar*, jsize); + public IntPtr GetStringLength; // jsize (*GetStringLength)(JNIEnv*, jstring); + public IntPtr GetStringChars; // const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*); + public IntPtr ReleaseStringChars; // void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*); + public IntPtr NewStringUTF; // jstring (*NewStringUTF)(JNIEnv*, const char*); + public IntPtr GetStringUTFLength; // jsize (*GetStringUTFLength)(JNIEnv*, jstring); + public IntPtr GetStringUTFChars; // const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*); + public IntPtr ReleaseStringUTFChars; // void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*); + public IntPtr GetArrayLength; // jsize (*GetArrayLength)(JNIEnv*, jarray); + public IntPtr NewObjectArray; // jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject); + public IntPtr GetObjectArrayElement; // jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize); + public IntPtr SetObjectArrayElement; // void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject); + public IntPtr NewBooleanArray; // jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize); + public IntPtr NewByteArray; // jbyteArray (*NewByteArray)(JNIEnv*, jsize); + public IntPtr NewCharArray; // jcharArray (*NewCharArray)(JNIEnv*, jsize); + public IntPtr NewShortArray; // jshortArray (*NewShortArray)(JNIEnv*, jsize); + public IntPtr NewIntArray; // jintArray (*NewIntArray)(JNIEnv*, jsize); + public IntPtr NewLongArray; // jlongArray (*NewLongArray)(JNIEnv*, jsize); + public IntPtr NewFloatArray; // jfloatArray (*NewFloatArray)(JNIEnv*, jsize); + public IntPtr NewDoubleArray; // jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize); + public IntPtr GetBooleanArrayElements; // jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*); + public IntPtr GetByteArrayElements; // jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*); + public IntPtr GetCharArrayElements; // jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*); + public IntPtr GetShortArrayElements; // jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*); + public IntPtr GetIntArrayElements; // jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*); + public IntPtr GetLongArrayElements; // jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*); + public IntPtr GetFloatArrayElements; // jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*); + public IntPtr GetDoubleArrayElements; // jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*); + public IntPtr ReleaseBooleanArrayElements; // void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*, jint); + public IntPtr ReleaseByteArrayElements; // void (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray, jbyte*, jint); + public IntPtr ReleaseCharArrayElements; // void (*ReleaseCharArrayElements)(JNIEnv*, jcharArray, jchar*, jint); + public IntPtr ReleaseShortArrayElements; // void (*ReleaseShortArrayElements)(JNIEnv*, jshortArray, jshort*, jint); + public IntPtr ReleaseIntArrayElements; // void (*ReleaseIntArrayElements)(JNIEnv*, jintArray, jint*, jint); + public IntPtr ReleaseLongArrayElements; // void (*ReleaseLongArrayElements)(JNIEnv*, jlongArray, jlong*, jint); + public IntPtr ReleaseFloatArrayElements; // void (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray, jfloat*, jint); + public IntPtr ReleaseDoubleArrayElements; // void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray, jdouble*, jint); + public IntPtr GetBooleanArrayRegion; // void (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray, jsize, jsize, jboolean*); + public IntPtr GetByteArrayRegion; // void (*GetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, jbyte*); + public IntPtr GetCharArrayRegion; // void (*GetCharArrayRegion)(JNIEnv*, jcharArray, jsize, jsize, jchar*); + public IntPtr GetShortArrayRegion; // void (*GetShortArrayRegion)(JNIEnv*, jshortArray, jsize, jsize, jshort*); + public IntPtr GetIntArrayRegion; // void (*GetIntArrayRegion)(JNIEnv*, jintArray, jsize, jsize, jint*); + public IntPtr GetLongArrayRegion; // void (*GetLongArrayRegion)(JNIEnv*, jlongArray, jsize, jsize, jlong*); + public IntPtr GetFloatArrayRegion; // void (*GetFloatArrayRegion)(JNIEnv*, jfloatArray, jsize, jsize, jfloat*); + public IntPtr GetDoubleArrayRegion; // void (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray, jsize, jsize, jdouble*); + public IntPtr SetBooleanArrayRegion; // void (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray, jsize, jsize, const jboolean*); + public IntPtr SetByteArrayRegion; // void (*SetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*); + public IntPtr SetCharArrayRegion; // void (*SetCharArrayRegion)(JNIEnv*, jcharArray, jsize, jsize, const jchar*); + public IntPtr SetShortArrayRegion; // void (*SetShortArrayRegion)(JNIEnv*, jshortArray, jsize, jsize, const jshort*); + public IntPtr SetIntArrayRegion; // void (*SetIntArrayRegion)(JNIEnv*, jintArray, jsize, jsize, const jint*); + public IntPtr SetLongArrayRegion; // void (*SetLongArrayRegion)(JNIEnv*, jlongArray, jsize, jsize, const jlong*); + public IntPtr SetFloatArrayRegion; // void (*SetFloatArrayRegion)(JNIEnv*, jfloatArray, jsize, jsize, const jfloat*); + public IntPtr SetDoubleArrayRegion; // void (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray, jsize, jsize, const jdouble*); + public IntPtr RegisterNatives; // jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*, jint); + public IntPtr UnregisterNatives; // jint (*UnregisterNatives)(JNIEnv*, jclass); + public IntPtr MonitorEnter; // jint (*MonitorEnter)(JNIEnv*, jobject); + public IntPtr MonitorExit; // jint (*MonitorExit)(JNIEnv*, jobject); + public IntPtr GetJavaVM; // jint (*GetJavaVM)(JNIEnv*, JavaVM**); + public IntPtr GetStringRegion; // void (*GetStringRegion)(JNIEnv*, jstring, jsize, jsize, jchar*); + public IntPtr GetStringUTFRegion; // void (*GetStringUTFRegion)(JNIEnv*, jstring, jsize, jsize, char*); + public IntPtr GetPrimitiveArrayCritical; // void* (*GetPrimitiveArrayCritical)(JNIEnv*, jarray, jboolean*); + public IntPtr ReleasePrimitiveArrayCritical; // void (*ReleasePrimitiveArrayCritical)(JNIEnv*, jarray, void*, jint); + public IntPtr GetStringCritical; // const jchar* (*GetStringCritical)(JNIEnv*, jstring, jboolean*); + public IntPtr ReleaseStringCritical; // void (*ReleaseStringCritical)(JNIEnv*, jstring, const jchar*); + public IntPtr NewWeakGlobalRef; // jweak (*NewWeakGlobalRef)(JNIEnv*, jobject); + public IntPtr DeleteWeakGlobalRef; // void (*DeleteWeakGlobalRef)(JNIEnv*, jweak); + public IntPtr ExceptionCheck; // jboolean (*ExceptionCheck)(JNIEnv*); + public IntPtr NewDirectByteBuffer; // jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong); + public IntPtr GetDirectBufferAddress; // void* (*GetDirectBufferAddress)(JNIEnv*, jobject); + public IntPtr GetDirectBufferCapacity; // jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject); + public IntPtr GetObjectRefType; // jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject); + } + + partial class JniNativeInterfaceInvoker { + + JniNativeInterfaceStruct JniEnv; + + public unsafe JniNativeInterfaceInvoker (JniNativeInterfaceStruct* p) + { + JniEnv = *p; + } + + + JNIEnv.IntPtr_int_Delegate _GetVersion; + public JNIEnv.IntPtr_int_Delegate GetVersion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_string_IntPtr_IntPtr_int_IntPtr_Delegate _DefineClass; + public JNIEnv.IntPtr_string_IntPtr_IntPtr_int_IntPtr_Delegate DefineClass { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_string_IntPtr_Delegate __FindClass; + public JNIEnv.IntPtr_string_IntPtr_Delegate _FindClass { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _FromReflectedMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate FromReflectedMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _FromReflectedField; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate FromReflectedField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_IntPtr_Delegate _ToReflectedMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_IntPtr_Delegate ToReflectedMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _GetSuperclass; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate GetSuperclass { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate _IsAssignableFrom; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate IsAssignableFrom { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_IntPtr_Delegate _ToReflectedField; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_IntPtr_Delegate ToReflectedField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _Throw; + public JNIEnv.IntPtr_IntPtr_int_Delegate Throw { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_string_int_Delegate _ThrowNew; + public JNIEnv.IntPtr_IntPtr_string_int_Delegate ThrowNew { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_Delegate _ExceptionOccurred; + public JNIEnv.IntPtr_IntPtr_Delegate ExceptionOccurred { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_void_Delegate _ExceptionDescribe; + public JNIEnv.IntPtr_void_Delegate ExceptionDescribe { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_void_Delegate _ExceptionClear; + public JNIEnv.IntPtr_void_Delegate ExceptionClear { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_string_void_Delegate _FatalError; + public JNIEnv.IntPtr_string_void_Delegate FatalError { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_int_Delegate __PushLocalFrame; + public JNIEnv.IntPtr_int_int_Delegate _PushLocalFrame { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _PopLocalFrame; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate PopLocalFrame { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _NewGlobalRef; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate NewGlobalRef { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_void_Delegate _DeleteGlobalRef; + public JNIEnv.IntPtr_IntPtr_void_Delegate DeleteGlobalRef { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_void_Delegate _DeleteLocalRef; + public JNIEnv.IntPtr_IntPtr_void_Delegate DeleteLocalRef { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate _IsSameObject; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate IsSameObject { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _NewLocalRef; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate NewLocalRef { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_int_Delegate __EnsureLocalCapacity; + public JNIEnv.IntPtr_int_int_Delegate _EnsureLocalCapacity { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _AllocObject; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate AllocObject { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _NewObject; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate NewObject { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate _NewObjectA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate NewObjectA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _GetObjectClass; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate GetObjectClass { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate _IsInstanceOf; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate IsInstanceOf { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate _GetMethodID; + public JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate GetMethodID { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _CallObjectMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate CallObjectMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate _CallObjectMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate CallObjectMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate _CallBooleanMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate CallBooleanMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate _CallBooleanMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate CallBooleanMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate _CallByteMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate CallByteMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate _CallByteMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate CallByteMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate _CallCharMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate CallCharMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate _CallCharMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate CallCharMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate _CallShortMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate CallShortMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate _CallShortMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate CallShortMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate _CallIntMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate CallIntMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate _CallIntMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate CallIntMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate _CallLongMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate CallLongMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate _CallLongMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate CallLongMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate _CallFloatMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate CallFloatMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate _CallFloatMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate CallFloatMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate _CallDoubleMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate CallDoubleMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate _CallDoubleMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate CallDoubleMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_void_Delegate _CallVoidMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_void_Delegate CallVoidMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate _CallVoidMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate CallVoidMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_IntPtr_Delegate _CallNonvirtualObjectMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_IntPtr_Delegate CallNonvirtualObjectMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate _CallNonvirtualObjectMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate CallNonvirtualObjectMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_bool_Delegate _CallNonvirtualBooleanMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_bool_Delegate CallNonvirtualBooleanMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate _CallNonvirtualBooleanMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate CallNonvirtualBooleanMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_sbyte_Delegate _CallNonvirtualByteMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_sbyte_Delegate CallNonvirtualByteMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate _CallNonvirtualByteMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate CallNonvirtualByteMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_char_Delegate _CallNonvirtualCharMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_char_Delegate CallNonvirtualCharMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate _CallNonvirtualCharMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate CallNonvirtualCharMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_short_Delegate _CallNonvirtualShortMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_short_Delegate CallNonvirtualShortMethod { + get { + if (_CallNonvirtualShortMethod == null) + _CallNonvirtualShortMethod = (JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_short_Delegate) Marshal.GetDelegateForFunctionPointer (JniEnv.CallNonvirtualShortMethod, typeof (JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_short_Delegate)); + return _CallNonvirtualShortMethod; + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate _CallNonvirtualShortMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate CallNonvirtualShortMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_int_Delegate _CallNonvirtualIntMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_int_Delegate CallNonvirtualIntMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate _CallNonvirtualIntMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate CallNonvirtualIntMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_long_Delegate _CallNonvirtualLongMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_long_Delegate CallNonvirtualLongMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate _CallNonvirtualLongMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate CallNonvirtualLongMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_float_Delegate _CallNonvirtualFloatMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_float_Delegate CallNonvirtualFloatMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate _CallNonvirtualFloatMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate CallNonvirtualFloatMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_double_Delegate _CallNonvirtualDoubleMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_double_Delegate CallNonvirtualDoubleMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate _CallNonvirtualDoubleMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate CallNonvirtualDoubleMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_void_Delegate _CallNonvirtualVoidMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_void_Delegate CallNonvirtualVoidMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate _CallNonvirtualVoidMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate CallNonvirtualVoidMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate _GetFieldID; + public JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate GetFieldID { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetObjectField; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetObjectField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate _GetBooleanField; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate GetBooleanField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate _GetByteField; + public JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate GetByteField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate _GetCharField; + public JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate GetCharField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate _GetShortField; + public JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate GetShortField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate _GetIntField; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate GetIntField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate _GetLongField; + public JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate GetLongField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate _GetFloatField; + public JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate GetFloatField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate _GetDoubleField; + public JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate GetDoubleField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_void_Delegate _SetObjectField; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_void_Delegate SetObjectField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_void_Delegate _SetBooleanField; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_void_Delegate SetBooleanField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_void_Delegate _SetByteField; + public JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_void_Delegate SetByteField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_char_void_Delegate _SetCharField; + public JNIEnv.IntPtr_IntPtr_IntPtr_char_void_Delegate SetCharField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_short_void_Delegate _SetShortField; + public JNIEnv.IntPtr_IntPtr_IntPtr_short_void_Delegate SetShortField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _SetIntField; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate SetIntField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_long_void_Delegate _SetLongField; + public JNIEnv.IntPtr_IntPtr_IntPtr_long_void_Delegate SetLongField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_float_void_Delegate _SetFloatField; + public JNIEnv.IntPtr_IntPtr_IntPtr_float_void_Delegate SetFloatField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_double_void_Delegate _SetDoubleField; + public JNIEnv.IntPtr_IntPtr_IntPtr_double_void_Delegate SetDoubleField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate _GetStaticMethodID; + public JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate GetStaticMethodID { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _CallStaticObjectMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate CallStaticObjectMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate _CallStaticObjectMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_IntPtr_Delegate CallStaticObjectMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate _CallStaticBooleanMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate CallStaticBooleanMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate _CallStaticBooleanMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_bool_Delegate CallStaticBooleanMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate _CallStaticByteMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate CallStaticByteMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate _CallStaticByteMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_sbyte_Delegate CallStaticByteMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate _CallStaticCharMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate CallStaticCharMethod { + get { + if (_CallStaticCharMethod == null) + _CallStaticCharMethod = (JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate) Marshal.GetDelegateForFunctionPointer (JniEnv.CallStaticCharMethod, typeof (JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate)); + return _CallStaticCharMethod; + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate _CallStaticCharMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_char_Delegate CallStaticCharMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate _CallStaticShortMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate CallStaticShortMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate _CallStaticShortMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_short_Delegate CallStaticShortMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate _CallStaticIntMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate CallStaticIntMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate _CallStaticIntMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_int_Delegate CallStaticIntMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate _CallStaticLongMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate CallStaticLongMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate _CallStaticLongMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_long_Delegate CallStaticLongMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate _CallStaticFloatMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate CallStaticFloatMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate _CallStaticFloatMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_float_Delegate CallStaticFloatMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate _CallStaticDoubleMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate CallStaticDoubleMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate _CallStaticDoubleMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_double_Delegate CallStaticDoubleMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_void_Delegate _CallStaticVoidMethod; + public JNIEnv.IntPtr_IntPtr_IntPtr_void_Delegate CallStaticVoidMethod { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate _CallStaticVoidMethodA; + public JNIEnv.IntPtr_IntPtr_IntPtr_JValueArray_void_Delegate CallStaticVoidMethodA { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate _GetStaticFieldID; + public JNIEnv.IntPtr_IntPtr_string_string_IntPtr_Delegate GetStaticFieldID { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetStaticObjectField; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetStaticObjectField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate _GetStaticBooleanField; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_Delegate GetStaticBooleanField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate _GetStaticByteField; + public JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_Delegate GetStaticByteField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate _GetStaticCharField; + public JNIEnv.IntPtr_IntPtr_IntPtr_char_Delegate GetStaticCharField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate _GetStaticShortField; + public JNIEnv.IntPtr_IntPtr_IntPtr_short_Delegate GetStaticShortField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate _GetStaticIntField; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_Delegate GetStaticIntField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate _GetStaticLongField; + public JNIEnv.IntPtr_IntPtr_IntPtr_long_Delegate GetStaticLongField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate _GetStaticFloatField; + public JNIEnv.IntPtr_IntPtr_IntPtr_float_Delegate GetStaticFloatField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate _GetStaticDoubleField; + public JNIEnv.IntPtr_IntPtr_IntPtr_double_Delegate GetStaticDoubleField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_void_Delegate _SetStaticObjectField; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_void_Delegate SetStaticObjectField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_bool_void_Delegate _SetStaticBooleanField; + public JNIEnv.IntPtr_IntPtr_IntPtr_bool_void_Delegate SetStaticBooleanField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_void_Delegate _SetStaticByteField; + public JNIEnv.IntPtr_IntPtr_IntPtr_sbyte_void_Delegate SetStaticByteField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_char_void_Delegate _SetStaticCharField; + public JNIEnv.IntPtr_IntPtr_IntPtr_char_void_Delegate SetStaticCharField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_short_void_Delegate _SetStaticShortField; + public JNIEnv.IntPtr_IntPtr_IntPtr_short_void_Delegate SetStaticShortField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _SetStaticIntField; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate SetStaticIntField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_long_void_Delegate _SetStaticLongField; + public JNIEnv.IntPtr_IntPtr_IntPtr_long_void_Delegate SetStaticLongField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_float_void_Delegate _SetStaticFloatField; + public JNIEnv.IntPtr_IntPtr_IntPtr_float_void_Delegate SetStaticFloatField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_double_void_Delegate _SetStaticDoubleField; + public JNIEnv.IntPtr_IntPtr_IntPtr_double_void_Delegate SetStaticDoubleField { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_IntPtr_Delegate _NewString; + public JNIEnv.IntPtr_IntPtr_int_IntPtr_Delegate NewString { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _GetStringLength; + public JNIEnv.IntPtr_IntPtr_int_Delegate GetStringLength { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetStringChars; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetStringChars { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_void_Delegate _ReleaseStringChars; + public JNIEnv.IntPtr_IntPtr_IntPtr_void_Delegate ReleaseStringChars { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_string_IntPtr_Delegate _NewStringUTF; + public JNIEnv.IntPtr_string_IntPtr_Delegate NewStringUTF { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _GetStringUTFLength; + public JNIEnv.IntPtr_IntPtr_int_Delegate GetStringUTFLength { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_string_Delegate _GetStringUTFChars; + public JNIEnv.IntPtr_IntPtr_IntPtr_string_Delegate GetStringUTFChars { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_string_void_Delegate _ReleaseStringUTFChars; + public JNIEnv.IntPtr_IntPtr_string_void_Delegate ReleaseStringUTFChars { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _GetArrayLength; + public JNIEnv.IntPtr_IntPtr_int_Delegate GetArrayLength { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_IntPtr_IntPtr_Delegate _NewObjectArray; + public JNIEnv.IntPtr_int_IntPtr_IntPtr_IntPtr_Delegate NewObjectArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_IntPtr_Delegate _GetObjectArrayElement; + public JNIEnv.IntPtr_IntPtr_int_IntPtr_Delegate GetObjectArrayElement { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_IntPtr_void_Delegate _SetObjectArrayElement; + public JNIEnv.IntPtr_IntPtr_int_IntPtr_void_Delegate SetObjectArrayElement { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewBooleanArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewBooleanArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewByteArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewByteArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewCharArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewCharArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewShortArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewShortArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewIntArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewIntArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewLongArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewLongArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewFloatArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewFloatArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_int_IntPtr_Delegate _NewDoubleArray; + public JNIEnv.IntPtr_int_IntPtr_Delegate NewDoubleArray { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetBooleanArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetBooleanArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetByteArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetByteArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetCharArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetCharArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetShortArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetShortArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetIntArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetIntArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetLongArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetLongArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetFloatArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetFloatArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetDoubleArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetDoubleArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseBooleanArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseBooleanArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseByteArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseByteArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseCharArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseCharArrayElements { + get { + if (_ReleaseCharArrayElements == null) + _ReleaseCharArrayElements = (JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate) Marshal.GetDelegateForFunctionPointer (JniEnv.ReleaseCharArrayElements, typeof (JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate)); + return _ReleaseCharArrayElements; + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseShortArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseShortArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseIntArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseIntArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseLongArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseLongArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseFloatArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseFloatArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleaseDoubleArrayElements; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleaseDoubleArrayElements { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate _GetBooleanArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate GetBooleanArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate _GetByteArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate GetByteArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_charArray_void_Delegate _GetCharArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_charArray_void_Delegate GetCharArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_shortArray_void_Delegate _GetShortArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_shortArray_void_Delegate GetShortArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_intArray_void_Delegate _GetIntArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_intArray_void_Delegate GetIntArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_longArray_void_Delegate _GetLongArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_longArray_void_Delegate GetLongArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_floatArray_void_Delegate _GetFloatArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_floatArray_void_Delegate GetFloatArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_doubleArray_void_Delegate _GetDoubleArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_doubleArray_void_Delegate GetDoubleArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate _SetBooleanArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate SetBooleanArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate _SetByteArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_byteArray_void_Delegate SetByteArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_charArray_void_Delegate _SetCharArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_charArray_void_Delegate SetCharArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_shortArray_void_Delegate _SetShortArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_shortArray_void_Delegate SetShortArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_intArray_void_Delegate _SetIntArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_intArray_void_Delegate SetIntArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_longArray_void_Delegate _SetLongArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_longArray_void_Delegate SetLongArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_floatArray_void_Delegate _SetFloatArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_floatArray_void_Delegate SetFloatArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_doubleArray_void_Delegate _SetDoubleArrayRegion; + public JNIEnv.IntPtr_IntPtr_int_int_doubleArray_void_Delegate SetDoubleArrayRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_JNINativeMethodArray_int_int_Delegate _RegisterNatives; + public JNIEnv.IntPtr_IntPtr_JNINativeMethodArray_int_int_Delegate RegisterNatives { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _UnregisterNatives; + public JNIEnv.IntPtr_IntPtr_int_Delegate UnregisterNatives { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _MonitorEnter; + public JNIEnv.IntPtr_IntPtr_int_Delegate MonitorEnter { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _MonitorExit; + public JNIEnv.IntPtr_IntPtr_int_Delegate MonitorExit { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_outIntPtr_int_Delegate _GetJavaVM; + public JNIEnv.IntPtr_outIntPtr_int_Delegate GetJavaVM { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_IntPtr_void_Delegate _GetStringRegion; + public JNIEnv.IntPtr_IntPtr_int_int_IntPtr_void_Delegate GetStringRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_int_IntPtr_void_Delegate _GetStringUTFRegion; + public JNIEnv.IntPtr_IntPtr_int_int_IntPtr_void_Delegate GetStringUTFRegion { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate _GetPrimitiveArrayCritical; + public JNIEnv.IntPtr_IntPtr_IntPtr_IntPtr_Delegate GetPrimitiveArrayCritical { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate _ReleasePrimitiveArrayCritical; + public JNIEnv.IntPtr_IntPtr_IntPtr_int_void_Delegate ReleasePrimitiveArrayCritical { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_string_Delegate _GetStringCritical; + public JNIEnv.IntPtr_IntPtr_IntPtr_string_Delegate GetStringCritical { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_string_void_Delegate _ReleaseStringCritical; + public JNIEnv.IntPtr_IntPtr_string_void_Delegate ReleaseStringCritical { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _NewWeakGlobalRef; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate NewWeakGlobalRef { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_void_Delegate _DeleteWeakGlobalRef; + public JNIEnv.IntPtr_IntPtr_void_Delegate DeleteWeakGlobalRef { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_bool_Delegate _ExceptionCheck; + public JNIEnv.IntPtr_bool_Delegate ExceptionCheck { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_long_IntPtr_Delegate _NewDirectByteBuffer; + public JNIEnv.IntPtr_IntPtr_long_IntPtr_Delegate NewDirectByteBuffer { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_IntPtr_Delegate _GetDirectBufferAddress; + public JNIEnv.IntPtr_IntPtr_IntPtr_Delegate GetDirectBufferAddress { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_long_Delegate _GetDirectBufferCapacity; + public JNIEnv.IntPtr_IntPtr_long_Delegate GetDirectBufferCapacity { + get { + throw new NotImplementedException (); + } + } + + JNIEnv.IntPtr_IntPtr_int_Delegate _GetObjectRefType; + public JNIEnv.IntPtr_IntPtr_int_Delegate GetObjectRefType { + get { + throw new NotImplementedException (); + } + } + } +} +#pragma warning restore + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JObjectRefType.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JObjectRefType.cs new file mode 100644 index 00000000000..479a580b625 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JObjectRefType.cs @@ -0,0 +1,13 @@ +using System; + +namespace Android.Runtime +{ + internal enum JObjectRefType + { + Invalid = 0, + Local = 1, + Global = 2, + WeakGlobal = 3, + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JValue.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JValue.cs new file mode 100644 index 00000000000..a7300588829 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JValue.cs @@ -0,0 +1,86 @@ +#if !JAVA_INTEROP1 + +#pragma warning disable +using System; +using System.Runtime.InteropServices; + +namespace Android.Runtime { + + [StructLayout(LayoutKind.Explicit)] + public struct JValue { + [FieldOffset(0)] bool z; + [FieldOffset(0)] sbyte b; + [FieldOffset(0)] char c; + [FieldOffset(0)] short s; + [FieldOffset(0)] int i; + [FieldOffset(0)] long j; + [FieldOffset(0)] float f; + [FieldOffset(0)] double d; + [FieldOffset(0)] IntPtr l; + + public static JValue Zero = new JValue (IntPtr.Zero); + + public JValue (bool value) + { + this = new JValue (); + z = value; + } + + public JValue (sbyte value) + { + this = new JValue (); + b = value; + } + + public JValue (char value) + { + this = new JValue (); + c = value; + } + + public JValue (short value) + { + this = new JValue (); + s = value; + } + + public JValue (int value) + { + this = new JValue (); + i = value; + } + + public JValue (long value) + { + this = new JValue (); + j = value; + } + + public JValue (float value) + { + this = new JValue (); + f = value; + } + + public JValue (double value) + { + this = new JValue (); + d = value; + } + + public JValue (IntPtr value) + { + this = new JValue (); + l = value; + } + + public JValue (IJavaObject value) + { + this = new JValue (); + l = value == null ? IntPtr.Zero : value.Handle; + } + } +} +#pragma warning restore + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaArray.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaArray.cs new file mode 100644 index 00000000000..638b1eb7231 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaArray.cs @@ -0,0 +1,411 @@ +#if !JAVA_INTEROP1 +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + + +namespace Android.Runtime { + + [Register ("mono/android/runtime/JavaArray", DoNotGenerateAcw=true)] + public sealed class JavaArray : Java.Lang.Object, IList { + + public JavaArray (IntPtr handle, JniHandleOwnership transfer) + { + } + + public int Count { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + + public bool IsReadOnly { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + public T this [int index] { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + public void Add (T item) + { + throw new NotImplementedException (); + } + + public void Clear () + { + throw new NotImplementedException (); + } + + public bool Contains (T item) + { + throw new NotImplementedException (); + } + + public void CopyTo (T[] array, int array_index) + { + throw new NotImplementedException (); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + throw new NotImplementedException (); + } + + public IEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + public int IndexOf (T item) + { + throw new NotImplementedException (); + } + + public void Insert (int index, T item) + { + throw new NotImplementedException (); + } + + public bool Remove (T item) + { + throw new NotImplementedException (); + } + + public void RemoveAt (int index) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static JavaArray FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (IList value) + { + throw new NotImplementedException (); + } + } + + public class JavaList : Java.Lang.Object, IList { + + public JavaList () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + } + + public JavaList (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) {} + + public JavaList (IEnumerable items) : this () + { + } + + public int Count { + get { + throw new NotImplementedException (); + } + } + + public bool IsFixedSize { + get { throw new NotImplementedException (); } + } + + public bool IsReadOnly { + get { throw new NotImplementedException (); } + } + + public bool IsSynchronized { + get { throw new NotImplementedException (); } + } + + public object SyncRoot { + get { throw new NotImplementedException (); } + } + + public object this [int index] { + get { + throw new NotImplementedException (); + } + set { throw new NotImplementedException (); } + } + + public int Add (object item) + { + throw new NotImplementedException (); + } + + public void Clear () + { + throw new NotImplementedException (); + } + + public bool Contains (object item) + { + throw new NotImplementedException (); + } + + public void CopyTo (Array array, int array_index) + { + throw new NotImplementedException (); + } + + public IEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + public virtual int IndexOf (object item) + { + throw new NotImplementedException (); + } + + public virtual int LastIndexOf (object item) + { + throw new NotImplementedException (); + } + + public void Insert (int index, object item) + { + throw new NotImplementedException (); + } + + public void Remove (object item) + { + throw new NotImplementedException (); + } + + public void RemoveAt (int index) + { + throw new NotImplementedException (); + } + + public virtual Java.Lang.Object Set (int location, Java.Lang.Object item) + { + throw new NotImplementedException (); + } + + public virtual JavaList SubList (int start, int end) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IList FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (IList items) + { + throw new NotImplementedException (); + } + + #region ArrayList "implementation" + // + // They provide "implementation" of java.util.ArrayList methods. + // They could be "overriden" in derived classes if there is + // some class that derives from ArrayList (since some methods + // are abstract, it is mandatory to implement them. + // + // Here's the scenario that happens to any class that derives + // from ArrayList and overrides add() method: + // + // - jar2xml excludes the add() override from the result api xml. + // In general, jar2xml excludes (AOSP excluded) any overrides + // that are defined enough in the base class. ArrayList has + // add() method, so the derived class does not need it. + // - but in reality, it is not java.util.ArrayList but our + // JavaList which actually takes part of the base class. + // - Since there is no API definition for add() because of above, + // they don't appear in the generated class. + // - but after that, the generator tries to *implement* missing + // methods from its implementing interfaces, which includes + // java.util.List. And that interface contains add() method. + // + // Java.Util.IList does not exist, so we cannot implement explicitly. + // + public virtual bool Add (Java.Lang.Object item) + { + throw new NotImplementedException (); + } + + public virtual bool Add (int index, Java.Lang.Object item) + { + throw new NotImplementedException (); + } + + public virtual bool Add (JavaList collection) + { + throw new NotImplementedException (); + } + + public virtual bool AddAll (int location, JavaList collection) + { + throw new NotImplementedException (); + } + + // Clear() exists. + + public virtual bool Contains (Java.Lang.Object item) + { + throw new NotImplementedException (); + } + + public virtual bool ContainsAll (JavaList collection) + { + throw new NotImplementedException (); + } + + public virtual bool Equals (Java.Lang.Object obj) + { + throw new NotImplementedException (); + } + + public virtual Java.Lang.Object Get (int location) + { + throw new NotImplementedException (); + } + + public virtual int IndexOf (Java.Lang.Object item) + { + throw new NotImplementedException (); + } + + public virtual bool IsEmpty { + get { throw new NotImplementedException (); } + } + + public virtual Java.Lang.Object Remove (int location) + { + throw new NotImplementedException (); + } + + public virtual bool Remove (Java.Lang.Object item) + { + throw new NotImplementedException (); + } + + public virtual bool RemoveAll (JavaList collection) + { + throw new NotImplementedException (); + } + + public virtual bool RetainAll (JavaList collection) + { + throw new NotImplementedException (); + } + + // Set() exists (added above, for code style consistency). + + public virtual int Size () + { + throw new NotImplementedException (); + } + + // SubList() exists (added above, for code style consistency). + + public virtual Java.Lang.Object [] ToArray (Java.Lang.Object [] array) + { + throw new NotImplementedException (); + } + + public virtual Java.Lang.Object [] ToArray () + { + throw new NotImplementedException (); + } + #endregion + } + + public sealed class JavaList : Java.Lang.Object, IList { + + public JavaList (IntPtr handle, JniHandleOwnership transfer) + : base (handle, transfer) + { + } + + public int Count { + get { throw new NotImplementedException (); } + } + + public bool IsReadOnly { + get { throw new NotImplementedException (); } + } + + public T this [int index] { + get { + throw new NotImplementedException (); + } + set { throw new NotImplementedException (); } + } + + public void Add (T item) + { + throw new NotImplementedException (); + } + + public void Clear () + { + throw new NotImplementedException (); + } + + public bool Contains (T item) + { + throw new NotImplementedException (); + } + + public void CopyTo (T[] array, int array_index) + { + throw new NotImplementedException (); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + throw new NotImplementedException (); + } + + public IEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + public int IndexOf (T item) + { + throw new NotImplementedException (); + } + + public void Insert (int index, T item) + { + throw new NotImplementedException (); + } + + public bool Remove (T item) + { + throw new NotImplementedException (); + } + + public void RemoveAt (int index) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static JavaArray FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (IList value) + { + throw new NotImplementedException (); + } + } +} +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaCollection.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaCollection.cs new file mode 100644 index 00000000000..c12eb759f19 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaCollection.cs @@ -0,0 +1,120 @@ +#if !JAVA_INTEROP1 + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using Android.Runtime; + +using Java.Interop; + +namespace Android.Runtime { + + [Register ("java/util/Collection", DoNotGenerateAcw=true)] + public class JavaCollection : Java.Lang.Object, System.Collections.ICollection { + + public JavaCollection (IntPtr handle, JniHandleOwnership transfer) + : base (handle, transfer) + { + } + + public int Count { + get { + throw new NotImplementedException (); + } + } + + public bool IsSynchronized { + get { throw new NotImplementedException (); } + } + + public object SyncRoot { + get { throw new NotImplementedException (); } + } + + public void CopyTo (Array array, int array_index) + { + throw new NotImplementedException (); + } + + public IEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static ICollection FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (ICollection items) + { + throw new NotImplementedException (); + } + } + + [Register ("java/util/Collection", DoNotGenerateAcw=true)] + public sealed class JavaCollection : JavaCollection, ICollection { + + public JavaCollection (IntPtr handle, JniHandleOwnership transfer) + : base (handle, transfer) + { + } + + public bool IsReadOnly { + get { throw new NotImplementedException (); } + } + + public void Add (T item) + { + throw new NotImplementedException (); + } + + public void Clear () + { + throw new NotImplementedException (); + } + + public bool Contains (T item) + { + throw new NotImplementedException (); + } + + public void CopyTo (T[] array, int array_index) + { + throw new NotImplementedException (); + } + + public bool Remove (T item) + { + throw new NotImplementedException (); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + throw new NotImplementedException (); + } + + public new IEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static new ICollection FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (ICollection items) + { + throw new NotImplementedException (); + } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaConvert.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaConvert.cs new file mode 100644 index 00000000000..429cb5008ed --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaConvert.cs @@ -0,0 +1,66 @@ +#if !JAVA_INTEROP1 + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +using Android.Runtime; + +namespace Java.Interop { + + static class JavaConvert { + + public static T FromJniHandle(IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + public static T FromJniHandle(IntPtr handle, JniHandleOwnership transfer, out bool set) + { + throw new NotImplementedException (); + } + + internal static string GetJniClassForType (Type type) + { + throw new NotImplementedException (); + } + + public static object FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + public static T FromJavaObject(IJavaObject value) + { + throw new NotImplementedException (); + } + + public static T FromJavaObject(IJavaObject value, out bool set) + { + throw new NotImplementedException (); + } + + public static object FromJavaObject (IJavaObject value) + { + throw new NotImplementedException (); + } + + public static IJavaObject ToJavaObject(T value) + { + throw new NotImplementedException (); + } + + public static TReturn WithLocalJniHandle(TValue value, Func action) + { + throw new NotImplementedException (); + } + + public static TReturn WithLocalJniHandle(object value, Func action) + { + throw new NotImplementedException (); + } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaDictionary.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaDictionary.cs new file mode 100644 index 00000000000..6bf331fca01 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaDictionary.cs @@ -0,0 +1,281 @@ +#if !JAVA_INTEROP1 + +using System; +using System.Collections; +using System.Collections.Generic; + +using Android.Runtime; + +using Java.Interop; + +namespace Android.Runtime { + + [Register ("java/util/HashMap", DoNotGenerateAcw=true)] + public class JavaDictionary : Java.Lang.Object, System.Collections.IDictionary { + + class DictionaryEnumerator : IDictionaryEnumerator { + + public DictionaryEnumerator (JavaDictionary owner) + { + throw new NotImplementedException (); + } + + public object Current { + get { throw new NotImplementedException (); } + } + + public DictionaryEntry Entry { + get { throw new NotImplementedException (); } + } + + public object Key { + get { throw new NotImplementedException (); } + } + + public object Value { + get { throw new NotImplementedException (); } + } + + public bool MoveNext () + { + throw new NotImplementedException (); + } + + public void Reset () + { + throw new NotImplementedException (); + } + } + + + internal object Get (object key) + { + throw new NotImplementedException (); + } + + internal IntPtr GetKeys () + { + throw new NotImplementedException (); + } + + internal IntPtr GetValues () + { + throw new NotImplementedException (); + } + + internal void Put (object key, object value) + { + throw new NotImplementedException (); + } + + public JavaDictionary () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + throw new NotImplementedException (); + } + + public JavaDictionary (IntPtr handle, JniHandleOwnership transfer) + : base (handle, transfer) + { + } + + public JavaDictionary (IDictionary items) : this () + { + throw new NotImplementedException (); + } + + public int Count { + get { + throw new NotImplementedException (); + } + } + + public bool IsFixedSize { + get { throw new NotImplementedException (); } + } + + public bool IsReadOnly { + get { throw new NotImplementedException (); } + } + + public bool IsSynchronized { + get { throw new NotImplementedException (); } + } + + public ICollection Keys { + get { throw new NotImplementedException (); } + } + + public object SyncRoot { + get { throw new NotImplementedException (); } + } + + public ICollection Values { + get { throw new NotImplementedException (); } + } + + public object this [object key] { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + public void Add (object key, object value) + { + throw new NotImplementedException (); + } + + public void Clear () + { + throw new NotImplementedException (); + } + + public bool Contains (object key) + { + throw new NotImplementedException (); + } + + public void CopyTo (Array array, int array_index) + { + throw new NotImplementedException (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + throw new NotImplementedException (); + } + + public IDictionaryEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + public void Remove (object key) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IDictionary FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (IDictionary dictionary) + { + throw new NotImplementedException (); + } + } + + [Register ("java/util/HashMap", DoNotGenerateAcw=true)] + public class JavaDictionary : JavaDictionary, IDictionary { + + [Register (".ctor", "()V", "")] + public JavaDictionary () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + throw new NotImplementedException (); + } + + public JavaDictionary (IntPtr handle, JniHandleOwnership transfer) + : base (handle, transfer) + { + } + + public JavaDictionary (IDictionary items) : this () + { + throw new NotImplementedException (); + } + + internal V Get (K key) + { + throw new NotImplementedException (); + } + + internal void Put (K key, V value) + { + throw new NotImplementedException (); + } + + public V this [K key] { + get { + throw new NotImplementedException (); + } + set { + throw new NotImplementedException (); + } + } + + public new ICollection Keys { + get { throw new NotImplementedException (); } + } + + public new ICollection Values { + get { throw new NotImplementedException (); } + } + + public void Add (KeyValuePair item) + { + throw new NotImplementedException (); + } + + public void Add (K key, V value) + { + throw new NotImplementedException (); + } + + public bool Contains (KeyValuePair item) + { + throw new NotImplementedException (); + } + + public bool ContainsKey (K key) + { + throw new NotImplementedException (); + } + + public void CopyTo (KeyValuePair[] array, int array_index) + { + throw new NotImplementedException (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + throw new NotImplementedException (); + } + + public new IEnumerator> GetEnumerator () + { + throw new NotImplementedException (); + } + + public bool Remove (KeyValuePair pair) + { + throw new NotImplementedException (); + } + + public bool Remove (K key) + { + throw new NotImplementedException (); + } + + public bool TryGetValue (K key, out V value) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static new IDictionary FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (IDictionary dictionary) + { + throw new NotImplementedException (); + } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs new file mode 100644 index 00000000000..6b927fea337 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Java.Interop { + + [AttributeUsage (AttributeTargets.Method)] + public sealed class JavaInterfaceDefaultMethodAttribute : Attribute { + } +} diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaObject.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaObject.cs new file mode 100644 index 00000000000..59c13fda808 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaObject.cs @@ -0,0 +1,196 @@ +#if !JAVA_INTEROP1 + +using System; + +namespace Android.Runtime { + + [Register ("mono/android/runtime/JavaObject")] + internal sealed class JavaObject : Java.Lang.Object { + + public static IntPtr GetHandle (object obj) + { + throw new NotImplementedException (); + } + + public static object GetObject (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + static TRet Dispose(T value, Func c) + where T : IDisposable + { + throw new NotImplementedException (); + } + + public JavaObject (object inst) + //: base ( + // JNIEnv.StartCreateInstance ("mono/android/runtime/JavaObject", "()V"), + // JniHandleOwnership.TransferLocalRef) + { + throw new NotImplementedException (); + } + + public object Instance { + get; + set; + } + /* + protected override Java.Lang.Object Clone () + { + throw new NotImplementedException (); + } + + public override bool Equals (Java.Lang.Object obj) + { + throw new NotImplementedException (); + } + + public override int GetHashCode () + { + throw new NotImplementedException (); + } + + public override string ToString () + { + throw new NotImplementedException (); + }*/ + } + + public static class JNINativeWrapper { + + static void get_runtime_types () + { + throw new NotImplementedException (); + } + + public static Delegate CreateDelegate (Delegate dlg) + { + throw new NotImplementedException (); + } + + } +} +namespace Java.Lang { + + using Android.Runtime; + + public partial class Object : IJavaObject, IDisposable { + + public IntPtr Handle { get; set; } + + protected virtual IntPtr ThresholdClass { + get; + set; + } + + protected virtual global::System.Type ThresholdType { + get; + set; + } + + public Object() + { + throw new NotImplementedException (); + } + + public Object (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + public static T GetObject(IntPtr jnienv, IntPtr native__this, JniHandleOwnership ownership) + { + throw new NotImplementedException (); + } + + public static T GetObject(IntPtr native__this, JniHandleOwnership ownership) + { + throw new NotImplementedException (); + } + + protected void SetHandle(IntPtr instance, JniHandleOwnership ownership) + { + throw new NotImplementedException (); + } + + public void Dispose() + { + throw new NotImplementedException (); + } + + protected virtual void Dispose (bool disposing) + { + throw new NotImplementedException (); + } + } + + public partial class Throwable : global::System.Exception, IJavaObject, IDisposable { + + public IntPtr Handle { get; set; } + + protected virtual IntPtr ThresholdClass { + get; + set; + } + + protected virtual global::System.Type ThresholdType { + get; + set; + } + + public Throwable () + { + throw new NotImplementedException (); + } + + public Throwable (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + protected void SetHandle(IntPtr instance, JniHandleOwnership ownership) + { + throw new NotImplementedException (); + } + + public void Dispose() + { + throw new NotImplementedException (); + } + + protected virtual void Dispose (bool disposing) + { + throw new NotImplementedException (); + } + } +} +namespace Java.Lang { + + using System.Collections.Generic; + + public partial interface ICharSequence : IEnumerable {} + +} +namespace Android.Graphics +{ + public struct Color + { + public Color (int argb) + { + throw new NotImplementedException (); + } + + private Color (uint argb) + { + throw new NotImplementedException (); + } + + public int ToArgb () + { + throw new NotImplementedException (); + } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaObjectExtensions.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaObjectExtensions.cs new file mode 100644 index 00000000000..a32d93f4165 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JavaObjectExtensions.cs @@ -0,0 +1,69 @@ +#if !JAVA_INTEROP1 + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Android.Runtime; + +namespace Java.Interop { + + public static class JavaObjectExtensions { + + [Obsolete ("Use Android.Runtime.JavaCollection.ToLocalJniHandle()")] + public static JavaCollection ToInteroperableCollection (this ICollection instance) + { + throw new NotImplementedException (); + } + + [Obsolete ("Use Android.Runtime.JavaCollection.ToLocalJniHandle()")] + public static JavaCollection ToInteroperableCollection (this ICollection instance) + { + throw new NotImplementedException (); + } + + [Obsolete ("Use Android.Runtime.JavaList.ToLocalJniHandle()")] + public static JavaList ToInteroperableCollection (this IList instance) + { + throw new NotImplementedException (); + } + + [Obsolete ("Use Android.Runtime.JavaList.ToLocalJniHandle()")] + public static JavaList ToInteroperableCollection (this IList instance) + { + throw new NotImplementedException (); + } + + [Obsolete ("Use Android.Runtime.JavaDictionary.ToLocalJniHandle()")] + public static JavaDictionary ToInteroperableCollection (this IDictionary instance) + { + throw new NotImplementedException (); + } + + [Obsolete ("Use Android.Runtime.JavaDictionary.ToLocalJniHandle()")] + public static JavaDictionary ToInteroperableCollection (this IDictionary instance) + { + throw new NotImplementedException (); + } + + public static TResult JavaCast (this IJavaObject instance) + where TResult : class, IJavaObject + { + throw new NotImplementedException (); + } + + internal static TResult _JavaCast (this IJavaObject instance) + { + throw new NotImplementedException (); + } + + // typeof(Foo) -> FooSuffix + // typeof(Foo<>) -> FooSuffix`1 + internal static Type GetHelperType (Type type, string suffix) + { + throw new NotImplementedException (); + } + } +} + +#endif // !JAVA_INTEROP1 \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_ICharSequence.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_ICharSequence.cs new file mode 100644 index 00000000000..47634bbb368 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_ICharSequence.cs @@ -0,0 +1,17 @@ + +using System; +using Java.Interop; + +namespace Java.Lang { + + public partial interface ICharSequence : IJavaPeerable +#if !JAVA_INTEROP1 + , Android.Runtime.IJavaObject +#endif // !JAVA_INTEROP1 + { + char CharAt (int index); + int Length (); + Java.Lang.ICharSequence SubSequenceFormatted (int start, int end); + string ToString (); + } +} diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_Object.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_Object.cs new file mode 100644 index 00000000000..6ab114ad35e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_Object.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; + +using Java.Interop; + +#if !JAVA_INTEROP1 +using Android.Runtime; +#endif // !JAVA_INTEROP1 + +namespace Java.Lang +{ + public partial class Object : +#if JAVA_INTEROP1 + global::Java.Interop.JavaObject, +#else + IJavaObject, +#endif // JAVA_INTEROP1 + IDisposable, IJavaPeerable + { +#if JAVA_INTEROP1 + + public Object (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } + +#else // !JAVA_INTEROP1 + + public virtual JniPeerMembers JniPeerMembers { + get { return null; } + } + + public int JniIdentityHashCode { + get { return 0; } + } + + public JniObjectReference PeerReference { + get { return default (JniObjectReference); } + } + + public JniManagedPeerStates JniManagedPeerState { + get {return 0;} + } + + public void DisposeUnlessReferenced () + { + } + + public void UnregisterFromRuntime () + { + } + + public void Disposed () + { + } + + public void Finalized () + { + } + + public void SetJniIdentityHashCode (int value) + { + } + + public void SetJniManagedPeerState (JniManagedPeerStates value) + { + } + + public void SetPeerReference (JniObjectReference value) + { + } + + internal void SetHandleOnDeserialized (StreamingContext context) + { + throw new NotImplementedException (); + } + + internal static void RegisterInstance (IJavaObject instance, IntPtr value, JniHandleOwnership transfer, out IntPtr handle) + { + throw new NotImplementedException (); + } + + static void _RegisterInstance (IJavaObject instance, IntPtr key, IntPtr handle) + { + throw new NotImplementedException (); + } + + static bool ShouldReplaceMapping (WeakReference current) + { + throw new NotImplementedException (); + } + + static void DeregisterInstance (object instance, IntPtr key_handle) + { + throw new NotImplementedException (); + } + + internal static List GetSurfacedObjects_ForDiagnosticsOnly () + { + throw new NotImplementedException (); + } + + internal static IJavaObject PeekObject (IntPtr handle) + { + throw new NotImplementedException (); + } + + internal static T _GetObject (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + internal static IJavaObject GetObject (IntPtr handle, JniHandleOwnership transfer, Type type = null) + { + throw new NotImplementedException (); + } + + public T[] ToArray () + { + throw new NotImplementedException (); + } + + public static Java.Lang.Object FromArray (T[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (bool value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (sbyte value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (char value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (int value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (long value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (float value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (double value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (string value) + { + throw new NotImplementedException (); + } + + public static explicit operator bool (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator sbyte (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator char (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator int (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator long (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator float (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator double (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator string (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (Java.Lang.Object[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (bool[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (byte[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (char[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (int[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (long[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (float[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (double[] value) + { + throw new NotImplementedException (); + } + + public static implicit operator Java.Lang.Object (string[] value) + { + throw new NotImplementedException (); + } + + public static explicit operator Java.Lang.Object[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator bool[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator byte[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator char[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator int[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator long[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator float[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator double[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } + + public static explicit operator string[] (Java.Lang.Object value) + { + throw new NotImplementedException (); + } +#endif // !JAVA_INTEROP1 + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_String.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_String.cs new file mode 100644 index 00000000000..91fbca7d4c5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_String.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Java.Lang { + + public sealed partial class String : global::Java.Lang.Object, Java.Lang.ICharSequence, IEnumerable + { + public unsafe String (string value) +#if JAVA_INTEROP1 + : base (ref *InvalidJniObjectReference, Java.Interop.JniObjectReferenceOptions.None) +#endif // JAVA_INTEROP1 + { + } + + public char CharAt (int index) + { + throw new NotImplementedException (); + } + + public int Length () + { + throw new NotImplementedException (); + } + + public Java.Lang.ICharSequence SubSequenceFormatted (int start, int end) + { + throw new NotImplementedException (); + } + + public override string ToString () + { + throw new NotImplementedException (); + } + + public IEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + throw new NotImplementedException (); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_Throwable.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_Throwable.cs new file mode 100644 index 00000000000..26266a6592a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/Java_Lang_Throwable.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; + +using Java.Interop; + +using Android.Runtime; + +namespace Java.Lang +{ + public partial class Throwable : +#if JAVA_INTEROP1 + JavaException, +#else // !JAVA_INTEROP1 + System.Exception, +#endif // !JAVA_INTEROP1 + IJavaPeerable + { +#if JAVA_INTEROP1 + public Throwable (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } +#else // !JAVA_INTEROP1 + + public virtual JniPeerMembers JniPeerMembers { + get { return null; } + } + + public int JniIdentityHashCode { + get { return 0; } + } + + public JniObjectReference PeerReference { + get { return default (JniObjectReference); } + } + + public JniManagedPeerStates JniManagedPeerState { + get { return 0; } + } + + public void DisposeUnlessReferenced () + { + } + + public void UnregisterFromRuntime () + { + } + + public void Disposed () + { + } + + public void Finalized () + { + } + + public void SetJniIdentityHashCode (int value) + { + } + + public void SetJniManagedPeerState (JniManagedPeerStates value) + { + } + + public void SetPeerReference (JniObjectReference value) + { + } +#endif // !JAVA_INTEROP1 + } +} diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/JniHandleOwnership.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/JniHandleOwnership.cs new file mode 100644 index 00000000000..5a7d7bcae82 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/JniHandleOwnership.cs @@ -0,0 +1,14 @@ +#if !JAVA_INTEROP1 + +using System; + +namespace Android.Runtime +{ + public enum JniHandleOwnership { + DoNotTransfer = 0, + TransferLocalRef = 1, + TransferGlobalRef = 2, + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/NamespaceMappingAttribute.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/NamespaceMappingAttribute.cs new file mode 100644 index 00000000000..2dc9157b38b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/NamespaceMappingAttribute.cs @@ -0,0 +1,19 @@ +#if !JAVA_INTEROP1 + +using System; + +namespace Android.Runtime +{ + [AttributeUsage (AttributeTargets.Assembly | AttributeTargets.Module, AllowMultiple = true)] + public class NamespaceMappingAttribute : Attribute + { + public NamespaceMappingAttribute () + { + } + + public string Java { get; set; } + public string Managed { get; set; } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/PreserveAttribute.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/PreserveAttribute.cs new file mode 100644 index 00000000000..dbf7ee3295a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/PreserveAttribute.cs @@ -0,0 +1,59 @@ +#if !JAVA_INTEROP1 + +// +// PreserveAttribute.cs +// +// Authors: +// Jb Evain +// +// Copyright 2009, Novell, Inc. +// Copyright 2010, Novell, Inc. +// +// 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. +// +// + +using System; + +namespace Android.Runtime { + + [AttributeUsage ( + AttributeTargets.Class + | AttributeTargets.Struct + | AttributeTargets.Enum + | AttributeTargets.Constructor + | AttributeTargets.Method + | AttributeTargets.Property + | AttributeTargets.Field + | AttributeTargets.Event + | AttributeTargets.Interface + | AttributeTargets.Delegate)] + public sealed class PreserveAttribute : Attribute { + + public bool AllMembers; + public bool Conditional; + + public PreserveAttribute () + { + } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/RegisterAttribute.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/RegisterAttribute.cs new file mode 100644 index 00000000000..2da73db4715 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/RegisterAttribute.cs @@ -0,0 +1,41 @@ +#if !JAVA_INTEROP1 + +using System; + +namespace Android.Runtime { + + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Property)] + public sealed class RegisterAttribute : Attribute { + + public RegisterAttribute (string name) + { + Name = name; + } + + public RegisterAttribute (string name, string signature, string connector) + : this (name) + { + Signature = signature; + Connector = connector; + } + + public string Connector { + get; + set; + } + + public string Name { + get; + set; + } + + public string Signature { + get; + set; + } + + public bool DoNotGenerateAcw {get; set;} + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/TypeManager.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/TypeManager.cs new file mode 100644 index 00000000000..7d269f6f50d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/TypeManager.cs @@ -0,0 +1,116 @@ +#if !JAVA_INTEROP1 + +#pragma warning disable +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; + +using Android.Runtime; + +namespace Java.Interop { + + public static partial class TypeManager { + + // Make this internal so that JNIEnv.Initialize can trigger the static + // constructor so that JNIEnv.RegisterJNINatives() doesn't include + // the static constructor execution. + + // Lock on jniToManaged before accessing EITHER jniToManaged or managedToJni. + internal static Dictionary jniToManaged = new Dictionary (); + + internal static IntPtr id_Class_getName; + + static TypeManager () + { + throw new NotImplementedException (); + } + + internal static string GetClassName (IntPtr class_ptr) + { + throw new NotImplementedException (); + } + + internal static string GetJniTypeName (Type type) + { + throw new NotImplementedException (); + } + + class TypeNameComparer : IComparer { + public int Compare (string x, string y) + { + throw new NotImplementedException (); + } + } + + public static string LookupTypeMapping (string[] mappings, string javaType) + { + throw new NotImplementedException (); + } + + internal static Delegate GetActivateHandler () + { + throw new NotImplementedException (); + } + + internal static bool ActivationEnabled { + get; + set; + } + + static Type[] GetParameterTypes (string signature) + { + throw new NotImplementedException (); + } + + static void n_Activate (IntPtr jnienv, IntPtr jclass, IntPtr typename_ptr, IntPtr signature_ptr, IntPtr jobject, IntPtr parameters_ptr) + { + throw new NotImplementedException (); + } + + static Exception CreateMissingConstructorException (Type type, Type[] ptypes) + { + throw new NotImplementedException (); + } + + static Exception CreateJavaLocationException () + { + throw new NotImplementedException (); + } + + internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership transfer, Type targetType) + { + throw new NotImplementedException (); + } + + internal static object CreateProxy (Type type, IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + public static void RegisterType (string java_class, Type t) + { + throw new NotImplementedException (); + } + + static Dictionary>> packageLookup = new Dictionary>> (); + + public static void RegisterPackage (string package, Converter lookup) + { + throw new NotImplementedException (); + } + + public static void RegisterPackages (string[] packages, Converter[] lookups) + { + throw new NotImplementedException (); + } + } +} +#pragma warning restore + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/SupportFiles/XAPeerMembers.cs b/external/Java.Interop/tests/generator-Tests/SupportFiles/XAPeerMembers.cs new file mode 100644 index 00000000000..b6044ed5013 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/SupportFiles/XAPeerMembers.cs @@ -0,0 +1,41 @@ +#if !JAVA_INTEROP1 + +using System; +using System.Collections.Generic; + +using Java.Interop; + +namespace Android.Runtime { + + public class XAPeerMembers : JniPeerMembers { + + static Dictionary LegacyPeerMembers = new Dictionary (StringComparer.Ordinal); + + public XAPeerMembers (string jniPeerTypeName, Type managedPeerType) + : base (jniPeerTypeName, managedPeerType) + { + } + + public XAPeerMembers (string jniPeerTypeName, Type managedPeerType, bool isInterface) + : base (jniPeerTypeName, managedPeerType, isInterface) + { + } + + protected override bool UsesVirtualDispatch (IJavaPeerable value, Type declaringType) + { + return false; + } + + static Type GetThresholdType (IJavaPeerable value) + { + return null; + } + + static IntPtr GetThresholdClass (IJavaPeerable value) + { + return IntPtr.Zero; + } + } +} + +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/AdjusterTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/AdjusterTests.cs new file mode 100644 index 00000000000..e6f68a741b2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/AdjusterTests.cs @@ -0,0 +1,118 @@ +using Mono.Cecil; +using MonoDroid.Generation; +using NUnit.Framework; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using Xamarin.Android.Tools.ApiXmlAdjuster; + +namespace generatortests +{ + //For now this is a basic smoke test to validate the `generator --only-xml-adjuster` option + // In the future, it should be expanded to fully test the Adjuster class + [TestFixture] + public class AdjusterTests + { + Adjuster adjuster; + CodeGenerationOptions options; + string inputFile, outputFile, temporaryAssembly; + ModuleDefinition module; + + [SetUp] + public void SetUp () + { + temporaryAssembly = Path.GetTempFileName (); + File.Copy (GetType ().Assembly.Location, temporaryAssembly, true); + module = ModuleDefinition.ReadModule (temporaryAssembly); + + adjuster = new Adjuster (); + options = new CodeGenerationOptions (); + inputFile = Path.GetTempFileName (); + outputFile = inputFile + ".adjusted"; + + //We should fail on warnings & errors, and just log debug + Log.LogDebugAction = TestContext.Out.WriteLine; + Log.LogWarningAction = + Log.LogErrorAction = Assert.Fail; + + File.WriteAllText (inputFile, @" + + + + + + + +"); + + foreach (var type in module.Types.Where (t => t.IsClass && t.Namespace == "Java.Lang")) { + //Make sure we use this method instead of SymbolTable directly, to match what happens in generator.exe + Xamarin.Android.Binder.CodeGenerator.ProcessReferencedType (type, options); + } + } + + [TearDown] + public void TearDown () + { + //HACK: put the Log callbacks back the way they were + Log.LogDebugAction = null; + Log.LogWarningAction = null; + Log.LogErrorAction = null; + + module.Dispose (); + File.Delete (temporaryAssembly); + File.Delete (inputFile); + File.Delete (outputFile); + } + + [Test] + public void Process () + { + adjuster.Process (inputFile, options, options.SymbolTable.AllRegisteredSymbols (options).OfType ().ToArray (), outputFile, (int)Log.LoggingLevel.Debug); + + FileAssert.Exists (outputFile); + } + + [Test] + public void AdjustNotNullAnnotations () + { + var input = @" + + + + + + + + + + +"; + + var api = new JavaApi (); + api.LoadReferences (options, options.SymbolTable.AllRegisteredSymbols (options).OfType ().ToArray ()); + + using (var sr = new StringReader (input)) + using (var xml = XmlReader.Create (sr)) + api.Load (xml, false); + + api.StripNonBindables (); + api.Resolve (); + api.CreateGenericInheritanceMapping (); + api.MarkOverrides (); + api.FindDefects (); + + using (var sb = new StringWriter ()) { + using (var writer = XmlWriter.Create (sb)) + api.Save (writer); + + var root = XElement.Parse (sb.ToString ()); + + Assert.AreEqual ("true", root.Element ("package").Element ("class").Element ("method").Attribute ("return-not-null").Value); + Assert.AreEqual ("true", root.Element ("package").Element ("class").Element ("method").Element ("parameter").Attribute ("not-null").Value); + Assert.AreEqual ("true", root.Element ("package").Element ("class").Element ("field").Attribute ("not-null").Value); + } + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/BlittableTypeTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/BlittableTypeTests.cs new file mode 100644 index 00000000000..11b49c10da7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/BlittableTypeTests.cs @@ -0,0 +1,142 @@ +using System; +using MonoDroid.Generation; +using NUnit.Framework; +using Xamarin.Android.Binder; + +namespace generatortests; + +[TestFixture] +class BlittableTypeTests : CodeGeneratorTestBase +{ + protected override CodeGenerationTarget Target => CodeGenerationTarget.XAJavaInterop1; + + [Test] + public void MethodWithBoolReturnType () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "IsEmpty", options, "boolean"); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Return type should be byte + Assert.That (actual, Contains.Substring ("static sbyte n_IsEmpty")); + + // Return statement should convert to 0 or 1 + Assert.That (actual, Contains.Substring ("return __this.IsEmpty () ? (sbyte)1 : (sbyte)0")); + + // Ensure the marshal delegate is byte + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_B")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_Z")); + } + + [Test] + public void MethodWithBoolParameter () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "SetEmpty", options, "void", parameters: new Parameter ("value", "boolean", "bool", false)); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Method parameter should be byte + Assert.That (actual, Contains.Substring ("static void n_SetEmpty_Z (IntPtr jnienv, IntPtr native__this, sbyte native_value)")); + + // Method should convert from 0 or 1 + Assert.That (actual, Contains.Substring ("var value = native_value != 0;")); + + // Ensure the marshal delegate is byte + Assert.That (actual, Contains.Substring ("new _JniMarshal_PPB_V")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PPZ_V")); + } + + [Test] + public void BoolProperty () + { + var klass = SupportTypeBuilder.CreateClassWithProperty ("MyClass", "com.example.myClass", "IsEmpty", "boolean", options); + var actual = GetGeneratedTypeOutput (klass); + + // Getter return type should be byte + Assert.That (actual, Contains.Substring ("static sbyte n_get_IsEmpty")); + + // Getter return statement should convert to 0 or 1 + Assert.That (actual, Contains.Substring ("return __this.IsEmpty ? (sbyte)1 : (sbyte)0")); + + // Setter parameter should be byte + Assert.That (actual, Contains.Substring ("static void n_set_IsEmpty_Z (IntPtr jnienv, IntPtr native__this, sbyte native_value)")); + + // Setter should convert from 0 or 1 + Assert.That (actual, Contains.Substring ("var value = native_value != 0;")); + + // Ensure the marshal delegate is byte + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_B")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_Z")); + } + + [Test] + public void MethodWithCharReturnType () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "GetFirstLetter", options, "char"); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Return type should be ushort + Assert.That (actual, Contains.Substring ("static ushort n_GetFirstLetter")); + + // Return statement should convert to ushort + Assert.That (actual, Contains.Substring ("return (ushort)__this.GetFirstLetter ()")); + + // Ensure the marshal delegate is ushort + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_s")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_C")); + } + + [Test] + public void MethodWithCharParameter () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "SetFirstLetter", options, "void", parameters: new Parameter ("value", "char", "char", false)); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Method parameter should be ushort + Assert.That (actual, Contains.Substring ("static void n_SetFirstLetter_C (IntPtr jnienv, IntPtr native__this, ushort native_value)")); + + // Method should convert from ushort to char + Assert.That (actual, Contains.Substring ("var value = (char)native_value;")); + + // Ensure the marshal delegate is ushort + Assert.That (actual, Contains.Substring ("new _JniMarshal_PPs_V")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PPC_V")); + } + + [Test] + public void CharProperty () + { + var klass = SupportTypeBuilder.CreateClassWithProperty ("MyClass", "com.example.myClass", "FirstLetter", "char", options); + var actual = GetGeneratedTypeOutput (klass); + + // Getter return type should be ushort + Assert.That (actual, Contains.Substring ("static ushort n_get_FirstLetter")); + + // Getter return statement should convert to ushort + Assert.That (actual, Contains.Substring ("return (ushort)__this.FirstLetter")); + + // Setter parameter should be ushort + Assert.That (actual, Contains.Substring ("static void n_set_FirstLetter_C (IntPtr jnienv, IntPtr native__this, ushort native_value)")); + + // Setter should convert from ushort to char + Assert.That (actual, Contains.Substring ("var value = (char)native_value;")); + + // Ensure the marshal delegate is ushort + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_s")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_C")); + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGenerationOptionsTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGenerationOptionsTests.cs new file mode 100644 index 00000000000..5ab2aceb49b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGenerationOptionsTests.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Linq; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class CodeGenerationOptionsTests + { + [Test] + public void GetOutputNameUseGlobal () + { + var opt = new CodeGenerationOptions { UseGlobal = true }; + + Assert.AreEqual (string.Empty, opt.GetOutputName (string.Empty)); + Assert.AreEqual ("int", opt.GetOutputName ("int")); + Assert.AreEqual ("void", opt.GetOutputName ("void")); + Assert.AreEqual ("void", opt.GetOutputName ("System.Void")); + Assert.AreEqual ("params int[]", opt.GetOutputName ("params int[]")); + Assert.AreEqual ("params global::System.Object[]", opt.GetOutputName ("params System.Object[]")); + Assert.AreEqual ("int[][][]", opt.GetOutputName ("int[][][]")); + Assert.AreEqual ("global::System.Object[][][]", opt.GetOutputName ("System.Object[][][]")); + + Assert.AreEqual ("global::System.Collections.Generic.List", + opt.GetOutputName ("System.Collections.Generic.List")); + + Assert.AreEqual ("global::System.Collections.Generic.Dictionary", + opt.GetOutputName ("System.Collections.Generic.Dictionary")); + + Assert.AreEqual ("global::System.Collections.Generic.List>", + opt.GetOutputName ("System.Collections.Generic.List>")); + + Assert.AreEqual ("global::System.Collections.Generic.List>>", + opt.GetOutputName ("System.Collections.Generic.List>>")); + + Assert.AreEqual ("global::System.Collections.Generic.IList", + opt.GetOutputName ("System.Collections.Generic.IList")); + + Assert.AreEqual ("global::System.Collections.Generic.IDictionary>", + opt.GetOutputName ("System.Collections.Generic.IDictionary>")); + + Assert.AreEqual ("global::System.Collections.Generic.IDictionary, global::Kotlin.Pair>", + opt.GetOutputName ("System.Collections.Generic.IDictionary, Kotlin.Pair>")); + + Assert.AreEqual ("global::System.Collections.Generic.IDictionary, global::System.Collections.Generic.IList>", + opt.GetOutputName ("System.Collections.Generic.IDictionary, System.Collections.Generic.IList>")); + + Assert.AreEqual ("global::System.Collections.Generic.List[]>[]", + opt.GetOutputName ("System.Collections.Generic.List[]>[]")); + + Assert.AreEqual ("global::System.Collections.Generic.List.Enumerator[]>", + opt.GetOutputName ("System.Collections.Generic.List.Enumerator[]>")); + } + + [Test] + public void GetTypeReferenceName_Nullable () + { + var opt = new CodeGenerationOptions { SupportNullableReferenceTypes = true }; + + // System.Void isn't a valid return type, ensure it gets changed to void + var system_void = new ReturnValue (null, "void", "System.Void", false, false); + system_void.Validate (opt, null, null); + + Assert.AreEqual ("void", opt.GetTypeReferenceName (system_void)); + + // Primitive types should not be nullable + var primitive_void = new ReturnValue (null, "void", "void", false, false); + primitive_void.Validate (opt, null, null); + + Assert.AreEqual ("void", opt.GetTypeReferenceName (primitive_void)); + + var system_uint = new ReturnValue (null, "uint", "System.UInt32", false, false); + system_uint.Validate (opt, null, null); + + Assert.AreEqual ("System.UInt32", opt.GetTypeReferenceName (system_uint)); + + var primitive_uint = new ReturnValue (null, "uint", "uint", false, false); + primitive_uint.Validate (opt, null, null); + + Assert.AreEqual ("uint", opt.GetTypeReferenceName (primitive_uint)); + } + + [Test, TestCaseSource (nameof (ReservedKeywords))] + [SetCulture ("cs-CZ")] + public void GetSafeIdentifierCultureInvariant (string keyword) + { + var opt = new CodeGenerationOptions (); + + Assert.AreEqual ($"{keyword}_", opt.GetSafeIdentifier (keyword)); + } + + private static IEnumerable ReservedKeywords + => TypeNameUtilities.reserved_keywords.Select (keyword => new TestCaseData (keyword)); + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorContextTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorContextTests.cs new file mode 100644 index 00000000000..c0501a3bc9d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorContextTests.cs @@ -0,0 +1,40 @@ +using System; +using System.Linq; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class CodeGeneratorContextTests + { + [Test] + public void GetContextTypeMember () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + + klass.AddMethod (SupportTypeBuilder.CreateMethod (klass, "Echo", new CodeGenerationOptions (), "uint", false, false, new Parameter ("value", "uint", "uint", false))); + klass.AddField (new TestField ("string", "Foo")); + + var context = new CodeGeneratorContext (); + context.ContextTypes.Push (klass); + + Assert.AreEqual ("java.code.MyClass", context.GetContextTypeMember ()); + + context.ContextMethod = klass.Methods.Single (); + + Assert.AreEqual ("java.code.MyClass.Echo (uint)", context.GetContextTypeMember ()); + + context.ContextMethod = null; + context.ContextField = klass.Fields.Single (); + + Assert.AreEqual ("java.code.MyClass.Foo", context.GetContextTypeMember ()); + + context.ContextMethod = klass.Methods.Single (); + context.ContextField = null; + context.ContextTypes.Clear (); + + Assert.AreEqual ("Echo (uint)", context.GetContextTypeMember ()); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteDuplicateInterfaceEventArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteDuplicateInterfaceEventArgs.txt new file mode 100644 index 00000000000..22e295d127f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteDuplicateInterfaceEventArgs.txt @@ -0,0 +1,227 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']" +[Register ("java/code/AnimatorListener", "", "java.code.AnimatorListenerInvoker")] +public partial interface AnimatorListener : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']/method[@name='OnAnimationEnd' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("OnAnimationEnd", "(I)Z", "GetOnAnimationEnd_IHandler:java.code.AnimatorListenerInvoker, ")] + bool OnAnimationEnd (int param1); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']/method[@name='OnAnimationEnd' and count(parameter)=2 and parameter[1][@type='int'] and parameter[2][@type='int']]" + [Register ("OnAnimationEnd", "(II)Z", "GetOnAnimationEnd_IIHandler:java.code.AnimatorListenerInvoker, ")] + bool OnAnimationEnd (int param1, int param2); + +} + +[global::Android.Runtime.Register ("java/code/AnimatorListener", DoNotGenerateAcw=true)] +internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, AnimatorListener { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/AnimatorListener", typeof (AnimatorListenerInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static AnimatorListener GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.AnimatorListener'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public AnimatorListenerInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_OnAnimationEnd_OnAnimationEnd_I_Z; +#pragma warning disable 0169 + static Delegate GetOnAnimationEnd_IHandler () + { + return cb_OnAnimationEnd_OnAnimationEnd_I_Z ??= new _JniMarshal_PPI_B (n_OnAnimationEnd_I); + } + + [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] + static sbyte n_OnAnimationEnd_I (IntPtr jnienv, IntPtr native__this, int param1) + { + if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.OnAnimationEnd (param1) ? (sbyte)1 : (sbyte)0; + } catch (global::System.Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + global::Java.Interop.JniEnvironment.EndMarshalMethod (ref __envp); + } + } +#pragma warning restore 0169 + + IntPtr id_OnAnimationEnd_I; + public unsafe bool OnAnimationEnd (int param1) + { + if (id_OnAnimationEnd_I == IntPtr.Zero) + id_OnAnimationEnd_I = JNIEnv.GetMethodID (class_ref, "OnAnimationEnd", "(I)Z"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (param1); + return JNIEnv.CallBooleanMethod (((global::Java.Lang.Object) this).Handle, id_OnAnimationEnd_I, __args); + } + + static Delegate cb_OnAnimationEnd_OnAnimationEnd_II_Z; +#pragma warning disable 0169 + static Delegate GetOnAnimationEnd_IIHandler () + { + return cb_OnAnimationEnd_OnAnimationEnd_II_Z ??= new _JniMarshal_PPII_B (n_OnAnimationEnd_II); + } + + [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] + static sbyte n_OnAnimationEnd_II (IntPtr jnienv, IntPtr native__this, int param1, int param2) + { + if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return default; + + try { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.OnAnimationEnd (param1, param2) ? (sbyte)1 : (sbyte)0; + } catch (global::System.Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + return default; + } finally { + global::Java.Interop.JniEnvironment.EndMarshalMethod (ref __envp); + } + } +#pragma warning restore 0169 + + IntPtr id_OnAnimationEnd_II; + public unsafe bool OnAnimationEnd (int param1, int param2) + { + if (id_OnAnimationEnd_II == IntPtr.Zero) + id_OnAnimationEnd_II = JNIEnv.GetMethodID (class_ref, "OnAnimationEnd", "(II)Z"); + JValue* __args = stackalloc JValue [2]; + __args [0] = new JValue (param1); + __args [1] = new JValue (param2); + return JNIEnv.CallBooleanMethod (((global::Java.Lang.Object) this).Handle, id_OnAnimationEnd_II, __args); + } + +} + +// event args for java.code.AnimatorListener.OnAnimationEnd +public partial class AnimationEndEventArgs : global::System.EventArgs { + bool handled; + + public bool Handled { + get { return handled; } + set { handled = value; } + } + + public AnimationEndEventArgs (bool handled, int param1) + { + this.handled = handled; + this.param1 = param1; + } + + int param1; + + public int Param1 { + get { return param1; } + } + + public AnimationEndEventArgs (bool handled, int param1, int param2) + { + this.handled = handled; + this.param1 = param1; + this.param2 = param2; + } + + int param2; + + public int Param2 { + get { return param2; } + } + +} + +[global::Android.Runtime.Register ("mono/java/code/AnimatorListenerImplementor")] +internal sealed partial class AnimatorListenerImplementor : global::Java.Lang.Object, AnimatorListener { + + object sender; + + public unsafe AnimatorListenerImplementor (object sender) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + var h = JniPeerMembers.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (h.Handle, JniHandleOwnership.TransferLocalRef); + JniPeerMembers.InstanceMethods.FinishCreateInstance (__id, this, null); + this.sender = sender; + } + + #pragma warning disable 0649 + public EventHandler OnAnimationEndHandler; + #pragma warning restore 0649 + + public bool OnAnimationEnd (int param1) + { + var __h = OnAnimationEndHandler; + if (__h == null) + return false; + var __e = new AnimationEndEventArgs (true, param1); + __h (sender, __e); + return __e.Handled; + } + + #pragma warning disable 0649 + public EventHandler OnAnimationEndHandler; + #pragma warning restore 0649 + + public bool OnAnimationEnd (int param1, int param2) + { + var __h = OnAnimationEndHandler; + if (__h == null) + return false; + var __e = new AnimationEndEventArgs (true, param1, param2); + __h (sender, __e); + return __e.Handled; + } + + internal static bool __IsEmpty (AnimatorListenerImplementor value) + { + return value.OnAnimationEndHandler == null && value.OnAnimationEndHandler == null; + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceExtensionsDeclaration.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceExtensionsDeclaration.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerEvent.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerEvent.txt new file mode 100644 index 00000000000..381b7754ef2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerEvent.txt @@ -0,0 +1,17 @@ +public event MyFullDelegateName MyName { + add { + global::Java.Interop.EventHelper.AddEventHandler( + ref weak_implementor_MyWrefSuffix, + __CreateIMyInterfaceImplementor, + Add, + __h => __h.MyNameSpecHandler += value); + } + remove { + global::Java.Interop.EventHelper.RemoveEventHandler( + ref weak_implementor_MyWrefSuffix, + java.code.IMyInterfaceImplementor.__IsEmpty, + Remove, + __h => __h.MyNameSpecHandler -= value); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerEventWithHandlerArgument.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerEventWithHandlerArgument.txt new file mode 100644 index 00000000000..7f1b240c06c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerEventWithHandlerArgument.txt @@ -0,0 +1,22 @@ +public event MyFullDelegateName MyName { + add { + global::Java.Interop.EventHelper.AddEventHandler( + ref weak_implementor_MyWrefSuffix, + __CreateIMyInterfaceImplementor, + AddMyName_Event_With_Handler_Helper, + __h => __h.MyNameSpecHandler += value); + } + remove { + global::Java.Interop.EventHelper.RemoveEventHandler( + ref weak_implementor_MyWrefSuffix, + java.code.IMyInterfaceImplementor.__IsEmpty, + RemoveMyName, + __h => __h.MyNameSpecHandler -= value); + } +} + +void AddMyName_Event_With_Handler_Helper (java.code.IMyInterface value) +{ + AddMyName (value, null); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerProperty.txt new file mode 100644 index 00000000000..e263eb3c6b4 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceListenerProperty.txt @@ -0,0 +1,15 @@ +public MyFullDelegateName MyName { + get { + java.code.IMyInterfaceImplementor impl = ImplMyName; + return impl == null ? null : impl.MyMethodNameHandler; + } + set { + java.code.IMyInterfaceImplementor impl = ImplMyName; + if (impl == null) { + impl = new java.code.IMyInterfaceImplementor (this); + ImplMyName = impl; + } else + impl.MyNameSpecHandler = value; + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokers.txt new file mode 100644 index 00000000000..e85b4961b1b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokers.txt @@ -0,0 +1,79 @@ +static Delegate cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate GetGetCountForKey_Ljava_lang_String_Handler () +{ + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; +} + +static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; +} +#pragma warning restore 0169 + +IntPtr id_GetCountForKey_Ljava_lang_String_; +public unsafe int GetCountForKey (string key) +{ + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString ((string)key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; +} + +static Delegate cb_Key; +#pragma warning disable 0169 +static Delegate GetKeyHandler () +{ + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; +} + +static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); +} +#pragma warning restore 0169 + +IntPtr id_Key; +public unsafe string Key () +{ + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); +} + +static Delegate cb_AbstractMethod; +#pragma warning disable 0169 +static Delegate GetAbstractMethodHandler () +{ + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; +} + +static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); +} +#pragma warning restore 0169 + +IntPtr id_AbstractMethod; +public unsafe void AbstractMethod () +{ + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokersWithSkips.txt new file mode 100644 index 00000000000..e85b4961b1b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethodInvokersWithSkips.txt @@ -0,0 +1,79 @@ +static Delegate cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate GetGetCountForKey_Ljava_lang_String_Handler () +{ + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; +} + +static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; +} +#pragma warning restore 0169 + +IntPtr id_GetCountForKey_Ljava_lang_String_; +public unsafe int GetCountForKey (string key) +{ + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString ((string)key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; +} + +static Delegate cb_Key; +#pragma warning disable 0169 +static Delegate GetKeyHandler () +{ + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; +} + +static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); +} +#pragma warning restore 0169 + +IntPtr id_Key; +public unsafe string Key () +{ + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); +} + +static Delegate cb_AbstractMethod; +#pragma warning disable 0169 +static Delegate GetAbstractMethodHandler () +{ + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; +} + +static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); +} +#pragma warning restore 0169 + +IntPtr id_AbstractMethod; +public unsafe void AbstractMethod () +{ + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethods.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethods.txt new file mode 100644 index 00000000000..9c0ea6c9813 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceMethods.txt @@ -0,0 +1,12 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] +int GetCountForKey (string key); + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='Key' and count(parameter)=0]" +[Register ("Key", "()Ljava/lang/String;", "GetKeyHandler:java.code.IMyInterfaceInvoker, ")] +string Key (); + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler:java.code.IMyInterfaceInvoker, ")] +void AbstractMethod (); + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceProperties.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceProperties.txt new file mode 100644 index 00000000000..4c99ec98122 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceProperties.txt @@ -0,0 +1,21 @@ +int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler:java.code.IMyInterfaceInvoker, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler:java.code.IMyInterfaceInvoker, ")] set; +} + +string Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler:java.code.IMyInterfaceInvoker, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] set; +} + +int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler:java.code.IMyInterfaceInvoker, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler:java.code.IMyInterfaceInvoker, ")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokers.txt new file mode 100644 index 00000000000..689362c1c7d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokers.txt @@ -0,0 +1,199 @@ +static Delegate cb_get_Count; +#pragma warning disable 0169 +static Delegate Getget_CountHandler () +{ + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; +} + +static int n_get_Count (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Count; +} +#pragma warning restore 0169 + +static Delegate cb_set_Count_I; +#pragma warning disable 0169 +static Delegate Getset_Count_IHandler () +{ + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; +} + +static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Count = value; +} +#pragma warning restore 0169 + +IntPtr id_get_Count; +IntPtr id_set_Count_I; +public unsafe int Count { + get { + if (id_get_Count == IntPtr.Zero) + id_get_Count = JNIEnv.GetMethodID (class_ref, "get_Count", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_Count); + } + set { + if (id_set_Count_I == IntPtr.Zero) + id_set_Count_I = JNIEnv.GetMethodID (class_ref, "set_Count", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Count_I, __args); + } +} + +static Delegate cb_get_Key; +#pragma warning disable 0169 +static Delegate Getget_KeyHandler () +{ + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; +} + +static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); +} +#pragma warning restore 0169 + +static Delegate cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate Getset_Key_Ljava_lang_String_Handler () +{ + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; +} + +static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; +} +#pragma warning restore 0169 + +IntPtr id_get_Key; +IntPtr id_set_Key_Ljava_lang_String_; +public unsafe string Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString ((string)value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } +} + +static Delegate cb_get_StaticCount; +#pragma warning disable 0169 +static Delegate Getget_StaticCountHandler () +{ + if (cb_get_StaticCount == null) + cb_get_StaticCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_StaticCount); + return cb_get_StaticCount; +} + +static int n_get_StaticCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.StaticCount; +} +#pragma warning restore 0169 + +static Delegate cb_set_StaticCount_I; +#pragma warning disable 0169 +static Delegate Getset_StaticCount_IHandler () +{ + if (cb_set_StaticCount_I == null) + cb_set_StaticCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_StaticCount_I); + return cb_set_StaticCount_I; +} + +static void n_set_StaticCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.StaticCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_StaticCount; +IntPtr id_set_StaticCount_I; +public unsafe int StaticCount { + get { + if (id_get_StaticCount == IntPtr.Zero) + id_get_StaticCount = JNIEnv.GetMethodID (class_ref, "get_StaticCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_StaticCount); + } + set { + if (id_set_StaticCount_I == IntPtr.Zero) + id_set_StaticCount_I = JNIEnv.GetMethodID (class_ref, "set_StaticCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_StaticCount_I, __args); + } +} + +static Delegate cb_get_AbstractCount; +#pragma warning disable 0169 +static Delegate Getget_AbstractCountHandler () +{ + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; +} + +static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; +} +#pragma warning restore 0169 + +static Delegate cb_set_AbstractCount_I; +#pragma warning disable 0169 +static Delegate Getset_AbstractCount_IHandler () +{ + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; +} + +static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_AbstractCount; +IntPtr id_set_AbstractCount_I; +public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokersWithSkips.txt new file mode 100644 index 00000000000..62e5a00ed20 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfacePropertyInvokersWithSkips.txt @@ -0,0 +1,150 @@ +static Delegate cb_get_Key; +#pragma warning disable 0169 +static Delegate Getget_KeyHandler () +{ + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; +} + +static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); +} +#pragma warning restore 0169 + +static Delegate cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate Getset_Key_Ljava_lang_String_Handler () +{ + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; +} + +static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; +} +#pragma warning restore 0169 + +IntPtr id_get_Key; +IntPtr id_set_Key_Ljava_lang_String_; +public unsafe string Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString ((string)value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } +} + +static Delegate cb_get_StaticCount; +#pragma warning disable 0169 +static Delegate Getget_StaticCountHandler () +{ + if (cb_get_StaticCount == null) + cb_get_StaticCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_StaticCount); + return cb_get_StaticCount; +} + +static int n_get_StaticCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.StaticCount; +} +#pragma warning restore 0169 + +static Delegate cb_set_StaticCount_I; +#pragma warning disable 0169 +static Delegate Getset_StaticCount_IHandler () +{ + if (cb_set_StaticCount_I == null) + cb_set_StaticCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_StaticCount_I); + return cb_set_StaticCount_I; +} + +static void n_set_StaticCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.StaticCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_StaticCount; +IntPtr id_set_StaticCount_I; +public unsafe int StaticCount { + get { + if (id_get_StaticCount == IntPtr.Zero) + id_get_StaticCount = JNIEnv.GetMethodID (class_ref, "get_StaticCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_StaticCount); + } + set { + if (id_set_StaticCount_I == IntPtr.Zero) + id_set_StaticCount_I = JNIEnv.GetMethodID (class_ref, "set_StaticCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_StaticCount_I, __args); + } +} + +static Delegate cb_get_AbstractCount; +#pragma warning disable 0169 +static Delegate Getget_AbstractCountHandler () +{ + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; +} + +static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; +} +#pragma warning restore 0169 + +static Delegate cb_set_AbstractCount_I; +#pragma warning disable 0169 +static Delegate Getset_AbstractCount_IHandler () +{ + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; +} + +static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_AbstractCount; +IntPtr id_set_AbstractCount_I; +public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceRedeclaredDefaultMethod.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceRedeclaredDefaultMethod.txt new file mode 100644 index 00000000000..a0888458ac6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteInterfaceRedeclaredDefaultMethod.txt @@ -0,0 +1,97 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface2']" +[Register ("java/code/IMyInterface2", "", "java.code.IMyInterface2Invoker")] +public partial interface IMyInterface2 : java.code.IMyInterface { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "GetDoSomethingHandler:java.code.IMyInterface2Invoker, MyAssembly")] + void DoSomething (); + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface2", DoNotGenerateAcw=true)] +internal partial class IMyInterface2Invoker : global::Java.Lang.Object, IMyInterface2 { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface2", typeof (IMyInterface2Invoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface2 GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface2'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterface2Invoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_DoSomething_DoSomething_V; +#pragma warning disable 0169 + static Delegate GetDoSomethingHandler () + { + return cb_DoSomething_DoSomething_V ??= new _JniMarshal_PP_V (n_DoSomething); + } + + [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] + static void n_DoSomething (IntPtr jnienv, IntPtr native__this) + { + if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) + return; + + try { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoSomething (); + } catch (global::System.Exception __e) { + __r.OnUserUnhandledException (ref __envp, __e); + } finally { + global::Java.Interop.JniEnvironment.EndMarshalMethod (ref __envp); + } + } +#pragma warning restore 0169 + + IntPtr id_DoSomething; + public unsafe void DoSomething () + { + if (id_DoSomething == IntPtr.Zero) + id_DoSomething = JNIEnv.GetMethodID (class_ref, "DoSomething", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_DoSomething); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/ObsoleteInterfaceAlternativeClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/ObsoleteInterfaceAlternativeClass.txt new file mode 100644 index 00000000000..f7419581f69 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/ObsoleteInterfaceAlternativeClass.txt @@ -0,0 +1,169 @@ +[Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +[global::System.Obsolete ("Use the 'Com.Xamarin.Android.IParent' type. This class will be removed in a future release.")] +public abstract class Parent : Java.Lang.Object { + internal Parent () + { + } + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ACCEPT_HANDOVER']" + [Register ("ACCEPT_HANDOVER")] + [Obsolete ("Use 'Com.Xamarin.Android.IParent.AcceptHandover'. This class will be removed in a future release.")] + public const string AcceptHandover = (string) "android.permission.ACCEPT_HANDOVER"; + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ALREADY_OBSOLETE']" + [Register ("ALREADY_OBSOLETE")] + [Obsolete ("deprecated")] + public const string AlreadyObsolete = (string) "android.permission.ACCEPT_HANDOVER"; + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='API_NAME']" + [Register ("API_NAME")] + [Obsolete ("Use 'Com.Xamarin.Android.IParent.ApiName'. This class will be removed in a future release.")] + public static string ApiName { + get { + const string __id = "API_NAME.Ljava/lang/String;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparing' and count(parameter)=0]" + [Obsolete (@"Use 'Com.Xamarin.Android.IParent.Comparing'. This class will be removed in a future release.")] + [Register ("comparing", "()I", "")] + public static unsafe int Comparing () + { + const string __id = "comparing.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparingOld' and count(parameter)=0]" + [Obsolete (@"deprecated")] + [Register ("comparingOld", "()I", "")] + public static unsafe int ComparingOld () + { + const string __id = "comparingOld.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (Parent)); + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (IParent), isInterface: true); + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ACCEPT_HANDOVER']" + [Register ("ACCEPT_HANDOVER")] + public const string AcceptHandover = (string) "android.permission.ACCEPT_HANDOVER"; + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ALREADY_OBSOLETE']" + [Register ("ALREADY_OBSOLETE")] + [Obsolete ("deprecated")] + public const string AlreadyObsolete = (string) "android.permission.ACCEPT_HANDOVER"; + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='API_NAME']" + [Register ("API_NAME")] + public static string ApiName { + get { + const string __id = "API_NAME.Ljava/lang/String;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparing' and count(parameter)=0]" + [Register ("comparing", "()I", "")] + public static unsafe int Comparing () + { + const string __id = "comparing.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparingOld' and count(parameter)=0]" + [Obsolete (@"deprecated")] + [Register ("comparingOld", "()I", "")] + public static unsafe int ComparingOld () + { + const string __id = "comparingOld.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCharSequenceEnumerator.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCharSequenceEnumerator.txt new file mode 100644 index 00000000000..0a27a4a22b7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCharSequenceEnumerator.txt @@ -0,0 +1,11 @@ +System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () +{ + return GetEnumerator (); +} + +public System.Collections.Generic.IEnumerator GetEnumerator () +{ + for (int i = 0; i < Length(); i++) + yield return CharAt (i); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClass.txt new file mode 100644 index 00000000000..9366fc206c3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClass.txt @@ -0,0 +1,168 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Java.Interop.JniTypeSignature ("java/code/MyClass", GenerateJavaPeer=false)] +public partial class MyClass { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + unsafe MyClass () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [global::Java.Interop.JniConstructorSignature ("(Ljava/lang/String;)V")] + unsafe MyClass (string? p0) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "(Ljava/lang/String;)V"; + + if (PeerReference.IsValid) + return; + + var native_p0 = global::Java.Interop.JniEnvironment.Strings.NewString (p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_p0); + } + } + + public virtual unsafe int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Count' and count(parameter)=0]" + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + } + + public virtual unsafe string? Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Key' and count(parameter)=0]" + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_value); + } + } + } + + public static unsafe int StaticCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_StaticCount' and count(parameter)=0]" + get { + const string __id = "get_StaticCount.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]" + set { + const string __id = "set_StaticCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + + public abstract int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("get_AbstractCount", "()I")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("set_AbstractCount", "(I)V")] + set; + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [global::Java.Interop.JniMethodSignature ("GetCountForKey", "(Ljava/lang/String;)I")] + public virtual unsafe int GetCountForKey (string? key) + { + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + var native_key = global::Java.Interop.JniEnvironment.Strings.NewString (key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_key); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Key' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("Key", "()Ljava/lang/String;")] + public virtual unsafe string? Key () + { + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='StaticMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("StaticMethod", "()V")] + public static unsafe void StaticMethod () + { + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" + public abstract void AbstractMethod (); + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassAbstractMembers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassAbstractMembers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassConstructors.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassConstructors.txt new file mode 100644 index 00000000000..3fc335908ca --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassConstructors.txt @@ -0,0 +1,42 @@ +protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + +// Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=0]" +[Register (".ctor", "()V", "")] + unsafe MyClass () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + +// Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register (".ctor", "(Ljava/lang/String;)V", "")] + unsafe MyClass (string p0) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/String;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_p0 = JNIEnv.NewString (p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassHandle.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassHandle.txt new file mode 100644 index 00000000000..00904b6f310 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassHandle.txt @@ -0,0 +1,7 @@ + static readonly JniPeerMembers _members = new JniPeerMembers ("com/mypackage/foo", typeof (foo)); + internal static IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvoker.txt new file mode 100644 index 00000000000..8d5aaa684e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvoker.txt @@ -0,0 +1,52 @@ +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +internal partial class MyClassInvoker : MyClass { + + public MyClassInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) {} + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClassInvoker)); + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" + [Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] + public override unsafe void AbstractMethod () + { + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvokerHandle.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvokerHandle.txt new file mode 100644 index 00000000000..5c1d16c85fa --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvokerHandle.txt @@ -0,0 +1,10 @@ +static readonly JniPeerMembers _members = new JniPeerMembers ("com/mypackage/foo", typeof (Com.MyPackage.Foo)); + +public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } +} + +protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvokerMembers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvokerMembers.txt new file mode 100644 index 00000000000..98bc27c15f0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassInvokerMembers.txt @@ -0,0 +1,35 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethodInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethodInvokers.txt new file mode 100644 index 00000000000..7fec3768027 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethodInvokers.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethodInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethodInvokersWithSkips.txt new file mode 100644 index 00000000000..7fec3768027 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethodInvokersWithSkips.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethods.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethods.txt new file mode 100644 index 00000000000..f054a3b8116 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassMethods.txt @@ -0,0 +1,93 @@ +static Delegate cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate GetGetCountForKey_Ljava_lang_String_Handler () +{ + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; +} + +static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler")] +public virtual unsafe int GetCountForKey (string key) +{ + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + IntPtr native_key = JNIEnv.NewString (key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_key); + } +} + +static Delegate cb_Key; +#pragma warning disable 0169 +static Delegate GetKeyHandler () +{ + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; +} + +static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Key' and count(parameter)=0]" +[Register ("Key", "()Ljava/lang/String;", "GetKeyHandler")] +public virtual unsafe string Key () +{ + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } +} + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='StaticMethod' and count(parameter)=0]" +[Register ("StaticMethod", "()V", "")] +public static unsafe void StaticMethod () +{ + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } +} + +static Delegate cb_AbstractMethod; +#pragma warning disable 0169 +static Delegate GetAbstractMethodHandler () +{ + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; +} + +static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public abstract void AbstractMethod (); + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassProperties.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassProperties.txt new file mode 100644 index 00000000000..6801b7f3978 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassProperties.txt @@ -0,0 +1,178 @@ +static Delegate cb_get_Count; +#pragma warning disable 0169 +static Delegate Getget_CountHandler () +{ + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; +} + +static int n_get_Count (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Count; +} +#pragma warning restore 0169 + +static Delegate cb_set_Count_I; +#pragma warning disable 0169 +static Delegate Getset_Count_IHandler () +{ + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; +} + +static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Count = value; +} +#pragma warning restore 0169 + +public virtual unsafe int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler")] + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler")] + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } +} + +static Delegate cb_get_Key; +#pragma warning disable 0169 +static Delegate Getget_KeyHandler () +{ + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; +} + +static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); +} +#pragma warning restore 0169 + +static Delegate cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate Getset_Key_Ljava_lang_String_Handler () +{ + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; +} + +static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; +} +#pragma warning restore 0169 + +public virtual unsafe string Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler")] + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler")] + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} + +public static unsafe int StaticCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_StaticCount' and count(parameter)=0]" + [Register ("get_StaticCount", "()I", "")] + get { + const string __id = "get_StaticCount.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_StaticCount", "(I)V", "")] + set { + const string __id = "set_StaticCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } +} + +static Delegate cb_get_AbstractCount; +#pragma warning disable 0169 +static Delegate Getget_AbstractCountHandler () +{ + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; +} + +static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; +} +#pragma warning restore 0169 + +static Delegate cb_set_AbstractCount_I; +#pragma warning disable 0169 +static Delegate Getset_AbstractCount_IHandler () +{ + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; +} + +static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; +} +#pragma warning restore 0169 + +public abstract int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassPropertyInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassPropertyInvokers.txt new file mode 100644 index 00000000000..55d7c1ca13e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassPropertyInvokers.txt @@ -0,0 +1,24 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassPropertyInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassPropertyInvokersWithSkips.txt new file mode 100644 index 00000000000..55d7c1ca13e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClassPropertyInvokersWithSkips.txt @@ -0,0 +1,24 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtor.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtor.txt new file mode 100644 index 00000000000..238012f4de2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtor.txt @@ -0,0 +1,18 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=0]" +[Register (".ctor", "", "")] + unsafe Object () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = ""; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtorDeprecated.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtorDeprecated.txt new file mode 100644 index 00000000000..159077c9b6b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtorDeprecated.txt @@ -0,0 +1,21 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=0]" +[Register (".ctor", "", "")] +[Obsolete (@"This constructor is obsolete")] +[MyAttribute] +[global::Android.Runtime.IntDefinition (null, JniField = "xamarin/test/SomeObject.SOME_VALUE")] + unsafe Object () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = ""; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtorWithStringOverload.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtorWithStringOverload.txt new file mode 100644 index 00000000000..eef2acbb8e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteCtorWithStringOverload.txt @@ -0,0 +1,43 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" +[Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + unsafe Object (Java.Lang.ICharSequence mystring) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_mystring = CharSequence.ToLocalJniHandle (mystring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_mystring); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_mystring); + } +} + +[Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + unsafe Object (string mystring) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_mystring = CharSequence.ToLocalJniHandle (mystring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_mystring); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_mystring); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDefaultInterfaceMethodInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDefaultInterfaceMethodInvoker.txt new file mode 100644 index 00000000000..dd52db14e8f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDefaultInterfaceMethodInvoker.txt @@ -0,0 +1,118 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoDeclaration' and count(parameter)=0]" + [Register ("DoDeclaration", "()V", "GetDoDeclarationHandler:java.code.IMyInterfaceInvoker, MyAssembly")] + void DoDeclaration (); + + private static Delegate cb_DoDefault; +#pragma warning disable 0169 + private static Delegate GetDoDefaultHandler () + { + if (cb_DoDefault == null) + cb_DoDefault = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_DoDefault); + return cb_DoDefault; + } + + private static void n_DoDefault (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoDefault (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoDefault' and count(parameter)=0]" + [Register ("DoDefault", "()V", "GetDoDefaultHandler:java.code.IMyInterface, MyAssembly")] + virtual unsafe void DoDefault () + { + const string __id = "DoDefault.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_DoDeclaration; +#pragma warning disable 0169 + static Delegate GetDoDeclarationHandler () + { + if (cb_DoDeclaration == null) + cb_DoDeclaration = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_DoDeclaration); + return cb_DoDeclaration; + } + + static void n_DoDeclaration (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoDeclaration (); + } +#pragma warning restore 0169 + + IntPtr id_DoDeclaration; + public unsafe void DoDeclaration () + { + if (id_DoDeclaration == IntPtr.Zero) + id_DoDeclaration = JNIEnv.GetMethodID (class_ref, "DoDeclaration", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_DoDeclaration); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDuplicateInterfaceEventArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDuplicateInterfaceEventArgs.txt new file mode 100644 index 00000000000..221e111c87b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteDuplicateInterfaceEventArgs.txt @@ -0,0 +1,140 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']" +[global::Java.Interop.JniTypeSignature ("java/code/AnimatorListener", GenerateJavaPeer=false, InvokerType=typeof (java.code.AnimatorListenerInvoker))] +public partial interface AnimatorListener : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']/method[@name='OnAnimationEnd' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("OnAnimationEnd", "(I)Z")] + bool OnAnimationEnd (int param1); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']/method[@name='OnAnimationEnd' and count(parameter)=2 and parameter[1][@type='int'] and parameter[2][@type='int']]" + [global::Java.Interop.JniMethodSignature ("OnAnimationEnd", "(II)Z")] + bool OnAnimationEnd (int param1, int param2); + +} + +[global::Java.Interop.JniTypeSignature ("java/code/AnimatorListener", GenerateJavaPeer=false)] +internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, AnimatorListener { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_code_AnimatorListener; } + } + + static readonly JniPeerMembers _members_java_code_AnimatorListener = new JniPeerMembers ("java/code/AnimatorListener", typeof (AnimatorListenerInvoker)); + + public AnimatorListenerInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool OnAnimationEnd (int param1) + { + const string __id = "OnAnimationEnd.(I)Z"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (param1); + var __rm = _members_java_code_AnimatorListener.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + } + } + + public unsafe bool OnAnimationEnd (int param1, int param2) + { + const string __id = "OnAnimationEnd.(II)Z"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [2]; + __args [0] = new JniArgumentValue (param1); + __args [1] = new JniArgumentValue (param2); + var __rm = _members_java_code_AnimatorListener.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + } + } + +} + +// event args for java.code.AnimatorListener.OnAnimationEnd +public partial class AnimationEndEventArgs : global::System.EventArgs { + bool handled; + + public bool Handled { + get { return handled; } + set { handled = value; } + } + + public AnimationEndEventArgs (bool handled, int param1) + { + this.handled = handled; + this.param1 = param1; + } + + int param1; + + public int Param1 { + get { return param1; } + } + + public AnimationEndEventArgs (bool handled, int param1, int param2) + { + this.handled = handled; + this.param1 = param1; + this.param2 = param2; + } + + int param2; + + public int Param2 { + get { return param2; } + } + +} + +[global::Android.Runtime.Register ("mono/java/code/AnimatorListenerImplementor")] +internal sealed partial class AnimatorListenerImplementor : global::Java.Lang.Object, AnimatorListener { + + object? sender; + + public unsafe AnimatorListenerImplementor (object sender) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + var h = JniPeerMembers.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (h.Handle, JniHandleOwnership.TransferLocalRef); + JniPeerMembers.InstanceMethods.FinishCreateInstance (__id, this, null); + this.sender = sender; + } + + #pragma warning disable 0649 + public EventHandler? OnAnimationEndHandler; + #pragma warning restore 0649 + + public bool OnAnimationEnd (int param1) + { + var __h = OnAnimationEndHandler; + if (__h == null) + return false; + var __e = new AnimationEndEventArgs (true, param1); + __h (sender, __e); + return __e.Handled; + } + + #pragma warning disable 0649 + public EventHandler? OnAnimationEndHandler; + #pragma warning restore 0649 + + public bool OnAnimationEnd (int param1, int param2) + { + var __h = OnAnimationEndHandler; + if (__h == null) + return false; + var __e = new AnimationEndEventArgs (true, param1, param2); + __h (sender, __e); + return __e.Handled; + } + + internal static bool __IsEmpty (AnimatorListenerImplementor value) + { + return value.OnAnimationEndHandler == null && value.OnAnimationEndHandler == null; + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstant.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstant.txt new file mode 100644 index 00000000000..73ac8ae2c10 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstant.txt @@ -0,0 +1,11 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public static string bar { + get { + const string __id = "bar.Ljava/lang/String;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstantWithIntValue.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstantWithIntValue.txt new file mode 100644 index 00000000000..a1f3257f0d2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstantWithIntValue.txt @@ -0,0 +1,3 @@ +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public const int bar = (int) 1234; diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstantWithStringValue.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstantWithStringValue.txt new file mode 100644 index 00000000000..1e7186b009f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldConstantWithStringValue.txt @@ -0,0 +1,3 @@ +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public const string bar = (string) "hello"; diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldGetBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldGetBody.txt new file mode 100644 index 00000000000..44cde23dc2f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldGetBody.txt @@ -0,0 +1,4 @@ +const string __id = "bar.Ljava/lang/String;"; + +var __v = _members.InstanceFields.GetObjectValue (__id, this); +return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldIdField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldIdField.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldInt.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldInt.txt new file mode 100644 index 00000000000..d1a71f54efe --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldInt.txt @@ -0,0 +1,19 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public int bar { + get { + const string __id = "bar.I"; + + var __v = _members.InstanceFields.GetInt32Value (__id, this); + return __v; + } + set { + const string __id = "bar.I"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldSetBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldSetBody.txt new file mode 100644 index 00000000000..77008f500d8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldSetBody.txt @@ -0,0 +1,8 @@ +const string __id = "bar.Ljava/lang/String;"; + +IntPtr native_value = JNIEnv.NewString (value); +try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); +} finally { + JNIEnv.DeleteLocalRef (native_value); +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldString.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldString.txt new file mode 100644 index 00000000000..71301606891 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteFieldString.txt @@ -0,0 +1,21 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public string bar { + get { + const string __id = "bar.Ljava/lang/String;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "bar.Ljava/lang/String;"; + + IntPtr native_value = JNIEnv.NewString (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterface.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterface.txt new file mode 100644 index 00000000000..5df892f297a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterface.txt @@ -0,0 +1,192 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[global::Java.Interop.JniTypeSignature ("java/code/IMyInterface", GenerateJavaPeer=false, InvokerType=typeof (java.code.IMyInterfaceInvoker))] +public partial interface IMyInterface : IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Count' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("get_Count", "()I")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("set_Count", "(I)V")] + set; + } + + string? Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Key' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("get_Key", "()Ljava/lang/String;")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [global::Java.Interop.JniMethodSignature ("set_Key", "(Ljava/lang/String;)V")] + set; + } + + int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_AbstractCount' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("get_AbstractCount", "()I")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("set_AbstractCount", "(I)V")] + set; + } + + static unsafe int StaticCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_StaticCount' and count(parameter)=0]" + get { + const string __id = "get_StaticCount.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]" + set { + const string __id = "set_StaticCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [global::Java.Interop.JniMethodSignature ("GetCountForKey", "(Ljava/lang/String;)I")] + int GetCountForKey (string? key); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='Key' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("Key", "()Ljava/lang/String;")] + string? Key (); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='AbstractMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("AbstractMethod", "()V")] + void AbstractMethod (); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='StaticMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("StaticMethod", "()V")] + public static unsafe void StaticMethod () + { + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + +} + +[global::Java.Interop.JniTypeSignature ("java/code/IMyInterface", GenerateJavaPeer=false)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_code_IMyInterface; } + } + + static readonly JniPeerMembers _members_java_code_IMyInterface = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + public IMyInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe int Count { + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe string? Key { + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_value); + } + } + } + + public unsafe int AbstractCount { + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members_java_code_IMyInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe int GetCountForKey (string? key) + { + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + var native_key = global::Java.Interop.JniEnvironment.Strings.NewString (key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_key); + } + } + + public unsafe string? Key () + { + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members_java_code_IMyInterface.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + public unsafe void AbstractMethod () + { + const string __id = "AbstractMethod.()V"; + try { + _members_java_code_IMyInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultMethod.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultMethod.txt new file mode 100644 index 00000000000..0519e02e94f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultMethod.txt @@ -0,0 +1,90 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + private static Delegate cb_DoSomething; +#pragma warning disable 0169 + private static Delegate GetDoSomethingHandler () + { + if (cb_DoSomething == null) + cb_DoSomething = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_DoSomething); + return cb_DoSomething; + } + + private static void n_DoSomething (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoSomething (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "GetDoSomethingHandler:java.code.IMyInterface, MyAssembly")] + virtual unsafe void DoSomething () + { + const string __id = "DoSomething.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultProperty.txt new file mode 100644 index 00000000000..86dc61b0306 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultProperty.txt @@ -0,0 +1,119 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + private static Delegate cb_get_Value; +#pragma warning disable 0169 + private static Delegate Getget_ValueHandler () + { + if (cb_get_Value == null) + cb_get_Value = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Value); + return cb_get_Value; + } + + private static int n_get_Value (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Value; + } +#pragma warning restore 0169 + + private static Delegate cb_set_Value_I; +#pragma warning disable 0169 + private static Delegate Getset_Value_IHandler () + { + if (cb_set_Value_I == null) + cb_set_Value_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Value_I); + return cb_set_Value_I; + } + + private static void n_set_Value_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Value = value; + } +#pragma warning restore 0169 + + virtual unsafe int Value { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Value' and count(parameter)=0]" + [Register ("get_Value", "()I", "Getget_ValueHandler:java.code.IMyInterface, MyAssembly")] + get { + const string __id = "get_Value.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Value' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Value", "(I)V", "Getset_Value_IHandler:java.code.IMyInterface, MyAssembly")] + set { + const string __id = "set_Value.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultPropertyGetterOnly.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultPropertyGetterOnly.txt new file mode 100644 index 00000000000..06c67141833 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceDefaultPropertyGetterOnly.txt @@ -0,0 +1,92 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + private static Delegate cb_get_Value; +#pragma warning disable 0169 + private static Delegate Getget_ValueHandler () + { + if (cb_get_Value == null) + cb_get_Value = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Value); + return cb_get_Value; + } + + private static int n_get_Value (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Value; + } +#pragma warning restore 0169 + + virtual unsafe int Value { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Value' and count(parameter)=0]" + [Register ("get_Value", "()I", "Getget_ValueHandler:java.code.IMyInterface, MyAssembly")] + get { + const string __id = "get_Value.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventArgs.txt new file mode 100644 index 00000000000..b184c765c4f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventArgs.txt @@ -0,0 +1,2 @@ +public delegate int MyIGetCountForKeyHandler (string? key); + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventArgsWithParamArray.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventArgsWithParamArray.txt new file mode 100644 index 00000000000..66e970b19d1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventArgsWithParamArray.txt @@ -0,0 +1,14 @@ +// event args for com.xamarin.android.MyListener.onDoSomething +public partial class MyEventArgs : global::System.EventArgs { + + public MyEventArgs (params Java.Lang.Object[]? args) + { + this.args = args; + } + + Java.Lang.Object[]? args; + public Java.Lang.Object[]? Args { + get { return args; } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandler.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandler.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandlerImpl.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandlerImpl.txt new file mode 100644 index 00000000000..e89b3987885 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandlerImpl.txt @@ -0,0 +1,59 @@ +[global::Android.Runtime.Register ("mono/java/code/IMyInterfaceImplementor")] +internal sealed partial class IMyInterfaceImplementor : global::Java.Lang.Object, IMyInterface { + + object sender; + + public IMyInterfaceImplementor (object sender) + : base ( + global::Android.Runtime.JNIEnv.StartCreateInstance ("mono/java/code/IMyInterfaceImplementor", "()V"), + JniHandleOwnership.TransferLocalRef) + { + global::Android.Runtime.JNIEnv.FinishCreateInstance (this.PeerReference, "()V"); + this.sender = sender; + } + +#pragma warning disable 0649 + public MyIGetCountForKeyHandler? GetCountForKeyHandler; +#pragma warning restore 0649 + + public int GetCountForKey (string? key) + { + var __h = GetCountForKeyHandler; + return __h != null ? __h (key) : default (int); + } +#pragma warning disable 0649 + public MyIKeyHandler? KeyHandler; +#pragma warning restore 0649 + + public string? Key () + { + var __h = KeyHandler; + return __h != null ? __h () : default (string?); + } +#pragma warning disable 0649 + public EventHandler? StaticMethodHandler; +#pragma warning restore 0649 + + public void StaticMethod () + { + var __h = StaticMethodHandler; + if (__h != null) + __h (sender, new EventArgs ()); + } +#pragma warning disable 0649 + public EventHandler? AbstractMethodHandler; +#pragma warning restore 0649 + + public void AbstractMethod () + { + var __h = AbstractMethodHandler; + if (__h != null) + __h (sender, new EventArgs ()); + } + + internal static bool __IsEmpty (IMyInterfaceImplementor value) + { + return value.GetCountForKeyHandler == null && value.KeyHandler == null && value.StaticMethodHandler == null && value.AbstractMethodHandler == null; + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandlerImplContent.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandlerImplContent.txt new file mode 100644 index 00000000000..e6011b413b9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceEventHandlerImplContent.txt @@ -0,0 +1,9 @@ +#pragma warning disable 0649 + public MyIGetCountForKeyHandler? GetCountForKeyHandler; +#pragma warning restore 0649 + + public int GetCountForKey (string? key) + { + var __h = GetCountForKeyHandler; + return __h != null ? __h (key) : default (int); + } diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceExtensionMethods.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceExtensionMethods.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceFieldAsDimProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceFieldAsDimProperty.txt new file mode 100644 index 00000000000..567ac0ad29e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceFieldAsDimProperty.txt @@ -0,0 +1,126 @@ +[Register ("com/xamarin/android/MyInterface", DoNotGenerateAcw=true)] +public abstract class MyInterface : Java.Lang.Object { + internal MyInterface () + { + } + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']/field[@name='EGL_NATIVE_VISUAL_ID']" + [Register ("EGL_NATIVE_VISUAL_ID")] + public const int EglNativeVisualId = (int) 12334; + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']/field[@name='EGL_NO_SURFACE']" + [Register ("EGL_NO_SURFACE")] + public static int EglNoSurface { + get { + const string __id = "EGL_NO_SURFACE.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + set { + const string __id = "EGL_NO_SURFACE.I"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/MyInterface", typeof (MyInterface)); + +} + +[Register ("com/xamarin/android/MyInterface", DoNotGenerateAcw=true)] +[global::System.Obsolete ("Use the 'MyInterface' type. This type will be removed in a future release.", error: true)] +public abstract class MyInterfaceConsts : MyInterface { + private MyInterfaceConsts () + { + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']" +[Register ("com/xamarin/android/MyInterface", "", "Com.Xamarin.Android.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/MyInterface", typeof (IMyInterface), isInterface: true); + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']/field[@name='EGL_NO_SURFACE']" + [Register ("EGL_NO_SURFACE")] + public static int EglNoSurface { + get { + const string __id = "EGL_NO_SURFACE.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + set { + const string __id = "EGL_NO_SURFACE.I"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/MyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/MyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.MyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceFields.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceFields.txt new file mode 100644 index 00000000000..25ae46f12a1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceFields.txt @@ -0,0 +1,14 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyConstantField']" + [Register ("MyConstantField")] + public const int MyConstantField = (int) 7; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "GetDoSomethingHandler:java.code.IMyInterfaceInvoker, ")] + void DoSomething (); + +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceInvoker.txt new file mode 100644 index 00000000000..e17cd33786e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceInvoker.txt @@ -0,0 +1,282 @@ +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.", + JNIEnv.GetClassNameFromInstance (handle), "java.code.IMyInterface")); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_get_Count; +#pragma warning disable 0169 + static Delegate Getget_CountHandler () + { + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; + } + + static int n_get_Count (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Count; + } +#pragma warning restore 0169 + + static Delegate cb_set_Count_I; +#pragma warning disable 0169 + static Delegate Getset_Count_IHandler () + { + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; + } + + static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Count = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Count; + IntPtr id_set_Count_I; + public unsafe int Count { + get { + if (id_get_Count == IntPtr.Zero) + id_get_Count = JNIEnv.GetMethodID (class_ref, "get_Count", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_Count); + } + set { + if (id_set_Count_I == IntPtr.Zero) + id_set_Count_I = JNIEnv.GetMethodID (class_ref, "set_Count", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Count_I, __args); + } + } + + static Delegate cb_get_Key; +#pragma warning disable 0169 + static Delegate Getget_KeyHandler () + { + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; + } + + static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); + } +#pragma warning restore 0169 + + static Delegate cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate Getset_Key_Ljava_lang_String_Handler () + { + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; + } + + static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Key; + IntPtr id_set_Key_Ljava_lang_String_; + public unsafe string Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } + } + + static Delegate cb_get_AbstractCount; +#pragma warning disable 0169 + static Delegate Getget_AbstractCountHandler () + { + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; + } + + static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; + } +#pragma warning restore 0169 + + static Delegate cb_set_AbstractCount_I; +#pragma warning disable 0169 + static Delegate Getset_AbstractCount_IHandler () + { + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; + } + + static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; + } +#pragma warning restore 0169 + + IntPtr id_get_AbstractCount; + IntPtr id_set_AbstractCount_I; + public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } + } + + static Delegate cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetGetCountForKey_Ljava_lang_String_Handler () + { + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; + } + + static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; + } +#pragma warning restore 0169 + + IntPtr id_GetCountForKey_Ljava_lang_String_; + public unsafe int GetCountForKey (string key) + { + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString (key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; + } + + static Delegate cb_Key; +#pragma warning disable 0169 + static Delegate GetKeyHandler () + { + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; + } + + static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); + } +#pragma warning restore 0169 + + IntPtr id_Key; + public unsafe string Key () + { + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); + } + + static Delegate cb_AbstractMethod; +#pragma warning disable 0169 + static Delegate GetAbstractMethodHandler () + { + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; + } + + static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); + } +#pragma warning restore 0169 + + IntPtr id_AbstractMethod; + public unsafe void AbstractMethod () + { + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); + } + +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceRedeclaredDefaultMethod.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceRedeclaredDefaultMethod.txt new file mode 100644 index 00000000000..e9c2e38cb81 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteInterfaceRedeclaredDefaultMethod.txt @@ -0,0 +1,89 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface2']" +[Register ("java/code/IMyInterface2", "", "java.code.IMyInterface2Invoker")] +public partial interface IMyInterface2 : java.code.IMyInterface { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "GetDoSomethingHandler:java.code.IMyInterface2Invoker, MyAssembly")] + void DoSomething (); + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface2", DoNotGenerateAcw=true)] +internal partial class IMyInterface2Invoker : global::Java.Lang.Object, IMyInterface2 { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface2", typeof (IMyInterface2Invoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface2 GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface2'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterface2Invoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_DoSomething; +#pragma warning disable 0169 + static Delegate GetDoSomethingHandler () + { + if (cb_DoSomething == null) + cb_DoSomething = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_DoSomething); + return cb_DoSomething; + } + + static void n_DoSomething (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoSomething (); + } +#pragma warning restore 0169 + + IntPtr id_DoSomething; + public unsafe void DoSomething () + { + if (id_DoSomething == IntPtr.Zero) + id_DoSomething = JNIEnv.GetMethodID (class_ref, "DoSomething", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_DoSomething); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt new file mode 100644 index 00000000000..284323bacb5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt @@ -0,0 +1,86 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Java.Interop.JniTypeSignature ("java/code/MyClass", GenerateJavaPeer=false)] +public partial class MyClass { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='uint[]']]" + [global::Java.Interop.JniMethodSignature ("Echo", "([I)[I")] + public unsafe Java.Interop.JavaInt32Array? Echo (uint[]? value) + { + const string __id = "Echo.([I)[I"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalInt32Array (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ushort[]']]" + [global::Java.Interop.JniMethodSignature ("Echo", "([S)[S")] + public unsafe Java.Interop.JavaInt16Array? Echo (ushort[]? value) + { + const string __id = "Echo.([S)[S"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalInt16Array (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ulong[]']]" + [global::Java.Interop.JniMethodSignature ("Echo", "([J)[J")] + public unsafe Java.Interop.JavaInt64Array? Echo (ulong[]? value) + { + const string __id = "Echo.([J)[J"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalInt64Array (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ubyte[]']]" + [global::Java.Interop.JniMethodSignature ("Echo", "([B)[B")] + public unsafe Java.Interop.JavaSByteArray? Echo (byte[]? value) + { + const string __id = "Echo.([B)[B"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt new file mode 100644 index 00000000000..67df154c853 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt @@ -0,0 +1,118 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Java.Interop.JniTypeSignature ("java/code/MyClass", GenerateJavaPeer=false)] +public partial class MyClass { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe Java.Interop.JavaInt32Array? UIntProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UIntProp' and count(parameter)=0]" + get { + const string __id = "get_UIntProp.()[I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UIntProp' and count(parameter)=1 and parameter[1][@type='uint[]']]" + set { + const string __id = "set_UIntProp.([I)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalInt32Array (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + } + + public unsafe Java.Interop.JavaInt16Array? UShortProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UShortProp' and count(parameter)=0]" + get { + const string __id = "get_UShortProp.()[S"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UShortProp' and count(parameter)=1 and parameter[1][@type='ushort[]']]" + set { + const string __id = "set_UShortProp.([S)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalInt16Array (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + } + + public unsafe Java.Interop.JavaInt64Array? ULongProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_ULongProp' and count(parameter)=0]" + get { + const string __id = "get_ULongProp.()[J"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_ULongProp' and count(parameter)=1 and parameter[1][@type='ulong[]']]" + set { + const string __id = "set_ULongProp.([J)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalInt64Array (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + } + + public unsafe Java.Interop.JavaSByteArray? UByteProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UByteProp' and count(parameter)=0]" + get { + const string __id = "get_UByteProp.()[B"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UByteProp' and count(parameter)=1 and parameter[1][@type='ubyte[]']]" + set { + const string __id = "set_UByteProp.([B)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt new file mode 100644 index 00000000000..ac069c810cf --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt @@ -0,0 +1,66 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Java.Interop.JniTypeSignature ("java/code/MyClass", GenerateJavaPeer=false)] +public partial class MyClass { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='uint']]" + [global::Java.Interop.JniMethodSignature ("Echo", "(I)I")] + public unsafe uint Echo (uint value) + { + const string __id = "Echo.(I)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return (uint)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ushort']]" + [global::Java.Interop.JniMethodSignature ("Echo", "(S)S")] + public unsafe ushort Echo (ushort value) + { + const string __id = "Echo.(S)S"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt16Method (__id, this, __args); + return (ushort)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ulong']]" + [global::Java.Interop.JniMethodSignature ("Echo", "(J)J")] + public unsafe ulong Echo (ulong value) + { + const string __id = "Echo.(J)J"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt64Method (__id, this, __args); + return (ulong)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ubyte']]" + [global::Java.Interop.JniMethodSignature ("Echo", "(B)B")] + public unsafe byte Echo (byte value) + { + const string __id = "Echo.(B)B"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractSByteMethod (__id, this, __args); + return (byte)__rm; + } finally { + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt new file mode 100644 index 00000000000..377c2f941a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt @@ -0,0 +1,98 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Java.Interop.JniTypeSignature ("java/code/MyClass", GenerateJavaPeer=false)] +public partial class MyClass { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe uint UIntProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UIntProp' and count(parameter)=0]" + get { + const string __id = "get_UIntProp.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return (uint)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UIntProp' and count(parameter)=1 and parameter[1][@type='uint']]" + set { + const string __id = "set_UIntProp.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe ushort UShortProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UShortProp' and count(parameter)=0]" + get { + const string __id = "get_UShortProp.()S"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt16Method (__id, this, null); + return (ushort)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UShortProp' and count(parameter)=1 and parameter[1][@type='ushort']]" + set { + const string __id = "set_UShortProp.(S)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe ulong ULongProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_ULongProp' and count(parameter)=0]" + get { + const string __id = "get_ULongProp.()J"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt64Method (__id, this, null); + return (ulong)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_ULongProp' and count(parameter)=1 and parameter[1][@type='ulong']]" + set { + const string __id = "set_ULongProp.(J)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe byte UByteProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UByteProp' and count(parameter)=0]" + get { + const string __id = "get_UByteProp.()B"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractSByteMethod (__id, this, null); + return (byte)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UByteProp' and count(parameter)=1 and parameter[1][@type='ubyte']]" + set { + const string __id = "set_UByteProp.(B)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAbstractWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAbstractWithVoidReturn.txt new file mode 100644 index 00000000000..7b481c02827 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAbstractWithVoidReturn.txt @@ -0,0 +1,27 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAsyncifiedWithIntReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAsyncifiedWithIntReturn.txt new file mode 100644 index 00000000000..0f42c6004d5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAsyncifiedWithIntReturn.txt @@ -0,0 +1,33 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_bar); + return cb_bar; +} + +static int n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()I", "GetbarHandler")] +public virtual unsafe int bar () +{ + const string __id = "bar.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } +} + +public global::System.Threading.Tasks.Task barAsync () +{ + return global::System.Threading.Tasks.Task.Run (() => bar ()); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAsyncifiedWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAsyncifiedWithVoidReturn.txt new file mode 100644 index 00000000000..3f8ee287ba9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodAsyncifiedWithVoidReturn.txt @@ -0,0 +1,32 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + +public global::System.Threading.Tasks.Task barAsync () +{ + return global::System.Threading.Tasks.Task.Run (() => bar ()); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodBody.txt new file mode 100644 index 00000000000..49e16b4888e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodBody.txt @@ -0,0 +1,5 @@ +const string __id = "bar.()V"; +try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); +} finally { +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodFinalWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodFinalWithVoidReturn.txt new file mode 100644 index 00000000000..28abf4fe7d6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodFinalWithVoidReturn.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "")] +public unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeNonvirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodIdField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodIdField.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodProtected.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodProtected.txt new file mode 100644 index 00000000000..d5025685d8c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodProtected.txt @@ -0,0 +1,27 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +protected virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodStaticWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodStaticWithVoidReturn.txt new file mode 100644 index 00000000000..05fb6bf0b0c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodStaticWithVoidReturn.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "")] +public static unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithCharSequenceArrays.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithCharSequenceArrays.txt new file mode 100644 index 00000000000..9aa270aee73 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithCharSequenceArrays.txt @@ -0,0 +1,42 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='com.example']/class[@name='MyClass']" +[global::Java.Interop.JniTypeSignature ("com/example/MyClass", GenerateJavaPeer=false)] +public partial class MyClass : Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/example/MyClass", typeof (MyClass)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.example']/class[@name='MyClass']/method[@name='echo' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence[]']]" + [global::Java.Interop.JniMethodSignature ("echo", "([Ljava/lang/CharSequence;)[Ljava/lang/CharSequence;")] + public virtual unsafe Java.Interop.JavaObjectArray? Echo (Java.Interop.JavaObjectArray? messages) + { + const string __id = "echo.([Ljava/lang/CharSequence;)[Ljava/lang/CharSequence;"; + var native_messages = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalObjectArray (messages); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_messages); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue>(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + if (native_messages != null) { + native_messages.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (messages); + } + } + + public Java.Interop.JavaObjectArray? Echo (Java.Interop.JavaObjectArray? messages) + { + Java.Interop.JavaObjectArray? __result = Echo (messages); + var __rsval = __result; + return __rsval; + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithIntReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithIntReturn.txt new file mode 100644 index 00000000000..c28a0162932 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithIntReturn.txt @@ -0,0 +1,28 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_bar); + return cb_bar; +} + +static int n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()I", "GetbarHandler")] +public virtual unsafe int bar () +{ + const string __id = "bar.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithStringReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithStringReturn.txt new file mode 100644 index 00000000000..6cc92638cee --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithStringReturn.txt @@ -0,0 +1,28 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_bar); + return cb_bar; +} + +static IntPtr n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.bar ()); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()Ljava/lang/String;", "GetbarHandler")] +public virtual unsafe string bar () +{ + const string __id = "bar.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithVoidReturn.txt new file mode 100644 index 00000000000..087d497576c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteMethodWithVoidReturn.txt @@ -0,0 +1,27 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceClass.txt new file mode 100644 index 00000000000..f45877dbb25 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceClass.txt @@ -0,0 +1,125 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] + get; + } + + // Metadata.xml XPath class reference: path="/api/package[@name='com.xamarin.android']/class[@name='Parent.Child']" + [global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] + public partial class Child : Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent$Child", typeof (Child)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Child (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + if (cb_getBar == null) + cb_getBar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceTypes.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceTypes.txt new file mode 100644 index 00000000000..ac13ce1b169 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceTypes.txt @@ -0,0 +1,185 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] + get; + } + + // Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']" + [Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParent/IChildInvoker")] + public partial interface IChild : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParent/IChildInvoker, MyAssembly")] + get; + } + + } + + [global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] + internal partial class IChildInvoker : global::Java.Lang.Object, IChild { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent$Child", typeof (IChildInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IChild GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent.Child'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IChildInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + if (cb_getBar == null) + cb_getBar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + if (cb_getBar == null) + cb_getBar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteObjectField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteObjectField.txt new file mode 100644 index 00000000000..dc5184f1864 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteObjectField.txt @@ -0,0 +1,30 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Java.Interop.JniTypeSignature ("java/code/MyClass", GenerateJavaPeer=false)] +public partial class MyClass { + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/class[@name='MyClass']/field[@name='field']" + public java.code.Example? field { + get { + const string __id = "field.Ljava/code/Example;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "field.Ljava/code/Example;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteParameterListCallArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteParameterListCallArgs.txt new file mode 100644 index 00000000000..a0d1315f35b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteParameterListCallArgs.txt @@ -0,0 +1,4 @@ +JniArgumentValue* __args = stackalloc JniArgumentValue [3]; +__args [0] = new JniArgumentValue (value); +__args [1] = new JniArgumentValue (native_str); +__args [2] = new JniArgumentValue (flag); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteParameterListCallArgsForInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteParameterListCallArgsForInvoker.txt new file mode 100644 index 00000000000..1506c62aa80 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteParameterListCallArgsForInvoker.txt @@ -0,0 +1,4 @@ +JValue* __args = stackalloc JValue [3]; +__args [0] = new JValue (value); +__args [1] = new JValue (native_str); +__args [2] = new JValue (flag); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteProperty.txt new file mode 100644 index 00000000000..46d1747a57e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteProperty.txt @@ -0,0 +1,56 @@ +static Delegate cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.MyProperty = value; +} +#pragma warning restore 0169 + +public virtual unsafe int MyProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='get_MyProperty' and count(parameter)=0]" + [Register ("get_MyProperty", "()I", "Getget_MyPropertyHandler")] + get { + const string __id = "get_MyProperty.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='set_MyProperty' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_MyProperty", "(I)V", "Getset_MyProperty_IHandler")] + set { + const string __id = "set_MyProperty.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyAbstractDeclaration.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyAbstractDeclaration.txt new file mode 100644 index 00000000000..b04f48c67b0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyAbstractDeclaration.txt @@ -0,0 +1,39 @@ +static Delegate? cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate? cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.MyProperty = value; +} +#pragma warning restore 0169 + +public abstract int MyProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='get_MyProperty' and count(parameter)=0]" + [Register ("get_MyProperty", "()I", "Getget_MyPropertyHandler")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='set_MyProperty' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_MyProperty", "(I)V", "Getset_MyProperty_IHandler")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyCallbacks.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyCallbacks.txt new file mode 100644 index 00000000000..fc4f514320e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyCallbacks.txt @@ -0,0 +1,32 @@ +static Delegate? cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate? cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.MyProperty = value; +} +#pragma warning restore 0169 + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyDeclaration.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyDeclaration.txt new file mode 100644 index 00000000000..d23bc113c00 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyDeclaration.txt @@ -0,0 +1,7 @@ +int MyProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='get_MyProperty' and count(parameter)=0]" + [Register ("get_MyProperty", "()I", "Getget_MyPropertyHandler:ObjectAdapter, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='set_MyProperty' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_MyProperty", "(I)V", "Getset_MyProperty_IHandler:ObjectAdapter, ")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyInvoker.txt new file mode 100644 index 00000000000..115683b9da9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyInvoker.txt @@ -0,0 +1,49 @@ +static Delegate? cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate? cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.MyProperty = value; +} +#pragma warning restore 0169 + +IntPtr id_get_MyProperty; +IntPtr id_set_MyProperty_I; +public unsafe int MyProperty { + get { + if (id_get_MyProperty == IntPtr.Zero) + id_get_MyProperty = JNIEnv.GetMethodID (class_ref, "get_MyProperty", "()I"); + return JNIEnv.CallIntMethod (this.PeerReference, id_get_MyProperty); + } + set { + if (id_set_MyProperty_I == IntPtr.Zero) + id_set_MyProperty_I = JNIEnv.GetMethodID (class_ref, "set_MyProperty", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (this.PeerReference, id_set_MyProperty_I, __args); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyStringVariant.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyStringVariant.txt new file mode 100644 index 00000000000..72025a88f84 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WritePropertyStringVariant.txt @@ -0,0 +1,9 @@ +public string? MyProperty { + get { return MyProperty == null ? null : MyProperty.ToString (); } + set { + var jls = value == null ? null : new global::Java.Lang.String (value); + MyProperty = jls; + if (jls != null) jls.Dispose (); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteStaticInterfaceMethod.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteStaticInterfaceMethod.txt new file mode 100644 index 00000000000..3f2286499f3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteStaticInterfaceMethod.txt @@ -0,0 +1,104 @@ +[Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +public abstract class MyInterface : Java.Lang.Object { + internal MyInterface () + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "")] + public static unsafe void DoSomething () + { + const string __id = "DoSomething.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (MyInterface)); + +} + +[Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +[global::System.Obsolete ("Use the 'MyInterface' type. This type will be removed in a future release.", error: true)] +public abstract class MyInterfaceConsts : MyInterface { + private MyInterfaceConsts () + { + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "")] + public static unsafe void DoSomething () + { + const string __id = "DoSomething.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteStaticInterfaceProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteStaticInterfaceProperty.txt new file mode 100644 index 00000000000..94761e7edd5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteStaticInterfaceProperty.txt @@ -0,0 +1,87 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + static unsafe int Value { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Value' and count(parameter)=0]" + [Register ("get_Value", "()I", "")] + get { + const string __id = "get_Value.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Value' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Value", "(I)V", "")] + set { + const string __id = "set_Value.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteUnnestedInterfaceTypes.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteUnnestedInterfaceTypes.txt new file mode 100644 index 00000000000..d8ef1ab567c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteUnnestedInterfaceTypes.txt @@ -0,0 +1,185 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']" +[Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParentChildInvoker")] +public partial interface IParentChild : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentChildInvoker, MyAssembly")] + get; + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] +internal partial class IParentChildInvoker : global::Java.Lang.Object, IParentChild { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent$Child", typeof (IParentChildInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParentChild GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent.Child'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentChildInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + if (cb_getBar == null) + cb_getBar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] + get; + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + if (cb_getBar == null) + cb_getBar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCharSequenceEnumerator.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCharSequenceEnumerator.txt new file mode 100644 index 00000000000..0a27a4a22b7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCharSequenceEnumerator.txt @@ -0,0 +1,11 @@ +System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () +{ + return GetEnumerator (); +} + +public System.Collections.Generic.IEnumerator GetEnumerator () +{ + for (int i = 0; i < Length(); i++) + yield return CharAt (i); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClass.txt new file mode 100644 index 00000000000..79bbf1b741a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClass.txt @@ -0,0 +1,362 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + unsafe MyClass () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register (".ctor", "(Ljava/lang/String;)V", "")] + unsafe MyClass (string? p0) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(Ljava/lang/String;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_p0 = JNIEnv.NewString ((string?)p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + } + } + + static Delegate? cb_get_Count_get_Count_I; +#pragma warning disable 0169 + static Delegate Getget_CountHandler () + { + return cb_get_Count_get_Count_I ??= new _JniMarshal_PP_I (n_get_Count); + } + + static int n_get_Count (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Count); + } + } + private static int __n_get_Count (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.Count; + } +#pragma warning restore 0169 + + static Delegate? cb_set_Count_set_Count_I_V; +#pragma warning disable 0169 + static Delegate Getset_Count_IHandler () + { + return cb_set_Count_set_Count_I_V ??= new _JniMarshal_PPI_V (n_set_Count_I); + } + + static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_Count_I); + } + } + private static void __n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.Count = value; + } +#pragma warning restore 0169 + + public virtual unsafe int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler")] + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler")] + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + } + + static Delegate? cb_get_Key_get_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate Getget_KeyHandler () + { + return cb_get_Key_get_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_get_Key); + } + + static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Key); + } + } + private static IntPtr __n_get_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key); + } +#pragma warning restore 0169 + + static Delegate? cb_set_Key_set_Key_Ljava_lang_String__V; +#pragma warning disable 0169 + static Delegate Getset_Key_Ljava_lang_String_Handler () + { + return cb_set_Key_set_Key_Ljava_lang_String__V ??= new _JniMarshal_PPL_V (n_set_Key_Ljava_lang_String_); + } + + static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_set_Key_Ljava_lang_String_); + } + } + private static void __n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; + } +#pragma warning restore 0169 + + public virtual unsafe string? Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler")] + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler")] + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString ((string?)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + public static unsafe int StaticCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_StaticCount' and count(parameter)=0]" + [Register ("get_StaticCount", "()I", "")] + get { + const string __id = "get_StaticCount.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_StaticCount", "(I)V", "")] + set { + const string __id = "set_StaticCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + + static Delegate? cb_get_AbstractCount_get_AbstractCount_I; +#pragma warning disable 0169 + static Delegate Getget_AbstractCountHandler () + { + return cb_get_AbstractCount_get_AbstractCount_I ??= new _JniMarshal_PP_I (n_get_AbstractCount); + } + + static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_AbstractCount); + } + } + private static int __n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.AbstractCount; + } +#pragma warning restore 0169 + + static Delegate? cb_set_AbstractCount_set_AbstractCount_I_V; +#pragma warning disable 0169 + static Delegate Getset_AbstractCount_IHandler () + { + return cb_set_AbstractCount_set_AbstractCount_I_V ??= new _JniMarshal_PPI_V (n_set_AbstractCount_I); + } + + static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_AbstractCount_I); + } + } + private static void __n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractCount = value; + } +#pragma warning restore 0169 + + public abstract int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set; + } + + static Delegate? cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I; +#pragma warning disable 0169 + static Delegate GetGetCountForKey_Ljava_lang_String_Handler () + { + return cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I ??= new _JniMarshal_PPL_I (n_GetCountForKey_Ljava_lang_String_); + } + + static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_key, &__n_GetCountForKey_Ljava_lang_String_); + } + } + private static int __n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler")] + public virtual unsafe int GetCountForKey (string? key) + { + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + IntPtr native_key = JNIEnv.NewString ((string?)key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_key); + } + } + + static Delegate? cb_Key_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetKeyHandler () + { + return cb_Key_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_Key); + } + + static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_Key); + } + } + private static IntPtr __n_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key ()); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Key' and count(parameter)=0]" + [Register ("Key", "()Ljava/lang/String;", "GetKeyHandler")] + public virtual unsafe string? Key () + { + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='StaticMethod' and count(parameter)=0]" + [Register ("StaticMethod", "()V", "")] + public static unsafe void StaticMethod () + { + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + + static Delegate? cb_AbstractMethod_AbstractMethod_V; +#pragma warning disable 0169 + static Delegate GetAbstractMethodHandler () + { + return cb_AbstractMethod_AbstractMethod_V ??= new _JniMarshal_PP_V (n_AbstractMethod); + } + + static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_AbstractMethod); + } + } + private static void __n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractMethod (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" + [Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] + public abstract void AbstractMethod (); + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassAbstractMembers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassAbstractMembers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassConstructors.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassConstructors.txt new file mode 100644 index 00000000000..8a45f35e38a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassConstructors.txt @@ -0,0 +1,42 @@ +protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + +// Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=0]" +[Register (".ctor", "()V", "")] + unsafe MyClass () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + +// Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register (".ctor", "(Ljava/lang/String;)V", "")] + unsafe MyClass (string? p0) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/String;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_p0 = JNIEnv.NewString (p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassHandle.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassHandle.txt new file mode 100644 index 00000000000..9cb131ceaff --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassHandle.txt @@ -0,0 +1,7 @@ + static readonly JniPeerMembers _members = new XAPeerMembers ("com/mypackage/foo", typeof (foo)); + internal static IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvoker.txt new file mode 100644 index 00000000000..9cd0169c047 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvoker.txt @@ -0,0 +1,52 @@ +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +internal partial class MyClassInvoker : MyClass { + + public MyClassInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) {} + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClassInvoker)); + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" + [Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] + public override unsafe void AbstractMethod () + { + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvokerHandle.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvokerHandle.txt new file mode 100644 index 00000000000..f19ad766ef7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvokerHandle.txt @@ -0,0 +1,10 @@ +static readonly JniPeerMembers _members = new XAPeerMembers ("com/mypackage/foo", typeof (Com.MyPackage.Foo)); + +public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } +} + +protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvokerMembers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvokerMembers.txt new file mode 100644 index 00000000000..98bc27c15f0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassInvokerMembers.txt @@ -0,0 +1,35 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethodInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethodInvokers.txt new file mode 100644 index 00000000000..7fec3768027 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethodInvokers.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethodInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethodInvokersWithSkips.txt new file mode 100644 index 00000000000..7fec3768027 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethodInvokersWithSkips.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethods.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethods.txt new file mode 100644 index 00000000000..e5240d2195e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassMethods.txt @@ -0,0 +1,93 @@ +static Delegate? cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate GetGetCountForKey_Ljava_lang_String_Handler () +{ + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; +} + +static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler")] +public virtual unsafe int GetCountForKey (string? key) +{ + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + IntPtr native_key = JNIEnv.NewString (key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_key); + } +} + +static Delegate? cb_Key; +#pragma warning disable 0169 +static Delegate GetKeyHandler () +{ + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; +} + +static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key ()); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Key' and count(parameter)=0]" +[Register ("Key", "()Ljava/lang/String;", "GetKeyHandler")] +public virtual unsafe string? Key () +{ + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } +} + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='StaticMethod' and count(parameter)=0]" +[Register ("StaticMethod", "()V", "")] +public static unsafe void StaticMethod () +{ + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } +} + +static Delegate? cb_AbstractMethod; +#pragma warning disable 0169 +static Delegate GetAbstractMethodHandler () +{ + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; +} + +static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractMethod (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public abstract void AbstractMethod (); + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassProperties.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassProperties.txt new file mode 100644 index 00000000000..e7efea76824 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassProperties.txt @@ -0,0 +1,178 @@ +static Delegate? cb_get_Count; +#pragma warning disable 0169 +static Delegate Getget_CountHandler () +{ + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; +} + +static int n_get_Count (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.Count; +} +#pragma warning restore 0169 + +static Delegate? cb_set_Count_I; +#pragma warning disable 0169 +static Delegate Getset_Count_IHandler () +{ + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; +} + +static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.Count = value; +} +#pragma warning restore 0169 + +public virtual unsafe int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler")] + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler")] + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } +} + +static Delegate? cb_get_Key; +#pragma warning disable 0169 +static Delegate Getget_KeyHandler () +{ + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; +} + +static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key); +} +#pragma warning restore 0169 + +static Delegate? cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate Getset_Key_Ljava_lang_String_Handler () +{ + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; +} + +static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; +} +#pragma warning restore 0169 + +public virtual unsafe string? Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler")] + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler")] + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} + +public static unsafe int StaticCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_StaticCount' and count(parameter)=0]" + [Register ("get_StaticCount", "()I", "")] + get { + const string __id = "get_StaticCount.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_StaticCount", "(I)V", "")] + set { + const string __id = "set_StaticCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } +} + +static Delegate? cb_get_AbstractCount; +#pragma warning disable 0169 +static Delegate Getget_AbstractCountHandler () +{ + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; +} + +static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.AbstractCount; +} +#pragma warning restore 0169 + +static Delegate? cb_set_AbstractCount_I; +#pragma warning disable 0169 +static Delegate Getset_AbstractCount_IHandler () +{ + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; +} + +static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractCount = value; +} +#pragma warning restore 0169 + +public abstract int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassPropertyInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassPropertyInvokers.txt new file mode 100644 index 00000000000..55d7c1ca13e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassPropertyInvokers.txt @@ -0,0 +1,24 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassPropertyInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassPropertyInvokersWithSkips.txt new file mode 100644 index 00000000000..55d7c1ca13e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteClassPropertyInvokersWithSkips.txt @@ -0,0 +1,24 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtor.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtor.txt new file mode 100644 index 00000000000..238012f4de2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtor.txt @@ -0,0 +1,18 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=0]" +[Register (".ctor", "", "")] + unsafe Object () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = ""; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtorDeprecated.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtorDeprecated.txt new file mode 100644 index 00000000000..159077c9b6b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtorDeprecated.txt @@ -0,0 +1,21 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=0]" +[Register (".ctor", "", "")] +[Obsolete (@"This constructor is obsolete")] +[MyAttribute] +[global::Android.Runtime.IntDefinition (null, JniField = "xamarin/test/SomeObject.SOME_VALUE")] + unsafe Object () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = ""; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtorWithStringOverload.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtorWithStringOverload.txt new file mode 100644 index 00000000000..342763a13e7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteCtorWithStringOverload.txt @@ -0,0 +1,43 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" +[Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + unsafe Object (Java.Lang.ICharSequence? mystring) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_mystring = CharSequence.ToLocalJniHandle (mystring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_mystring); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_mystring); + } +} + +[Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + unsafe Object (string? mystring) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_mystring = CharSequence.ToLocalJniHandle (mystring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_mystring); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_mystring); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstant.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstant.txt new file mode 100644 index 00000000000..ad70609e670 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstant.txt @@ -0,0 +1,11 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public static string? bar { + get { + const string __id = "bar.Ljava/lang/String;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstantWithIntValue.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstantWithIntValue.txt new file mode 100644 index 00000000000..a1f3257f0d2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstantWithIntValue.txt @@ -0,0 +1,3 @@ +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public const int bar = (int) 1234; diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstantWithStringValue.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstantWithStringValue.txt new file mode 100644 index 00000000000..1e7186b009f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldConstantWithStringValue.txt @@ -0,0 +1,3 @@ +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public const string bar = (string) "hello"; diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldGetBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldGetBody.txt new file mode 100644 index 00000000000..44cde23dc2f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldGetBody.txt @@ -0,0 +1,4 @@ +const string __id = "bar.Ljava/lang/String;"; + +var __v = _members.InstanceFields.GetObjectValue (__id, this); +return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldIdField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldIdField.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldInt.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldInt.txt new file mode 100644 index 00000000000..d1a71f54efe --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldInt.txt @@ -0,0 +1,19 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public int bar { + get { + const string __id = "bar.I"; + + var __v = _members.InstanceFields.GetInt32Value (__id, this); + return __v; + } + set { + const string __id = "bar.I"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldSetBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldSetBody.txt new file mode 100644 index 00000000000..77008f500d8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldSetBody.txt @@ -0,0 +1,8 @@ +const string __id = "bar.Ljava/lang/String;"; + +IntPtr native_value = JNIEnv.NewString (value); +try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); +} finally { + JNIEnv.DeleteLocalRef (native_value); +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldString.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldString.txt new file mode 100644 index 00000000000..f4d68991940 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteFieldString.txt @@ -0,0 +1,21 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public string? bar { + get { + const string __id = "bar.Ljava/lang/String;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "bar.Ljava/lang/String;"; + + IntPtr native_value = JNIEnv.NewString (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterface.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterface.txt new file mode 100644 index 00000000000..a2862dff7aa --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterface.txt @@ -0,0 +1,398 @@ +[Register ("mono/internal/java/code/IMyInterface", DoNotGenerateAcw=true)] +public abstract class MyInterface : Java.Lang.Object { + internal MyInterface () + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='StaticMethod' and count(parameter)=0]" + [Register ("StaticMethod", "()V", "")] + public static unsafe void StaticMethod () + { + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (MyInterface)); + +} + +[Register ("mono/internal/java/code/IMyInterface", DoNotGenerateAcw=true)] +[global::System.Obsolete (@"Use the 'MyInterface' type. This type will be removed in a future release.", error: true)] +public abstract class MyInterfaceConsts : MyInterface { + private MyInterfaceConsts () + { + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler:java.code.IMyInterfaceInvoker, ")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler:java.code.IMyInterfaceInvoker, ")] + set; + } + + string? Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler:java.code.IMyInterfaceInvoker, ")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] + set; + } + + int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler:java.code.IMyInterfaceInvoker, ")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler:java.code.IMyInterfaceInvoker, ")] + set; + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] + int GetCountForKey (string? key); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='Key' and count(parameter)=0]" + [Register ("Key", "()Ljava/lang/String;", "GetKeyHandler:java.code.IMyInterfaceInvoker, ")] + string? Key (); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='AbstractMethod' and count(parameter)=0]" + [Register ("AbstractMethod", "()V", "GetAbstractMethodHandler:java.code.IMyInterfaceInvoker, ")] + void AbstractMethod (); + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface? GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate? cb_get_Count_get_Count_I; +#pragma warning disable 0169 + static Delegate Getget_CountHandler () + { + return cb_get_Count_get_Count_I ??= new _JniMarshal_PP_I (n_get_Count); + } + + static int n_get_Count (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Count); + } + } + private static int __n_get_Count (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.Count; + } +#pragma warning restore 0169 + + static Delegate? cb_set_Count_set_Count_I_V; +#pragma warning disable 0169 + static Delegate Getset_Count_IHandler () + { + return cb_set_Count_set_Count_I_V ??= new _JniMarshal_PPI_V (n_set_Count_I); + } + + static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_Count_I); + } + } + private static void __n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.Count = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Count; + IntPtr id_set_Count_I; + public unsafe int Count { + get { + if (id_get_Count == IntPtr.Zero) + id_get_Count = JNIEnv.GetMethodID (class_ref, "get_Count", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_Count); + } + set { + if (id_set_Count_I == IntPtr.Zero) + id_set_Count_I = JNIEnv.GetMethodID (class_ref, "set_Count", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Count_I, __args); + } + } + + static Delegate? cb_get_Key_get_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate Getget_KeyHandler () + { + return cb_get_Key_get_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_get_Key); + } + + static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Key); + } + } + private static IntPtr __n_get_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key); + } +#pragma warning restore 0169 + + static Delegate? cb_set_Key_set_Key_Ljava_lang_String__V; +#pragma warning disable 0169 + static Delegate Getset_Key_Ljava_lang_String_Handler () + { + return cb_set_Key_set_Key_Ljava_lang_String__V ??= new _JniMarshal_PPL_V (n_set_Key_Ljava_lang_String_); + } + + static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_set_Key_Ljava_lang_String_); + } + } + private static void __n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Key; + IntPtr id_set_Key_Ljava_lang_String_; + public unsafe string? Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString ((string?)value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } + } + + static Delegate? cb_get_AbstractCount_get_AbstractCount_I; +#pragma warning disable 0169 + static Delegate Getget_AbstractCountHandler () + { + return cb_get_AbstractCount_get_AbstractCount_I ??= new _JniMarshal_PP_I (n_get_AbstractCount); + } + + static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_AbstractCount); + } + } + private static int __n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.AbstractCount; + } +#pragma warning restore 0169 + + static Delegate? cb_set_AbstractCount_set_AbstractCount_I_V; +#pragma warning disable 0169 + static Delegate Getset_AbstractCount_IHandler () + { + return cb_set_AbstractCount_set_AbstractCount_I_V ??= new _JniMarshal_PPI_V (n_set_AbstractCount_I); + } + + static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_AbstractCount_I); + } + } + private static void __n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractCount = value; + } +#pragma warning restore 0169 + + IntPtr id_get_AbstractCount; + IntPtr id_set_AbstractCount_I; + public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } + } + + static Delegate? cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I; +#pragma warning disable 0169 + static Delegate GetGetCountForKey_Ljava_lang_String_Handler () + { + return cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I ??= new _JniMarshal_PPL_I (n_GetCountForKey_Ljava_lang_String_); + } + + static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_key, &__n_GetCountForKey_Ljava_lang_String_); + } + } + private static int __n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; + } +#pragma warning restore 0169 + + IntPtr id_GetCountForKey_Ljava_lang_String_; + public unsafe int GetCountForKey (string? key) + { + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString ((string?)key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; + } + + static Delegate? cb_Key_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetKeyHandler () + { + return cb_Key_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_Key); + } + + static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_Key); + } + } + private static IntPtr __n_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key ()); + } +#pragma warning restore 0169 + + IntPtr id_Key; + public unsafe string? Key () + { + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); + } + + static Delegate? cb_AbstractMethod_AbstractMethod_V; +#pragma warning disable 0169 + static Delegate GetAbstractMethodHandler () + { + return cb_AbstractMethod_AbstractMethod_V ??= new _JniMarshal_PP_V (n_AbstractMethod); + } + + static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_AbstractMethod); + } + } + private static void __n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractMethod (); + } +#pragma warning restore 0169 + + IntPtr id_AbstractMethod; + public unsafe void AbstractMethod () + { + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventArgs.txt new file mode 100644 index 00000000000..b184c765c4f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventArgs.txt @@ -0,0 +1,2 @@ +public delegate int MyIGetCountForKeyHandler (string? key); + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventArgsWithParamArray.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventArgsWithParamArray.txt new file mode 100644 index 00000000000..66e970b19d1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventArgsWithParamArray.txt @@ -0,0 +1,14 @@ +// event args for com.xamarin.android.MyListener.onDoSomething +public partial class MyEventArgs : global::System.EventArgs { + + public MyEventArgs (params Java.Lang.Object[]? args) + { + this.args = args; + } + + Java.Lang.Object[]? args; + public Java.Lang.Object[]? Args { + get { return args; } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandler.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandler.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandlerImpl.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandlerImpl.txt new file mode 100644 index 00000000000..7b680517df5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandlerImpl.txt @@ -0,0 +1,59 @@ +[global::Android.Runtime.Register ("mono/java/code/IMyInterfaceImplementor")] +internal sealed partial class IMyInterfaceImplementor : global::Java.Lang.Object, IMyInterface { + + object sender; + + public IMyInterfaceImplementor (object sender) + : base ( + global::Android.Runtime.JNIEnv.StartCreateInstance ("mono/java/code/IMyInterfaceImplementor", "()V"), + JniHandleOwnership.TransferLocalRef) + { + global::Android.Runtime.JNIEnv.FinishCreateInstance (((global::Java.Lang.Object) this).Handle, "()V"); + this.sender = sender; + } + +#pragma warning disable 0649 + public MyIGetCountForKeyHandler? GetCountForKeyHandler; +#pragma warning restore 0649 + + public int GetCountForKey (string? key) + { + var __h = GetCountForKeyHandler; + return __h != null ? __h (key) : default (int); + } +#pragma warning disable 0649 + public MyIKeyHandler? KeyHandler; +#pragma warning restore 0649 + + public string? Key () + { + var __h = KeyHandler; + return __h != null ? __h () : default (string?); + } +#pragma warning disable 0649 + public EventHandler? StaticMethodHandler; +#pragma warning restore 0649 + + public void StaticMethod () + { + var __h = StaticMethodHandler; + if (__h != null) + __h (sender, new EventArgs ()); + } +#pragma warning disable 0649 + public EventHandler? AbstractMethodHandler; +#pragma warning restore 0649 + + public void AbstractMethod () + { + var __h = AbstractMethodHandler; + if (__h != null) + __h (sender, new EventArgs ()); + } + + internal static bool __IsEmpty (IMyInterfaceImplementor value) + { + return value.GetCountForKeyHandler == null && value.KeyHandler == null && value.StaticMethodHandler == null && value.AbstractMethodHandler == null; + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandlerImplContent.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandlerImplContent.txt new file mode 100644 index 00000000000..e6011b413b9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceEventHandlerImplContent.txt @@ -0,0 +1,9 @@ +#pragma warning disable 0649 + public MyIGetCountForKeyHandler? GetCountForKeyHandler; +#pragma warning restore 0649 + + public int GetCountForKey (string? key) + { + var __h = GetCountForKeyHandler; + return __h != null ? __h (key) : default (int); + } diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceExtensionMethods.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceExtensionMethods.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceExtensionsDeclaration.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceExtensionsDeclaration.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceInvoker.txt new file mode 100644 index 00000000000..106523c3be9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceInvoker.txt @@ -0,0 +1,282 @@ +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface? GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.", + JNIEnv.GetClassNameFromInstance (handle), "java.code.IMyInterface")); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate? cb_get_Count; +#pragma warning disable 0169 + static Delegate Getget_CountHandler () + { + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; + } + + static int n_get_Count (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.Count; + } +#pragma warning restore 0169 + + static Delegate? cb_set_Count_I; +#pragma warning disable 0169 + static Delegate Getset_Count_IHandler () + { + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; + } + + static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.Count = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Count; + IntPtr id_set_Count_I; + public unsafe int Count { + get { + if (id_get_Count == IntPtr.Zero) + id_get_Count = JNIEnv.GetMethodID (class_ref, "get_Count", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_Count); + } + set { + if (id_set_Count_I == IntPtr.Zero) + id_set_Count_I = JNIEnv.GetMethodID (class_ref, "set_Count", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Count_I, __args); + } + } + + static Delegate? cb_get_Key; +#pragma warning disable 0169 + static Delegate Getget_KeyHandler () + { + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; + } + + static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key); + } +#pragma warning restore 0169 + + static Delegate? cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate Getset_Key_Ljava_lang_String_Handler () + { + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; + } + + static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Key; + IntPtr id_set_Key_Ljava_lang_String_; + public unsafe string? Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } + } + + static Delegate? cb_get_AbstractCount; +#pragma warning disable 0169 + static Delegate Getget_AbstractCountHandler () + { + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; + } + + static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.AbstractCount; + } +#pragma warning restore 0169 + + static Delegate? cb_set_AbstractCount_I; +#pragma warning disable 0169 + static Delegate Getset_AbstractCount_IHandler () + { + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; + } + + static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractCount = value; + } +#pragma warning restore 0169 + + IntPtr id_get_AbstractCount; + IntPtr id_set_AbstractCount_I; + public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } + } + + static Delegate? cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetGetCountForKey_Ljava_lang_String_Handler () + { + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; + } + + static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; + } +#pragma warning restore 0169 + + IntPtr id_GetCountForKey_Ljava_lang_String_; + public unsafe int GetCountForKey (string? key) + { + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString (key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; + } + + static Delegate? cb_Key; +#pragma warning disable 0169 + static Delegate GetKeyHandler () + { + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; + } + + static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key ()); + } +#pragma warning restore 0169 + + IntPtr id_Key; + public unsafe string? Key () + { + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); + } + + static Delegate? cb_AbstractMethod; +#pragma warning disable 0169 + static Delegate GetAbstractMethodHandler () + { + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; + } + + static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractMethod (); + } +#pragma warning restore 0169 + + IntPtr id_AbstractMethod; + public unsafe void AbstractMethod () + { + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); + } + +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerEvent.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerEvent.txt new file mode 100644 index 00000000000..381b7754ef2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerEvent.txt @@ -0,0 +1,17 @@ +public event MyFullDelegateName MyName { + add { + global::Java.Interop.EventHelper.AddEventHandler( + ref weak_implementor_MyWrefSuffix, + __CreateIMyInterfaceImplementor, + Add, + __h => __h.MyNameSpecHandler += value); + } + remove { + global::Java.Interop.EventHelper.RemoveEventHandler( + ref weak_implementor_MyWrefSuffix, + java.code.IMyInterfaceImplementor.__IsEmpty, + Remove, + __h => __h.MyNameSpecHandler -= value); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerEventWithHandlerArgument.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerEventWithHandlerArgument.txt new file mode 100644 index 00000000000..7f1b240c06c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerEventWithHandlerArgument.txt @@ -0,0 +1,22 @@ +public event MyFullDelegateName MyName { + add { + global::Java.Interop.EventHelper.AddEventHandler( + ref weak_implementor_MyWrefSuffix, + __CreateIMyInterfaceImplementor, + AddMyName_Event_With_Handler_Helper, + __h => __h.MyNameSpecHandler += value); + } + remove { + global::Java.Interop.EventHelper.RemoveEventHandler( + ref weak_implementor_MyWrefSuffix, + java.code.IMyInterfaceImplementor.__IsEmpty, + RemoveMyName, + __h => __h.MyNameSpecHandler -= value); + } +} + +void AddMyName_Event_With_Handler_Helper (java.code.IMyInterface value) +{ + AddMyName (value, null); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerProperty.txt new file mode 100644 index 00000000000..dbb6cfeab0f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceListenerProperty.txt @@ -0,0 +1,15 @@ +public MyFullDelegateName? MyName { + get { + java.code.IMyInterfaceImplementor? impl = ImplMyName; + return impl == null ? null : impl.MyMethodNameHandler; + } + set { + java.code.IMyInterfaceImplementor? impl = ImplMyName; + if (impl == null) { + impl = new java.code.IMyInterfaceImplementor (this); + ImplMyName = impl; + } else + impl.MyNameSpecHandler = value; + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethodInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethodInvokers.txt new file mode 100644 index 00000000000..84eeec41f61 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethodInvokers.txt @@ -0,0 +1,79 @@ +static Delegate? cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate GetGetCountForKey_Ljava_lang_String_Handler () +{ + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; +} + +static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; +} +#pragma warning restore 0169 + +IntPtr id_GetCountForKey_Ljava_lang_String_; +public unsafe int GetCountForKey (string? key) +{ + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString (key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; +} + +static Delegate? cb_Key; +#pragma warning disable 0169 +static Delegate GetKeyHandler () +{ + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; +} + +static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key ()); +} +#pragma warning restore 0169 + +IntPtr id_Key; +public unsafe string? Key () +{ + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); +} + +static Delegate? cb_AbstractMethod; +#pragma warning disable 0169 +static Delegate GetAbstractMethodHandler () +{ + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; +} + +static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractMethod (); +} +#pragma warning restore 0169 + +IntPtr id_AbstractMethod; +public unsafe void AbstractMethod () +{ + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethodInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethodInvokersWithSkips.txt new file mode 100644 index 00000000000..84eeec41f61 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethodInvokersWithSkips.txt @@ -0,0 +1,79 @@ +static Delegate? cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate GetGetCountForKey_Ljava_lang_String_Handler () +{ + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; +} + +static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; +} +#pragma warning restore 0169 + +IntPtr id_GetCountForKey_Ljava_lang_String_; +public unsafe int GetCountForKey (string? key) +{ + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString (key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; +} + +static Delegate? cb_Key; +#pragma warning disable 0169 +static Delegate GetKeyHandler () +{ + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; +} + +static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key ()); +} +#pragma warning restore 0169 + +IntPtr id_Key; +public unsafe string? Key () +{ + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); +} + +static Delegate? cb_AbstractMethod; +#pragma warning disable 0169 +static Delegate GetAbstractMethodHandler () +{ + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; +} + +static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractMethod (); +} +#pragma warning restore 0169 + +IntPtr id_AbstractMethod; +public unsafe void AbstractMethod () +{ + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethods.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethods.txt new file mode 100644 index 00000000000..8972f95d943 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceMethods.txt @@ -0,0 +1,12 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] +int GetCountForKey (string? key); + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='Key' and count(parameter)=0]" +[Register ("Key", "()Ljava/lang/String;", "GetKeyHandler:java.code.IMyInterfaceInvoker, ")] +string? Key (); + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler:java.code.IMyInterfaceInvoker, ")] +void AbstractMethod (); + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceProperties.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceProperties.txt new file mode 100644 index 00000000000..e519f8dd9e7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfaceProperties.txt @@ -0,0 +1,21 @@ +int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler:java.code.IMyInterfaceInvoker, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler:java.code.IMyInterfaceInvoker, ")] set; +} + +string? Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler:java.code.IMyInterfaceInvoker, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] set; +} + +int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler:java.code.IMyInterfaceInvoker, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler:java.code.IMyInterfaceInvoker, ")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfacePropertyInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfacePropertyInvokers.txt new file mode 100644 index 00000000000..292eeaeb712 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfacePropertyInvokers.txt @@ -0,0 +1,199 @@ +static Delegate? cb_get_Count; +#pragma warning disable 0169 +static Delegate Getget_CountHandler () +{ + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; +} + +static int n_get_Count (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.Count; +} +#pragma warning restore 0169 + +static Delegate? cb_set_Count_I; +#pragma warning disable 0169 +static Delegate Getset_Count_IHandler () +{ + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; +} + +static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.Count = value; +} +#pragma warning restore 0169 + +IntPtr id_get_Count; +IntPtr id_set_Count_I; +public unsafe int Count { + get { + if (id_get_Count == IntPtr.Zero) + id_get_Count = JNIEnv.GetMethodID (class_ref, "get_Count", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_Count); + } + set { + if (id_set_Count_I == IntPtr.Zero) + id_set_Count_I = JNIEnv.GetMethodID (class_ref, "set_Count", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Count_I, __args); + } +} + +static Delegate? cb_get_Key; +#pragma warning disable 0169 +static Delegate Getget_KeyHandler () +{ + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; +} + +static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key); +} +#pragma warning restore 0169 + +static Delegate? cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate Getset_Key_Ljava_lang_String_Handler () +{ + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; +} + +static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; +} +#pragma warning restore 0169 + +IntPtr id_get_Key; +IntPtr id_set_Key_Ljava_lang_String_; +public unsafe string? Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } +} + +static Delegate? cb_get_StaticCount; +#pragma warning disable 0169 +static Delegate Getget_StaticCountHandler () +{ + if (cb_get_StaticCount == null) + cb_get_StaticCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_StaticCount); + return cb_get_StaticCount; +} + +static int n_get_StaticCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.StaticCount; +} +#pragma warning restore 0169 + +static Delegate? cb_set_StaticCount_I; +#pragma warning disable 0169 +static Delegate Getset_StaticCount_IHandler () +{ + if (cb_set_StaticCount_I == null) + cb_set_StaticCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_StaticCount_I); + return cb_set_StaticCount_I; +} + +static void n_set_StaticCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.StaticCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_StaticCount; +IntPtr id_set_StaticCount_I; +public unsafe int StaticCount { + get { + if (id_get_StaticCount == IntPtr.Zero) + id_get_StaticCount = JNIEnv.GetMethodID (class_ref, "get_StaticCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_StaticCount); + } + set { + if (id_set_StaticCount_I == IntPtr.Zero) + id_set_StaticCount_I = JNIEnv.GetMethodID (class_ref, "set_StaticCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_StaticCount_I, __args); + } +} + +static Delegate? cb_get_AbstractCount; +#pragma warning disable 0169 +static Delegate Getget_AbstractCountHandler () +{ + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; +} + +static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.AbstractCount; +} +#pragma warning restore 0169 + +static Delegate? cb_set_AbstractCount_I; +#pragma warning disable 0169 +static Delegate Getset_AbstractCount_IHandler () +{ + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; +} + +static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_AbstractCount; +IntPtr id_set_AbstractCount_I; +public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfacePropertyInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfacePropertyInvokersWithSkips.txt new file mode 100644 index 00000000000..2b877dc6ac9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteInterfacePropertyInvokersWithSkips.txt @@ -0,0 +1,150 @@ +static Delegate? cb_get_Key; +#pragma warning disable 0169 +static Delegate Getget_KeyHandler () +{ + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; +} + +static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.Key); +} +#pragma warning restore 0169 + +static Delegate? cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate Getset_Key_Ljava_lang_String_Handler () +{ + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; +} + +static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; +} +#pragma warning restore 0169 + +IntPtr id_get_Key; +IntPtr id_set_Key_Ljava_lang_String_; +public unsafe string? Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } +} + +static Delegate? cb_get_StaticCount; +#pragma warning disable 0169 +static Delegate Getget_StaticCountHandler () +{ + if (cb_get_StaticCount == null) + cb_get_StaticCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_StaticCount); + return cb_get_StaticCount; +} + +static int n_get_StaticCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.StaticCount; +} +#pragma warning restore 0169 + +static Delegate? cb_set_StaticCount_I; +#pragma warning disable 0169 +static Delegate Getset_StaticCount_IHandler () +{ + if (cb_set_StaticCount_I == null) + cb_set_StaticCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_StaticCount_I); + return cb_set_StaticCount_I; +} + +static void n_set_StaticCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.StaticCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_StaticCount; +IntPtr id_set_StaticCount_I; +public unsafe int StaticCount { + get { + if (id_get_StaticCount == IntPtr.Zero) + id_get_StaticCount = JNIEnv.GetMethodID (class_ref, "get_StaticCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_StaticCount); + } + set { + if (id_set_StaticCount_I == IntPtr.Zero) + id_set_StaticCount_I = JNIEnv.GetMethodID (class_ref, "set_StaticCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_StaticCount_I, __args); + } +} + +static Delegate? cb_get_AbstractCount; +#pragma warning disable 0169 +static Delegate Getget_AbstractCountHandler () +{ + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; +} + +static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.AbstractCount; +} +#pragma warning restore 0169 + +static Delegate? cb_set_AbstractCount_I; +#pragma warning disable 0169 +static Delegate Getset_AbstractCount_IHandler () +{ + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; +} + +static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.AbstractCount = value; +} +#pragma warning restore 0169 + +IntPtr id_get_AbstractCount; +IntPtr id_set_AbstractCount_I; +public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAbstractWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAbstractWithVoidReturn.txt new file mode 100644 index 00000000000..be52828cc65 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAbstractWithVoidReturn.txt @@ -0,0 +1,27 @@ +static Delegate? cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAsyncifiedWithIntReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAsyncifiedWithIntReturn.txt new file mode 100644 index 00000000000..633ee44bf7c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAsyncifiedWithIntReturn.txt @@ -0,0 +1,33 @@ +static Delegate? cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_bar); + return cb_bar; +} + +static int n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()I", "GetbarHandler")] +public virtual unsafe int bar () +{ + const string __id = "bar.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } +} + +public global::System.Threading.Tasks.Task barAsync () +{ + return global::System.Threading.Tasks.Task.Run (() => bar ()); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAsyncifiedWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAsyncifiedWithVoidReturn.txt new file mode 100644 index 00000000000..377f9978784 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodAsyncifiedWithVoidReturn.txt @@ -0,0 +1,32 @@ +static Delegate? cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + +public global::System.Threading.Tasks.Task barAsync () +{ + return global::System.Threading.Tasks.Task.Run (() => bar ()); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodBody.txt new file mode 100644 index 00000000000..49e16b4888e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodBody.txt @@ -0,0 +1,5 @@ +const string __id = "bar.()V"; +try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); +} finally { +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodFinalWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodFinalWithVoidReturn.txt new file mode 100644 index 00000000000..28abf4fe7d6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodFinalWithVoidReturn.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "")] +public unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeNonvirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodIdField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodIdField.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodProtected.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodProtected.txt new file mode 100644 index 00000000000..c2eb3b7db33 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodProtected.txt @@ -0,0 +1,27 @@ +static Delegate? cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +protected virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodStaticWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodStaticWithVoidReturn.txt new file mode 100644 index 00000000000..05fb6bf0b0c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodStaticWithVoidReturn.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "")] +public static unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithCharSequenceArrays.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithCharSequenceArrays.txt new file mode 100644 index 00000000000..b266160f0a1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithCharSequenceArrays.txt @@ -0,0 +1,85 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='com.example']/class[@name='MyClass']" +[global::Android.Runtime.Register ("com/example/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass : Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/example/MyClass", typeof (MyClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate? cb_echo_Echo_arrayLjava_lang_CharSequence__arrayLjava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetEcho_arrayLjava_lang_CharSequence_Handler () + { + return cb_echo_Echo_arrayLjava_lang_CharSequence__arrayLjava_lang_CharSequence_ ??= new _JniMarshal_PPL_L (n_Echo_arrayLjava_lang_CharSequence_); + } + + static IntPtr n_Echo_arrayLjava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_messages) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_messages, &__n_Echo_arrayLjava_lang_CharSequence_); + } + } + private static IntPtr __n_Echo_arrayLjava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_messages) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + var messages = (Java.Lang.ICharSequence[]?) JNIEnv.GetArray (native_messages, JniHandleOwnership.DoNotTransfer, typeof (Java.Lang.ICharSequence)); + IntPtr __ret = JNIEnv.NewArray (__this.EchoFormatted (messages)); + if (messages != null) + JNIEnv.CopyArray (messages, native_messages); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='com.example']/class[@name='MyClass']/method[@name='echo' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence[]']]" + [Register ("echo", "([Ljava/lang/CharSequence;)[Ljava/lang/CharSequence;", "GetEcho_arrayLjava_lang_CharSequence_Handler")] + public virtual unsafe Java.Lang.ICharSequence[]? EchoFormatted (Java.Lang.ICharSequence[]? messages) + { + const string __id = "echo.([Ljava/lang/CharSequence;)[Ljava/lang/CharSequence;"; + IntPtr native_messages = JNIEnv.NewArray (messages); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_messages); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return (Java.Lang.ICharSequence[]?) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (Java.Lang.ICharSequence)); + } finally { + if (messages != null) { + JNIEnv.CopyArray (native_messages, messages); + JNIEnv.DeleteLocalRef (native_messages); + } + global::System.GC.KeepAlive (messages); + } + } + + public string[]? Echo (string[]? messages) + { + var jlca_messages = CharSequence.ArrayFromStringArray (messages); + Java.Lang.ICharSequence[]? __result = EchoFormatted (jlca_messages); + var __rsval = CharSequence.ArrayToStringArray (__result); + if (jlca_messages != null) foreach (var s in jlca_messages) s?.Dispose (); + return __rsval; + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithIntReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithIntReturn.txt new file mode 100644 index 00000000000..0eb4a9e84e3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithIntReturn.txt @@ -0,0 +1,28 @@ +static Delegate? cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_bar); + return cb_bar; +} + +static int n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()I", "GetbarHandler")] +public virtual unsafe int bar () +{ + const string __id = "bar.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithStringReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithStringReturn.txt new file mode 100644 index 00000000000..6b3c37fa31b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithStringReturn.txt @@ -0,0 +1,28 @@ +static Delegate? cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_bar); + return cb_bar; +} + +static IntPtr n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return JNIEnv.NewString (__this.bar ()); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()Ljava/lang/String;", "GetbarHandler")] +public virtual unsafe string? bar () +{ + const string __id = "bar.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithVoidReturn.txt new file mode 100644 index 00000000000..afcab8b5b60 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteMethodWithVoidReturn.txt @@ -0,0 +1,27 @@ +static Delegate? cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteObjectField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteObjectField.txt new file mode 100644 index 00000000000..f8d48920f86 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteObjectField.txt @@ -0,0 +1,36 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/class[@name='MyClass']/field[@name='field']" + [Register ("field")] + public java.code.Example? field { + get { + const string __id = "field.Ljava/code/Example;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "field.Ljava/code/Example;"; + + IntPtr native_value = global::Android.Runtime.JNIEnv.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteParameterListCallArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteParameterListCallArgs.txt new file mode 100644 index 00000000000..a0d1315f35b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteParameterListCallArgs.txt @@ -0,0 +1,4 @@ +JniArgumentValue* __args = stackalloc JniArgumentValue [3]; +__args [0] = new JniArgumentValue (value); +__args [1] = new JniArgumentValue (native_str); +__args [2] = new JniArgumentValue (flag); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteParameterListCallArgsForInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteParameterListCallArgsForInvoker.txt new file mode 100644 index 00000000000..1506c62aa80 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteParameterListCallArgsForInvoker.txt @@ -0,0 +1,4 @@ +JValue* __args = stackalloc JValue [3]; +__args [0] = new JValue (value); +__args [1] = new JValue (native_str); +__args [2] = new JValue (flag); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteProperty.txt new file mode 100644 index 00000000000..cae42272129 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WriteProperty.txt @@ -0,0 +1,56 @@ +static Delegate? cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate? cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.MyProperty = value; +} +#pragma warning restore 0169 + +public virtual unsafe int MyProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='get_MyProperty' and count(parameter)=0]" + [Register ("get_MyProperty", "()I", "Getget_MyPropertyHandler")] + get { + const string __id = "get_MyProperty.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='set_MyProperty' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_MyProperty", "(I)V", "Getset_MyProperty_IHandler")] + set { + const string __id = "set_MyProperty.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyAbstractDeclaration.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyAbstractDeclaration.txt new file mode 100644 index 00000000000..b04f48c67b0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyAbstractDeclaration.txt @@ -0,0 +1,39 @@ +static Delegate? cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate? cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.MyProperty = value; +} +#pragma warning restore 0169 + +public abstract int MyProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='get_MyProperty' and count(parameter)=0]" + [Register ("get_MyProperty", "()I", "Getget_MyPropertyHandler")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='set_MyProperty' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_MyProperty", "(I)V", "Getset_MyProperty_IHandler")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyCallbacks.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyCallbacks.txt new file mode 100644 index 00000000000..fc4f514320e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyCallbacks.txt @@ -0,0 +1,32 @@ +static Delegate? cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate? cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.MyProperty = value; +} +#pragma warning restore 0169 + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyDeclaration.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyDeclaration.txt new file mode 100644 index 00000000000..d23bc113c00 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyDeclaration.txt @@ -0,0 +1,7 @@ +int MyProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='get_MyProperty' and count(parameter)=0]" + [Register ("get_MyProperty", "()I", "Getget_MyPropertyHandler:ObjectAdapter, ")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='set_MyProperty' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_MyProperty", "(I)V", "Getset_MyProperty_IHandler:ObjectAdapter, ")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyInvoker.txt new file mode 100644 index 00000000000..e2f135044db --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyInvoker.txt @@ -0,0 +1,49 @@ +static Delegate? cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate? cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!; + __this.MyProperty = value; +} +#pragma warning restore 0169 + +IntPtr id_get_MyProperty; +IntPtr id_set_MyProperty_I; +public unsafe int MyProperty { + get { + if (id_get_MyProperty == IntPtr.Zero) + id_get_MyProperty = JNIEnv.GetMethodID (class_ref, "get_MyProperty", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_MyProperty); + } + set { + if (id_set_MyProperty_I == IntPtr.Zero) + id_set_MyProperty_I = JNIEnv.GetMethodID (class_ref, "set_MyProperty", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_MyProperty_I, __args); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyStringVariant.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyStringVariant.txt new file mode 100644 index 00000000000..72025a88f84 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1-NRT/WritePropertyStringVariant.txt @@ -0,0 +1,9 @@ +public string? MyProperty { + get { return MyProperty == null ? null : MyProperty.ToString (); } + set { + var jls = value == null ? null : new global::Java.Lang.String (value); + MyProperty = jls; + if (jls != null) jls.Dispose (); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/ObsoleteInterfaceAlternativeClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/ObsoleteInterfaceAlternativeClass.txt new file mode 100644 index 00000000000..e33507b67f6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/ObsoleteInterfaceAlternativeClass.txt @@ -0,0 +1,169 @@ +[Register ("mono/internal/com/xamarin/android/Parent", DoNotGenerateAcw=true)] +[global::System.Obsolete (@"Use the 'Com.Xamarin.Android.IParent' type. This class will be removed in a future release.")] +public abstract class Parent : Java.Lang.Object { + internal Parent () + { + } + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ACCEPT_HANDOVER']" + [Register ("ACCEPT_HANDOVER")] + [global::System.Obsolete (@"Use 'Com.Xamarin.Android.IParent.AcceptHandover'. This class will be removed in a future release.")] + public const string AcceptHandover = (string) "android.permission.ACCEPT_HANDOVER"; + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ALREADY_OBSOLETE']" + [Register ("ALREADY_OBSOLETE")] + [global::System.Obsolete (@"deprecated")] + public const string AlreadyObsolete = (string) "android.permission.ACCEPT_HANDOVER"; + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='API_NAME']" + [Register ("API_NAME")] + [global::System.Obsolete (@"Use 'Com.Xamarin.Android.IParent.ApiName'. This class will be removed in a future release.")] + public static string ApiName { + get { + const string __id = "API_NAME.Ljava/lang/String;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparing' and count(parameter)=0]" + [global::System.Obsolete (@"Use 'Com.Xamarin.Android.IParent.Comparing'. This class will be removed in a future release.")] + [Register ("comparing", "()I", "")] + public static unsafe int Comparing () + { + const string __id = "comparing.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparingOld' and count(parameter)=0]" + [global::System.Obsolete (@"deprecated")] + [Register ("comparingOld", "()I", "")] + public static unsafe int ComparingOld () + { + const string __id = "comparingOld.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent", typeof (Parent)); + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent", typeof (IParent), isInterface: true); + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ACCEPT_HANDOVER']" + [Register ("ACCEPT_HANDOVER")] + public const string AcceptHandover = (string) "android.permission.ACCEPT_HANDOVER"; + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='ALREADY_OBSOLETE']" + [Register ("ALREADY_OBSOLETE")] + [global::System.Obsolete (@"deprecated")] + public const string AlreadyObsolete = (string) "android.permission.ACCEPT_HANDOVER"; + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/field[@name='API_NAME']" + [Register ("API_NAME")] + public static string ApiName { + get { + const string __id = "API_NAME.Ljava/lang/String;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparing' and count(parameter)=0]" + [Register ("comparing", "()I", "")] + public static unsafe int Comparing () + { + const string __id = "comparing.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='comparingOld' and count(parameter)=0]" + [global::System.Obsolete (@"deprecated")] + [Register ("comparingOld", "()I", "")] + public static unsafe int ComparingOld () + { + const string __id = "comparingOld.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClass.txt new file mode 100644 index 00000000000..1c657d1b170 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClass.txt @@ -0,0 +1,362 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + unsafe MyClass () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register (".ctor", "(Ljava/lang/String;)V", "")] + unsafe MyClass (string p0) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(Ljava/lang/String;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_p0 = JNIEnv.NewString ((string)p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + } + } + + static Delegate cb_get_Count_get_Count_I; +#pragma warning disable 0169 + static Delegate Getget_CountHandler () + { + return cb_get_Count_get_Count_I ??= new _JniMarshal_PP_I (n_get_Count); + } + + static int n_get_Count (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Count); + } + } + private static int __n_get_Count (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Count; + } +#pragma warning restore 0169 + + static Delegate cb_set_Count_set_Count_I_V; +#pragma warning disable 0169 + static Delegate Getset_Count_IHandler () + { + return cb_set_Count_set_Count_I_V ??= new _JniMarshal_PPI_V (n_set_Count_I); + } + + static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_Count_I); + } + } + private static void __n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Count = value; + } +#pragma warning restore 0169 + + public virtual unsafe int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler")] + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler")] + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + } + + static Delegate cb_get_Key_get_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate Getget_KeyHandler () + { + return cb_get_Key_get_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_get_Key); + } + + static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Key); + } + } + private static IntPtr __n_get_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); + } +#pragma warning restore 0169 + + static Delegate cb_set_Key_set_Key_Ljava_lang_String__V; +#pragma warning disable 0169 + static Delegate Getset_Key_Ljava_lang_String_Handler () + { + return cb_set_Key_set_Key_Ljava_lang_String__V ??= new _JniMarshal_PPL_V (n_set_Key_Ljava_lang_String_); + } + + static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_set_Key_Ljava_lang_String_); + } + } + private static void __n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; + } +#pragma warning restore 0169 + + public virtual unsafe string Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler")] + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler")] + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString ((string)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + public static unsafe int StaticCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_StaticCount' and count(parameter)=0]" + [Register ("get_StaticCount", "()I", "")] + get { + const string __id = "get_StaticCount.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_StaticCount", "(I)V", "")] + set { + const string __id = "set_StaticCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + + static Delegate cb_get_AbstractCount_get_AbstractCount_I; +#pragma warning disable 0169 + static Delegate Getget_AbstractCountHandler () + { + return cb_get_AbstractCount_get_AbstractCount_I ??= new _JniMarshal_PP_I (n_get_AbstractCount); + } + + static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_AbstractCount); + } + } + private static int __n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; + } +#pragma warning restore 0169 + + static Delegate cb_set_AbstractCount_set_AbstractCount_I_V; +#pragma warning disable 0169 + static Delegate Getset_AbstractCount_IHandler () + { + return cb_set_AbstractCount_set_AbstractCount_I_V ??= new _JniMarshal_PPI_V (n_set_AbstractCount_I); + } + + static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_AbstractCount_I); + } + } + private static void __n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; + } +#pragma warning restore 0169 + + public abstract int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set; + } + + static Delegate cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I; +#pragma warning disable 0169 + static Delegate GetGetCountForKey_Ljava_lang_String_Handler () + { + return cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I ??= new _JniMarshal_PPL_I (n_GetCountForKey_Ljava_lang_String_); + } + + static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_key, &__n_GetCountForKey_Ljava_lang_String_); + } + } + private static int __n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler")] + public virtual unsafe int GetCountForKey (string key) + { + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + IntPtr native_key = JNIEnv.NewString ((string)key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_key); + } + } + + static Delegate cb_Key_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetKeyHandler () + { + return cb_Key_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_Key); + } + + static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_Key); + } + } + private static IntPtr __n_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Key' and count(parameter)=0]" + [Register ("Key", "()Ljava/lang/String;", "GetKeyHandler")] + public virtual unsafe string Key () + { + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='StaticMethod' and count(parameter)=0]" + [Register ("StaticMethod", "()V", "")] + public static unsafe void StaticMethod () + { + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + + static Delegate cb_AbstractMethod_AbstractMethod_V; +#pragma warning disable 0169 + static Delegate GetAbstractMethodHandler () + { + return cb_AbstractMethod_AbstractMethod_V ??= new _JniMarshal_PP_V (n_AbstractMethod); + } + + static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_AbstractMethod); + } + } + private static void __n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" + [Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] + public abstract void AbstractMethod (); + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassConstructors.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassConstructors.txt new file mode 100644 index 00000000000..3fc335908ca --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassConstructors.txt @@ -0,0 +1,42 @@ +protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + +// Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=0]" +[Register (".ctor", "()V", "")] + unsafe MyClass () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + +// Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register (".ctor", "(Ljava/lang/String;)V", "")] + unsafe MyClass (string p0) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/String;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_p0 = JNIEnv.NewString (p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassHandle.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassHandle.txt new file mode 100644 index 00000000000..9cb131ceaff --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassHandle.txt @@ -0,0 +1,7 @@ + static readonly JniPeerMembers _members = new XAPeerMembers ("com/mypackage/foo", typeof (foo)); + internal static IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvoker.txt new file mode 100644 index 00000000000..9cd0169c047 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvoker.txt @@ -0,0 +1,52 @@ +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +internal partial class MyClassInvoker : MyClass { + + public MyClassInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) {} + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClassInvoker)); + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" + [Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] + public override unsafe void AbstractMethod () + { + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvokerHandle.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvokerHandle.txt new file mode 100644 index 00000000000..f19ad766ef7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvokerHandle.txt @@ -0,0 +1,10 @@ +static readonly JniPeerMembers _members = new XAPeerMembers ("com/mypackage/foo", typeof (Com.MyPackage.Foo)); + +public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } +} + +protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvokerMembers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvokerMembers.txt new file mode 100644 index 00000000000..98bc27c15f0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassInvokerMembers.txt @@ -0,0 +1,35 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethodInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethodInvokers.txt new file mode 100644 index 00000000000..7fec3768027 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethodInvokers.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethodInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethodInvokersWithSkips.txt new file mode 100644 index 00000000000..7fec3768027 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethodInvokersWithSkips.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public override unsafe void AbstractMethod () +{ + const string __id = "AbstractMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethods.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethods.txt new file mode 100644 index 00000000000..f054a3b8116 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassMethods.txt @@ -0,0 +1,93 @@ +static Delegate cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate GetGetCountForKey_Ljava_lang_String_Handler () +{ + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; +} + +static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" +[Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler")] +public virtual unsafe int GetCountForKey (string key) +{ + const string __id = "GetCountForKey.(Ljava/lang/String;)I"; + IntPtr native_key = JNIEnv.NewString (key); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_key); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_key); + } +} + +static Delegate cb_Key; +#pragma warning disable 0169 +static Delegate GetKeyHandler () +{ + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; +} + +static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Key' and count(parameter)=0]" +[Register ("Key", "()Ljava/lang/String;", "GetKeyHandler")] +public virtual unsafe string Key () +{ + const string __id = "Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } +} + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='StaticMethod' and count(parameter)=0]" +[Register ("StaticMethod", "()V", "")] +public static unsafe void StaticMethod () +{ + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } +} + +static Delegate cb_AbstractMethod; +#pragma warning disable 0169 +static Delegate GetAbstractMethodHandler () +{ + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; +} + +static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='AbstractMethod' and count(parameter)=0]" +[Register ("AbstractMethod", "()V", "GetAbstractMethodHandler")] +public abstract void AbstractMethod (); + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassProperties.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassProperties.txt new file mode 100644 index 00000000000..6801b7f3978 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassProperties.txt @@ -0,0 +1,178 @@ +static Delegate cb_get_Count; +#pragma warning disable 0169 +static Delegate Getget_CountHandler () +{ + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; +} + +static int n_get_Count (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Count; +} +#pragma warning restore 0169 + +static Delegate cb_set_Count_I; +#pragma warning disable 0169 +static Delegate Getset_Count_IHandler () +{ + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; +} + +static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Count = value; +} +#pragma warning restore 0169 + +public virtual unsafe int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler")] + get { + const string __id = "get_Count.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler")] + set { + const string __id = "set_Count.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } +} + +static Delegate cb_get_Key; +#pragma warning disable 0169 +static Delegate Getget_KeyHandler () +{ + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; +} + +static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); +} +#pragma warning restore 0169 + +static Delegate cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 +static Delegate Getset_Key_Ljava_lang_String_Handler () +{ + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; +} + +static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; +} +#pragma warning restore 0169 + +public virtual unsafe string Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler")] + get { + const string __id = "get_Key.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler")] + set { + const string __id = "set_Key.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} + +public static unsafe int StaticCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_StaticCount' and count(parameter)=0]" + [Register ("get_StaticCount", "()I", "")] + get { + const string __id = "get_StaticCount.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_StaticCount", "(I)V", "")] + set { + const string __id = "set_StaticCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } +} + +static Delegate cb_get_AbstractCount; +#pragma warning disable 0169 +static Delegate Getget_AbstractCountHandler () +{ + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; +} + +static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; +} +#pragma warning restore 0169 + +static Delegate cb_set_AbstractCount_I; +#pragma warning disable 0169 +static Delegate Getset_AbstractCount_IHandler () +{ + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; +} + +static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; +} +#pragma warning restore 0169 + +public abstract int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] get; + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] set; +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassPropertyInvokers.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassPropertyInvokers.txt new file mode 100644 index 00000000000..55d7c1ca13e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassPropertyInvokers.txt @@ -0,0 +1,24 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassPropertyInvokersWithSkips.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassPropertyInvokersWithSkips.txt new file mode 100644 index 00000000000..55d7c1ca13e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteClassPropertyInvokersWithSkips.txt @@ -0,0 +1,24 @@ +public override unsafe int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler")] + get { + const string __id = "get_AbstractCount.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler")] + set { + const string __id = "set_AbstractCount.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteConstSugarInterfaceFields.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteConstSugarInterfaceFields.txt new file mode 100644 index 00000000000..b488f9a2fae --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteConstSugarInterfaceFields.txt @@ -0,0 +1,64 @@ +[Register ("mono/internal/java/code/IMyInterface", DoNotGenerateAcw=true)] +public abstract class MyInterface : Java.Lang.Object { + internal MyInterface () + { + } + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyConstantField']" + [Register ("MyConstantField")] + public const int MyConstantField = (int) 7; + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyConstantStringField']" + [Register ("MyConstantStringField")] + public const string MyConstantStringField = (string) "hello"; + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyDeprecatedField']" + [Register ("MyDeprecatedField")] + [global::System.Obsolete] + public const int MyDeprecatedField = (int) 7; + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyDeprecatedEnumField']" + [Register ("MyDeprecatedEnumField")] + [global::System.Obsolete (@"This constant will be removed in the future version.")] + public const int MyDeprecatedEnumField = (int) MyEnumValue; + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyStaticField']" + [Register ("MyStaticField")] + public static int MyStaticField { + get { + const string __id = "MyStaticField.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + set { + const string __id = "MyStaticField.I"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (MyInterface)); + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +public partial interface IMyInterface { + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyConstantField']" + [Register ("MyConstantField")] + public const int MyConstantField = (int) 7; + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyConstantStringField']" + [Register ("MyConstantStringField")] + public const string MyConstantStringField = (string) "hello"; + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/field[@name='MyDeprecatedField']" + [Register ("MyDeprecatedField")] + [global::System.Obsolete] + public const int MyDeprecatedField = (int) 7; + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtor.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtor.txt new file mode 100644 index 00000000000..238012f4de2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtor.txt @@ -0,0 +1,18 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=0]" +[Register (".ctor", "", "")] + unsafe Object () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = ""; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtorDeprecated.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtorDeprecated.txt new file mode 100644 index 00000000000..159077c9b6b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtorDeprecated.txt @@ -0,0 +1,21 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=0]" +[Register (".ctor", "", "")] +[Obsolete (@"This constructor is obsolete")] +[MyAttribute] +[global::Android.Runtime.IntDefinition (null, JniField = "xamarin/test/SomeObject.SOME_VALUE")] + unsafe Object () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = ""; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtorWithStringOverload.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtorWithStringOverload.txt new file mode 100644 index 00000000000..eef2acbb8e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteCtorWithStringOverload.txt @@ -0,0 +1,43 @@ +// Metadata.xml XPath constructor reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/constructor[@name='foo' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" +[Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + unsafe Object (Java.Lang.ICharSequence mystring) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_mystring = CharSequence.ToLocalJniHandle (mystring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_mystring); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_mystring); + } +} + +[Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + unsafe Object (string mystring) + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) +{ + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_mystring = CharSequence.ToLocalJniHandle (mystring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_mystring); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_mystring); + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDefaultInterfaceMethodInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDefaultInterfaceMethodInvoker.txt new file mode 100644 index 00000000000..5d59da94f58 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDefaultInterfaceMethodInvoker.txt @@ -0,0 +1,126 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoDeclaration' and count(parameter)=0]" + [Register ("DoDeclaration", "()V", "GetDoDeclarationHandler:java.code.IMyInterfaceInvoker, MyAssembly")] + void DoDeclaration (); + + private static Delegate cb_DoDefault_DoDefault_V; +#pragma warning disable 0169 + private static Delegate GetDoDefaultHandler () + { + return cb_DoDefault_DoDefault_V ??= new _JniMarshal_PP_V (n_DoDefault); + } + + private static void n_DoDefault (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_DoDefault); + } + } + private static void __n_DoDefault (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoDefault (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoDefault' and count(parameter)=0]" + [Register ("DoDefault", "()V", "GetDoDefaultHandler:java.code.IMyInterface, MyAssembly")] + virtual unsafe void DoDefault () + { + const string __id = "DoDefault.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_DoDeclaration_DoDeclaration_V; +#pragma warning disable 0169 + static Delegate GetDoDeclarationHandler () + { + return cb_DoDeclaration_DoDeclaration_V ??= new _JniMarshal_PP_V (n_DoDeclaration); + } + + static void n_DoDeclaration (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_DoDeclaration); + } + } + private static void __n_DoDeclaration (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoDeclaration (); + } +#pragma warning restore 0169 + + IntPtr id_DoDeclaration; + public unsafe void DoDeclaration () + { + if (id_DoDeclaration == IntPtr.Zero) + id_DoDeclaration = JNIEnv.GetMethodID (class_ref, "DoDeclaration", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_DoDeclaration); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDuplicateInterfaceEventArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDuplicateInterfaceEventArgs.txt new file mode 100644 index 00000000000..d9a9e147628 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDuplicateInterfaceEventArgs.txt @@ -0,0 +1,217 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']" +[Register ("java/code/AnimatorListener", "", "java.code.AnimatorListenerInvoker")] +public partial interface AnimatorListener : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']/method[@name='OnAnimationEnd' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("OnAnimationEnd", "(I)Z", "GetOnAnimationEnd_IHandler:java.code.AnimatorListenerInvoker, ")] + bool OnAnimationEnd (int param1); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='AnimatorListener']/method[@name='OnAnimationEnd' and count(parameter)=2 and parameter[1][@type='int'] and parameter[2][@type='int']]" + [Register ("OnAnimationEnd", "(II)Z", "GetOnAnimationEnd_IIHandler:java.code.AnimatorListenerInvoker, ")] + bool OnAnimationEnd (int param1, int param2); + +} + +[global::Android.Runtime.Register ("java/code/AnimatorListener", DoNotGenerateAcw=true)] +internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, AnimatorListener { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/AnimatorListener", typeof (AnimatorListenerInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static AnimatorListener GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.AnimatorListener'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public AnimatorListenerInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_OnAnimationEnd_OnAnimationEnd_I_Z; +#pragma warning disable 0169 + static Delegate GetOnAnimationEnd_IHandler () + { + return cb_OnAnimationEnd_OnAnimationEnd_I_Z ??= new _JniMarshal_PPI_B (n_OnAnimationEnd_I); + } + + static sbyte n_OnAnimationEnd_I (IntPtr jnienv, IntPtr native__this, int param1) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, param1, &__n_OnAnimationEnd_I); + } + } + private static sbyte __n_OnAnimationEnd_I (IntPtr jnienv, IntPtr native__this, int param1) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.OnAnimationEnd (param1) ? (sbyte)1 : (sbyte)0; + } +#pragma warning restore 0169 + + IntPtr id_OnAnimationEnd_I; + public unsafe bool OnAnimationEnd (int param1) + { + if (id_OnAnimationEnd_I == IntPtr.Zero) + id_OnAnimationEnd_I = JNIEnv.GetMethodID (class_ref, "OnAnimationEnd", "(I)Z"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (param1); + return JNIEnv.CallBooleanMethod (((global::Java.Lang.Object) this).Handle, id_OnAnimationEnd_I, __args); + } + + static Delegate cb_OnAnimationEnd_OnAnimationEnd_II_Z; +#pragma warning disable 0169 + static Delegate GetOnAnimationEnd_IIHandler () + { + return cb_OnAnimationEnd_OnAnimationEnd_II_Z ??= new _JniMarshal_PPII_B (n_OnAnimationEnd_II); + } + + static sbyte n_OnAnimationEnd_II (IntPtr jnienv, IntPtr native__this, int param1, int param2) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, param1, param2, &__n_OnAnimationEnd_II); + } + } + private static sbyte __n_OnAnimationEnd_II (IntPtr jnienv, IntPtr native__this, int param1, int param2) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.OnAnimationEnd (param1, param2) ? (sbyte)1 : (sbyte)0; + } +#pragma warning restore 0169 + + IntPtr id_OnAnimationEnd_II; + public unsafe bool OnAnimationEnd (int param1, int param2) + { + if (id_OnAnimationEnd_II == IntPtr.Zero) + id_OnAnimationEnd_II = JNIEnv.GetMethodID (class_ref, "OnAnimationEnd", "(II)Z"); + JValue* __args = stackalloc JValue [2]; + __args [0] = new JValue (param1); + __args [1] = new JValue (param2); + return JNIEnv.CallBooleanMethod (((global::Java.Lang.Object) this).Handle, id_OnAnimationEnd_II, __args); + } + +} + +// event args for java.code.AnimatorListener.OnAnimationEnd +public partial class AnimationEndEventArgs : global::System.EventArgs { + bool handled; + + public bool Handled { + get { return handled; } + set { handled = value; } + } + + public AnimationEndEventArgs (bool handled, int param1) + { + this.handled = handled; + this.param1 = param1; + } + + int param1; + + public int Param1 { + get { return param1; } + } + + public AnimationEndEventArgs (bool handled, int param1, int param2) + { + this.handled = handled; + this.param1 = param1; + this.param2 = param2; + } + + int param2; + + public int Param2 { + get { return param2; } + } + +} + +[global::Android.Runtime.Register ("mono/java/code/AnimatorListenerImplementor")] +internal sealed partial class AnimatorListenerImplementor : global::Java.Lang.Object, AnimatorListener { + + object sender; + + public unsafe AnimatorListenerImplementor (object sender) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + var h = JniPeerMembers.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (h.Handle, JniHandleOwnership.TransferLocalRef); + JniPeerMembers.InstanceMethods.FinishCreateInstance (__id, this, null); + this.sender = sender; + } + + #pragma warning disable 0649 + public EventHandler OnAnimationEndHandler; + #pragma warning restore 0649 + + public bool OnAnimationEnd (int param1) + { + var __h = OnAnimationEndHandler; + if (__h == null) + return false; + var __e = new AnimationEndEventArgs (true, param1); + __h (sender, __e); + return __e.Handled; + } + + #pragma warning disable 0649 + public EventHandler OnAnimationEndHandler; + #pragma warning restore 0649 + + public bool OnAnimationEnd (int param1, int param2) + { + var __h = OnAnimationEndHandler; + if (__h == null) + return false; + var __e = new AnimationEndEventArgs (true, param1, param2); + __h (sender, __e); + return __e.Handled; + } + + internal static bool __IsEmpty (AnimatorListenerImplementor value) + { + return value.OnAnimationEndHandler == null && value.OnAnimationEndHandler == null; + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstant.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstant.txt new file mode 100644 index 00000000000..73ac8ae2c10 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstant.txt @@ -0,0 +1,11 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public static string bar { + get { + const string __id = "bar.Ljava/lang/String;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstantWithIntValue.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstantWithIntValue.txt new file mode 100644 index 00000000000..a1f3257f0d2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstantWithIntValue.txt @@ -0,0 +1,3 @@ +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public const int bar = (int) 1234; diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstantWithStringValue.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstantWithStringValue.txt new file mode 100644 index 00000000000..1e7186b009f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldConstantWithStringValue.txt @@ -0,0 +1,3 @@ +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public const string bar = (string) "hello"; diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldGetBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldGetBody.txt new file mode 100644 index 00000000000..44cde23dc2f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldGetBody.txt @@ -0,0 +1,4 @@ +const string __id = "bar.Ljava/lang/String;"; + +var __v = _members.InstanceFields.GetObjectValue (__id, this); +return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldIdField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldIdField.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldInt.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldInt.txt new file mode 100644 index 00000000000..d1a71f54efe --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldInt.txt @@ -0,0 +1,19 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public int bar { + get { + const string __id = "bar.I"; + + var __v = _members.InstanceFields.GetInt32Value (__id, this); + return __v; + } + set { + const string __id = "bar.I"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldSetBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldSetBody.txt new file mode 100644 index 00000000000..77008f500d8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldSetBody.txt @@ -0,0 +1,8 @@ +const string __id = "bar.Ljava/lang/String;"; + +IntPtr native_value = JNIEnv.NewString (value); +try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); +} finally { + JNIEnv.DeleteLocalRef (native_value); +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldString.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldString.txt new file mode 100644 index 00000000000..71301606891 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteFieldString.txt @@ -0,0 +1,21 @@ + +// Metadata.xml XPath field reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/field[@name='bar']" +[Register ("bar")] +public string bar { + get { + const string __id = "bar.Ljava/lang/String;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return JNIEnv.GetString (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "bar.Ljava/lang/String;"; + + IntPtr native_value = JNIEnv.NewString (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterface.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterface.txt new file mode 100644 index 00000000000..95e0067dee4 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterface.txt @@ -0,0 +1,398 @@ +[Register ("mono/internal/java/code/IMyInterface", DoNotGenerateAcw=true)] +public abstract class MyInterface : Java.Lang.Object { + internal MyInterface () + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='StaticMethod' and count(parameter)=0]" + [Register ("StaticMethod", "()V", "")] + public static unsafe void StaticMethod () + { + const string __id = "StaticMethod.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (MyInterface)); + +} + +[Register ("mono/internal/java/code/IMyInterface", DoNotGenerateAcw=true)] +[global::System.Obsolete (@"Use the 'MyInterface' type. This type will be removed in a future release.", error: true)] +public abstract class MyInterfaceConsts : MyInterface { + private MyInterfaceConsts () + { + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + int Count { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Count' and count(parameter)=0]" + [Register ("get_Count", "()I", "Getget_CountHandler:java.code.IMyInterfaceInvoker, ")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Count' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Count", "(I)V", "Getset_Count_IHandler:java.code.IMyInterfaceInvoker, ")] + set; + } + + string Key { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Key' and count(parameter)=0]" + [Register ("get_Key", "()Ljava/lang/String;", "Getget_KeyHandler:java.code.IMyInterfaceInvoker, ")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Key' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("set_Key", "(Ljava/lang/String;)V", "Getset_Key_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] + set; + } + + int AbstractCount { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_AbstractCount' and count(parameter)=0]" + [Register ("get_AbstractCount", "()I", "Getget_AbstractCountHandler:java.code.IMyInterfaceInvoker, ")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_AbstractCount' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_AbstractCount", "(I)V", "Getset_AbstractCount_IHandler:java.code.IMyInterfaceInvoker, ")] + set; + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("GetCountForKey", "(Ljava/lang/String;)I", "GetGetCountForKey_Ljava_lang_String_Handler:java.code.IMyInterfaceInvoker, ")] + int GetCountForKey (string key); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='Key' and count(parameter)=0]" + [Register ("Key", "()Ljava/lang/String;", "GetKeyHandler:java.code.IMyInterfaceInvoker, ")] + string Key (); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='AbstractMethod' and count(parameter)=0]" + [Register ("AbstractMethod", "()V", "GetAbstractMethodHandler:java.code.IMyInterfaceInvoker, ")] + void AbstractMethod (); + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_get_Count_get_Count_I; +#pragma warning disable 0169 + static Delegate Getget_CountHandler () + { + return cb_get_Count_get_Count_I ??= new _JniMarshal_PP_I (n_get_Count); + } + + static int n_get_Count (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Count); + } + } + private static int __n_get_Count (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Count; + } +#pragma warning restore 0169 + + static Delegate cb_set_Count_set_Count_I_V; +#pragma warning disable 0169 + static Delegate Getset_Count_IHandler () + { + return cb_set_Count_set_Count_I_V ??= new _JniMarshal_PPI_V (n_set_Count_I); + } + + static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_Count_I); + } + } + private static void __n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Count = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Count; + IntPtr id_set_Count_I; + public unsafe int Count { + get { + if (id_get_Count == IntPtr.Zero) + id_get_Count = JNIEnv.GetMethodID (class_ref, "get_Count", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_Count); + } + set { + if (id_set_Count_I == IntPtr.Zero) + id_set_Count_I = JNIEnv.GetMethodID (class_ref, "set_Count", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Count_I, __args); + } + } + + static Delegate cb_get_Key_get_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate Getget_KeyHandler () + { + return cb_get_Key_get_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_get_Key); + } + + static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Key); + } + } + private static IntPtr __n_get_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); + } +#pragma warning restore 0169 + + static Delegate cb_set_Key_set_Key_Ljava_lang_String__V; +#pragma warning disable 0169 + static Delegate Getset_Key_Ljava_lang_String_Handler () + { + return cb_set_Key_set_Key_Ljava_lang_String__V ??= new _JniMarshal_PPL_V (n_set_Key_Ljava_lang_String_); + } + + static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_set_Key_Ljava_lang_String_); + } + } + private static void __n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Key; + IntPtr id_set_Key_Ljava_lang_String_; + public unsafe string Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString ((string)value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } + } + + static Delegate cb_get_AbstractCount_get_AbstractCount_I; +#pragma warning disable 0169 + static Delegate Getget_AbstractCountHandler () + { + return cb_get_AbstractCount_get_AbstractCount_I ??= new _JniMarshal_PP_I (n_get_AbstractCount); + } + + static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_AbstractCount); + } + } + private static int __n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; + } +#pragma warning restore 0169 + + static Delegate cb_set_AbstractCount_set_AbstractCount_I_V; +#pragma warning disable 0169 + static Delegate Getset_AbstractCount_IHandler () + { + return cb_set_AbstractCount_set_AbstractCount_I_V ??= new _JniMarshal_PPI_V (n_set_AbstractCount_I); + } + + static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_AbstractCount_I); + } + } + private static void __n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; + } +#pragma warning restore 0169 + + IntPtr id_get_AbstractCount; + IntPtr id_set_AbstractCount_I; + public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } + } + + static Delegate cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I; +#pragma warning disable 0169 + static Delegate GetGetCountForKey_Ljava_lang_String_Handler () + { + return cb_GetCountForKey_GetCountForKey_Ljava_lang_String__I ??= new _JniMarshal_PPL_I (n_GetCountForKey_Ljava_lang_String_); + } + + static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_key, &__n_GetCountForKey_Ljava_lang_String_); + } + } + private static int __n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; + } +#pragma warning restore 0169 + + IntPtr id_GetCountForKey_Ljava_lang_String_; + public unsafe int GetCountForKey (string key) + { + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString ((string)key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; + } + + static Delegate cb_Key_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetKeyHandler () + { + return cb_Key_Key_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_Key); + } + + static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_Key); + } + } + private static IntPtr __n_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); + } +#pragma warning restore 0169 + + IntPtr id_Key; + public unsafe string Key () + { + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); + } + + static Delegate cb_AbstractMethod_AbstractMethod_V; +#pragma warning disable 0169 + static Delegate GetAbstractMethodHandler () + { + return cb_AbstractMethod_AbstractMethod_V ??= new _JniMarshal_PP_V (n_AbstractMethod); + } + + static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_AbstractMethod); + } + } + private static void __n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); + } +#pragma warning restore 0169 + + IntPtr id_AbstractMethod; + public unsafe void AbstractMethod () + { + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultMethod.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultMethod.txt new file mode 100644 index 00000000000..ac082d8eb41 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultMethod.txt @@ -0,0 +1,94 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + private static Delegate cb_DoSomething_DoSomething_V; +#pragma warning disable 0169 + private static Delegate GetDoSomethingHandler () + { + return cb_DoSomething_DoSomething_V ??= new _JniMarshal_PP_V (n_DoSomething); + } + + private static void n_DoSomething (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_DoSomething); + } + } + private static void __n_DoSomething (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoSomething (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "GetDoSomethingHandler:java.code.IMyInterface, MyAssembly")] + virtual unsafe void DoSomething () + { + const string __id = "DoSomething.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultProperty.txt new file mode 100644 index 00000000000..67421f99016 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultProperty.txt @@ -0,0 +1,127 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + private static Delegate cb_get_Value_get_Value_I; +#pragma warning disable 0169 + private static Delegate Getget_ValueHandler () + { + return cb_get_Value_get_Value_I ??= new _JniMarshal_PP_I (n_get_Value); + } + + private static int n_get_Value (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Value); + } + } + private static int __n_get_Value (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Value; + } +#pragma warning restore 0169 + + private static Delegate cb_set_Value_set_Value_I_V; +#pragma warning disable 0169 + private static Delegate Getset_Value_IHandler () + { + return cb_set_Value_set_Value_I_V ??= new _JniMarshal_PPI_V (n_set_Value_I); + } + + private static void n_set_Value_I (IntPtr jnienv, IntPtr native__this, int value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, value, &__n_set_Value_I); + } + } + private static void __n_set_Value_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Value = value; + } +#pragma warning restore 0169 + + virtual unsafe int Value { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Value' and count(parameter)=0]" + [Register ("get_Value", "()I", "Getget_ValueHandler:java.code.IMyInterface, MyAssembly")] + get { + const string __id = "get_Value.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Value' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Value", "(I)V", "Getset_Value_IHandler:java.code.IMyInterface, MyAssembly")] + set { + const string __id = "set_Value.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultPropertyGetterOnly.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultPropertyGetterOnly.txt new file mode 100644 index 00000000000..488953adf75 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceDefaultPropertyGetterOnly.txt @@ -0,0 +1,96 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + private static Delegate cb_get_Value_get_Value_I; +#pragma warning disable 0169 + private static Delegate Getget_ValueHandler () + { + return cb_get_Value_get_Value_I ??= new _JniMarshal_PP_I (n_get_Value); + } + + private static int n_get_Value (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_get_Value); + } + } + private static int __n_get_Value (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Value; + } +#pragma warning restore 0169 + + virtual unsafe int Value { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Value' and count(parameter)=0]" + [Register ("get_Value", "()I", "Getget_ValueHandler:java.code.IMyInterface, MyAssembly")] + get { + const string __id = "get_Value.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceFieldAsDimProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceFieldAsDimProperty.txt new file mode 100644 index 00000000000..f19f65d0f07 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceFieldAsDimProperty.txt @@ -0,0 +1,126 @@ +[Register ("mono/internal/com/xamarin/android/MyInterface", DoNotGenerateAcw=true)] +public abstract class MyInterface : Java.Lang.Object { + internal MyInterface () + { + } + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']/field[@name='EGL_NATIVE_VISUAL_ID']" + [Register ("EGL_NATIVE_VISUAL_ID")] + public const int EglNativeVisualId = (int) 12334; + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']/field[@name='EGL_NO_SURFACE']" + [Register ("EGL_NO_SURFACE")] + public static int EglNoSurface { + get { + const string __id = "EGL_NO_SURFACE.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + set { + const string __id = "EGL_NO_SURFACE.I"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/MyInterface", typeof (MyInterface)); + +} + +[Register ("mono/internal/com/xamarin/android/MyInterface", DoNotGenerateAcw=true)] +[global::System.Obsolete (@"Use the 'MyInterface' type. This type will be removed in a future release.", error: true)] +public abstract class MyInterfaceConsts : MyInterface { + private MyInterfaceConsts () + { + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']" +[Register ("com/xamarin/android/MyInterface", "", "Com.Xamarin.Android.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/MyInterface", typeof (IMyInterface), isInterface: true); + + + // Metadata.xml XPath field reference: path="/api/package[@name='com.xamarin.android']/interface[@name='MyInterface']/field[@name='EGL_NO_SURFACE']" + [Register ("EGL_NO_SURFACE")] + public static int EglNoSurface { + get { + const string __id = "EGL_NO_SURFACE.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + set { + const string __id = "EGL_NO_SURFACE.I"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/MyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/MyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.MyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceInvoker.txt new file mode 100644 index 00000000000..32ccaa9ae4d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceInvoker.txt @@ -0,0 +1,282 @@ +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.", + JNIEnv.GetClassNameFromInstance (handle), "java.code.IMyInterface")); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_get_Count; +#pragma warning disable 0169 + static Delegate Getget_CountHandler () + { + if (cb_get_Count == null) + cb_get_Count = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_Count); + return cb_get_Count; + } + + static int n_get_Count (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Count; + } +#pragma warning restore 0169 + + static Delegate cb_set_Count_I; +#pragma warning disable 0169 + static Delegate Getset_Count_IHandler () + { + if (cb_set_Count_I == null) + cb_set_Count_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_Count_I); + return cb_set_Count_I; + } + + static void n_set_Count_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Count = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Count; + IntPtr id_set_Count_I; + public unsafe int Count { + get { + if (id_get_Count == IntPtr.Zero) + id_get_Count = JNIEnv.GetMethodID (class_ref, "get_Count", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_Count); + } + set { + if (id_set_Count_I == IntPtr.Zero) + id_set_Count_I = JNIEnv.GetMethodID (class_ref, "set_Count", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Count_I, __args); + } + } + + static Delegate cb_get_Key; +#pragma warning disable 0169 + static Delegate Getget_KeyHandler () + { + if (cb_get_Key == null) + cb_get_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_get_Key); + return cb_get_Key; + } + + static IntPtr n_get_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key); + } +#pragma warning restore 0169 + + static Delegate cb_set_Key_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate Getset_Key_Ljava_lang_String_Handler () + { + if (cb_set_Key_Ljava_lang_String_ == null) + cb_set_Key_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_set_Key_Ljava_lang_String_); + return cb_set_Key_Ljava_lang_String_; + } + + static void n_set_Key_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = JNIEnv.GetString (native_value, JniHandleOwnership.DoNotTransfer); + __this.Key = value; + } +#pragma warning restore 0169 + + IntPtr id_get_Key; + IntPtr id_set_Key_Ljava_lang_String_; + public unsafe string Key { + get { + if (id_get_Key == IntPtr.Zero) + id_get_Key = JNIEnv.GetMethodID (class_ref, "get_Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_get_Key), JniHandleOwnership.TransferLocalRef); + } + set { + if (id_set_Key_Ljava_lang_String_ == IntPtr.Zero) + id_set_Key_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "set_Key", "(Ljava/lang/String;)V"); + IntPtr native_value = JNIEnv.NewString (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_Key_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_value); + } + } + + static Delegate cb_get_AbstractCount; +#pragma warning disable 0169 + static Delegate Getget_AbstractCountHandler () + { + if (cb_get_AbstractCount == null) + cb_get_AbstractCount = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_AbstractCount); + return cb_get_AbstractCount; + } + + static int n_get_AbstractCount (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.AbstractCount; + } +#pragma warning restore 0169 + + static Delegate cb_set_AbstractCount_I; +#pragma warning disable 0169 + static Delegate Getset_AbstractCount_IHandler () + { + if (cb_set_AbstractCount_I == null) + cb_set_AbstractCount_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_AbstractCount_I); + return cb_set_AbstractCount_I; + } + + static void n_set_AbstractCount_I (IntPtr jnienv, IntPtr native__this, int value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractCount = value; + } +#pragma warning restore 0169 + + IntPtr id_get_AbstractCount; + IntPtr id_set_AbstractCount_I; + public unsafe int AbstractCount { + get { + if (id_get_AbstractCount == IntPtr.Zero) + id_get_AbstractCount = JNIEnv.GetMethodID (class_ref, "get_AbstractCount", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_get_AbstractCount); + } + set { + if (id_set_AbstractCount_I == IntPtr.Zero) + id_set_AbstractCount_I = JNIEnv.GetMethodID (class_ref, "set_AbstractCount", "(I)V"); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_set_AbstractCount_I, __args); + } + } + + static Delegate cb_GetCountForKey_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetGetCountForKey_Ljava_lang_String_Handler () + { + if (cb_GetCountForKey_Ljava_lang_String_ == null) + cb_GetCountForKey_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_I) n_GetCountForKey_Ljava_lang_String_); + return cb_GetCountForKey_Ljava_lang_String_; + } + + static int n_GetCountForKey_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_key) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var key = JNIEnv.GetString (native_key, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetCountForKey (key); + return __ret; + } +#pragma warning restore 0169 + + IntPtr id_GetCountForKey_Ljava_lang_String_; + public unsafe int GetCountForKey (string key) + { + if (id_GetCountForKey_Ljava_lang_String_ == IntPtr.Zero) + id_GetCountForKey_Ljava_lang_String_ = JNIEnv.GetMethodID (class_ref, "GetCountForKey", "(Ljava/lang/String;)I"); + IntPtr native_key = JNIEnv.NewString (key); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_key); + var __ret = JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_GetCountForKey_Ljava_lang_String_, __args); + JNIEnv.DeleteLocalRef (native_key); + return __ret; + } + + static Delegate cb_Key; +#pragma warning disable 0169 + static Delegate GetKeyHandler () + { + if (cb_Key == null) + cb_Key = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_Key); + return cb_Key; + } + + static IntPtr n_Key (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Key ()); + } +#pragma warning restore 0169 + + IntPtr id_Key; + public unsafe string Key () + { + if (id_Key == IntPtr.Zero) + id_Key = JNIEnv.GetMethodID (class_ref, "Key", "()Ljava/lang/String;"); + return JNIEnv.GetString (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_Key), JniHandleOwnership.TransferLocalRef); + } + + static Delegate cb_AbstractMethod; +#pragma warning disable 0169 + static Delegate GetAbstractMethodHandler () + { + if (cb_AbstractMethod == null) + cb_AbstractMethod = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_AbstractMethod); + return cb_AbstractMethod; + } + + static void n_AbstractMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.AbstractMethod (); + } +#pragma warning restore 0169 + + IntPtr id_AbstractMethod; + public unsafe void AbstractMethod () + { + if (id_AbstractMethod == IntPtr.Zero) + id_AbstractMethod = JNIEnv.GetMethodID (class_ref, "AbstractMethod", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_AbstractMethod); + } + +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceRedeclaredDefaultMethod.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceRedeclaredDefaultMethod.txt new file mode 100644 index 00000000000..3a4dfc43f0e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteInterfaceRedeclaredDefaultMethod.txt @@ -0,0 +1,93 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface2']" +[Register ("java/code/IMyInterface2", "", "java.code.IMyInterface2Invoker")] +public partial interface IMyInterface2 : java.code.IMyInterface { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "GetDoSomethingHandler:java.code.IMyInterface2Invoker, MyAssembly")] + void DoSomething (); + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface2", DoNotGenerateAcw=true)] +internal partial class IMyInterface2Invoker : global::Java.Lang.Object, IMyInterface2 { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface2", typeof (IMyInterface2Invoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface2 GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface2'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterface2Invoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_DoSomething_DoSomething_V; +#pragma warning disable 0169 + static Delegate GetDoSomethingHandler () + { + return cb_DoSomething_DoSomething_V ??= new _JniMarshal_PP_V (n_DoSomething); + } + + static void n_DoSomething (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_DoSomething); + } + } + private static void __n_DoSomething (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.DoSomething (); + } +#pragma warning restore 0169 + + IntPtr id_DoSomething; + public unsafe void DoSomething () + { + if (id_DoSomething == IntPtr.Zero) + id_DoSomething = JNIEnv.GetMethodID (class_ref, "DoSomething", "()V"); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_DoSomething); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt new file mode 100644 index 00000000000..cbdfcb4f6c2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt @@ -0,0 +1,94 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='uint[]']]" + [Register ("Echo", "([I)[I", "")] + public unsafe uint[] Echo (uint[] value) + { + const string __id = "Echo.([I)[I"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (uint[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (uint)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ushort[]']]" + [Register ("Echo", "([S)[S", "")] + public unsafe ushort[] Echo (ushort[] value) + { + const string __id = "Echo.([S)[S"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (ushort[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ushort)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ulong[]']]" + [Register ("Echo", "([J)[J", "")] + public unsafe ulong[] Echo (ulong[] value) + { + const string __id = "Echo.([J)[J"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (ulong[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ulong)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ubyte[]']]" + [Register ("Echo", "([B)[B", "")] + public unsafe byte[] Echo (byte[] value) + { + const string __id = "Echo.([B)[B"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (byte[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (byte)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt new file mode 100644 index 00000000000..8736f0eab7d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt @@ -0,0 +1,134 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + public unsafe uint[] UIntProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UIntProp' and count(parameter)=0]" + [Register ("get_UIntProp", "()[I", "")] + get { + const string __id = "get_UIntProp.()[I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (uint[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (uint)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UIntProp' and count(parameter)=1 and parameter[1][@type='uint[]']]" + [Register ("set_UIntProp", "([I)V", "")] + set { + const string __id = "set_UIntProp.([I)V"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + } + + public unsafe ushort[] UShortProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UShortProp' and count(parameter)=0]" + [Register ("get_UShortProp", "()[S", "")] + get { + const string __id = "get_UShortProp.()[S"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (ushort[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ushort)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UShortProp' and count(parameter)=1 and parameter[1][@type='ushort[]']]" + [Register ("set_UShortProp", "([S)V", "")] + set { + const string __id = "set_UShortProp.([S)V"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + } + + public unsafe ulong[] ULongProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_ULongProp' and count(parameter)=0]" + [Register ("get_ULongProp", "()[J", "")] + get { + const string __id = "get_ULongProp.()[J"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (ulong[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ulong)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_ULongProp' and count(parameter)=1 and parameter[1][@type='ulong[]']]" + [Register ("set_ULongProp", "([J)V", "")] + set { + const string __id = "set_ULongProp.([J)V"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + } + + public unsafe byte[] UByteProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UByteProp' and count(parameter)=0]" + [Register ("get_UByteProp", "()[B", "")] + get { + const string __id = "get_UByteProp.()[B"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (byte[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (byte)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UByteProp' and count(parameter)=1 and parameter[1][@type='ubyte[]']]" + [Register ("set_UByteProp", "([B)V", "")] + set { + const string __id = "set_UByteProp.([B)V"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt new file mode 100644 index 00000000000..3b132be4563 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt @@ -0,0 +1,70 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='uint']]" + [Register ("Echo", "(I)I", "")] + public unsafe uint Echo (uint value) + { + const string __id = "Echo.(I)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return (uint)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ushort']]" + [Register ("Echo", "(S)S", "")] + public unsafe ushort Echo (ushort value) + { + const string __id = "Echo.(S)S"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt16Method (__id, this, __args); + return (ushort)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ulong']]" + [Register ("Echo", "(J)J", "")] + public unsafe ulong Echo (ulong value) + { + const string __id = "Echo.(J)J"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt64Method (__id, this, __args); + return (ulong)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ubyte']]" + [Register ("Echo", "(B)B", "")] + public unsafe byte Echo (byte value) + { + const string __id = "Echo.(B)B"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractSByteMethod (__id, this, __args); + return (byte)__rm; + } finally { + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt new file mode 100644 index 00000000000..7538d95984a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt @@ -0,0 +1,110 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + public unsafe uint UIntProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UIntProp' and count(parameter)=0]" + [Register ("get_UIntProp", "()I", "")] + get { + const string __id = "get_UIntProp.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return (uint)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UIntProp' and count(parameter)=1 and parameter[1][@type='uint']]" + [Register ("set_UIntProp", "(I)V", "")] + set { + const string __id = "set_UIntProp.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe ushort UShortProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UShortProp' and count(parameter)=0]" + [Register ("get_UShortProp", "()S", "")] + get { + const string __id = "get_UShortProp.()S"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt16Method (__id, this, null); + return (ushort)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UShortProp' and count(parameter)=1 and parameter[1][@type='ushort']]" + [Register ("set_UShortProp", "(S)V", "")] + set { + const string __id = "set_UShortProp.(S)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe ulong ULongProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_ULongProp' and count(parameter)=0]" + [Register ("get_ULongProp", "()J", "")] + get { + const string __id = "get_ULongProp.()J"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt64Method (__id, this, null); + return (ulong)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_ULongProp' and count(parameter)=1 and parameter[1][@type='ulong']]" + [Register ("set_ULongProp", "(J)V", "")] + set { + const string __id = "set_ULongProp.(J)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe byte UByteProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UByteProp' and count(parameter)=0]" + [Register ("get_UByteProp", "()B", "")] + get { + const string __id = "get_UByteProp.()B"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractSByteMethod (__id, this, null); + return (byte)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UByteProp' and count(parameter)=1 and parameter[1][@type='ubyte']]" + [Register ("set_UByteProp", "(B)V", "")] + set { + const string __id = "set_UByteProp.(B)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAbstractWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAbstractWithVoidReturn.txt new file mode 100644 index 00000000000..7b481c02827 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAbstractWithVoidReturn.txt @@ -0,0 +1,27 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAsyncifiedWithIntReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAsyncifiedWithIntReturn.txt new file mode 100644 index 00000000000..0f42c6004d5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAsyncifiedWithIntReturn.txt @@ -0,0 +1,33 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_bar); + return cb_bar; +} + +static int n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()I", "GetbarHandler")] +public virtual unsafe int bar () +{ + const string __id = "bar.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } +} + +public global::System.Threading.Tasks.Task barAsync () +{ + return global::System.Threading.Tasks.Task.Run (() => bar ()); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAsyncifiedWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAsyncifiedWithVoidReturn.txt new file mode 100644 index 00000000000..3f8ee287ba9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodAsyncifiedWithVoidReturn.txt @@ -0,0 +1,32 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + +public global::System.Threading.Tasks.Task barAsync () +{ + return global::System.Threading.Tasks.Task.Run (() => bar ()); +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodBody.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodBody.txt new file mode 100644 index 00000000000..49e16b4888e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodBody.txt @@ -0,0 +1,5 @@ +const string __id = "bar.()V"; +try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); +} finally { +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodFinalWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodFinalWithVoidReturn.txt new file mode 100644 index 00000000000..28abf4fe7d6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodFinalWithVoidReturn.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "")] +public unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeNonvirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodIdField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodIdField.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodProtected.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodProtected.txt new file mode 100644 index 00000000000..d5025685d8c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodProtected.txt @@ -0,0 +1,27 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +protected virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodStaticWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodStaticWithVoidReturn.txt new file mode 100644 index 00000000000..05fb6bf0b0c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodStaticWithVoidReturn.txt @@ -0,0 +1,11 @@ +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "")] +public static unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithCharSequenceArrays.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithCharSequenceArrays.txt new file mode 100644 index 00000000000..8c8faaf179f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithCharSequenceArrays.txt @@ -0,0 +1,85 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='com.example']/class[@name='MyClass']" +[global::Android.Runtime.Register ("com/example/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass : Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/example/MyClass", typeof (MyClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_echo_Echo_arrayLjava_lang_CharSequence__arrayLjava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetEcho_arrayLjava_lang_CharSequence_Handler () + { + return cb_echo_Echo_arrayLjava_lang_CharSequence__arrayLjava_lang_CharSequence_ ??= new _JniMarshal_PPL_L (n_Echo_arrayLjava_lang_CharSequence_); + } + + static IntPtr n_Echo_arrayLjava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_messages) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_messages, &__n_Echo_arrayLjava_lang_CharSequence_); + } + } + private static IntPtr __n_Echo_arrayLjava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_messages) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var messages = (Java.Lang.ICharSequence[]) JNIEnv.GetArray (native_messages, JniHandleOwnership.DoNotTransfer, typeof (Java.Lang.ICharSequence)); + IntPtr __ret = JNIEnv.NewArray (__this.EchoFormatted (messages)); + if (messages != null) + JNIEnv.CopyArray (messages, native_messages); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='com.example']/class[@name='MyClass']/method[@name='echo' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence[]']]" + [Register ("echo", "([Ljava/lang/CharSequence;)[Ljava/lang/CharSequence;", "GetEcho_arrayLjava_lang_CharSequence_Handler")] + public virtual unsafe Java.Lang.ICharSequence[] EchoFormatted (Java.Lang.ICharSequence[] messages) + { + const string __id = "echo.([Ljava/lang/CharSequence;)[Ljava/lang/CharSequence;"; + IntPtr native_messages = JNIEnv.NewArray (messages); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_messages); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return (Java.Lang.ICharSequence[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (Java.Lang.ICharSequence)); + } finally { + if (messages != null) { + JNIEnv.CopyArray (native_messages, messages); + JNIEnv.DeleteLocalRef (native_messages); + } + global::System.GC.KeepAlive (messages); + } + } + + public string[] Echo (string[] messages) + { + var jlca_messages = CharSequence.ArrayFromStringArray (messages); + Java.Lang.ICharSequence[] __result = EchoFormatted (jlca_messages); + var __rsval = CharSequence.ArrayToStringArray (__result); + if (jlca_messages != null) foreach (var s in jlca_messages) s?.Dispose (); + return __rsval; + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithIntReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithIntReturn.txt new file mode 100644 index 00000000000..c28a0162932 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithIntReturn.txt @@ -0,0 +1,28 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_bar); + return cb_bar; +} + +static int n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()I", "GetbarHandler")] +public virtual unsafe int bar () +{ + const string __id = "bar.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithStringReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithStringReturn.txt new file mode 100644 index 00000000000..6cc92638cee --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithStringReturn.txt @@ -0,0 +1,28 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_L) n_bar); + return cb_bar; +} + +static IntPtr n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.bar ()); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()Ljava/lang/String;", "GetbarHandler")] +public virtual unsafe string bar () +{ + const string __id = "bar.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithVoidReturn.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithVoidReturn.txt new file mode 100644 index 00000000000..087d497576c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteMethodWithVoidReturn.txt @@ -0,0 +1,27 @@ +static Delegate cb_bar; +#pragma warning disable 0169 +static Delegate GetbarHandler () +{ + if (cb_bar == null) + cb_bar = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_bar); + return cb_bar; +} + +static void n_bar (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.bar (); +} +#pragma warning restore 0169 + +// Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='bar' and count(parameter)=0]" +[Register ("bar", "()V", "GetbarHandler")] +public virtual unsafe void bar () +{ + const string __id = "bar.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceClass.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceClass.txt new file mode 100644 index 00000000000..3175217a21f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceClass.txt @@ -0,0 +1,129 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] + get; + } + + // Metadata.xml XPath class reference: path="/api/package[@name='com.xamarin.android']/class[@name='Parent.Child']" + [global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] + public partial class Child : Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent$Child", typeof (Child)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Child (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar_GetBar_I; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + return cb_getBar_GetBar_I ??= new _JniMarshal_PP_I (n_GetBar); + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetBar); + } + } + private static int __n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceTypes.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceTypes.txt new file mode 100644 index 00000000000..6e87c1e9f95 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceTypes.txt @@ -0,0 +1,193 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] + get; + } + + // Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']" + [Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParent/IChildInvoker")] + public partial interface IChild : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParent/IChildInvoker, MyAssembly")] + get; + } + + } + + [global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] + internal partial class IChildInvoker : global::Java.Lang.Object, IChild { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent$Child", typeof (IChildInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IChild GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent.Child'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IChildInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar_GetBar_I; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + return cb_getBar_GetBar_I ??= new _JniMarshal_PP_I (n_GetBar); + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetBar); + } + } + private static int __n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar_GetBar_I; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + return cb_getBar_GetBar_I ??= new _JniMarshal_PP_I (n_GetBar); + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetBar); + } + } + private static int __n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteObjectField.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteObjectField.txt new file mode 100644 index 00000000000..bd1187d9dce --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteObjectField.txt @@ -0,0 +1,36 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + + // Metadata.xml XPath field reference: path="/api/package[@name='java.code']/class[@name='MyClass']/field[@name='field']" + [Register ("field")] + public java.code.Example field { + get { + const string __id = "field.Ljava/code/Example;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "field.Ljava/code/Example;"; + + IntPtr native_value = global::Android.Runtime.JNIEnv.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/MyClass", typeof (MyClass)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteParameterListCallArgs.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteParameterListCallArgs.txt new file mode 100644 index 00000000000..a0d1315f35b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteParameterListCallArgs.txt @@ -0,0 +1,4 @@ +JniArgumentValue* __args = stackalloc JniArgumentValue [3]; +__args [0] = new JniArgumentValue (value); +__args [1] = new JniArgumentValue (native_str); +__args [2] = new JniArgumentValue (flag); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteParameterListCallArgsForInvoker.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteParameterListCallArgsForInvoker.txt new file mode 100644 index 00000000000..1506c62aa80 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteParameterListCallArgsForInvoker.txt @@ -0,0 +1,4 @@ +JValue* __args = stackalloc JValue [3]; +__args [0] = new JValue (value); +__args [1] = new JValue (native_str); +__args [2] = new JValue (flag); diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteProperty.txt new file mode 100644 index 00000000000..46d1747a57e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteProperty.txt @@ -0,0 +1,56 @@ +static Delegate cb_get_MyProperty; +#pragma warning disable 0169 +static Delegate Getget_MyPropertyHandler () +{ + if (cb_get_MyProperty == null) + cb_get_MyProperty = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_I) n_get_MyProperty); + return cb_get_MyProperty; +} + +static int n_get_MyProperty (IntPtr jnienv, IntPtr native__this) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.MyProperty; +} +#pragma warning restore 0169 + +static Delegate cb_set_MyProperty_I; +#pragma warning disable 0169 +static Delegate Getset_MyProperty_IHandler () +{ + if (cb_set_MyProperty_I == null) + cb_set_MyProperty_I = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPI_V) n_set_MyProperty_I); + return cb_set_MyProperty_I; +} + +static void n_set_MyProperty_I (IntPtr jnienv, IntPtr native__this, int value) +{ + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.MyProperty = value; +} +#pragma warning restore 0169 + +public virtual unsafe int MyProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='get_MyProperty' and count(parameter)=0]" + [Register ("get_MyProperty", "()I", "Getget_MyPropertyHandler")] + get { + const string __id = "get_MyProperty.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='com.mypackage']/class[@name='foo']/method[@name='set_MyProperty' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_MyProperty", "(I)V", "Getset_MyProperty_IHandler")] + set { + const string __id = "set_MyProperty.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteStaticInterfaceMethod.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteStaticInterfaceMethod.txt new file mode 100644 index 00000000000..7a37f828b97 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteStaticInterfaceMethod.txt @@ -0,0 +1,104 @@ +[Register ("mono/internal/java/code/IMyInterface", DoNotGenerateAcw=true)] +public abstract class MyInterface : Java.Lang.Object { + internal MyInterface () + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "")] + public static unsafe void DoSomething () + { + const string __id = "DoSomething.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (MyInterface)); + +} + +[Register ("mono/internal/java/code/IMyInterface", DoNotGenerateAcw=true)] +[global::System.Obsolete (@"Use the 'MyInterface' type. This type will be removed in a future release.", error: true)] +public abstract class MyInterfaceConsts : MyInterface { + private MyInterfaceConsts () + { + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='DoSomething' and count(parameter)=0]" + [Register ("DoSomething", "()V", "")] + public static unsafe void DoSomething () + { + const string __id = "DoSomething.()V"; + try { + _members.StaticMethods.InvokeVoidMethod (__id, null); + } finally { + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteStaticInterfaceProperty.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteStaticInterfaceProperty.txt new file mode 100644 index 00000000000..8afb38a63bd --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteStaticInterfaceProperty.txt @@ -0,0 +1,87 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']" +[Register ("java/code/IMyInterface", "", "java.code.IMyInterfaceInvoker")] +public partial interface IMyInterface : IJavaObject, IJavaPeerable { + private static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true); + + static unsafe int Value { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Value' and count(parameter)=0]" + [Register ("get_Value", "()I", "")] + get { + const string __id = "get_Value.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_Value' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("set_Value", "(I)V", "")] + set { + const string __id = "set_Value.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + +} + +[global::Android.Runtime.Register ("java/code/IMyInterface", DoNotGenerateAcw=true)] +internal partial class IMyInterfaceInvoker : global::Java.Lang.Object, IMyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/code/IMyInterface", typeof (IMyInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + IntPtr class_ref; + + public static IMyInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'java.code.IMyInterface'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IMyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteUnnestedInterfaceTypes.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteUnnestedInterfaceTypes.txt new file mode 100644 index 00000000000..9c535303019 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteUnnestedInterfaceTypes.txt @@ -0,0 +1,193 @@ +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']" +[Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParentChildInvoker")] +public partial interface IParentChild : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentChildInvoker, MyAssembly")] + get; + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] +internal partial class IParentChildInvoker : global::Java.Lang.Object, IParentChild { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent$Child", typeof (IParentChildInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParentChild GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent.Child'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentChildInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar_GetBar_I; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + return cb_getBar_GetBar_I ??= new _JniMarshal_PP_I (n_GetBar); + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetBar); + } + } + private static int __n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} + +// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']" +[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")] +public partial interface IParent : IJavaObject, IJavaPeerable { + int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] + get; + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + new IntPtr class_ref; + + public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException ($"Unable to convert instance of type '{JNIEnv.GetClassNameFromInstance (handle)}' to type 'com.xamarin.android.Parent'."); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + + static Delegate cb_getBar_GetBar_I; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + return cb_getBar_GetBar_I ??= new _JniMarshal_PP_I (n_GetBar); + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetBar); + } + } + private static int __n_GetBar (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + IntPtr id_getBar; + public unsafe int Bar { + get { + if (id_getBar == IntPtr.Zero) + id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I"); + return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar); + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs new file mode 100644 index 00000000000..5709772e53c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Xml.Linq; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + abstract class CodeGeneratorTestBase + { + protected JavaInteropCodeGenerator generator; + protected StringBuilder builder; + protected StringWriter writer; + protected CodeGenerationOptions options; + + [SetUp] + public void SetUp () + { + builder = new StringBuilder (); + writer = new StringWriter (builder); + options = CreateOptions (); + + generator = options.CreateCodeGenerator (writer); + } + + [TearDown] + public void TearDown () + { + writer.Dispose (); + } + + protected virtual CodeGenerationOptions CreateOptions () + { + return new CodeGenerationOptions { + CodeGenerationTarget = Target, + EmitLegacyInterfaceInvokers = Target == Xamarin.Android.Binder.CodeGenerationTarget.XAJavaInterop1, + }; + } + + protected abstract Xamarin.Android.Binder.CodeGenerationTarget Target { get; } + + // Optionally override the directory where the expected test results are located. + // For example, we duplicate the "XAJavaInterop1" tests with NRT as "XAJavaInterop1-NRT". + protected virtual string TargetedDirectoryOverride => null; + protected virtual string CommonDirectoryOverride => null; + + // Get the test results from "Common" for tests with the same results regardless of Target + protected string GetExpected (string testName) => GetOriginalExpected (testName).NormalizeLineEndings (); + string GetOriginalExpected (string testName) => GetExpectedResults (testName, CommonDirectoryOverride ?? "Common"); + + // Get the test results from "JavaInterop1" or "XamarinAndroid" for tests with different results per Target + protected string GetTargetedExpected (string testName) => GetOriginalTargetExpected (testName).NormalizeLineEndings (); + string GetOriginalTargetExpected (string testName) => GetExpectedResults (testName, TargetedDirectoryOverride ?? Target.ToString ()); + + string GetExpectedResults (string testName, string target) + { + var root = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location); + var path = Path.Combine (root, "Unit-Tests", "CodeGeneratorExpectedResults", target, $"{testName}.txt"); + Console.WriteLine ($"# jonp: test {GetType().Name}.{testName}: expected path: {path}"); + return File.ReadAllText (path); + } + + protected List ParseApiDefinition (string xml) + { + var doc = XDocument.Parse (xml); + var gens = XmlApiImporter.Parse (doc, options); + + foreach (var gen in gens) + options.SymbolTable.AddType (gen); + + foreach (var gen in gens) + gen.FixupAccessModifiers (options); + + foreach (var gen in gens) + gen.Validate (options, new GenericParameterDefinitionList (), generator.Context); + + foreach (var gen in gens) + gen.FillProperties (); + + foreach (var gen in gens) + gen.FixupMethodOverrides (options); + + return gens; + } + + protected void AssertTargetedExpected (string testName, string actual) + { + WriteActualContents (testName, actual); + + var expected = GetTargetedExpected (testName); + Assert.AreEqual (expected, actual.NormalizeLineEndings ()); + } + + protected void AssertOriginalExpected (string testName, string actual) + { + WriteActualContents (testName, actual); + + var expected = GetOriginalExpected (testName); + Assert.AreEqual (expected.NormalizeLineEndings (), actual.NormalizeLineEndings (), + GetAssertionMessage ($"Test `{testName}` failed.", expected, actual)); + } + + protected void WriteActualContents (string testName, string contents) + { + var t = this.TargetedDirectoryOverride; + if (string.IsNullOrEmpty (t)) + t = this.CommonDirectoryOverride; + if (string.IsNullOrEmpty (t)) + t = GetType ().Name; + var dir = Path.Combine ("__jonp", t); + Directory.CreateDirectory (dir); + File.WriteAllText (Path.Combine (dir, testName + ".txt"), contents); + } + + protected void AssertOriginalTargetExpected (string testName, string actual) + { + WriteActualContents (testName, actual); + + var expected = GetOriginalTargetExpected (testName); + Assert.AreEqual (expected.NormalizeLineEndings (), actual.NormalizeLineEndings (), + GetAssertionMessage ($"Test `{testName}` failed.", expected, actual)); + } + + protected static string GetAssertionMessage (string header, string expected, string actual) + { + return header + "\n" + + $"Expected:\n```\n{expected}\n```\n" + + $"Actual:\n```\n{actual}\n```"; + } + + protected string GetGeneratedTypeOutput (GenBase gen) + { + generator.Context.ContextTypes.Push (gen); + generator.WriteType (gen, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + return writer.ToString (); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs new file mode 100644 index 00000000000..bc7adf68e67 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs @@ -0,0 +1,1833 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using generator.SourceWriters; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using NUnit.Framework; +using Xamarin.Android.Binder; +using Xamarin.SourceWriter; + +namespace generatortests +{ + abstract class AnyJavaInteropCodeGeneratorTests : CodeGeneratorTests + { + [Test] + public void WriteKotlinUnsignedTypeMethodsClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "uint", false, false, new Parameter ("value", "uint", "uint", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ushort", false, false, new Parameter ("value", "ushort", "ushort", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ulong", false, false, new Parameter ("value", "ulong", "ulong", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ubyte", false, false, new Parameter ("value", "ubyte", "byte", false))); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Methods) + m.IsVirtual = false; + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertOriginalTargetExpected (nameof (WriteKotlinUnsignedTypeMethodsClass), writer.ToString ()); + } + + [Test] + public void WriteKotlinUnsignedTypePropertiesClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UIntProp", "uint", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UShortProp", "ushort", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "ULongProp", "ulong", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UByteProp", "ubyte", options, false, false)); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Properties) { + m.Getter.IsVirtual = false; + m.Setter.IsVirtual = false; + } + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertOriginalTargetExpected (nameof (WriteKotlinUnsignedTypePropertiesClass), writer.ToString ()); + } + + [Test] + public void WriteKotlinUnsignedArrayTypeMethodsClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "uint[]", false, false, new Parameter ("value", "uint[]", "uint[]", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ushort[]", false, false, new Parameter ("value", "ushort[]", "ushort[]", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ulong[]", false, false, new Parameter ("value", "ulong[]", "ulong[]", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ubyte[]", false, false, new Parameter ("value", "ubyte[]", "byte[]", false))); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Methods) + m.IsVirtual = false; + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertOriginalTargetExpected (nameof (WriteKotlinUnsignedArrayTypeMethodsClass), writer.ToString ()); + } + + [Test] + public void WriteKotlinUnsignedArrayTypePropertiesClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UIntProp", "uint[]", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UShortProp", "ushort[]", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "ULongProp", "ulong[]", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UByteProp", "ubyte[]", options, false, false)); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Properties) { + m.Getter.IsVirtual = false; + m.Setter.IsVirtual = false; + } + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertOriginalTargetExpected (nameof (WriteKotlinUnsignedArrayTypePropertiesClass), writer.ToString ()); + } + + [Test] + public void ManagedOverrideMethod_Virtual () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().Contains ("public virtual unsafe int DoStuff ()"), $"was: `{writer.ToString ()}`"); + } + + [Test] + public void ManagedOverrideMethod_Override () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().Contains ("public override unsafe int DoStuff ()"), $"was: `{writer.ToString ()}`"); + } + + [Test] + public void ManagedOverrideAbstractMethod_Override () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().Contains ("public override abstract int DoStuff ();"), $"was: `{writer}`"); + } + + [Test] + public void ManagedOverrideMethod_None () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This would contain 'virtual' if the 'managedOverride' was not working + Assert.True (writer.ToString ().Contains ("public unsafe int DoStuff ()"), $"was: `{writer}`"); + } + + [Test] + public void ManagedOverrideInterfaceMethod_Reabstract () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "IMyInterface"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This would not contain 'abstract' if the 'managedOverride' was not working + Assert.True (writer.ToString ().Contains ("abstract int DoStuff ()"), $"was: `{writer}`"); + } + + [Test] + public void ManagedOverrideProperty_Virtual () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().Contains ("public virtual unsafe int Name {"), $"was: `{writer.ToString ()}`"); + } + + [Test] + public void ManagedOverrideProperty_Override () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().Contains ("public override unsafe int Name {"), $"was: `{writer.ToString ()}`"); + } + + [Test] + public void ManagedOverrideProperty_None () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This would contain 'virtual' if the 'managedOverride' was not working + Assert.True (writer.ToString ().Contains ("public unsafe int Name {"), $"was: `{writer}`"); + } + + [Test] + public void ManagedOverrideInterfaceProperty_Reabstract () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "IMyInterface"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This would not contain 'abstract' if the 'managedOverride' was not working + Assert.True (writer.ToString ().Contains ("abstract int Name {"), $"was: `{writer}`"); + } + + [Test] + public void SkipInvokerMethodsMetadata () + { + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // `override abstract` causes both invoker methods to get generated. We use metadata + // to suppress the base class's method to prevent a conflict. + Assert.True (writer.ToString ().Contains ("public override abstract Com.Xamarin.Android.MyClass DoStuff ();"), $"was: `{writer}`"); + Assert.False (writer.ToString ().Contains ("public abstract Com.Xamarin.Android.MyBaseClass DoStuff ();"), $"was: `{writer}`"); + } + + [Test] + public void SkipInterfaceInvokerMethodsMetadata () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "IMyInterface"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure the invoker for 'countAffectedRows' isn't generated + Assert.False (writer.ToString ().Contains ("static Delegate cb_countAffectedRows;"), $"was: `{writer}`"); + Assert.False (writer.ToString ().Contains ("InvokeAbstractInt32Method"), $"was: `{writer}`"); + } + + [Test] + public void SkipInterfaceMethodsMetadata () + { + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyBaseClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // The abstract method should not get generated because we are suppressing it with 'skipInterfaceMethods' + Assert.False (writer.ToString ().Contains ("public abstract int CountAffectedRows ();"), $"was: `{writer}`"); + } + + [Test] + public void CompatVirtualMethod_Class () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("catch (Java.Lang.NoSuchMethodError) { throw new Java.Lang.AbstractMethodError (__id); }".NormalizeLineEndings ()), $"was: `{writer}`"); + } + + [Test] + public void PeerConstructorPartialMethod_Class () + { + var xml = @" + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("partial void _OnMyClassCreated ();".NormalizeLineEndings ()), $"was: `{writer}`"); + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("{ _OnMyClassCreated (); }".NormalizeLineEndings ()), $"was: `{writer}`"); + } + [Test] + public void WriteDuplicateInterfaceEventArgs () + { + // If we have 2 methods that would each create the same EventArgs class, + // make sure we combine them into 1 class with both members instead. + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.AnimatorListener"); + + var method1 = SupportTypeBuilder.CreateMethod (iface, "OnAnimationEnd", options, "boolean", false, true, new Parameter ("param1", "int", "int", false)); + var method2 = SupportTypeBuilder.CreateMethod (iface, "OnAnimationEnd", options, "boolean", false, true, new Parameter ("param1", "int", "int", false), new Parameter ("param2", "int", "int", false)); + + iface.Methods.Add (method1); + iface.Methods.Add (method2); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertTargetedExpected (nameof (WriteDuplicateInterfaceEventArgs), writer.ToString ()); + } + + [Test] + public void InheritedInterfaceAsClass () + { + // This is a somewhat cheating way to repro a real issue. + // The real issue is: + // - Binding an interface which implements 'android.provider.BaseColumns' + // - android.provider.BaseColumns is an interface in android.jar + // - Mono.Android.dll has both: + // - [Register ("android.provider.BaseColumns")] public abstract class BaseColumns + // - [Register ("android.provider.BaseColumns")] public interface IBaseColumns + // Our Java type resolution is "last one wins" and happens to pick the class instead of + // the interface. So our code is trying to bind an interface that implements a class. + var xml = @" + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + + // Disable "BuildingCoreAssembly" + (gens.Single (g => g.Name == "Object") as ClassGen).FromXml = false; + + var klass = gens.Single (g => g.Name == "IMyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.Pass ("WriteType did not NRE"); + } + + [Test] + public void ExplicitInterfaceMetadata_InterfaceMethod () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "IMyInterface"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure explicit interface was written + Assert.True (writer.ToString ().Contains ("int IRowCounter.CountAffectedRows ("), $"was: `{writer}`"); + } + + [Test] + public void ExplicitInterfaceMetadata_InterfaceProperty () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "IMyInterface"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure explicit interface was written + Assert.True (writer.ToString ().Contains ("int IHasAge.Age {"), $"was: `{writer}`"); + } + + [Test] + public void ExplicitInterfaceMetadata_ClassMethod () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure explicit interface was written + Assert.True (writer.ToString ().Contains ("int IRowCounter.CountAffectedRows ("), $"was: `{writer}`"); + } + + [Test] + public void ExplicitInterfaceMetadata_ClassProperty () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure explicit interface was written + Assert.True (writer.ToString ().Contains ("int IHasAge.Age {"), $"was: `{writer}`"); + } + + [Test] + public void ExplicitInterfaceMetadata_AbstractClassMethod () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure explicit interface was written + Assert.True (writer.ToString ().Contains ("abstract int IRowCounter.CountAffectedRows ("), $"was: `{writer}`"); + } + + [Test] + public void ExplicitInterfaceMetadata_AbstractClassProperty () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure explicit interface was written + Assert.True (writer.ToString ().Contains ("abstract int IHasAge.Age {"), $"was: `{writer}`"); + } + + [Test] + public void ObsoleteBoundMethodAbstractDeclaration () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure [Obsolete] was written + Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is so old!\")]"), writer.ToString ()); + } + + [Test] + public void ObsoletedOSPlatformAttributeSupport () + { + var xml = @" + + + + + + + + + + + + + + + "; + + options.UseObsoletedOSPlatformAttributes = true; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // Ensure [ObsoletedOSPlatform] was written + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a class deprecated since 25!\")]"), writer.ToString ()); + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a field deprecated since 25!\")]"), writer.ToString ()); + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a constructor deprecated since 25!\")]"), writer.ToString ()); + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a method deprecated since 25!\")]"), writer.ToString ()); + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a property getter deprecated since 25!\")]"), writer.ToString ()); + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\", @\"This is a property setter deprecated since 25!\")]"), writer.ToString ()); + } + + [Test] + public void ObsoletedOSPlatformAttributeUnneededSupport () + { + var xml = @" + + + + + + + + + + + + + + + + "; + + options.UseObsoletedOSPlatformAttributes = true; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // These should use [Obsolete] because they have always been obsolete in all currently supported versions (21+) + Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is a field deprecated since 0!\")]"), writer.ToString ()); + Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This is a constructor deprecated since empty string!\")]"), writer.ToString ()); + + // This should not have a message because the default "deprecated" message isn't useful + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android25.0\")]"), writer.ToString ()); + Assert.True (writer.ToString ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android22.0\")]"), writer.ToString ()); + + // This should use [Obsolete] because the 'deprecated-since' attribute could not be parsed + Assert.True (writer.ToString ().Contains ("[global::System.Obsolete (@\"This method has an invalid deprecated-since!\")]"), writer.ToString ()); + } + + [Test] + public void ObsoletedOSPlatformAttributeInterfaceInfrastructureSupport () + { + var xml = @" + + + + "; + + options.UseObsoletedOSPlatformAttributes = true; + + var gens = ParseApiDefinition (xml); + var iface = gens.OfType ().Single (g => g.Name == "IMyType"); + + generator.Context.ContextTypes.Push (iface); + var invoker = new InterfaceInvokerClass (iface, options, generator.Context); + var extensions = new InterfaceExtensionsClass (iface, iface.Name, options); + generator.Context.ContextTypes.Pop (); + + // Ensure attribute was added to invoker class + var invoker_attribute = invoker.Attributes.OfType ().Single (); + Assert.AreEqual ("This interface was deprecated in API-25", invoker_attribute.Message); + Assert.AreEqual (25, invoker_attribute.Version.ApiLevel); + + // Ensure attribute was added to extensions class + var extensions_attribute = invoker.Attributes.OfType ().Single (); + Assert.AreEqual ("This interface was deprecated in API-25", extensions_attribute.Message); + Assert.AreEqual (25, extensions_attribute.Version.ApiLevel); + } + + [Test] + public void ObsoleteGetterOnlyProperty () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use [Obsolete] on the entire property because the getter is obsolete and there is no setter + Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete (@\"deprecated\")]public virtual unsafe int Count".NormalizeLineEndings ()), writer.ToString ()); + + // Ensure we don't write getter attribute + Assert.False (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]get"), writer.ToString ()); + } + + [Test] + public void ObsoletePropertyGetter () + { + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use [Obsolete] on just the property getter since the setter is not obsolete + Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]get"), writer.ToString ()); + } + + [Test] + public void ObsoletePropertySetter () + { + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use [Obsolete] on just the property setter since the getter is not obsolete + Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]set"), writer.ToString ()); + } + + [Test] + public void ObsoleteBothPropertyMethods () + { + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use [Obsolete] on both property methods because the deprecation messages are different + Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"getter_message\")]get"), writer.ToString ()); + Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"setter_message\")]set"), writer.ToString ()); + } + + [Test] + public void ObsoleteEntireProperty () + { + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use [Obsolete] on the entire property because the getter and setter are both obsoleted with the same message + Assert.True (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete (@\"deprecated\")]public virtual unsafe int Count".NormalizeLineEndings ()), writer.ToString ()); + + // Ensure we don't write getter/setter attributes + Assert.False (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]get"), writer.ToString ()); + Assert.False (StripRegisterAttributes (writer.ToString ()).NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]set"), writer.ToString ()); + } + + [Test] + public void RestrictToType () + { + options.UseRestrictToAttributes = true; + + var xml = @" + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use a special [Obsolete] describing the "internal" nature of this API + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete (\"While this type is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings ()), writer.ToString ()); + } + + [Test] + public void RestrictToField () + { + options.UseRestrictToAttributes = true; + + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use a special [Obsolete] describing the "internal" nature of this API + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings ()), writer.ToString ()); + } + + [Test] + public void RestrictToMethod () + { + options.UseRestrictToAttributes = true; + + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use a special [Obsolete] describing the "internal" nature of this API + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings ()), writer.ToString ()); + } + + [Test] + public void RestrictToProperty () + { + options.UseRestrictToAttributes = true; + + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This should use a special [Obsolete] describing the "internal" nature of this API + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings ()), writer.ToString ()); + } + + [Test] + public void DoNotWriteObsoleteAndRestrictTo () + { + options.UseRestrictToAttributes = true; + + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // This method is both @Deprecated and @RestrictTo. We cannot write 2 [Obsolete] attributes, so + // only write the deprecated one. + Assert.True (writer.ToString ().Replace (" (@\"deprecated\")", "").NormalizeLineEndings ().Contains ("[global::System.Obsolete]".NormalizeLineEndings ()), writer.ToString ()); + Assert.False (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete (\"While this member is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]".NormalizeLineEndings ()), writer.ToString ()); + } + + [Test] + [NonParallelizable] // We are setting a static property on Report + public void WarnIfTypeNameMatchesNamespace () + { + var @class = new TestClass ("Object", "java.myclass.MyClass"); + var sb = new StringBuilder (); + + var write_output = new Action ((t, s) => { sb.AppendLine (s); }); + Report.OutputDelegate = write_output; + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Report.OutputDelegate = null; + + // Ensure the warning was raised + Assert.True (sb.ToString ().Contains ("warning BG8403")); + } + + [Test] + [NonParallelizable] // We are setting a static property on Report + public void DontWarnIfNestedTypeNameMatchesNamespace () + { + var @class = new TestClass ("Object", "java.myclass.MyParentClass"); + @class.NestedTypes.Add (new TestClass ("Object", "java.myclass.MyParentClass.MyClass")); + var sb = new StringBuilder (); + + var write_output = new Action ((t, s) => { sb.AppendLine (s); }); + Report.OutputDelegate = write_output; + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Report.OutputDelegate = null; + + // The warning should not be raised if the nested type matches enclosing namespace + Assert.False (sb.ToString ().Contains ("warning BG8403")); + } + + + [Test] + public void AvoidNREOnInvalidBaseMethod () + { + // We copy methods from the package-private base class to the public class, however + // the copied method is not valid because it doesn't understand the generic argument + // type. The method is remove from the public class, but we need to ensure the + // base class method still exists and IsValid. + var xml = @" + + + + + + + + + + + + + + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + + var public_class = gens.Single (g => g.Name == "Behavior"); + var base_class = gens.Single (g => g.Name == "ViewOffsetBehavior"); + + // Method got removed + Assert.AreEqual (0, public_class.Methods.Count); + + // Method still exists and is valid + Assert.AreEqual (1, base_class.Methods.Count); + Assert.AreEqual (true, base_class.Methods [0].IsValid); + } + + [Test] + public void FixupDeprecatedBaseMethods () + { + var xml = @" + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + + // Override method should not be marked deprecated because it's: deprecated='not deprecated' + Assert.IsNull (gens.Single (g => g.Name == "MyClass").Methods.Single (m => m.Name == "DoStuff").Deprecated); + + options.FixObsoleteOverrides = true; + gens = ParseApiDefinition (xml); + + // Override method should be marked deprecated because base method is + Assert.AreEqual ("deprecated", gens.Single (g => g.Name == "MyClass").Methods.Single (m => m.Name == "DoStuff").Deprecated); + } + + [Test] + public void FixupDeprecatedSinceBaseMethods () + { + var xml = @" + + + + + + + + + + + "; + + options.FixObsoleteOverrides = true; + var gens = ParseApiDefinition (xml); + + // Override method should match base method's 'deprecated-since' + Assert.AreEqual (11, gens.Single (g => g.Name == "MyClass").Methods.Single (m => m.Name == "DoStuff").DeprecatedSince?.ApiLevel ?? 0); + } + + protected static IEnumerable GetLinesThatStartWith (string source, string value) + { + using (var reader = new StringReader (source)) { + string line; + while ((line = reader.ReadLine ()) != null) { + if (line.TrimStart ().StartsWith (value, StringComparison.Ordinal)) + yield return line; + } + } + } + static string StripRegisterAttributes (string str) + { + // It is hard to test if the [Obsolete] is on the setter/etc due to the [Register], so remove all [Register]s + // [global::System.Obsolete (@"setter_message")] + // [Register ("setCount", "(I)V", "GetSetCount_IHandler")] + // set { + int index; + + while ((index = str.IndexOf ("[Register", StringComparison.Ordinal)) > -1) + str = str.Substring (0, index) + str.Substring (str.IndexOf (']', index) + 1); + + return str; + } + } + + [TestFixture] + class JavaInteropCodeGeneratorTests : AnyJavaInteropCodeGeneratorTests + { + protected override CodeGenerationTarget Target => CodeGenerationTarget.JavaInterop1; + protected override string CommonDirectoryOverride => "JavaInterop1"; + + protected override CodeGenerationOptions CreateOptions () + { + var options = new CodeGenerationOptions { + CodeGenerationTarget = Target, + SupportDefaultInterfaceMethods = true, + SupportInterfaceConstants = true, + SupportNestedInterfaceTypes = true, + SupportNullableReferenceTypes = true, + }; + return options; + } + + [Test] + public void StringPropertyOverride ([Values("true", "false")] string final) + { + var xml = @$" + + + + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "TextView"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + if (final == "true") { + Assert.True (writer.ToString ().Contains ( + @"set { + const string __id = ""setText.(Ljava/lang/CharSequence;)V""; + global::Java.Interop.JniObjectReference text = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (text); + _members.InstanceMethods.InvokeNonvirtualVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref text); + } + } + }"), $"was: `{writer}`"); + } else { + Assert.True (writer.ToString ().Contains ( + @"set { + var jls = value == null ? null : new global::Java.Lang.String (value); + TextFormatted = jls; + if (jls != null) jls.Dispose (); + }"), $"was: `{writer}`"); + } + } + } + + [TestFixture] + class XAJavaInteropCodeGeneratorTests : AnyJavaInteropCodeGeneratorTests + { + protected override CodeGenerationTarget Target => CodeGenerationTarget.XAJavaInterop1; + + [Test] + public void WriteClassExternalBase () + { + // Tests the case where a class inherits from a class that is not in the same assembly. + // Specifically, the internal class_ref field does NOT need the new modifier. + // - This prevents a CS0109 warning from being generated. + + options.SymbolTable.AddType (new TestClass (null, "Java.Lang.Object")); + + var @class = SupportTypeBuilder.CreateClass ("java.code.MyClass", options, "Java.Lang.Object"); + @class.Validate (options, new GenericParameterDefinitionList (), generator.Context); + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + var result = writer.ToString ().NormalizeLineEndings (); + Assert.True (result.Contains ("internal static IntPtr class_ref".NormalizeLineEndings ())); + Assert.False (result.Contains ("internal static new IntPtr class_ref".NormalizeLineEndings ())); + } + + [Test] + public void WriteClassInternalBase () + { + // Tests the case where a class inherits from Java.Lang.Object and is in the same assembly. + // Specifically, the internal class_ref field does need the new modifier. + // - This prevents a CS0108 warning from being generated. + + options.SymbolTable.AddType (new TestClass (null, "Java.Lang.Object")); + + var @class = SupportTypeBuilder.CreateClass ("java.code.MyClass", options, "Java.Lang.Object"); + @class.Validate (options, new GenericParameterDefinitionList (), generator.Context); + + // FromXml is set to true when a class is set to true when the api.xml contains an entry for the class. + // Therefore, if a class's base has FromXml set to true, the class and its base will be in the same C# assembly. + @class.BaseGen.FromXml = true; + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + var result = writer.ToString ().NormalizeLineEndings (); + Assert.True (result.Contains ("internal static new IntPtr class_ref".NormalizeLineEndings ())); + Assert.False (result.Contains ("internal static IntPtr class_ref".NormalizeLineEndings ())); + } + + [Test] + public void SupportedOSPlatform () + { + // We do not write [SupportedOSPlatform] for JavaInterop, only XAJavaInterop + var klass = SupportTypeBuilder.CreateClass ("java.code.MyClass", options); + klass.ApiAvailableSince = new AndroidSdkVersion (30); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + StringAssert.Contains ("[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android30.0\")]", builder.ToString (), "Should contain SupportedOSPlatform!"); + } + + [Test] + public void SupportedOSPlatformConstFields () + { + // Ensure we write [SupportedOSPlatform] for const fields + var klass = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar").SetConstant ("MY_VALUE"); + + field.ApiAvailableSince = new AndroidSdkVersion (30); + + klass.Fields.Add (field); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + StringAssert.Contains ("[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android30.0\")]", builder.ToString (), "Should contain SupportedOSPlatform!"); + } + + [Test] + public void UnsupportedOSPlatform () + { + var klass = SupportTypeBuilder.CreateClass ("java.code.MyClass", options); + klass.ApiRemovedSince = new AndroidSdkVersion (30); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + StringAssert.Contains ("[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android30.0\")]", builder.ToString (), "Should contain UnsupportedOSPlatform!"); + } + + [Test] + public void UnsupportedOSPlatformConstFields () + { + var klass = new TestClass ("java.lang.Object", "com.mypackage.foo"); + var field = new TestField ("java.lang.String", "bar").SetConstant ("MY_VALUE"); + + field.ApiRemovedSince = new AndroidSdkVersion (30); + + klass.Fields.Add (field); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + StringAssert.Contains ("[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android30.0\")]", builder.ToString (), "Should contain UnsupportedOSPlatform!"); + } + + + [Test] + public void UnsupportedOSPlatformIgnoresMethodOverrides () + { + // Given: + // Class inheritance scenario: + // public class TextView { + // public Object doThing () { ... } + // } + // public class TextView2 : TextView { + // public Object doThing () { ... } // removed-since = 30 + // } + // Interface inheritance scenario: + // public interface IFoo { + // public Object doSomething () { ... } + // public static final String DATE_TAKEN = "datetaken"; + // } + // public interface IBar : IFoo { + // public Object doSomething () { ... } // removed-since = 30 + // public static final String DATE_TAKEN = "datetaken"; // removed-since = 30 + // } + // We should not write [UnsupportedOSPlatform] on overriding methods or fields, because the base methods/fields aren't "removed". + var xml = @$" + + + + + + + + + + + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + + // Test class inheritance scenario + var klass = gens.Single (g => g.Name == "TextView2"); + var actual = GetGeneratedTypeOutput (klass); + StringAssert.DoesNotContain ("[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android30.0\")]", actual, "Should not contain UnsupportedOSPlatform on class override!"); + + // Test interface inheritance scenario + var iface = gens.OfType ().Single (g => g.Name == "IBar"); + var ifaceActual = GetGeneratedTypeOutput (iface); + StringAssert.DoesNotContain ("[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android30.0\")]", ifaceActual, "Should not contain UnsupportedOSPlatform on interface override!"); + } + + [Test] + public void UnsupportedOSPlatformIgnoresPropertyOverrides () + { + // Given: + // Class inheritance scenario: + // public class TextView { + // public Object getThing () { ... } + // public void setThing (Object value) { ... } + // } + // public class TextView2 : TextView { + // public Object getThing () { ... } // removed-since = 30 + // public void setThing (Object value) { ... } // removed-since = 30 + // } + // Interface inheritance scenario: + // public interface IPropertyProvider { + // public Object getSomething () { ... } + // public static final String DATE_TAKEN = "datetaken"; + // } + // public interface IExtendedProvider : IPropertyProvider { + // public Object getSomething () { ... } // removed-since = 30 + // public static final String DATE_TAKEN = "datetaken"; // removed-since = 30 + // } + // We should not write [UnsupportedOSPlatform] on overriding properties or fields, because the base methods/fields aren't "removed". + var xml = @$" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + + // Test class inheritance scenario + var klass = gens.Single (g => g.Name == "TextView2"); + var actual = GetGeneratedTypeOutput (klass); + StringAssert.DoesNotContain ("[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android30.0\")]", actual, "Should not contain UnsupportedOSPlatform on class property override!"); + + // Test interface inheritance scenario + var iface = gens.OfType ().Single (g => g.Name == "IExtendedProvider"); + var ifaceActual = GetGeneratedTypeOutput (iface); + StringAssert.DoesNotContain ("[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android30.0\")]", ifaceActual, "Should not contain UnsupportedOSPlatform on interface property override!"); + } + + [Test] + public void StringPropertyOverride ([Values ("true", "false")] string final) + { + var xml = @$" + + + + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "TextView"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + if (final == "true") { + Assert.True (writer.ToString ().Contains ( + @"set { + const string __id = ""setText.(Ljava/lang/CharSequence;)V""; + global::Java.Interop.JniObjectReference native_text = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_text); + _members.InstanceMethods.InvokeNonvirtualVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_text); + } + }"), $"was: `{writer}`"); + } else { + Assert.True (writer.ToString ().Contains ( + @"set { + var jls = value == null ? null : new global::Java.Lang.String (value); + TextFormatted = jls; + if (jls != null) jls.Dispose (); + }"), $"was: `{writer}`"); + } + } + + [Test] + public void CallbackVariableNamesShouldntCollide () + { + var xml = @" + + + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "MyClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + var a = writer.ToString (); + var lines = GetLinesThatStartWith (writer.ToString (), "static Delegate cb_"); + + // Ensure that 2 cb_ delegates got written, and they do not have the same name + Assert.AreEqual (2, lines.Count ()); + Assert.AreNotEqual (lines.ElementAt (0), lines.ElementAt (1)); + } + } + + abstract class CodeGeneratorTests : CodeGeneratorTestBase + { + [Test] + public void WriteClass () + { + var @class = SupportTypeBuilder.CreateClass ("java.code.MyClass", options); + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertTargetedExpected (nameof (WriteClass), writer.ToString ()); + } + + [Test] + public void WriteObjectField () + { + options.SymbolTable.AddType (new TestClass (null, "Java.Lang.Object")); + var eClass = new TestClass ("Java.Lang.Object", "java.code.Example"); + options.SymbolTable.AddType (eClass); + + var @class = new TestClass ("Object", "java.code.MyClass"); + + var field = SupportTypeBuilder.CreateField ("field", options, "java.code.Example"); + + @class.Fields.Add (field); + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertTargetedExpected (nameof (WriteObjectField), writer.ToString ()); + } + + [Test] + public void WriteInterface () + { + var iface = SupportTypeBuilder.CreateInterface ("java.code.IMyInterface", options); + var gen_info = new GenerationInfo (null, null, null); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, gen_info); + generator.Context.ContextTypes.Pop (); + + AssertTargetedExpected (nameof (WriteInterface), writer.ToString ()); + } + + [Test] + public void WriteMethodWithCharSequenceArrays () + { + var gens = ParseApiDefinition (@" + + + + + + + + + + + + + "); + + var @class = gens.OfType ().First (c => c.Name == "MyClass"); + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + AssertOriginalTargetExpected (nameof (WriteMethodWithCharSequenceArrays), writer.ToString ()); + } + + [Test] + public void WritePropertyExplicitInterfaceParameterName () + { + // Fix a case where we were not overriding a property setter's parameter name ("p0") + // to "value", resulting in invalid C#. Like: + // public string MyProperty { + // set => my_property = p0; + // } + var gens = ParseApiDefinition (@" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "); + + var @class = gens.OfType ().First (c => c.Name == "SingleDateSelector"); + + generator.Context.ContextTypes.Push (@class); + generator.WriteType (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + var result = writer.ToString ().NormalizeLineEndings (); + Assert.False (result.Contains ("p0")); + } + + [Test] + public void WriteBoundMethodAbstractDeclarationWithGenericReturn () + { + // Fix a case where the ReturnType of a class method implementing a generic interface method + // that has a generic parameter type return (like T) wasn't getting set, resulting in a NRE. + var gens = ParseApiDefinition (@" + + + + + + + + + + + + + + + + + + + + + + + + + "); + + var declIface = gens.OfType ().Single (c => c.Name == "IFlowIterator"); + var declClass = options.SupportNestedInterfaceTypes + ? declIface.NestedTypes.OfType ().Single (c => c.Name == "RangeIterator") + : declIface.NestedTypes.OfType ().Single (c => c.Name == "FlowIteratorRangeIterator"); + var method = declClass.Methods.Single (); + + var bmad = new BoundMethodAbstractDeclaration (declClass, method, options, null); + var source_writer = new CodeWriter (writer); + + bmad.Write (source_writer); + + var expected = options.SupportNestedInterfaceTypes + ? @"Java.Lang.Object Com.Example.IFlowIterator.RangeIterator.Next () + { + throw new NotImplementedException (); + }" + : @"Java.Lang.Object Com.Example.FlowIteratorRangeIterator.Next () + { + throw new NotImplementedException (); + }"; + + // Ignore nullable operator so this test works on all generators ;) + Assert.AreEqual (expected.NormalizeLineEndings (), writer.ToString ().NormalizeLineEndings ().Replace ("?", "")); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs new file mode 100644 index 00000000000..7269620a091 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs @@ -0,0 +1,554 @@ +using System; +using System.Linq; +using MonoDroid.Generation; +using NUnit.Framework; +using Xamarin.Android.Binder; + +namespace generatortests +{ +#if TODO_JAVA_INTEROP1 + [TestFixture] + class JavaInteropDefaultInterfaceMethodsTests : DefaultInterfaceMethodsTests + { + protected override CodeGenerationTarget Target => CodeGenerationTarget.JavaInterop1; + } +#endif // TODO_JAVA_INTEROP1 + + [TestFixture] + class XAJavaInteropDefaultInterfaceMethodsTests : DefaultInterfaceMethodsTests + { + protected override CodeGenerationTarget Target => CodeGenerationTarget.XAJavaInterop1; + } + + abstract class DefaultInterfaceMethodsTests : CodeGeneratorTestBase + { + protected override CodeGenerationOptions CreateOptions () + { + var options = base.CreateOptions (); + + options.AssemblyName = "MyAssembly"; + options.SupportDefaultInterfaceMethods = true; + + return options; + } + + [Test] + public void WriteInterfaceDefaultMethod () + { + // Create an interface with a default method + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + + iface.Methods.Add (new TestMethod (iface, "DoSomething").SetDefaultInterfaceMethod ()); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (null, null, null)); + + AssertTargetedExpected (nameof (WriteInterfaceDefaultMethod), writer.ToString ()); + } + + [Test] + public void WriteInterfaceRedeclaredDefaultMethod () + { + // Create an interface with a default method + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + iface.Methods.Add (new TestMethod (iface, "DoSomething").SetDefaultInterfaceMethod ()); + options.SymbolTable.AddType (iface); + + // Create a second interface that inherits the first, declaring the method as not default + var iface2 = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface2"); + iface2.AddImplementedInterface ("java.code.IMyInterface"); + iface2.Methods.Add (new TestMethod (iface, "DoSomething")); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + iface2.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface2, string.Empty, new GenerationInfo (null, null, null)); + + // IMyInterface2 should generate the method as abstract, not a default method + AssertTargetedExpected (nameof (WriteInterfaceRedeclaredDefaultMethod), writer.ToString ()); + } + + [Test] + public void WriteInterfaceDefaultProperty () + { + // Create an interface with a default method + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + var prop = SupportTypeBuilder.CreateProperty (iface, "Value", "int", options); + + prop.Getter.IsInterfaceDefaultMethod = true; + prop.Setter.IsInterfaceDefaultMethod = true; + + iface.Properties.Add (prop); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (null, null, null)); + + AssertTargetedExpected (nameof (WriteInterfaceDefaultProperty), writer.ToString ()); + } + + [Test] + public void WriteInterfaceDefaultPropertyGetterOnly () + { + // Create an interface with a default method + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + var prop = SupportTypeBuilder.CreateProperty (iface, "Value", "int", options); + + prop.Getter.IsInterfaceDefaultMethod = true; + prop.Setter = null; + + iface.Properties.Add (prop); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (null, null, null)); + + AssertTargetedExpected (nameof (WriteInterfaceDefaultPropertyGetterOnly), writer.ToString ()); + } + + + [Test] + public void WriteDefaultInterfaceMethodInvoker () + { + // Create an interface with a default method + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + + iface.Methods.Add (new TestMethod (iface, "DoDeclaration")); + iface.Methods.Add (new TestMethod (iface, "DoDefault").SetDefaultInterfaceMethod ()); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo (null, null, null)); + generator.Context.ContextTypes.Pop (); + + AssertTargetedExpected (nameof (WriteDefaultInterfaceMethodInvoker), writer.ToString ()); + } + + [Test] + public void WriteSealedOverriddenDefaultMethod () + { + // Create an interface with a default method + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + iface.Methods.Add (new TestMethod (iface, "DoSomething").SetDefaultInterfaceMethod ()); + options.SymbolTable.AddType (iface); + + // Create a type that inherits the interface, overriding the method as final + var klass = new TestClass ("java.code.IMyInterface", "java.code.MyClass"); + klass.AddImplementedInterface ("java.code.IMyInterface"); + klass.Methods.Add (new TestMethod (iface, "DoSomething").SetFinal ()); + + iface.Validate (options, new GenericParameterDefinitionList (), generator.Context); + klass.Validate (options, new GenericParameterDefinitionList (), generator.Context); + + klass.FixupMethodOverrides (options); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + // The method should not be marked as 'virtual sealed' + Assert.False (writer.ToString ().Contains ("virtual sealed")); + } + + [Test] + public void WriteInterfaceRedeclaredChainDefaultMethod () + { + // Fix a case where a property declared in this hierarchy was generated as "override" instead of "virtual" + // public interface MyInterface { default int getValue () { return 0; } } + // public class MyClass implements MyInterface { } + // public class MySecondClass extends MyClass { @Override public int getValue () { return 1; } } + var gens = ParseApiDefinition (@" + + + + + + + + + + + + + + + + + + + + + + + + "); + + var klass = (ClassGen)gens.First (g => g.Name == "ImplementedChainOverrideClass"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().Contains ("public virtual unsafe int Bar")); + } + + [Test] + public void WriteStaticInterfaceMethod () + { + // Create an interface with a static method + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + iface.Methods.Add (new TestMethod (iface, "DoSomething").SetStatic ()); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + AssertTargetedExpected (nameof (WriteStaticInterfaceMethod), writer.ToString ()); + } + + [Test] + public void WriteStaticInterfaceProperty () + { + // Create an interface with a static property + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + var prop = SupportTypeBuilder.CreateProperty (iface, "Value", "int", options); + + prop.Getter.IsStatic = true; + prop.Getter.IsVirtual = false; + prop.Setter.IsStatic = true; + prop.Setter.IsVirtual = false; + + iface.Properties.Add (prop); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (null, null, null)); + + AssertTargetedExpected (nameof (WriteStaticInterfaceProperty), writer.ToString ()); + } + + readonly string nested_interface_api = @" + + + + + + + + + + + + "; + + readonly string nested_class_api = @" + + + + + + + + + + "; + + [Test] + public void WriteUnnestedInterfaceTypes () + { + // Ensure we don't break the original un-nested interface types + var gens = ParseApiDefinition (nested_interface_api); + + var parent_iface = gens.OfType ().Single (); + + parent_iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (parent_iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + AssertTargetedExpected (nameof (WriteUnnestedInterfaceTypes), writer.ToString ()); + } + + [Test] + public void WriteNestedInterfaceTypes () + { + // Traditionally this would have created namespace.IParent and namespace.IParentChild + // With nested types this creates namespace.IParent and namespace.IParent.IChild + options.SupportNestedInterfaceTypes = true; + + var gens = ParseApiDefinition (nested_interface_api); + + var parent_iface = gens.OfType ().Single (); + + parent_iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (parent_iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + AssertTargetedExpected (nameof (WriteNestedInterfaceTypes), writer.ToString ()); + } + + [Test] + public void WriteNestedInterfaceClass () + { + // Traditionally this would have created namespace.IParent and namespace.IParentChild + // With nested types this creates namespace.IParent and namespace.IParent.IChild + options.SupportNestedInterfaceTypes = true; + + var gens = ParseApiDefinition (nested_class_api); + + var parent_iface = gens.OfType ().Single (); + + parent_iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (parent_iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + AssertTargetedExpected (nameof (WriteNestedInterfaceClass), writer.ToString ()); + } + + [Test] + public void DontWriteInterfaceConstsClass () + { + // If SupportInterfaceConstants is true we no longer write the legacy + // XXXXConsts class that has been [Obsolete (iseeror: true)] for a while. + options.SupportInterfaceConstants = true; + + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.OfType ().Single (); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + Assert.False (writer.ToString ().Contains ("class ParentConsts")); + } + + [Test] + public void ObsoleteInterfaceAlternativeClass () + { + // If SupportInterfaceConstants and SupportDefaultInterfaceMethods is true we want to + // [Obsolete] the members of the "interface alternative" class so we can eventually remove it. + options.SupportInterfaceConstants = true; + + var xml = @" + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.OfType ().Single (); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + AssertTargetedExpected (nameof (ObsoleteInterfaceAlternativeClass), writer.ToString ()); + } + + [Test] + public void RespectNoAlternativesForInterfaces () + { + // If an interface is marked with no-alternatives='true', do + // not generate any legacy alternative classes for it + options.SupportInterfaceConstants = true; + + var xml = @" + + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.OfType ().Single (); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteType (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + Assert.False (writer.ToString ().Contains ("class ParentConsts")); + Assert.False (writer.ToString ().Contains ("class Parent")); + } + + [Test] + public void DontInvalidateInterfaceDueToStaticOrDefaultMethods () + { + // This interface contains a static and a default interface method that cannot + // be bound due to an unknown return type. However the user doesn't have to + // provide an implementation for these methods, so it's ok to bind the interface. + + var xml = @" + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.OfType ().Single (); + + var result = iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + // Inteface should pass validation despite invalid static/default methods + Assert.True (result); + + generator.WriteType (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + var generated = writer.ToString (); + + Assert.True (generated.Contains ("interface IParent")); + Assert.True (generated.Contains ("NormalMethod")); + Assert.False (generated.Contains ("StaticMethod")); + Assert.False (generated.Contains ("DefaultMethod")); + } + + [Test] + public void GenerateProperNestedInterfaceSignatures () + { + // https://github.com/dotnet/java-interop/issues/661 + // Ensure that when we write the invoker type for a nested default interface method + // we use `/` to denote nested as needed by Type.GetType () + var xml = @" + + + + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens[1].NestedTypes.OfType ().Single (); + + generator.WriteType (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + var generated = writer.ToString (); + + Assert.True (generated.Contains ("GetOnActivityDestroyed_IHandler:Com.Xamarin.Android.Application/IActivityLifecycleInterface, MyAssembly")); + Assert.False (generated.Contains ("GetOnActivityDestroyed_IHandler:Com.Xamarin.Android.Application.IActivityLifecycleInterface, MyAssembly")); + } + + [Test] + public void WriteInterfaceFieldAsDimProperty () + { + // Ensure we write interface fields that are not constant, and thus must be written as properties + var xml = @" + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var iface = gens.OfType ().Single (); + + var result = iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + Assert.True (result); + + generator.WriteType (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + var generated = writer.ToString (); + + AssertTargetedExpected (nameof (WriteInterfaceFieldAsDimProperty), writer.ToString ()); + } + + [Test] + public void CompatVirtualMethod_Interface () + { + var xml = @" + + + + + + + + + "; + + var gens = ParseApiDefinition (xml); + var klass = gens.Single (g => g.Name == "ICursor"); + + generator.Context.ContextTypes.Push (klass); + generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("catch (Java.Lang.NoSuchMethodError) { throw new Java.Lang.AbstractMethodError (__id); }".NormalizeLineEndings ()), $"was: `{writer}`"); + } + + [Test] + public void FixDefaultInterfaceMethodStackOverflow () + { + // The bug was that this causes a stack overflow, but this also tests + // that the OverriddenInterfaceMethod is now correctly set in the interface method. + var xml = """ + + + + + + + + + + + """; + + var gens = ParseApiDefinition (xml); + + foreach (var iface in gens.OfType ()) { + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + } + + var klass1 = gens.Single (g => g.Name == "IInternalConfigurator"); + var klass2 = gens.Single (g => g.Name == "IConfigurator"); + + Assert.AreEqual (1, klass1.Methods.Count); + Assert.AreEqual (1, klass2.Methods.Count); + + Assert.AreNotSame (klass1.Methods [0], klass2.Methods [0]); + Assert.AreSame (klass1.Methods [0].OverriddenInterfaceMethod, klass2.Methods [0]); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteBasicEnum.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteBasicEnum.txt new file mode 100644 index 00000000000..7ec7750b80e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteBasicEnum.txt @@ -0,0 +1,13 @@ +namespace Android.App +{ +public enum RecentTaskFlags +{ + [global::Android.Runtime.IntDefinition (null, JniField = "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE")] + [global::System.Runtime.Versioning.SupportedOSPlatformAttribute ("android30.0")] + WithExcluded = 1, + + [global::Android.Runtime.IntDefinition (null, JniField = "android/app/ActivityManager.RECENT_WITH_EXCLUDED")] + IgnoreUnavailable = 2, + +} +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteEnumWithGens.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteEnumWithGens.txt new file mode 100644 index 00000000000..5d437326f07 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteEnumWithGens.txt @@ -0,0 +1,13 @@ +namespace Android.App +{ +public enum RecentTaskFlags +{ + [global::Android.Runtime.IntDefinition ("android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE", JniField = "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE")] + [global::System.Runtime.Versioning.SupportedOSPlatformAttribute ("android30.0")] + WithExcluded = 1, + + [global::Android.Runtime.IntDefinition (null, JniField = "android/app/ActivityManager.RECENT_WITH_EXCLUDED")] + IgnoreUnavailable = 2, + +} +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteFlagsEnum.txt b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteFlagsEnum.txt new file mode 100644 index 00000000000..6f6bbc154ee --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorExpectedResults/WriteFlagsEnum.txt @@ -0,0 +1,14 @@ +namespace Android.App +{ +[System.Flags] +public enum RecentTaskFlags +{ + [global::Android.Runtime.IntDefinition (null, JniField = "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE")] + [global::System.Runtime.Versioning.SupportedOSPlatformAttribute ("android30.0")] + WithExcluded = 1, + + [global::Android.Runtime.IntDefinition (null, JniField = "android/app/ActivityManager.RECENT_WITH_EXCLUDED")] + IgnoreUnavailable = 2, + +} +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs new file mode 100644 index 00000000000..f000b149782 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.Generator.Enumification; +using MonoDroid.Generation; +using NUnit.Framework; +using NUnit.Framework.Internal; +using Xamarin.Android.Binder; + +namespace generatortests +{ + [TestFixture] + class EnumGeneratorTests : CodeGeneratorTestBase + { + protected new EnumGenerator generator; + + protected override CodeGenerationTarget Target => CodeGenerationTarget.XAJavaInterop1; + + [SetUp] + public new void SetUp () + { + builder = new StringBuilder (); + writer = new StringWriter (builder); + + generator = new EnumGenerator (writer); + } + + [Test] + public void WriteBasicEnum () + { + var enu = CreateEnum (); + enu.Value.FieldsRemoved = true; + + generator.WriteEnumeration (new CodeGenerationOptions (), enu, null); + + Assert.AreEqual (GetExpected (nameof (WriteBasicEnum)), writer.ToString ().NormalizeLineEndings ()); + } + + [Test] + public void WriteFlagsEnum () + { + var enu = CreateEnum (); + enu.Value.BitField = true; + enu.Value.FieldsRemoved = true; + + generator.WriteEnumeration (new CodeGenerationOptions (), enu, null); + + Assert.AreEqual (GetExpected (nameof (WriteFlagsEnum)), writer.ToString ().NormalizeLineEndings ()); + } + + [Test] + public void WriteEnumWithGens () + { + var enu = CreateEnum (); + var gens = CreateGens (); + + generator.WriteEnumeration (new CodeGenerationOptions (), enu, gens); + + Assert.AreEqual (GetExpected (nameof (WriteEnumWithGens)), writer.ToString ().NormalizeLineEndings ()); + } + + [Test] + public void ObsoletedOSPlatformAttributeSupport () + { + var xml = @" + + + + + + + + + "; + + options.UseObsoletedOSPlatformAttributes = true; + + var enu = CreateEnum (); + var gens = ParseApiDefinition (xml); + + generator.WriteEnumeration (options, enu, gens.ToArray ()); + + // Ensure [ObsoletedOSPlatform] and [SupportedOSPlatform] are written + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Runtime.Versioning.SupportedOSPlatformAttribute(\"android30.0\")][global::System.Runtime.Versioning.ObsoletedOSPlatform(\"android31.0\")]WithExcluded=1"), writer.ToString ()); + } + + [Test] + public void ObsoleteAttributeSupport () + { + var xml = @" + + + + + + + + + "; + + var enu = CreateEnum (); + var gens = ParseApiDefinition (xml); + + generator.WriteEnumeration (options, enu, gens.ToArray ()); + + // Ensure [Obsolete] is written + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]WithExcluded=1"), writer.ToString ()); + } + + [Test] + public void ObsoleteFieldButNotEnumAttributeSupport () + { + var xml = @" + + + + + + + + + "; + + var enu = CreateEnum (); + var gens = ParseApiDefinition (xml); + + generator.WriteEnumeration (options, enu, gens.ToArray ()); + + // [Obsolete] should not be written because the value isn't deprecated, just the _field_ is deprecated because we want people to use the enum instead + Assert.False (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"deprecated\")]WithExcluded=1"), writer.ToString ()); + } + + [Test] + public void ObsoletedOSPlatformAttributeOverrideSupport () + { + var xml = @" + + + + + + + + + "; + + options.UseObsoletedOSPlatformAttributes = true; + + var enu = CreateEnum (); + enu.Value.Members.Single (m => m.EnumMember == "WithExcluded").DeprecatedSince = new AndroidSdkVersion (33); + + var gens = ParseApiDefinition (xml); + + generator.WriteEnumeration (options, enu, gens.ToArray ()); + + // The field itself is not deprecated, but [ObsoletedOSPlatform] should be written because we set `DeprecatedSince` on the enum map + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Runtime.Versioning.ObsoletedOSPlatform(\"android33.0\")]WithExcluded=1"), writer.ToString ()); + } + + [Test] + public void ObsoleteAccidentalAddition () + { + var xml = @" + + + + + + + + + "; + + options.UseObsoletedOSPlatformAttributes = true; + + var enu = CreateEnum (); + enu.Value.Members.Single (m => m.EnumMember == "WithExcluded").DeprecatedSince = new AndroidSdkVersion (-1); + + var gens = ParseApiDefinition (xml); + + generator.WriteEnumeration (options, enu, gens.ToArray ()); + + // "-1" is a "magic" API level which adds a message indicating the enum value shouldn't even exist + Assert.True (writer.ToString ().NormalizeLineEndings ().Contains ("[global::System.Obsolete(@\"Thisvaluewasincorrectlyaddedtotheenumerationandisnotavalidvalue\")]WithExcluded=1"), writer.ToString ()); + } + + protected new string GetExpected (string testName) + { + var root = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location); + + return File.ReadAllText (Path.Combine (root, "Unit-Tests", "EnumGeneratorExpectedResults", $"{testName}.txt")).NormalizeLineEndings (); + } + + KeyValuePair CreateEnum () + { + var enu = new EnumMappings.EnumDescription { + Members = new List { + new ConstantEntry { EnumMember = "WithExcluded", Value = "1", JavaSignature = "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE", ApiLevel = new AndroidSdkVersion (30) }, + new ConstantEntry { EnumMember = "IgnoreUnavailable", Value = "2", JavaSignature = "android/app/ActivityManager.RECENT_WITH_EXCLUDED" } + }, + BitField = false, + FieldsRemoved = false + }; + + return new KeyValuePair ("Android.App.RecentTaskFlags", enu); + } + + GenBase[] CreateGens () + { + var klass = new TestClass (string.Empty, "android.app.ActivityManager"); + + klass.Fields.Add (new TestField ("int", "RECENT_IGNORE_UNAVAILABLE")); + + return new [] { klass }; + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs new file mode 100644 index 00000000000..b8adbb59f2a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs @@ -0,0 +1,387 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using MonoDroid.Generation; +using NUnit.Framework; + +using Java.Interop.Tools.Generator; + +namespace generatortests +{ + [TestFixture] + public class EnumMappingsTests + { + [Test] + public void BasicEnumificationTest () + { + // This should create a new enum and remove the field + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); + + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); + Assert.AreEqual (false, enums.Single ().Value.BitField); + Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); + } + + [Test] + public void RemoveFieldOnlyTest () + { + // This should only remove the field + var csv = "10,,,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); + + Assert.AreEqual (0, enums.Count); + } + + [Test] + public void AddConstantOnlyTest () + { + // This should only add an enum + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual (0, removes.Count); + + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); + Assert.AreEqual (false, enums.Single ().Value.BitField); + Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved); + Assert.AreEqual ("", enums.First ().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); + } + + [Test] + public void FlagsEnumerationTest () + { + // This should create a new enum with [Flags] because of the ",Flags" field + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Flags"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual (true, enums.Single ().Value.BitField); + } + + [Test] + public void ExternalFlagsEnumerationTest () + { + // This should create a new enum with [Flags] because of the "enumFlags" parameter + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new [] { "Org.XmlPull.V1.XmlPullParserNode" }, new AndroidSdkVersion (30), removes); + + Assert.AreEqual (true, enums.Single ().Value.BitField); + } + + [Test] + public void ApiVersionExcludedTest () + { + // This should be completely ignored because it's API=10 and we're looking for API=5 + var csv = "10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Flags"; + var mappings = new EnumMappings (string.Empty, string.Empty, "5", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (5), removes); + + Assert.AreEqual (0, removes.Count); + Assert.AreEqual (0, enums.Count); + } + + [Test] + public void TransientEnumificationTest () + { + // This should create a new enum and remove the field + var csv = $"- ENTER TRANSIENT MODE -{Environment.NewLine}10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, Org.XmlPull.V1.XmlPullParserNode]", removes.Single ().ToString ()); + + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); + Assert.AreEqual (false, enums.Single ().Value.BitField); + Assert.AreEqual (false, enums.Single ().Value.FieldsRemoved); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); + } + + [Test] + public void TransientRemoveFieldOnlyTest () + { + // Transient has no effect here + var csv = $"- ENTER TRANSIENT MODE -{Environment.NewLine}10,,,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); + + Assert.AreEqual (0, enums.Count); + } + + [Test] + public void TransientAddConstantOnlyTest () + { + // This should only add an enum + var csv = $"- ENTER TRANSIENT MODE -{Environment.NewLine}10,Org.XmlPull.V1.XmlPullParserNode,Cdsect,,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual (0, removes.Count); + + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); + Assert.AreEqual (false, enums.Single ().Value.BitField); + Assert.AreEqual (false, enums.Single ().Value.FieldsRemoved); + Assert.AreEqual ("", enums.First ().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); + } + [Test] + public void BasicEnumificationV2Test () + { + // This should create a new enum and remove the field + var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); + + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); + Assert.AreEqual (false, enums.Single ().Value.BitField); + Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); + } + + [Test] + public void RemoveFieldOnlyV2Test () + { + // This should only remove the field + var csv = "R,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, ]", removes.Single ().ToString ()); + + Assert.AreEqual (0, enums.Count); + } + + [Test] + public void AddConstantOnlyV2Test () + { + // This should only add an enum + var csv = "A,10,,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual (0, removes.Count); + + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); + Assert.AreEqual (false, enums.Single ().Value.BitField); + Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved); + Assert.AreEqual ("", enums.First ().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); + } + + [Test] + public void FlagsEnumerationV2Test () + { + // This should create a new enum with [Flags] because of the ",Flags" field + var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect,remove,Flags"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual (true, enums.Single ().Value.BitField); + } + + [Test] + public void ExternalFlagsEnumerationV2Test () + { + // This should create a new enum with [Flags] because of the "enumFlags" parameter + var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new [] { "Org.XmlPull.V1.XmlPullParserNode" }, new AndroidSdkVersion (30), removes); + + Assert.AreEqual (true, enums.Single ().Value.BitField); + } + + [Test] + public void ApiVersionExcludedV2Test () + { + // This should be completely ignored because it's API=10 and we're looking for API=5 + var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect"; + var mappings = new EnumMappings (string.Empty, string.Empty, "5", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (5), removes); + + Assert.AreEqual (0, removes.Count); + Assert.AreEqual (0, enums.Count); + } + + [Test] + public void TransientEnumificationV2Test () + { + // This should create a new enum and remove the field + var csv = "E,10,I:org/xmlpull/v1/XmlPullParser.CDSECT,5,Org.XmlPull.V1.XmlPullParserNode,Cdsect,remove"; + var mappings = new EnumMappings (string.Empty, string.Empty, "30", false); + var sr = new StringReader (csv); + + var removes = new List> (); + var enums = mappings.ParseFieldMappings (sr, new string [0], new AndroidSdkVersion (30), removes); + + Assert.AreEqual ("[I:org/xmlpull/v1/XmlPullParser.CDSECT, Org.XmlPull.V1.XmlPullParserNode]", removes.Single ().ToString ()); + + Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key); + Assert.AreEqual (false, enums.Single ().Value.BitField); + Assert.AreEqual (false, enums.Single ().Value.FieldsRemoved); + Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature); + Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ()); + } + + [Test] + public void XmlEnumMapWithJNI () + { + var xml = @" + + + + + + "; + + var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var sr = EnumMappings.FieldXmlToCsv (doc); + + var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + var expected = new [] { + "0, Android.Support.V4.App.FragmentTagType, Name, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_name, 0", + "0, Android.Support.V4.App.FragmentTagType, Id, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1", + "0, Android.Support.V4.App.FragmentTagType, Tag, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_tag, 2" + }; + + Assert.AreEqual (expected, lines); + } + + [Test] + public void XmlEnumMapWithInterfaceJNI () + { + var xml = @" + + + + + + "; + + var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var sr = EnumMappings.FieldXmlToCsv (doc); + + var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + var expected = new [] { + "0, Android.Support.V4.App.FragmentTagType, Name, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_name, 0, Flags", + "0, Android.Support.V4.App.FragmentTagType, Id, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1, Flags", + "0, Android.Support.V4.App.FragmentTagType, Tag, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_tag, 2, Flags" + }; + + Assert.AreEqual (expected, lines); + } + + [Test] + public void XmlEnumMapWithoutJNI () + { + var xml = @" + + + + + + "; + + var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var sr = EnumMappings.FieldXmlToCsv (doc); + + var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + var expected = new [] { + "0, Android.Support.V4.App.FragmentTagType, Name, , 0, Flags", + "0, Android.Support.V4.App.FragmentTagType, Id, , 1, Flags", + "0, Android.Support.V4.App.FragmentTagType, Tag, , 2, Flags" + }; + + Assert.AreEqual (expected, lines); + } + + [Test] + public void XmlEnumMapWithMixedJNI () + { + var xml = @" + + + + + + "; + + var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var sr = EnumMappings.FieldXmlToCsv (doc); + + var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + var expected = new [] { + "0, Android.Support.V4.App.FragmentTagType, Name, , 0, Flags", + "0, Android.Support.V4.App.FragmentTagType, Id, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1, Flags", + "0, Android.Support.V4.App.FragmentTagType, Tag, , 2, Flags" + }; + + Assert.AreEqual (expected, lines); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/FixupXmlDocumentTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/FixupXmlDocumentTests.cs new file mode 100644 index 00000000000..728b3c2cd0c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/FixupXmlDocumentTests.cs @@ -0,0 +1,125 @@ +using System; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class FixupXmlDocumentTests + { + [Test] + public void RemoveNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument (""); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void AddNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument (""); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void ChangeNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("method"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void MoveNode () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("/api/package[@name='android']"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void SetNewAttribute () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("true"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void ChangeAttribute () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument ("android2"); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void RemoveAttribute () + { + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument (""); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void RemoveNotFoundAttribute () + { + // Attribute 'foo' doesn't exist on node + var api = GetXmlApiDocument (); + var fixup = GetFixupXmlDocument (""); + + api.ApplyFixupFile (fixup); + + Assert.AreEqual ("", api.ApiDocument.ToString (SaveOptions.DisableFormatting).Replace ('\"', '\'')); + } + + [Test] + public void ParseNamespaceTransforms () + { + var fixup = GetFixupXmlDocument (""); + var transforms = fixup.GetNamespaceTransforms (); + + Assert.AreEqual (2, transforms.Count); + Assert.AreEqual ("androidx", transforms [0].OldValue); + Assert.AreEqual ("AndroidX", transforms [0].NewValue); + Assert.AreEqual ("com.google", transforms [1].OldValue); + Assert.AreEqual ("Xamarin", transforms [1].NewValue); + } + + ApiXmlDocument GetXmlApiDocument () + { + var api = ""; + + return new ApiXmlDocument (XDocument.Parse (api), "30", 0); + } + + FixupXmlDocument GetFixupXmlDocument (string text) + { + return new FixupXmlDocument (XDocument.Parse ("" + text + "")); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/GenBaseTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/GenBaseTests.cs new file mode 100644 index 00000000000..02e494b4fbc --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/GenBaseTests.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class GenBaseTests + { + CodeGenerationOptions options = new CodeGenerationOptions (); + + [Test] + public void PropertyRequiresNew () + { + var c = SupportTypeBuilder.CreateClassWithProperty ("MyClass", "java.myClass", "Handle", "int", options); + Assert.True (c.RequiresNew (c.Properties.First ())); + + c.Properties.First ().Name = "GetHashCode"; + Assert.True (c.RequiresNew (c.Properties.First ())); + + c.Properties.First ().Name = "GetType"; + Assert.True (c.RequiresNew (c.Properties.First ())); + + c.Properties.First ().Name = "ToString"; + Assert.True (c.RequiresNew (c.Properties.First ())); + + c.Properties.First ().Name = "Equals"; + Assert.True (c.RequiresNew (c.Properties.First ())); + + c.Properties.First ().Name = "ReferenceEquals"; + Assert.True (c.RequiresNew (c.Properties.First ())); + + c.Properties.First ().Name = "Handle2"; + Assert.False (c.RequiresNew (c.Properties.First ())); + } + + [Test] + public void ToStringRequiresNew () => TestParameterlessMethods ("ToString"); + + [Test] + public void GetTypeRequiresNew () => TestParameterlessMethods ("GetType"); + + [Test] + public void GetHashCodeRequiresNew () => TestParameterlessMethods ("GetHashCode"); + + [Test] + public void StaticEqualsCodeRequiresNew () => TestStaticMethodsWithTwoParameters ("Equals"); + + [Test] + public void ReferenceEqualsEqualsCodeRequiresNew () => TestStaticMethodsWithTwoParameters ("ReferenceEquals"); + + [Test] + public void HandleAlwaysRequiresNew () + { + // The same name as a property always requires new, no matter the parameters + var c = SupportTypeBuilder.CreateClass ("java.myClass", options); + var m = SupportTypeBuilder.CreateMethod (c, "Handle", options); + + // Yes + Assert.True (c.RequiresNew (m.Name, m)); + + // Yes, even with parameters + m.Parameters.Add (new Parameter ("value", "int", "int", false)); + + Assert.True (c.RequiresNew (m.Name, m)); + } + + [Test] + public void TestEqualsMethodsWithOneParameter () + { + var c = SupportTypeBuilder.CreateClass ("java.myClass", options); + var m = SupportTypeBuilder.CreateMethod (c, "Equals", options, "void", false, false); + + // No because 0 parameters + Assert.False (c.RequiresNew (m.Name, m)); + + var p0 = new Parameter ("p0", "object", "object", false); + m.Parameters.Add (p0); + + // Yes + Assert.True (c.RequiresNew (m.Name, m)); + + // No because parameter is wrong type + var p1 = new Parameter ("p1", "string", "string", false); + m = SupportTypeBuilder.CreateMethod (c, "Equals", options, "void", true, false, p1); + + Assert.False (c.RequiresNew (m.Name, m)); + } + + [Test] + public void TestMethodClone_GenericArguments () + { + var c = SupportTypeBuilder.CreateClass ("java.myClass", options); + var m = SupportTypeBuilder.CreateMethod (c, "DoStuff", options); + + m.GenericArguments = new GenericParameterDefinitionList { + new GenericParameterDefinition ("T", null) + }; + + var clone = m.Clone (c); + + Assert.AreEqual (1, clone.GenericArguments.Count); + Assert.AreEqual ("T", clone.GenericArguments [0].Name); + } + + void TestParameterlessMethods (string name) + { + var c = SupportTypeBuilder.CreateClass ("java.myClass", options); + var m = SupportTypeBuilder.CreateMethod (c, name, options); + + // Yes + Assert.True (c.RequiresNew (m.Name, m)); + + // No because > 0 parameters + m.Parameters.Add (new Parameter ("value", "int", "int", false)); + + Assert.False (c.RequiresNew (m.Name, m)); + } + + void TestStaticMethodsWithTwoParameters (string name) + { + var c = SupportTypeBuilder.CreateClass ("java.myClass", options); + + var p0 = new Parameter ("p0", "object", "object", false); + var p1 = new Parameter ("p1", "object", "object", false); + var m = SupportTypeBuilder.CreateMethod (c, name, options, "void", true, false, p0, p1); + + // Yes + Assert.True (c.RequiresNew (m.Name, m)); + + // No because != 2 parameters + m.Parameters.Add (new Parameter ("value", "int", "int", false)); + Assert.False (c.RequiresNew (m.Name, m)); + + // No because parameter is wrong type + var p2 = new Parameter ("p1", "string", "string", false); + m = SupportTypeBuilder.CreateMethod (c, name, options, "void", true, false, p0, p2); + + Assert.False (c.RequiresNew (m.Name, m)); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/InterfaceConstantsTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/InterfaceConstantsTests.cs new file mode 100644 index 00000000000..0b3124b31d0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/InterfaceConstantsTests.cs @@ -0,0 +1,56 @@ +using System; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + class XAJavaInteropInterfaceConstantsTests : InterfaceConstantsTests + { + protected override Xamarin.Android.Binder.CodeGenerationTarget Target => Xamarin.Android.Binder.CodeGenerationTarget.XAJavaInterop1; + } + + abstract class InterfaceConstantsTests : CodeGeneratorTestBase + { + protected override CodeGenerationOptions CreateOptions () + { + var options = base.CreateOptions (); + + options.SupportInterfaceConstants = true; + + return options; + } + + [Test] + public void WriteConstSugarInterfaceFields () + { + // Need a JLO class "FromXml" to trigger ConstSugar logic. (ie: this is "building" Mono.Android.dll) + var klass = new TestClass ("java.lang.Object", "java.lang.Object") { + FromXml = true, + }; + + options.SymbolTable.AddType (klass); + + // This is an interface that only has fields (IsConstSugar) + // We treat a little differenly because they don't need to interop with Java + var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.IMyInterface"); + + // These interface fields are supported and should be in the output + iface.Fields.Add (new TestField ("int", "MyConstantField").SetConstant ().SetValue ("7")); + iface.Fields.Add (new TestField ("java.lang.String", "MyConstantStringField").SetConstant ().SetValue ("\"hello\"")); + iface.Fields.Add (new TestField ("int", "MyDeprecatedField").SetConstant ().SetValue ("7").SetDeprecated ()); + + // These interface fields are not supported and should be ignored + iface.Fields.Add (new TestField ("int", "MyDeprecatedEnumField").SetConstant ().SetValue ("MyEnumValue").SetDeprecated ("This constant will be removed in the future version.")); + iface.Fields.Add (new TestField ("int", "MyStaticField").SetStatic ().SetValue ("7")); + + iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.Context.ContextTypes.Push (iface); + generator.WriteType (iface, string.Empty, new GenerationInfo (null, null, null)); + generator.Context.ContextTypes.Pop (); + + Assert.AreEqual (GetTargetedExpected (nameof (WriteConstSugarInterfaceFields)), writer.ToString ().NormalizeLineEndings ()); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/InterfaceTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/InterfaceTests.cs new file mode 100644 index 00000000000..d619910fdab --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/InterfaceTests.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + public class InterfaceTests + { + [Test] + public void ValidateInterfaceMethods () + { + var options = new CodeGenerationOptions { SupportDefaultInterfaceMethods = true }; + var iface = SupportTypeBuilder.CreateEmptyInterface ("My.Test.Interface"); + + iface.Methods.Add (SupportTypeBuilder.CreateMethod (iface, "DoAbstractThing", options)); + iface.Methods.Add (SupportTypeBuilder.CreateMethod (iface, "DoDefaultThing", options).SetDefaultInterfaceMethod ()); + + // The interface should be valid + Assert.True (iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ())); + + Assert.AreEqual (2, iface.Methods.Count); + } + + [Test] + public void ValidateInvalidDefaultInterfaceMethods () + { + var options = new CodeGenerationOptions { SupportDefaultInterfaceMethods = true }; + var iface = SupportTypeBuilder.CreateEmptyInterface ("My.Test.Interface"); + + iface.Methods.Add (SupportTypeBuilder.CreateMethod (iface, "DoAbstractThing", options)); + iface.Methods.Add (SupportTypeBuilder.CreateMethod (iface, "DoDefaultThing", options, "potato").SetDefaultInterfaceMethod ()); + + // The interface should still be valid despite the default method being invalid + Assert.True (iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ())); + + // The invalid default method should be removed, leaving just the valid abstract method + Assert.AreEqual (1, iface.Methods.Count); + } + + [Test] + public void ValidateInvalidAbstractInterfaceMethods () + { + var options = new CodeGenerationOptions { SupportDefaultInterfaceMethods = true }; + var iface = SupportTypeBuilder.CreateEmptyInterface ("My.Test.Interface"); + + iface.Methods.Add (SupportTypeBuilder.CreateMethod (iface, "DoAbstractThing", options, "potato")); + iface.Methods.Add (SupportTypeBuilder.CreateMethod (iface, "DoDefaultThing", options).SetDefaultInterfaceMethod ()); + + // The interface should be invalid because an abstract method is invalid + Assert.False (iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ())); + + // The invalid abstract method should be removed, leaving just the valid default method + Assert.AreEqual (1, iface.Methods.Count); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinFixupsTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinFixupsTests.cs new file mode 100644 index 00000000000..326fd7ab7b7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinFixupsTests.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.Generator.Transformation; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class KotlinFixupsTests + { + [Test] + public void CreateMethod_EnsureKotlinImplFix () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions ()); + + KotlinFixups.Fixup (new [] { (GenBase)klass }.ToList ()); + + Assert.AreEqual ("Add", klass.Methods [0].Name); + Assert.IsTrue (klass.Methods [0].IsFinal); + Assert.IsFalse (klass.Methods [0].IsVirtual); + } + + [Test] + public void CreateMethod_EnsureKotlinHashcodeFix () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions ()); + + KotlinFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual ("Add", klass.Methods [0].Name); + Assert.IsTrue (klass.Methods [0].IsFinal); + Assert.IsFalse (klass.Methods [0].IsVirtual); + } + + [Test, NonParallelizable] + public void CollidingHashSiblings_AreDeduplicated () + { + // Two Kotlin hash-mangled siblings that erase to the same C# signature + // (one `long` parameter). After the rename to `Add` both would collide, + // so we keep only the first. + var xml = XDocument.Parse (@" + + + + + + + + + "); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions ()); + + using var warnings = CaptureWarnings (); + KotlinFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual (1, klass.Methods.Count, "Duplicate hash-mangled sibling should have been removed."); + Assert.AreEqual ("Add", klass.Methods [0].Name); + Assert.AreEqual ("add-AAAAAAA", klass.Methods [0].JavaName, "The first hash-mangled sibling in source order should survive."); + Assert.IsTrue (warnings.Messages.Any (m => m.Contains ("BG8C02")), "Expected BG8C02 warning, got: " + string.Join (Environment.NewLine, warnings.Messages)); + } + + [Test] + public void NonCollidingHashSiblings_AreBothKept () + { + // Two siblings with distinct parameter lists: both should rename to `Add` + // and survive as overloads. + var xml = XDocument.Parse (@" + + + + + + + + + "); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions ()); + + KotlinFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual (2, klass.Methods.Count); + Assert.IsTrue (klass.Methods.All (m => m.Name == "Add")); + } + + [Test] + public void MixedCollidingAndUniqueHashSiblings () + { + // Three siblings of the same source-name: the long+long pair collide, + // the float arg is unique. Expect 2 methods to survive. + var xml = XDocument.Parse (@" + + + + + + + + + + + + "); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions ()); + + KotlinFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual (2, klass.Methods.Count); + Assert.IsTrue (klass.Methods.All (m => m.Name == "Add")); + CollectionAssert.AreEquivalent (new [] { "long", "float" }, klass.Methods.Select (m => m.Parameters [0].RawNativeType).ToArray ()); + } + + [Test, NonParallelizable] + public void MangledMethod_CollidesWithNonMangledOverload () + { + // A pre-existing non-mangled overload `add(long)` plus a mangled + // `add-AAAAAAA(long)` that also reduces to `add(long)` after rename. + // The mangled one is the duplicate -- drop it, keep the non-mangled. + var xml = XDocument.Parse (@" + + + + + + + + + "); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions ()); + + using var warnings = CaptureWarnings (); + KotlinFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual (1, klass.Methods.Count, "Mangled duplicate should have been removed, leaving the pre-existing non-mangled method."); + Assert.AreEqual ("add", klass.Methods [0].JavaName, "The kept method should be the non-mangled one."); + Assert.IsTrue (warnings.Messages.Any (m => m.Contains ("BG8C02")), "Expected BG8C02 warning."); + } + + [Test, NonParallelizable] + public void MangledMethod_CollidesWithNonMangledOverload_ReversedOrder () + { + // Same as above but with the mangled method declared FIRST. The + // non-mangled real Kotlin API must still win regardless of order. + var xml = XDocument.Parse (@" + + + + + + + + + "); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions ()); + + using var warnings = CaptureWarnings (); + KotlinFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual (1, klass.Methods.Count, "Mangled duplicate should have been removed regardless of source order."); + Assert.AreEqual ("add", klass.Methods [0].JavaName, "The non-mangled method should survive regardless of order."); + Assert.IsTrue (warnings.Messages.Any (m => m.Contains ("BG8C02")), "Expected BG8C02 warning."); + } + + static WarningCapture CaptureWarnings () => new WarningCapture (); + + sealed class WarningCapture : IDisposable + { + readonly Action previous; + public List Messages { get; } = new List (); + + public WarningCapture () + { + previous = Report.OutputDelegate; + Report.OutputDelegate = (level, msg) => Messages.Add (msg); + } + + public void Dispose () + { + Report.OutputDelegate = previous; + } + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinInlineClassEndToEndTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinInlineClassEndToEndTests.cs new file mode 100644 index 00000000000..512749e8d3b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinInlineClassEndToEndTests.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using NUnit.Framework; +using Xamarin.Android.Binder; +using Xamarin.Android.Tools.Bytecode; + +namespace generatortests +{ + // dotnet/java-interop#1431 (Phase 2): end-to-end test that drives real + // Kotlin .class files (compiled by tests/Xamarin.Android.Tools.Bytecode-Tests/ + // kotlin-gradle/) through KotlinFixups -> XmlClassDeclarationBuilder -> + // XmlApiImporter -> JavaInteropCodeGenerator and asserts the projected C# + // output uses the generated `readonly partial struct` wrapper types in + // method signatures while keeping the JNI marshaling on the underlying + // primitive. + [TestFixture] + public class KotlinInlineClassEndToEndTests + { + [Test] + public void GeneratorProjectsRealKotlinInlineClassesAsStructs () + { + var apiXml = BuildApiXmlFromKotlinFixture (); + + // Sanity: api.xml carries the Phase 2 attributes class-parse emits. + StringAssert.Contains ("kotlin-inline-class=\"true\"", apiXml); + StringAssert.Contains ("kotlin-inline-class-jni-type=\"Lxat/bytecode/tests/MyColor;\"", apiXml); + StringAssert.Contains ("kotlin-inline-class-return-jni-type=\"Lxat/bytecode/tests/MyDp;\"", apiXml); + + var output = GenerateCSharp (apiXml, out var gens); + + // MyColor / MyAlpha / MyDp must be projected as readonly partial structs. + StringAssert.Contains ("readonly partial struct MyColor", output); + StringAssert.Contains ("readonly partial struct MyAlpha", output); + StringAssert.Contains ("readonly partial struct MyDp", output); + + // Underlying-primitive marshaling: MyColor/MyAlpha back J (long), + // MyDp backs F (float). + StringAssert.Contains ("public static implicit operator long (MyColor", output); + StringAssert.Contains ("public static implicit operator MyColor (long", output); + StringAssert.Contains ("public static implicit operator float (MyDp", output); + StringAssert.Contains ("public static implicit operator MyDp (float", output); + + // Widgets.tint(MyColor) / tint(MyAlpha) / tint(MyDp) overloads must + // project the inline-class param in the C# signature. The Kotlin + // compiler mangles the JVM names for inline-class binary compat + // (e.g. `tint-Rn_QMJI`); we recover the unmangled name so they + // emit as plain C# overloads distinguished by struct type. + StringAssert.Contains ("Tint (Xat.Bytecode.Tests.MyColor color)", output); + StringAssert.Contains ("Tint (Xat.Bytecode.Tests.MyAlpha alpha)", output); + StringAssert.Contains ("Tint (Xat.Bytecode.Tests.MyDp dp)", output); + + // Widgets.pad(MyDp): MyDp -> the return type uses MyDp. + StringAssert.Contains ("Xat.Bytecode.Tests.MyDp Pad (Xat.Bytecode.Tests.MyDp dp)", output); + StringAssert.Contains ("Xat.Bytecode.Tests.MyDp Pad (Xat.Bytecode.Tests.MyDp dp1, Xat.Bytecode.Tests.MyDp dp2)", output); + + // Widgets.tintColor: MyColor -> a Kotlin `var` typed as an inline + // class projects as a C# property typed as the wrapper struct, with + // the getter/setter still marshaling the underlying primitive (long) + // across JNI. This exercises the KotlinFixups.FixupProperty path. + StringAssert.Contains ("Xat.Bytecode.Tests.MyColor TintColor", output); + + // And the JVM-mangled hash-suffix names must NOT leak into the + // generated C# (regression guard for the unmangling path). + StringAssert.DoesNotContain ("Tint_", output); + StringAssert.DoesNotContain ("Pad_", output); + + // And no `Java.Lang.Object`-derived peer class for the inline classes + // (the wrapper struct fully replaces the peer-class binding). + StringAssert.DoesNotContain ("public partial class MyColor", output); + StringAssert.DoesNotContain ("public partial class MyAlpha", output); + StringAssert.DoesNotContain ("public partial class MyDp", output); + + // All three inline classes survived as ClassGen entries with the + // IsKotlinInlineClass flag set. + Assert.IsTrue (gens.OfType ().Count (g => g.IsKotlinInlineClass) >= 3, + $"Expected at least 3 inline-class ClassGens, generator output was:\n{output}"); + } + + // Run the four kotlin-gradle .class files through KotlinFixups and + // XmlClassDeclarationBuilder to produce the same api.xml the generator + // would normally consume off disk. + static string BuildApiXmlFromKotlinFixture () + { + var classes = new List { + LoadClassFile ("MyColor.class"), + LoadClassFile ("MyAlpha.class"), + LoadClassFile ("MyDp.class"), + LoadClassFile ("Widgets.class"), + }; + Xamarin.Android.Tools.Bytecode.KotlinFixups.Fixup (classes); + + var classPath = new ClassPath { ApiSource = "class-parse" }; + foreach (var c in classes) + classPath.Add (c); + + var sw = new StringWriter (); + classPath.SaveXmlDescription (sw); + var xml = sw.ToString (); + + // XmlApiImporter needs java.lang.Object in the symbol table so the + // generated peer types (and their RetVal/Parameter symbols) resolve + // during Validate. Splice a minimal stub package into the api root. + var doc = XDocument.Parse (xml); + doc.Root.AddFirst (XElement.Parse ( + "" + + "" + + "")); + return doc.ToString (); + } + + static ClassFile LoadClassFile (string resource) + { + var assembly = typeof (KotlinInlineClassEndToEndTests).Assembly; + var name = assembly.GetManifestResourceNames () + .FirstOrDefault (n => n.EndsWith ("." + resource, System.StringComparison.OrdinalIgnoreCase)) + ?? throw new FileNotFoundException ($"Embedded resource '{resource}' not found."); + using (var stream = assembly.GetManifestResourceStream (name)) + return new ClassFile (stream); + } + + // Drive the parsed api.xml through XmlApiImporter + Validate + the + // JavaInteropCodeGenerator to produce the C# binding text. + static string GenerateCSharp (string apiXml, out List gens) + { + var options = new CodeGenerationOptions { + CodeGenerationTarget = CodeGenerationTarget.JavaInterop1, + }; + var sb = new System.Text.StringBuilder (); + var writer = new StringWriter (sb); + var generator = options.CreateCodeGenerator (writer); + + var doc = XDocument.Parse (apiXml); + gens = XmlApiImporter.Parse (doc, options); + + foreach (var gen in gens) + options.SymbolTable.AddType (gen); + + foreach (var gen in gens) + gen.FixupAccessModifiers (options); + + // dotnet/java-interop#1431 (Phase 2): match the real CodeGenerator + // pipeline (see CodeGenerator.cs line 209), which runs + // Java.Interop.Tools.Generator.Transformation.KotlinFixups.Fixup + // (including RemoveCollidingSiblings) before Validate. Without + // this, the test would mask the interaction between Phase 1's + // mangled-name dedup and Phase 2's inline-class projection. + Java.Interop.Tools.Generator.Transformation.KotlinFixups.Fixup (gens); + + foreach (var gen in gens) + gen.Validate (options, new GenericParameterDefinitionList (), generator.Context); + + foreach (var gen in gens) + gen.FillProperties (); + + foreach (var gen in gens) + gen.FixupMethodOverrides (options); + + var info = new GenerationInfo ("", "", "MyAssembly"); + foreach (var gen in gens) { + generator.Context.ContextTypes.Push (gen); + generator.WriteType (gen, string.Empty, info); + generator.Context.ContextTypes.Pop (); + } + + return sb.ToString (); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinInlineClassTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinInlineClassTests.cs new file mode 100644 index 00000000000..2b83ba51870 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/KotlinInlineClassTests.cs @@ -0,0 +1,101 @@ +using System.Linq; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class KotlinInlineClassTests + { + CodeGenerationOptions opt = new CodeGenerationOptions (); + + [Test] + public void CreateClass_ReadsKotlinInlineClassAttributes () + { + var xml = XDocument.Parse ( + "" + + "" + + ""); + + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.IsTrue (klass.IsKotlinInlineClass); + Assert.AreEqual ("J", klass.KotlinInlineClassUnderlyingJniType); + } + + [Test] + public void CreateClass_DefaultsForNonInlineClass () + { + var xml = XDocument.Parse ( + "" + + "" + + ""); + + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.IsFalse (klass.IsKotlinInlineClass); + } + + [Test] + public void CreateParameter_ReadsKotlinInlineClassJniType () + { + var xml = XDocument.Parse ( + ""); + + var p = XmlApiImporter.CreateParameter (xml.Root, opt); + + Assert.AreEqual ("Lcom/example/MyColor;", p.KotlinInlineClassJniType); + } + + [Test] + public void CreateMethod_ReadsKotlinInlineClassReturnJniType () + { + var xml = XDocument.Parse ( + "" + + "" + + "" + + ""); + + var pkg = xml.Root; + var classElem = pkg.Element ("class"); + var klass = XmlApiImporter.CreateClass (pkg, classElem, opt); + var method = klass.Methods.First (); + + Assert.AreEqual ("Lcom/example/MyDp;", method.KotlinInlineClassReturnJniType); + } + + [Test] + public void Parameter_Clone_PreservesKotlinInlineClassJniType () + { + var xml = XDocument.Parse ( + ""); + + var p = XmlApiImporter.CreateParameter (xml.Root, opt); + var clone = p.Clone (); + + Assert.AreEqual ("Lcom/example/MyColor;", clone.KotlinInlineClassJniType); + } + + [Test] + public void TypeNameUtilities_JniSignatureToJavaTypeName_HandlesReferenceTypes () + { + Assert.AreEqual ("com.example.MyColor", + TypeNameUtilities.JniSignatureToJavaTypeName ("Lcom/example/MyColor;")); + Assert.AreEqual ("java.lang.String", + TypeNameUtilities.JniSignatureToJavaTypeName ("Ljava/lang/String;")); + } + + [Test] + public void TypeNameUtilities_JniSignatureToJavaTypeName_RejectsPrimitivesAndArrays () + { + Assert.IsNull (TypeNameUtilities.JniSignatureToJavaTypeName ("J")); + Assert.IsNull (TypeNameUtilities.JniSignatureToJavaTypeName ("")); + Assert.IsNull (TypeNameUtilities.JniSignatureToJavaTypeName (null)); + // Array types intentionally not supported by inline-class projection. + Assert.IsNull (TypeNameUtilities.JniSignatureToJavaTypeName ("[Lcom/example/MyColor;")); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/ManagedExtensionsTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/ManagedExtensionsTests.cs new file mode 100644 index 00000000000..562afb84a35 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/ManagedExtensionsTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class ManagedExtensionsTests + { + [Test] + public void StripArity () + { + Assert.AreEqual ("List", "List`1".StripArity ()); + Assert.AreEqual ("List>", "List`10>".StripArity ()); + Assert.AreEqual ("List", "List".StripArity ()); + Assert.AreEqual ("List`1", "List`1".StripArity ()); + Assert.AreEqual ("List", "List`1".StripArity ()); + Assert.AreEqual ("List", "List`1`".StripArity ()); + Assert.AreEqual ("List<", "List`1<".StripArity ()); + Assert.AreEqual ("List<", "List`<".StripArity ()); + Assert.AreEqual ("<", "`1<".StripArity ()); + Assert.AreEqual ("`", "`".StripArity ()); + Assert.AreEqual (string.Empty, string.Empty.StripArity ()); + Assert.IsNull ((null as string).StripArity ()); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/ManagedTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/ManagedTests.cs new file mode 100644 index 00000000000..746e4709dda --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/ManagedTests.cs @@ -0,0 +1,327 @@ +using Android.Runtime; +using Mono.Cecil; +using MonoDroid.Generation; +using NUnit.Framework; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Java.Lang +{ + [Register ("java/lang/Object")] + public class Object { } + + [Register ("java/lang/String")] + public sealed class String : Object { } +} + +namespace Com.Mypackage +{ + [Register ("com/mypackage/foo")] + public class Foo : Java.Lang.Object + { + [Register ("foo", "()V", "")] + public Foo () { } + + [Register ("bar", "()V", "")] + public void Bar () { } + + [Register ("barWithParams", "(ZID)Ljava/lang/String;", "")] + public string BarWithParams (bool a, int b, double c) => string.Empty; + + [Register ("unknownTypes", "(Lmy/package/foo/Unknown;)V", "")] + public void UnknownTypes (object unknown) { } + + [Register ("unknownTypes", "(Lmy/package/foo/Unknown;)Lmy/package/foo/Unknown;", "")] + public object UnknownTypesReturn (object unknown) => null; + + [Register ("value")] + public const int Value = 1234; + } + + [Register ("com/mypackage/service")] + public interface IService { } + + [Register ("com/mypackage/FieldClass")] + public class FieldClass : Java.Lang.Object + { + public NestedFieldClass field; + + public class NestedFieldClass : Java.Lang.Object { } + } + +} + +namespace GenericTestClasses +{ + public class MyCollection : List + { + [Register ("mycollection", "()V", "")] + public MyCollection (List p0, List p1) + { + } + + public List field; + + public Dictionary field2; + + [Register ("dostuff", "()V", "")] + public Dictionary> DoStuff (IEnumerable>>> p) + { + return new Dictionary> (); + } + } +} + +namespace NullableTestTypes +{ +#nullable enable + public class NullableClass + { + [Register ("", "(Ljava/lang/String;Ljava/lang/String;)", "")] + public NullableClass (string notnull, string? nullable) + { + } + + public string? null_field; + public string not_null_field = string.Empty; + + [Register ("nullable_return_method", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", "")] + public string? NullableReturnMethod (string notnull, string? nullable) => null; + + [Register ("not_null_return_method", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", "")] + public string NotNullReturnMethod (string notnull, string? nullable) => string.Empty; + } +} +#nullable disable + +namespace generatortests +{ + [TestFixture] + public class ManagedTests + { + string tempFile; + ModuleDefinition module; + CodeGenerationOptions options; + + [SetUp] + public void SetUp () + { + tempFile = Path.GetTempFileName (); + File.Copy (GetType ().Assembly.Location, tempFile, true); + module = ModuleDefinition.ReadModule (tempFile); + options = new CodeGenerationOptions (); + + foreach (var type in module.Types.Where(t => t.IsClass && t.Namespace == "Java.Lang")) { + var @class = CecilApiImporter.CreateClass (type, options); + Assert.IsTrue (@class.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext()), "@class.Validate failed!"); + options.SymbolTable.AddType (@class); + } + } + + [TearDown] + public void TearDown () + { + module.Dispose (); + File.Delete (tempFile); + } + + [Test] + public void Class () + { + var @class = CecilApiImporter.CreateClass (module.GetType ("Com.Mypackage.Foo"), options); + Assert.IsTrue (@class.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "@class.Validate failed!"); + + Assert.AreEqual ("public", @class.Visibility); + Assert.AreEqual ("Foo", @class.Name); + Assert.AreEqual ("com.mypackage.foo", @class.JavaName); + Assert.AreEqual ("Lcom/mypackage/foo;", @class.JniName); + Assert.IsFalse (@class.IsAbstract); + Assert.IsFalse (@class.IsFinal); + Assert.IsFalse (@class.IsDeprecated); + Assert.IsNull (@class.DeprecatedComment); + } + + [Test] + public void FieldWithNestedType () + { + var @class = CecilApiImporter.CreateClass (module.GetType ("Com.Mypackage.FieldClass"), options); + var @class2 = CecilApiImporter.CreateClass (module.GetType ("Com.Mypackage.FieldClass/NestedFieldClass"), options); + + options.SymbolTable.AddType (@class); + options.SymbolTable.AddType (@class2); + + Assert.IsTrue (@class.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "@class.Validate failed!"); + + // Ensure the front slash is replaced with a period + Assert.AreEqual ("Com.Mypackage.FieldClass.NestedFieldClass", @class.Fields [0].TypeName); + } + + [Test] + public void Method () + { + var type = module.GetType ("Com.Mypackage.Foo"); + var @class = CecilApiImporter.CreateClass (type, options); + var method = CecilApiImporter.CreateMethod (@class, type.Methods.First (m => m.Name == "Bar"), options); + Assert.IsTrue (method.Validate (new CodeGenerationOptions (), new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "method.Validate failed!"); + + Assert.AreEqual ("public", method.Visibility); + Assert.AreEqual ("void", method.Return); + Assert.AreEqual ("void", method.ReturnType); + Assert.AreEqual ("Bar", method.Name); + Assert.AreEqual ("bar", method.JavaName); + Assert.AreEqual ("()V", method.JniSignature); + Assert.IsFalse (method.IsAbstract); + Assert.IsFalse (method.IsFinal); + Assert.IsFalse (method.IsStatic); + Assert.IsNull (method.Deprecated); + } + + [Test] + public void Method_Matches_True () + { + var type = module.GetType ("Com.Mypackage.Foo"); + var @class = CecilApiImporter.CreateClass (type, options); + var unknownTypes = type.Methods.First (m => m.Name == "UnknownTypes"); + var methodA = CecilApiImporter.CreateMethod (@class, unknownTypes, options); + var methodB = CecilApiImporter.CreateMethod (@class, unknownTypes, options); + Assert.IsTrue (methodA.Matches (methodB), "Methods should match!"); + } + + [Test] + public void Method_Matches_False () + { + var type = module.GetType ("Com.Mypackage.Foo"); + var @class = CecilApiImporter.CreateClass (type, options); + var unknownTypesA = type.Methods.First (m => m.Name == "UnknownTypes"); + var unknownTypesB = type.Methods.First (m => m.Name == "UnknownTypesReturn"); + unknownTypesB.Name = "UnknownTypes"; + var methodA = CecilApiImporter.CreateMethod (@class, unknownTypesA, options); + var methodB = CecilApiImporter.CreateMethod (@class, unknownTypesB, options); + //Everything the same besides return type + Assert.IsFalse (methodA.Matches (methodB), "Methods should not match!"); + } + + [Test] + public void MethodWithParameters () + { + var type = module.GetType ("Com.Mypackage.Foo"); + var @class = CecilApiImporter.CreateClass (type, options); + var method = CecilApiImporter.CreateMethod (@class, type.Methods.First (m => m.Name == "BarWithParams"), options); + Assert.IsTrue (method.Validate (new CodeGenerationOptions (), new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "method.Validate failed!"); + Assert.AreEqual ("(ZID)Ljava/lang/String;", method.JniSignature); + Assert.AreEqual ("java.lang.String", method.Return); + Assert.AreEqual ("string", method.ManagedReturn); + + var parameter = method.Parameters [0]; + Assert.AreEqual ("a", parameter.Name); + Assert.AreEqual ("bool", parameter.Type); + Assert.AreEqual ("boolean", parameter.JavaType); + Assert.AreEqual ("Z", parameter.JniType); + + parameter = method.Parameters [1]; + Assert.AreEqual ("b", parameter.Name); + Assert.AreEqual ("int", parameter.Type); + Assert.AreEqual ("int", parameter.JavaType); + Assert.AreEqual ("I", parameter.JniType); + + parameter = method.Parameters [2]; + Assert.AreEqual ("c", parameter.Name); + Assert.AreEqual ("double", parameter.Type); + Assert.AreEqual ("double", parameter.JavaType); + Assert.AreEqual ("D", parameter.JniType); + } + + [Test] + public void Ctor () + { + var type = module.GetType ("Com.Mypackage.Foo"); + var @class = CecilApiImporter.CreateClass (type, options); + var ctor = CecilApiImporter.CreateCtor (@class, type.Methods.First (m => m.IsConstructor && !m.IsStatic), options); + Assert.IsTrue (ctor.Validate (new CodeGenerationOptions (), new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "ctor.Validate failed!"); + + Assert.AreEqual ("public", ctor.Visibility); + Assert.AreEqual (".ctor", ctor.Name); + Assert.AreEqual ("()V", ctor.JniSignature); + Assert.IsNull (ctor.Deprecated); + } + + [Test] + public void Field () + { + var type = module.GetType ("Com.Mypackage.Foo"); + var @class = CecilApiImporter.CreateClass (type, options); + var field = CecilApiImporter.CreateField (type.Fields.First (f => f.Name == "Value"), options); + Assert.IsTrue (field.Validate (new CodeGenerationOptions (), new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "field.Validate failed!"); + + Assert.AreEqual ("Value", field.Name); + Assert.AreEqual ("value", field.JavaName); + Assert.AreEqual ("1234", field.Value); + Assert.AreEqual ("System.Int32", field.TypeName); + Assert.IsTrue (field.IsStatic); + Assert.IsTrue (field.IsConst); + } + + [Test] + public void Interface () + { + var type = module.GetType ("Com.Mypackage.IService"); + var @interface = CecilApiImporter.CreateInterface (type, options); + Assert.IsTrue (@interface.Validate (new CodeGenerationOptions (), new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "interface.Validate failed!"); + + Assert.AreEqual ("public", @interface.Visibility); + Assert.AreEqual ("IService", @interface.Name); + Assert.AreEqual ("com.mypackage.service", @interface.JavaName); + Assert.AreEqual ("Lcom/mypackage/service;", @interface.JniName); + } + + [Test] + public void StripArity () + { + var @class = CecilApiImporter.CreateClass (module.GetType ("GenericTestClasses.MyCollection`1"), options); + + // Class (Leave Arity on types) + Assert.AreEqual ("GenericTestClasses.MyCollection`1", @class.FullName); + + // Constructor + Assert.AreEqual ("System.Collections.Generic.List", @class.Ctors [0].Parameters [0].RawNativeType); + Assert.AreEqual ("System.Collections.Generic.List", @class.Ctors [0].Parameters [1].RawNativeType); + + // Field + Assert.AreEqual ("System.Collections.Generic.List", @class.Fields [0].TypeName); + Assert.AreEqual ("System.Collections.Generic.Dictionary", @class.Fields [1].TypeName); + + // Method + Assert.AreEqual ("System.Collections.Generic.IEnumerable>>>", @class.Methods [0].Parameters [0].RawNativeType); + Assert.AreEqual ("System.Collections.Generic.Dictionary>", @class.Methods [0].ReturnType); + Assert.AreEqual ("System.Collections.Generic.Dictionary>", @class.Methods [0].ManagedReturn); + } + + [Test] + public void TypeNullability () + { + var type = module.GetType ("NullableTestTypes.NullableClass"); + var gen = CecilApiImporter.CreateClass (module.GetType ("NullableTestTypes.NullableClass"), options); + + var not_null_field = CecilApiImporter.CreateField (type.Fields.First (f => f.Name == "not_null_field"), options); + Assert.AreEqual (true, not_null_field.NotNull); + + var null_field = CecilApiImporter.CreateField (type.Fields.First (f => f.Name == "null_field"), options); + Assert.AreEqual (false, null_field.NotNull); + + var null_method = CecilApiImporter.CreateMethod (gen, type.Methods.First (f => f.Name == "NullableReturnMethod"), options); + Assert.AreEqual (false, null_method.ReturnNotNull); + Assert.AreEqual (true, null_method.Parameters.First (f => f.Name == "notnull").NotNull); + Assert.AreEqual (false, null_method.Parameters.First (f => f.Name == "nullable").NotNull); + + var not_null_method = CecilApiImporter.CreateMethod (gen, type.Methods.First (f => f.Name == "NotNullReturnMethod"), options); + Assert.AreEqual (true, not_null_method.ReturnNotNull); + Assert.AreEqual (true, not_null_method.Parameters.First (f => f.Name == "notnull").NotNull); + Assert.AreEqual (false, not_null_method.Parameters.First (f => f.Name == "nullable").NotNull); + + var ctor = CecilApiImporter.CreateCtor (gen, type.Methods.First (f => f.Name == ".ctor"), options); + Assert.AreEqual (true, ctor.Parameters.First (f => f.Name == "notnull").NotNull); + Assert.AreEqual (false, ctor.Parameters.First (f => f.Name == "nullable").NotNull); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/NRTJavaInteropCodeGeneratorTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/NRTJavaInteropCodeGeneratorTests.cs new file mode 100644 index 00000000000..d86486258b6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/NRTJavaInteropCodeGeneratorTests.cs @@ -0,0 +1,24 @@ +using MonoDroid.Generation; +using NUnit.Framework; +using Xamarin.Android.Binder; + +namespace generatortests +{ + [TestFixture] + class NRTJavaInteropCodeGeneratorTests : CodeGeneratorTests + { + protected override CodeGenerationTarget Target => CodeGenerationTarget.XAJavaInterop1; + + protected override CodeGenerationOptions CreateOptions () + { + var options = base.CreateOptions (); + + options.SupportNullableReferenceTypes = true; + + return options; + } + + protected override string CommonDirectoryOverride => "XAJavaInterop1-NRT"; + protected override string TargetedDirectoryOverride => "XAJavaInterop1-NRT"; + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/ReportTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/ReportTests.cs new file mode 100644 index 00000000000..65a73e3ad69 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/ReportTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + public class ReportTests + { + [Test] + public void FormatTests () + { + var code = 0x37; + var msg = "There was a {0} error"; + var args = "bad"; + var sourcefile = @"C:\code\test.cs"; + var line = 32; + var col = 12; + + Assert.AreEqual ("error BG0037: There was a bad error", Report.Format (true, code, null, 0, 0, msg, args)); + Assert.AreEqual (@"C:\code\test.cs: error BG0037: There was a bad error", Report.Format (true, code, sourcefile, 0, 0, msg, args)); + Assert.AreEqual (@"C:\code\test.cs(32): error BG0037: There was a bad error", Report.Format (true, code, sourcefile, line, 0, msg, args)); + Assert.AreEqual (@"C:\code\test.cs(32,12): error BG0037: There was a bad error", Report.Format (true, code, sourcefile, line, col, msg, args)); + Assert.AreEqual (@"C:\code\test.cs(32,12): warning BG0037: There was a bad error", Report.Format (false, code, sourcefile, line, col, msg, args)); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SealedProtectedFixupsTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SealedProtectedFixupsTests.cs new file mode 100644 index 00000000000..5b9897d0c3c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SealedProtectedFixupsTests.cs @@ -0,0 +1,93 @@ +using System; +using System.Linq; +using System.Xml.Linq; +using Java.Interop.Tools.Generator.Transformation; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class SealedProtectedFixupsTests + { + private CodeGenerationOptions options = new CodeGenerationOptions (); + + [Test] + public void FixProtectedMethod () + { + var klass = CreateSealedClass (); + + var method = SupportTypeBuilder.CreateMethod (klass, "ToString", options); + + klass.Methods.Add (method); + + method.Visibility = "protected"; + method.IsOverride = false; + + SealedProtectedFixups.Fixup (new [] { (GenBase)klass }.ToList ()); + + Assert.AreEqual ("private", method.Visibility); + } + + [Test] + public void FixProtectedProperty () + { + var klass = CreateSealedClass (); + + var method = SupportTypeBuilder.CreateProperty (klass, "Handle", "int", options); + + klass.Properties.Add (method); + + method.Getter.Visibility = "protected"; + method.Getter.IsOverride = false; + + method.Setter.Visibility = "protected"; + method.Setter.IsOverride = false; + + SealedProtectedFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual ("private", method.Getter.Visibility); + Assert.AreEqual ("private", method.Setter.Visibility); + } + + [Test] + public void FixProtectedField () + { + var klass = CreateSealedClass (); + + var field = new Field { + Name = "MyConstant", + TypeName = "int", + Visibility = "protected" + }; + + klass.Fields.Add (field); + + SealedProtectedFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual ("private", field.Visibility); + } + + [Test] + public void FixProtectedType () + { + var klass = CreateSealedClass (); + + var type = SupportTypeBuilder.CreateClass ("my.example.class.inner", options); + type.Visibility = "protected"; + + klass.NestedTypes.Add (type); + + SealedProtectedFixups.Fixup (new [] { (GenBase) klass }.ToList ()); + + Assert.AreEqual ("private", type.Visibility); + } + + private ClassGen CreateSealedClass () + { + var klass = SupportTypeBuilder.CreateClass ("my.example.class", options); + klass.IsFinal = true; + return klass; + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/MethodExplicitInterfaceImplementationTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/MethodExplicitInterfaceImplementationTests.cs new file mode 100644 index 00000000000..9bb1d05f616 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/MethodExplicitInterfaceImplementationTests.cs @@ -0,0 +1,28 @@ +using System.Linq; +using generator.SourceWriters; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests.SourceWriters +{ + [TestFixture] + public class MethodExplicitInterfaceImplementationTests : SourceWritersTestBase + { + [Test] + public void MethodExplicitInterfaceImplementation () + { + var opt = new CodeGenerationOptions (); + var iface = SupportTypeBuilder.CreateInterface ("MyNamespace.IMyObject", opt); + var method = iface.Methods.First (m => m.Name == "GetCountForKey"); + + var wrapper = new MethodExplicitInterfaceImplementation (iface, method, opt); + var expected = +@"int MyNamespace.IMyObject.GetCountForKey (string key) +{ + return GetCountForKey (key) +}"; + + Assert.AreEqual (expected, GetOutput (wrapper).Trim ()); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/MethodExtensionAsyncWrapperTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/MethodExtensionAsyncWrapperTests.cs new file mode 100644 index 00000000000..ab3f4f6162f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/MethodExtensionAsyncWrapperTests.cs @@ -0,0 +1,45 @@ +using System.Linq; +using generator.SourceWriters; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests.SourceWriters +{ + [TestFixture] + public class MethodExtensionAsyncWrapperTests : SourceWritersTestBase + { + [Test] + public void MethodExtensionAsyncWrapper () + { + var opt = new CodeGenerationOptions (); + var klass = SupportTypeBuilder.CreateClass ("MyNamespace.MyObject", opt); + var method = klass.Methods.First (m => m.Name == "GetCountForKey"); + + var wrapper = new MethodExtensionAsyncWrapper (method, opt, "OtherObject"); + var expected = +@"public static global::System.Threading.Tasks.Task GetCountForKeyAsync (this OtherObject self, string key) +{ + return global::System.Threading.Tasks.Task.Run (() => self.GetCountForKey (key)); +}"; + + Assert.AreEqual (expected, GetOutput (wrapper).Trim ()); + } + + [Test] + public void MethodExtensionAsyncWrapper_VoidReturnType () + { + var opt = new CodeGenerationOptions (); + var klass = SupportTypeBuilder.CreateClass ("MyNamespace.MyObject", opt); + var method = klass.Methods.First (m => m.Name == "StaticMethod"); + + var wrapper = new MethodExtensionAsyncWrapper (method, opt, "OtherObject"); + var expected = +@"public static global::System.Threading.Tasks.Task StaticMethodAsync (this OtherObject self) +{ + return global::System.Threading.Tasks.Task.Run (() => self.StaticMethod ()); +}"; + + Assert.AreEqual (expected, GetOutput (wrapper).Trim ()); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/PeerMembersFieldTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/PeerMembersFieldTests.cs new file mode 100644 index 00000000000..947ae59be20 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/PeerMembersFieldTests.cs @@ -0,0 +1,27 @@ +using generator.SourceWriters; +using MonoDroid.Generation; +using NUnit.Framework; +using Xamarin.Android.Binder; + +namespace generatortests.SourceWriters +{ + [TestFixture] + public class PeerMembersFieldTests : SourceWritersTestBase + { + [Test] + public void PeerMembersField_Class () + { + var field = new PeerMembersField (new CodeGenerationOptions { CodeGenerationTarget = CodeGenerationTarget.JavaInterop1 }, "B", "MyJavaType", false); + + Assert.AreEqual ("static readonly JniPeerMembers _members = new JniPeerMembers (\"B\", typeof (MyJavaType));", GetOutput (field).Trim ()); + } + + [Test] + public void WeakImplementorField_Interface () + { + var field = new PeerMembersField (new CodeGenerationOptions { CodeGenerationTarget = CodeGenerationTarget.XAJavaInterop1 }, "B", "IMyJavaType", true); + + Assert.AreEqual ("private static readonly JniPeerMembers _members = new XAPeerMembers (\"B\", typeof (IMyJavaType), isInterface: true);", GetOutput (field).Trim ()); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/SourceWritersTestBase.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/SourceWritersTestBase.cs new file mode 100644 index 00000000000..edffa935a3a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/SourceWritersTestBase.cs @@ -0,0 +1,21 @@ +using System; +using System.IO; +using NUnit.Framework; +using Xamarin.SourceWriter; + +namespace generatortests.SourceWriters +{ + [TestFixture] + public class SourceWritersTestBase + { + protected string GetOutput (ISourceWriter writer) + { + var sw = new StringWriter (); + var cw = new CodeWriter (sw); + + writer.Write (cw); + + return sw.ToString (); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/WeakImplementorFieldTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/WeakImplementorFieldTests.cs new file mode 100644 index 00000000000..c5aa53c7a65 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SourceWriters/WeakImplementorFieldTests.cs @@ -0,0 +1,26 @@ +using generator.SourceWriters; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests.SourceWriters +{ + [TestFixture] + public class WeakImplementorFieldTests : SourceWritersTestBase + { + [Test] + public void WeakImplementorField_Regular () + { + var field = new WeakImplementorField ("foo", new CodeGenerationOptions ()); + + Assert.AreEqual ("WeakReference weak_implementor_foo;", GetOutput (field).Trim ()); + } + + [Test] + public void WeakImplementorField_Nullable () + { + var field = new WeakImplementorField ("foo", new CodeGenerationOptions { SupportNullableReferenceTypes = true }); + + Assert.AreEqual ("WeakReference? weak_implementor_foo;", GetOutput (field).Trim ()); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SupportTypes.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SupportTypes.cs new file mode 100644 index 00000000000..54fcf6b7092 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SupportTypes.cs @@ -0,0 +1,341 @@ +using MonoDroid.Generation; +using System.Linq; + +namespace generatortests +{ + class TestClass : ClassGen + { + public TestClass (string baseType, string javaName) : base (new TestBaseSupport (javaName)) + { + BaseType = baseType; + IsAbstract = false; + IsFinal = false; + } + } + + class TestBaseSupport : GenBaseSupport + { + public TestBaseSupport (string javaName) + { + var split = javaName.Split ('.'); + Name = split.Last (); + FullName = javaName; + JavaSimpleName = Name; + PackageName = javaName.Substring (0, javaName.Length - Name.Length - 1); + Namespace = PackageName; + IsGeneratable = true; + Visibility = "public"; + TypeParameters = new GenericParameterDefinitionList (); + } + } + + class TestField : Field + { + public TestField (string type, string name) + { + TypeName = type; + JavaName = name; + Name = name; + Visibility = "public"; + + //NOTE: passing `type` for `managedType`, required since `SymbolTable` is no longer static + // This currently isn't causing any test failures + SetterParameter = new Parameter ("value", TypeName, TypeName, IsEnumified); + } + + public TestField SetStatic () + { + IsStatic = true; + return this; + } + + public TestField SetConstant (string value = null) + { + IsFinal = true; + IsStatic = true; + Value = value; + return this; + } + + public TestField SetEnumified () + { + IsEnumified = true; + SetterParameter = new Parameter ("value", TypeName, TypeName, IsEnumified); + return this; + } + + public TestField SetDeprecated (string comment = null, bool error = false) + { + IsDeprecated = true; + IsDeprecatedError = error; + DeprecatedComment = comment; + return this; + } + + public TestField SetVisibility (string visibility) + { + Visibility = visibility; + return this; + } + + public TestField SetValue (string value) + { + Value = value; + return this; + } + } + + class TestMethod : Method + { + public TestMethod (GenBase @class, string name, string @return = "void") : base (@class) + { + Name = name; + JavaName = name; + SourceApiLevel = 27; + IsVirtual = true; + Visibility = "public"; + Return = @return; + + FillReturnType (); + } + + public TestMethod SetApiLevel (int apiLevel) + { + SourceApiLevel = apiLevel; + return this; + } + + public TestMethod SetManagedReturn (string managedReturn) + { + ManagedReturn = managedReturn; + FillReturnType (); + return this; + } + + public TestMethod SetFinal () + { + IsFinal = true; + IsVirtual = false; + return this; + } + + public TestMethod SetAbstract () + { + IsAbstract = true; + return this; + } + + public TestMethod SetStatic () + { + IsFinal = + IsStatic = true; + IsVirtual = false; + return this; + } + + public TestMethod SetAsyncify () + { + GenerateAsyncWrapper = true; + return this; + } + + public TestMethod SetVisibility (string visibility) + { + Visibility = visibility; + return this; + } + + public TestMethod SetDeprecated (string deprecated) + { + Deprecated = deprecated; + return this; + } + + public TestMethod SetReturnEnumified () + { + IsReturnEnumified = true; + return this; + } + + public TestMethod SetDefaultInterfaceMethod () + { + IsAbstract = false; + IsStatic = false; + IsInterfaceDefaultMethod = true; + + return this; + } + } + + class TestCtor : Ctor + { + public TestCtor (GenBase @class, string name) : base (@class) + { + Name = name; + } + + public TestCtor SetAnnotation (string value) + { + Annotation = value; + return this; + } + + public TestCtor SetCustomAttributes (string value) + { + CustomAttributes = value; + return this; + } + + public TestCtor SetDeprecated (string value) + { + Deprecated = value; + return this; + } + + public TestCtor SetIsNonStaticNestedType (bool value) + { + IsNonStaticNestedType = value; + return this; + } + + public TestCtor SetVisibility (string value) + { + Visibility = value; + return this; + } + } + + class TestInterface : InterfaceGen + { + public TestInterface (string argsType, string javaName) : base (new TestBaseSupport (javaName)) + { + ArgsType = argsType; + } + } + + static class SupportTypeBuilder + { + public static TestClass CreateClass (string className, CodeGenerationOptions options, string baseClass = "Object") + { + var @class = new TestClass (baseClass, className); + + var ctor_name = className.Contains ('.') ? className.Substring (className.LastIndexOf ('.') + 1) : className; + @class.Ctors.Add (CreateConstructor (@class, ctor_name, options)); + @class.Ctors.Add (CreateConstructor (@class, ctor_name, options, + new Parameter ("p0", "java.lang.String", options.SymbolTable.Lookup ("java.lang.String", null).FullName, false))); + + @class.Properties.Add (CreateProperty (@class, "Count", "int", options)); + @class.Properties.Add (CreateProperty (@class, "Key", "java.lang.String", options)); + @class.Properties.Add (CreateProperty (@class, "StaticCount", "int", options, true)); + @class.Properties.Add (CreateProperty (@class, "AbstractCount", "int", options, false, true)); + + @class.Methods.Add (CreateMethod (@class, "GetCountForKey", options, "int", false, + parameters: new Parameter ("key", "java.lang.String", options.SymbolTable.Lookup ("java.lang.String", null).FullName, false))); + @class.Methods.Add (CreateMethod (@class, "Key", options, "java.lang.String")); + @class.Methods.Add (CreateMethod (@class, "StaticMethod", options, "void", true)); + @class.Methods.Add (CreateMethod (@class, "AbstractMethod", options, "void", false, true)); + + return @class; + } + + public static TestClass CreateClassWithProperty (string className, string classJavaName, string propertyName, string propertyType, CodeGenerationOptions options) + { + var @class = new TestClass (className, classJavaName); + + @class.Properties.Add (CreateProperty (@class, propertyName, propertyType, options)); + + return @class; + } + + public static TestCtor CreateConstructor (GenBase parent, string methodName, CodeGenerationOptions options, params Parameter [] parameters) + { + var ctor = new TestCtor (parent, methodName); + + foreach (var p in parameters) + ctor.Parameters.Add (p); + + ctor.Validate (options, null, new CodeGeneratorContext ()); + + return ctor; + } + + public static TestInterface CreateEmptyInterface (string interfaceName) + { + var iface = new TestInterface (null, interfaceName); + + return iface; + } + + public static TestField CreateField (string fieldName, CodeGenerationOptions options, string fieldType, bool isStatic = false) + { + var field = new TestField (fieldType, fieldName); + + if (isStatic) + field.SetStatic (); + + field.Validate (options, null, new CodeGeneratorContext ()); + + return field; + } + + public static TestInterface CreateInterface (string interfaceName, CodeGenerationOptions options) + { + var iface = CreateEmptyInterface (interfaceName); + + iface.Properties.Add (CreateProperty (iface, "Count", "int", options)); + iface.Properties.Add (CreateProperty (iface, "Key", "java.lang.String", options)); + iface.Properties.Add (CreateProperty (iface, "StaticCount", "int", options, true)); + iface.Properties.Add (CreateProperty (iface, "AbstractCount", "int", options, false, true)); + + iface.Methods.Add (CreateMethod (iface, "GetCountForKey", options, "int", false, + parameters: new Parameter ("key", "java.lang.String", options.SymbolTable.Lookup ("java.lang.String", null).FullName, false))); + iface.Methods.Add (CreateMethod (iface, "Key", options, "java.lang.String")); + iface.Methods.Add (CreateMethod (iface, "StaticMethod", options, "void", true)); + iface.Methods.Add (CreateMethod (iface, "AbstractMethod", options, "void", false, true)); + + return iface; + } + + public static TestMethod CreateMethod (GenBase parent, string methodName, CodeGenerationOptions options, string returnType = "void", bool isStatic = false, bool isAbstract = false, params Parameter [] parameters) + { + var method = new TestMethod (parent, methodName, returnType); + + if (isStatic) + method.SetStatic (); + if (isAbstract) + method.SetAbstract (); + + foreach (var p in parameters) + method.Parameters.Add (p); + + method.Validate (options, null, new CodeGeneratorContext ()); + method.RetVal.Validate (options, null, new CodeGeneratorContext ()); + + return method; + } + + public static Property CreateProperty (GenBase parent, string propertyName, string propertyType, CodeGenerationOptions options, bool isStatic = false, bool isAbstract = false) + { + var prop = new Property (propertyName) { + Getter = CreateMethod (parent, $"get_{propertyName}", options, propertyType, isStatic, isAbstract), + Setter = CreateMethod (parent, $"set_{propertyName}", options, "void", isStatic, isAbstract, parameters: new Parameter ("value", propertyType, propertyType, false)) + }; + + return prop; + } + + public static ParameterList CreateParameterList (CodeGenerationOptions options) + { + var list = new ParameterList { + new Parameter ("value", "int", "int", false), + new Parameter ("str", "java.lang.String", options.SymbolTable.Lookup ("java.lang.String", null).FullName, false), + new Parameter ("flag", "int", "OptionTypes", true) + }; + + foreach (var p in list) + p.Validate (options, null, new CodeGeneratorContext ()); + + return list; + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/SymbolTableTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SymbolTableTests.cs new file mode 100644 index 00000000000..13b7bb880e7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/SymbolTableTests.cs @@ -0,0 +1,42 @@ +using System; +using MonoDroid.Generation; +using NUnit.Framework; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generatortests +{ + [TestFixture] + public class SymbolTableTests + { + [Test] + public void FindGenericTypes () + { + var table = new SymbolTable (CodeGenerationTarget.XAJavaInterop1); + + var list = new InterfaceGen (new GenBaseSupport { + Name = "System.Collections.Generic.IList`1", + FullName = "System.Collections.Generic.IList`1", + JavaSimpleName = "System.Collections.Generic.IList`1" + }); + + table.AddType (list); + + var dict = new InterfaceGen (new GenBaseSupport { + Name = "System.Collections.Generic.IDictionary`2", + FullName = "System.Collections.Generic.IDictionary`2", + JavaSimpleName = "System.Collections.Generic.IDictionary`2" + }); + + table.AddType (dict); + + Assert.AreEqual ("System.Collections.Generic.IList`1", table.Lookup ("System.Collections.Generic.IList").FullName); + Assert.AreEqual ("System.Collections.Generic.IList`1", table.Lookup ("System.Collections.Generic.IList>").FullName); + + Assert.AreEqual ("System.Collections.Generic.IDictionary`2", table.Lookup ("System.Collections.Generic.IDictionary").FullName); + Assert.AreEqual ("System.Collections.Generic.IDictionary`2", table.Lookup ("System.Collections.Generic.IDictionary>").FullName); + + Assert.AreEqual ("System.Collections.Generic.IList`1", table.Lookup ("System.Collections.Generic.IList>").FullName); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/TestExtensions.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/TestExtensions.cs new file mode 100644 index 00000000000..aa619a11f9f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/TestExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace generatortests +{ + static class TestExtensions + { + public static string NormalizeLineEndings (this string str) + { + // Normalize all line endings to \n so that our tests pass on + // both Mac and Windows + return str?.Replace ("\r\n", "\n").Replace ("\n", "").Replace ("\t", "").Replace (" ", ""); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/TypeNameUtilitiesTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/TypeNameUtilitiesTests.cs new file mode 100644 index 00000000000..2eaddf859af --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/TypeNameUtilitiesTests.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class TypeNameUtilitiesTests + { + [Test] + public void MangleName () + { + Assert.AreEqual ("@abstract", TypeNameUtilities.MangleName ("abstract")); + Assert.AreEqual ("@case", TypeNameUtilities.MangleName ("case")); + Assert.AreEqual ("@namespace", TypeNameUtilities.MangleName ("namespace")); + Assert.AreEqual ("@while", TypeNameUtilities.MangleName ("while")); + + Assert.AreEqual ("e", TypeNameUtilities.MangleName ("event")); + Assert.AreEqual ("byte_var", TypeNameUtilities.MangleName ("byte_var")); + Assert.AreEqual ("foo", TypeNameUtilities.MangleName ("foo")); + } + + [Test, TestCaseSource (nameof (ReservedKeywords))] + [SetCulture ("cs-CZ")] + public void MangleNameCutlureInvariant (string keyword) + { + Assert.AreEqual ($"@{keyword}", TypeNameUtilities.MangleName (keyword)); + } + + private static IEnumerable ReservedKeywords + => TypeNameUtilities.reserved_keywords + .Where (keyword => keyword != "event") // "event" is a special case which is mapped to "e" instead of "@event" + .Select (keyword => new TestCaseData (keyword)); + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs new file mode 100644 index 00000000000..472be69f4e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/XmlApiImporterTests.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using NUnit.Framework; + +namespace generatortests +{ + [TestFixture] + public class XmlApiImporterTests + { + CodeGenerationOptions opt = new CodeGenerationOptions (); + + [Test] + public void CreateClass_EnsureValidName () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual ("_3", klass.Name); + } + + [Test] + public void CreateClass_CorrectApiSince () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateClass_CorrectApiSinceFromPackage () + { + // Make sure we inherit it from . + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateClass_CorrectApiSinceOverridePackage () + { + // Make sure we inherit it from . + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (9, klass.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateClass_CorrectApiRemoved () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.ApiRemovedSince.ApiLevel); + } + + [Test] + public void CreateCtor_EnsureValidName () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual ("_3", klass.Ctors[0].Name); + } + + [Test] + public void CreateCtor_CorrectApiSince () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateCtor_CorrectApiSinceFromClass () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.Ctors [0].ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateCtor_CorrectDeprecatedSinceFromClass () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.Ctors [0].DeprecatedSince.Value.ApiLevel); + } + + [Test] + public void CreateField_StudlyCaseName () + { + var klass = new TestClass ("object", "MyNamespace.MyType"); + var xml = XDocument.Parse (""); + var field = XmlApiImporter.CreateField (klass, xml.Root); + + Assert.AreEqual ("DesEdeCbc", field.Name); + } + + [Test] + public void CreateField_EnsureValidName () + { + var klass = new TestClass ("object", "MyNamespace.MyType"); + var xml = XDocument.Parse (""); + var field = XmlApiImporter.CreateField (klass, xml.Root); + + Assert.AreEqual ("_3desEdeCbc", field.Name); + } + + [Test] + public void CreateField_HandleDollarSign () + { + var klass = new TestClass ("object", "MyNamespace.MyType"); + var xml = XDocument.Parse (""); + var field = XmlApiImporter.CreateField (klass, xml.Root); + + Assert.AreEqual ("A_3", field.Name); + } + + [Test] + public void CreateField_HandleDollarSignNumber () + { + var klass = new TestClass ("object", "MyNamespace.MyType"); + var xml = XDocument.Parse (""); + var field = XmlApiImporter.CreateField (klass, xml.Root); + + Assert.AreEqual ("_3", field.Name); + } + + [Test] + public void CreateField_CorrectApiVersion () + { + var klass = new TestClass ("object", "MyNamespace.MyType"); + var xml = XDocument.Parse (""); + var field = XmlApiImporter.CreateField (klass, xml.Root); + + Assert.AreEqual (7, field.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateField_CorrectApiVersionFromClass () + { + var klass = new TestClass ("object", "MyNamespace.MyType") { ApiAvailableSince = new AndroidSdkVersion (7) }; + var xml = XDocument.Parse (""); + var field = XmlApiImporter.CreateField (klass, xml.Root); + + Assert.AreEqual (7, field.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateField_CorrectDeprecatedSinceFromClass () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.Fields [0].DeprecatedSince.Value.ApiLevel); + } + + [Test] + public void CreateInterface_EnsureValidName () + { + var xml = XDocument.Parse (""); + var iface = XmlApiImporter.CreateInterface (xml.Root, xml.Root.Element ("interface"), opt); + + Assert.AreEqual ("I_3", iface.Name); + } + + [Test] + public void CreateInterface_CorrectApiSince () + { + var xml = XDocument.Parse (""); + var iface = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("interface"), opt); + + Assert.AreEqual (7, iface.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateInterface_CorrectApiSinceFromPackage () + { + // Make sure we inherit it from . + var xml = XDocument.Parse (""); + var iface = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("interface"), opt); + + Assert.AreEqual (7, iface.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateInterface_CorrectApiSinceOverridePackage () + { + // Make sure we inherit it from . + var xml = XDocument.Parse (""); + var iface = XmlApiImporter.CreateInterface (xml.Root, xml.Root.Element ("interface"), opt); + + Assert.AreEqual (9, iface.ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateMethod_EnsureValidName () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual ("_3", klass.Methods [0].Name); + } + + [Test] + public void CreateMethod_EnsureValidNameHyphen () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual ("_3", klass.Methods [0].Name); + } + + [Test] + public void CreateMethod_CorrectApiSince () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateMethod_CorrectApiSinceFromClass () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.Methods [0].ApiAvailableSince.ApiLevel); + } + + [Test] + public void CreateMethod_CorrectDeprecatedSinceFromClass () + { + var xml = XDocument.Parse (""); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), opt); + + Assert.AreEqual (7, klass.Methods [0].DeprecatedSince.Value.ApiLevel); + } + + [Test] + public void CreateParameter_EnsureValidName () + { + var xml = XDocument.Parse (""); + var p = XmlApiImporter.CreateParameter (xml.Root); + + Assert.AreEqual ("_3", p.Name); + } + + [Test] + public void CreateParameter_NotNull () + { + var xml = XDocument.Parse (""); + var p = XmlApiImporter.CreateParameter (xml.Root); + + Assert.True (p.NotNull); + } + + [Test] + public void PreserveSourceLineInfo () + { + var xml = XDocument.Parse ("\n\n\n\n", LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class"), new CodeGenerationOptions { ApiXmlFile = "obj/Debug/api.xml" }); + + Assert.AreEqual (2, klass.LineNumber); + Assert.AreEqual (2, klass.LinePosition); + Assert.AreEqual ("obj/Debug/api.xml", klass.SourceFile); + + var method = klass.Methods.Single (); + + Assert.AreEqual (3, method.LineNumber); + Assert.AreEqual (2, method.LinePosition); + Assert.AreEqual ("obj/Debug/api.xml", method.SourceFile); + } + + [Test] + public void IgnoreKotlinInternalMembers () + { + var xml = XDocument.Parse (@" + + + + + + + + + "); + + var gens = XmlApiImporter.Parse (xml, opt); + var klass = gens.Single (); + + Assert.AreEqual (0, klass.Fields.Count); + Assert.AreEqual (0, klass.Methods.Count); + } + + [Test] + public void IgnoreTypesWithInvalidNames () + { + var xml = XDocument.Parse (@" + + + + + + + + "); + + var gens = XmlApiImporter.Parse (xml, opt); + + // None of these should be parsed because they have invalid names + Assert.AreEqual (0, gens.Count); + } + + [Test] + public void IgnoreUserObfuscatedTypes () + { + var xml = XDocument.Parse (@" + + + + + + "); + + var gens = XmlApiImporter.Parse (xml, opt); + + // None of these should be parsed because the user has said they are obfuscated + Assert.AreEqual (0, gens.Count); + } + + [Test] + public void TransformNamespaces () + { + var xml = XDocument.Parse (@" + + + + + "); + + var opt = new CodeGenerationOptions (); + opt.NamespaceTransforms.Add (new NamespaceTransform ("com.example", "Example")); + opt.NamespaceTransforms.Add (new NamespaceTransform (".test", "Tests")); + + var gens = XmlApiImporter.Parse (xml, opt); + + Assert.AreEqual (1, gens.Count); + Assert.AreEqual ("Example.Tests", gens [0].Namespace); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/Unit-Tests/XmlTests.cs b/external/Java.Interop/tests/generator-Tests/Unit-Tests/XmlTests.cs new file mode 100644 index 00000000000..44a1b55dcee --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/Unit-Tests/XmlTests.cs @@ -0,0 +1,198 @@ +using MonoDroid.Generation; +using NUnit.Framework; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace generatortests +{ + [TestFixture] + public class XmlTests + { + XDocument xml; + XElement package; + CodeGenerationOptions options; + + [SetUp] + public void SetUp () + { + using (var reader = new StringReader (@" + + + + + + + + + + + + + + + + + + + + + + + + + +")) { + xml = XDocument.Load (reader); + } + + options = new CodeGenerationOptions (); + var javaLang = xml.Element ("api").Element ("package"); + foreach (var type in javaLang.Elements("class")) { + var @class = XmlApiImporter.CreateClass (javaLang, type, options); + Assert.IsTrue (@class.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "@class.Validate failed!"); + options.SymbolTable.AddType (@class); + } + + package = (XElement)javaLang.NextNode; + } + + [Test] + public void Class () + { + var element = package.Element ("class"); + var @class = XmlApiImporter.CreateClass (package, element, options); + Assert.IsTrue (@class.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "@class.Validate failed!"); + + Assert.AreEqual ("public", @class.Visibility); + Assert.AreEqual ("Foo", @class.Name); + Assert.AreEqual ("com.mypackage.foo", @class.JavaName); + Assert.AreEqual ("Lcom/mypackage/foo;", @class.JniName); + Assert.IsFalse (@class.IsAbstract); + Assert.IsFalse (@class.IsFinal); + Assert.IsFalse (@class.IsDeprecated); + Assert.IsNull (@class.DeprecatedComment); + } + + [Test] + public void Method () + { + var element = package.Element ("class"); + var @class = XmlApiImporter.CreateClass (package, element, options); + var method = XmlApiImporter.CreateMethod (@class, element.Element ("method")); + Assert.IsTrue (method.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "method.Validate failed!"); + + Assert.AreEqual ("public", method.Visibility); + Assert.AreEqual ("void", method.Return); + Assert.AreEqual ("System.Void", method.ReturnType); + Assert.AreEqual ("Bar", method.Name); + Assert.AreEqual ("bar", method.JavaName); + Assert.AreEqual ("()V", method.JniSignature); + Assert.IsFalse (method.IsAbstract); + Assert.IsFalse (method.IsFinal); + Assert.IsFalse (method.IsStatic); + Assert.IsNull (method.Deprecated); + } + + [Test] + public void Method_Matches_True () + { + var element = package.Element ("class"); + var @class = XmlApiImporter.CreateClass (package, element, options); + var unknownTypes = element.Elements ("method").Where (e => e.Attribute ("name").Value == "unknownTypes").First (); + var methodA = XmlApiImporter.CreateMethod (@class, unknownTypes); + var methodB = XmlApiImporter.CreateMethod (@class, unknownTypes); + Assert.IsTrue (methodA.Matches (methodB), "Methods should match!"); + } + + [Test] + public void Method_Matches_False () + { + var element = package.Element ("class"); + var @class = XmlApiImporter.CreateClass (package, element, options); + var unknownTypesA = element.Elements ("method").Where (e => e.Attribute ("name").Value == "unknownTypes").First (); + var unknownTypesB = element.Elements ("method").Where (e => e.Attribute ("name").Value == "unknownTypesReturn").First (); + unknownTypesB.Attribute ("name").Value = "unknownTypes"; + var methodA = XmlApiImporter.CreateMethod (@class, unknownTypesA); + var methodB = XmlApiImporter.CreateMethod (@class, unknownTypesB); + //Everything the same besides return type + Assert.IsFalse (methodA.Matches (methodB), "Methods should not match!"); + } + + [Test] + public void MethodWithParameters () + { + var element = package.Element ("class"); + var @class = XmlApiImporter.CreateClass (package, element, options); + var method = XmlApiImporter.CreateMethod (@class, element.Elements ("method").Where (e => e.Attribute ("name").Value == "barWithParams").First ()); + Assert.IsTrue (method.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "method.Validate failed!"); + Assert.AreEqual ("(ZID)Ljava/lang/String;", method.JniSignature); + Assert.AreEqual ("java.lang.String", method.Return); + Assert.AreEqual ("System.String", method.ManagedReturn); + + var parameter = method.Parameters [0]; + Assert.AreEqual ("a", parameter.Name); + Assert.AreEqual ("bool", parameter.Type); + Assert.AreEqual ("boolean", parameter.JavaType); + Assert.AreEqual ("Z", parameter.JniType); + + parameter = method.Parameters [1]; + Assert.AreEqual ("b", parameter.Name); + Assert.AreEqual ("int", parameter.Type); + Assert.AreEqual ("int", parameter.JavaType); + Assert.AreEqual ("I", parameter.JniType); + + parameter = method.Parameters [2]; + Assert.AreEqual ("c", parameter.Name); + Assert.AreEqual ("double", parameter.Type); + Assert.AreEqual ("double", parameter.JavaType); + Assert.AreEqual ("D", parameter.JniType); + } + + [Test] + public void Ctor () + { + var element = package.Element ("class"); + var @class = XmlApiImporter.CreateClass (package, element, options); + var ctor = XmlApiImporter.CreateCtor (@class, element.Element ("constructor")); + Assert.IsTrue (ctor.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "ctor.Validate failed!"); + + Assert.AreEqual ("public", ctor.Visibility); + Assert.AreEqual ("foo", ctor.Name); + Assert.AreEqual ("()V", ctor.JniSignature); + Assert.IsNull (ctor.Deprecated); + } + + [Test] + public void Field () + { + var element = package.Element ("class"); + var @class = XmlApiImporter.CreateClass (package, element, options); + var field = XmlApiImporter.CreateField (@class, element.Element ("field")); + Assert.IsTrue (field.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "field.Validate failed!"); + + Assert.AreEqual ("Value", field.Name); + Assert.AreEqual ("value", field.JavaName); + Assert.AreEqual ("1234", field.Value); + Assert.AreEqual ("int", field.TypeName); + Assert.IsTrue (field.IsStatic); + Assert.IsTrue (field.IsConst); + } + + [Test] + public void Interface () + { + var element = package.Element ("interface"); + var @interface = XmlApiImporter.CreateInterface (package, element, options); + Assert.IsTrue (@interface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()), "interface.Validate failed!"); + + Assert.AreEqual ("public", @interface.Visibility); + Assert.AreEqual ("IService", @interface.Name); + Assert.AreEqual ("com.mypackage.service", @interface.JavaName); + Assert.AreEqual ("Lcom/mypackage/service;", @interface.JniName); + } + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/AccessModifiers.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/AccessModifiers.xml new file mode 100644 index 00000000000..cae0ae1fe0c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/AccessModifiers.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + > + + + + > + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Mono.Android.projitems new file mode 100644 index 00000000000..cceaf3aec12 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Mono.Android.projitems @@ -0,0 +1,19 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.BasePublicClass.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.BasePublicClass.cs new file mode 100644 index 00000000000..e7622dd0d29 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.BasePublicClass.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='BasePublicClass']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/BasePublicClass", GenerateJavaPeer=false)] + public partial class BasePublicClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/BasePublicClass", typeof (BasePublicClass)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected BasePublicClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='BasePublicClass']/method[@name='baseMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("baseMethod", "()V")] + public virtual unsafe void BaseMethod () + { + const string __id = "baseMethod.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.ExtendPublicClass.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.ExtendPublicClass.cs new file mode 100644 index 00000000000..4940693b031 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.ExtendPublicClass.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='ExtendPublicClass']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/ExtendPublicClass", GenerateJavaPeer=false)] + public partial class ExtendPublicClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/ExtendPublicClass", typeof (ExtendPublicClass)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected ExtendPublicClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='ExtendPublicClass']/constructor[@name='ExtendPublicClass' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe ExtendPublicClass () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='ExtendPublicClass']/method[@name='foo' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("foo", "()V")] + public virtual unsafe void Foo () + { + const string __id = "foo.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs new file mode 100644 index 00000000000..e95004b2cd1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='ExtendedInterface']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/ExtendedInterface", GenerateJavaPeer=false, InvokerType=typeof (Xamarin.Test.IExtendedInterfaceInvoker))] + public partial interface IExtendedInterface : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='ExtendedInterface']/method[@name='extendedMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("extendedMethod", "()V")] + void ExtendedMethod (); + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='ExtendedInterface']/method[@name='baseMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("baseMethod", "()V")] + void BaseMethod (); + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/ExtendedInterface", GenerateJavaPeer=false)] + internal partial class IExtendedInterfaceInvoker : global::Java.Lang.Object, IExtendedInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_ExtendedInterface; } + } + + static readonly JniPeerMembers _members_xamarin_test_BaseInterface = new JniPeerMembers ("xamarin/test/BaseInterface", typeof (IExtendedInterfaceInvoker)); + + static readonly JniPeerMembers _members_xamarin_test_ExtendedInterface = new JniPeerMembers ("xamarin/test/ExtendedInterface", typeof (IExtendedInterfaceInvoker)); + + public IExtendedInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void ExtendedMethod () + { + const string __id = "extendedMethod.()V"; + try { + _members_xamarin_test_ExtendedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + public unsafe void BaseMethod () + { + const string __id = "baseMethod.()V"; + try { + _members_xamarin_test_ExtendedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicClass.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicClass.cs new file mode 100644 index 00000000000..3b4bd69b428 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicClass.cs @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='PublicClass']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/PublicClass", GenerateJavaPeer=false)] + public partial class PublicClass : global::Java.Lang.Object { + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='PublicClass.ProtectedInterface']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/PublicClass$ProtectedInterface", GenerateJavaPeer=false, InvokerType=typeof (Xamarin.Test.PublicClass.IProtectedInterfaceInvoker))] + protected internal partial interface IProtectedInterface : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='PublicClass.ProtectedInterface']/method[@name='foo' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("foo", "()V")] + void Foo (); + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/PublicClass$ProtectedInterface", GenerateJavaPeer=false)] + internal partial class IProtectedInterfaceInvoker : global::Java.Lang.Object, IProtectedInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_PublicClass_ProtectedInterface; } + } + + static readonly JniPeerMembers _members_xamarin_test_PublicClass_ProtectedInterface = new JniPeerMembers ("xamarin/test/PublicClass$ProtectedInterface", typeof (IProtectedInterfaceInvoker)); + + public IProtectedInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Foo () + { + const string __id = "foo.()V"; + try { + _members_xamarin_test_PublicClass_ProtectedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/PublicClass", typeof (PublicClass)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected PublicClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='PublicClass']/constructor[@name='PublicClass' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe PublicClass () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicClass']/method[@name='foo' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("foo", "()V")] + public virtual unsafe void Foo () + { + const string __id = "foo.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs new file mode 100644 index 00000000000..762a41a2186 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/PublicFinalClass", GenerateJavaPeer=false)] + public sealed partial class PublicFinalClass : global::Xamarin.Test.BasePublicClass { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/PublicFinalClass", typeof (PublicFinalClass)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + internal PublicFinalClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='publicMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("publicMethod", "()V")] + public unsafe void PublicMethod () + { + const string __id = "publicMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodB' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("packageMethodB", "()V")] + public unsafe void PackageMethodB () + { + const string __id = "packageMethodB.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodA' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("packageMethodA", "()V")] + public unsafe void PackageMethodA () + { + const string __id = "packageMethodA.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.TestClass.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.TestClass.cs new file mode 100644 index 00000000000..3589da87056 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/Xamarin.Test.TestClass.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='TestClass']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/TestClass", GenerateJavaPeer=false)] + public partial class TestClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/TestClass", typeof (TestClass)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected TestClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='TestClass']/constructor[@name='TestClass' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe TestClass () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='TestClass']/method[@name='baseMethod' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("baseMethod", "()V")] + public virtual unsafe void BaseMethod () + { + const string __id = "baseMethod.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/AccessModifiers/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Adapters.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Adapters.xml new file mode 100644 index 00000000000..18244696687 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Adapters.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Mono.Android.projitems new file mode 100644 index 00000000000..e44fcabbd6e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Mono.Android.projitems @@ -0,0 +1,18 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/SupportFiles/AdapterView.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/SupportFiles/AdapterView.cs new file mode 100644 index 00000000000..0e5f395358c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/SupportFiles/AdapterView.cs @@ -0,0 +1,46 @@ +using System; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test +{ + public abstract class AdapterView : AdapterView where T : IAdapter + { +#if JAVA_INTEROP1 + + public AdapterView (ref JniObjectReference reference, JniObjectReferenceOptions options) + : base (ref reference, options) + { + } + + protected override Java.Lang.Object RawAdapter { + get => throw new NotImplementedException (); + set {} + } + + public abstract T Adapter { + get; + set; + } + +#else // !JAVA_INTEROP1 + + public AdapterView (IntPtr handle, JniHandleOwnership transfer) + : base (handle, transfer) + { + } + + protected override Java.Lang.Object RawAdapter { + get { return JavaObjectExtensions.JavaCast(JavaConvert.ToJavaObject (Adapter)); } + set { Adapter = JavaConvert.FromJavaObject(value); } + } + + public abstract T Adapter { + [Register ("getAdapter", "()Landroid/widget/Adapter;", "GetGetAdapterHandler")] get; + [Register ("setAdapter", "(Landroid/widget/Adapter;)V", "GetSetAdapter_Landroid_widget_Adapter_Handler")] set; + } + +#endif // !JAVA_INTEROP1 + } +} + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.AbsSpinner.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.AbsSpinner.cs new file mode 100644 index 00000000000..72e9142528b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.AbsSpinner.cs @@ -0,0 +1,96 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='AbsSpinner']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/AbsSpinner", GenerateJavaPeer=false, InvokerType=typeof (AbsSpinnerInvoker))] + public abstract partial class AbsSpinner : Xamarin.Test.AdapterView { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/AbsSpinner", typeof (AbsSpinner)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected AbsSpinner (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public override unsafe global::Xamarin.Test.ISpinnerAdapter Adapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AbsSpinner']/method[@name='getAdapter' and count(parameter)=0]" + get { + const string __id = "getAdapter.()Lxamarin/test/SpinnerAdapter;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AbsSpinner']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='xamarin.test.SpinnerAdapter']]" + set { + const string __id = "setAdapter.(Lxamarin/test/SpinnerAdapter;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/AbsSpinner", GenerateJavaPeer=false)] + internal partial class AbsSpinnerInvoker : AbsSpinner { + public AbsSpinnerInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/AbsSpinner", typeof (AbsSpinnerInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override unsafe global::Java.Lang.Object RawAdapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='getAdapter' and count(parameter)=0]" + get { + const string __id = "getAdapter.()Lxamarin/test/Adapter;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='T']]" + set { + const string __id = "setAdapter.(Lxamarin/test/Adapter;)V"; + var native_value = (value?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.AdapterView.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.AdapterView.cs new file mode 100644 index 00000000000..70e9a218080 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.AdapterView.cs @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/AdapterView", GenerateJavaPeer=false, InvokerType=typeof (AdapterViewInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends xamarin.test.Adapter"})] + public abstract partial class AdapterView : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/AdapterView", typeof (AdapterView)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected AdapterView (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + protected abstract global::Java.Lang.Object RawAdapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='getAdapter' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("getAdapter", "()Lxamarin/test/Adapter;")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='T']]" + [global::Java.Interop.JniMethodSignature ("setAdapter", "(Lxamarin/test/Adapter;)V")] + set; + } + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/AdapterView", GenerateJavaPeer=false)] + internal partial class AdapterViewInvoker : AdapterView { + public AdapterViewInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/AdapterView", typeof (AdapterViewInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override unsafe global::Java.Lang.Object RawAdapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='getAdapter' and count(parameter)=0]" + get { + const string __id = "getAdapter.()Lxamarin/test/Adapter;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='T']]" + set { + const string __id = "setAdapter.(Lxamarin/test/Adapter;)V"; + var native_value = (value?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.GenericReturnObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.GenericReturnObject.cs new file mode 100644 index 00000000000..2ddfe6c4d14 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.GenericReturnObject.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='GenericReturnObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/GenericReturnObject", GenerateJavaPeer=false)] + public partial class GenericReturnObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/GenericReturnObject", typeof (GenericReturnObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected GenericReturnObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='GenericReturnObject']/method[@name='GenericReturn' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("GenericReturn", "()Lxamarin/test/AdapterView;")] + public virtual unsafe global::Xamarin.Test.AdapterView GenericReturn () + { + const string __id = "GenericReturn.()Lxamarin/test/AdapterView;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.IAdapter.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.IAdapter.cs new file mode 100644 index 00000000000..8084cf8422b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.IAdapter.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='Adapter']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/Adapter", GenerateJavaPeer=false, InvokerType=typeof (Xamarin.Test.IAdapterInvoker))] + public partial interface IAdapter : IJavaPeerable { + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/Adapter", GenerateJavaPeer=false)] + internal partial class IAdapterInvoker : global::Java.Lang.Object, IAdapter { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_Adapter; } + } + + static readonly JniPeerMembers _members_xamarin_test_Adapter = new JniPeerMembers ("xamarin/test/Adapter", typeof (IAdapterInvoker)); + + public IAdapterInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.ISpinnerAdapter.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.ISpinnerAdapter.cs new file mode 100644 index 00000000000..d14675f34a6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/Xamarin.Test.ISpinnerAdapter.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='SpinnerAdapter']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SpinnerAdapter", GenerateJavaPeer=false, InvokerType=typeof (Xamarin.Test.ISpinnerAdapterInvoker))] + public partial interface ISpinnerAdapter : global::Xamarin.Test.IAdapter { + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/SpinnerAdapter", GenerateJavaPeer=false)] + internal partial class ISpinnerAdapterInvoker : global::Java.Lang.Object, ISpinnerAdapter { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_SpinnerAdapter; } + } + + static readonly JniPeerMembers _members_xamarin_test_Adapter = new JniPeerMembers ("xamarin/test/Adapter", typeof (ISpinnerAdapterInvoker)); + + static readonly JniPeerMembers _members_xamarin_test_SpinnerAdapter = new JniPeerMembers ("xamarin/test/SpinnerAdapter", typeof (ISpinnerAdapterInvoker)); + + public ISpinnerAdapterInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/Adapters/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Android.Graphics.Color.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Android.Graphics.Color.xml new file mode 100644 index 00000000000..c9eb6ed9354 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Android.Graphics.Color.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..a261989cce7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/Xamarin.Test.SomeObject.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false, InvokerType=typeof (SomeObjectInvoker))] + public abstract partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + internal partial class SomeObjectInvoker : SomeObject { + public SomeObjectInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObjectInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/Android.Graphics.Color/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Arrays.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Arrays.xml new file mode 100644 index 00000000000..7fb28694218 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Arrays.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..8ee4768affc --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/Xamarin.Test.SomeObject.cs @@ -0,0 +1,173 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myStrings']" + public global::Java.Interop.JavaObjectArray MyStrings { + get { + const string __id = "myStrings.[Ljava/lang/String;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue >(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myStrings.[Ljava/lang/String;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myInts']" + public global::Java.Interop.JavaInt32Array MyInts { + get { + const string __id = "myInts.[I"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myInts.[I"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mybools']" + public global::Java.Interop.JavaBooleanArray Mybools { + get { + const string __id = "mybools.[Z"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "mybools.[Z"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myObjects']" + public global::Java.Interop.JavaObjectArray MyObjects { + get { + const string __id = "myObjects.[Ljava/lang/Object;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue >(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myObjects.[Ljava/lang/Object;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myfloats']" + public global::Java.Interop.JavaSingleArray Myfloats { + get { + const string __id = "myfloats.[F"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myfloats.[F"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mydoubles']" + public global::Java.Interop.JavaDoubleArray Mydoubles { + get { + const string __id = "mydoubles.[D"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "mydoubles.[D"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mylongs']" + public global::Java.Interop.JavaInt64Array Mylongs { + get { + const string __id = "mylongs.[J"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "mylongs.[J"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/Arrays/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/CSharpKeywords.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/CSharpKeywords.xml new file mode 100644 index 00000000000..9ceb7d5b727 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/CSharpKeywords.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Java.Lang.Throwable.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Java.Lang.Throwable.cs new file mode 100644 index 00000000000..f627b04b98c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Java.Lang.Throwable.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Throwable']" + [global::Java.Interop.JniTypeSignature ("java/lang/Throwable", GenerateJavaPeer=false)] + public partial class Throwable { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Throwable", typeof (Throwable)); + + public new virtual unsafe string Message { + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/class[@name='Throwable']/method[@name='getMessage' and count(parameter)=0]" + get { + const string __id = "getMessage.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Mono.Android.projitems new file mode 100644 index 00000000000..449fda2e99c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Mono.Android.projitems @@ -0,0 +1,15 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Xamarin.Test.CSharpKeywords.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Xamarin.Test.CSharpKeywords.cs new file mode 100644 index 00000000000..a0ec376a3c5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/Xamarin.Test.CSharpKeywords.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='CSharpKeywords']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/CSharpKeywords", GenerateJavaPeer=false)] + public partial class CSharpKeywords : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/CSharpKeywords", typeof (CSharpKeywords)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected CSharpKeywords (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='CSharpKeywords']/method[@name='usePartial' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("usePartial", "(I)Ljava/lang/String;")] + public virtual unsafe string UsePartial (int partial) + { + const string __id = "usePartial.(I)Ljava/lang/String;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (partial); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='CSharpKeywords']/method[@name='useThis' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [global::Java.Interop.JniMethodSignature ("useThis", "(Ljava/lang/String;)Ljava/lang/String;")] + public static unsafe string UseThis (string this_) + { + const string __id = "useThis.(Ljava/lang/String;)Ljava/lang/String;"; + var native_this = global::Java.Interop.JniEnvironment.Strings.NewString (this_); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_this); + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, __args); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_this); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/CSharpKeywords/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Constructors.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Constructors.xml new file mode 100644 index 00000000000..ef292222958 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Constructors.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Mono.Android.projitems new file mode 100644 index 00000000000..5f74b81c012 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Mono.Android.projitems @@ -0,0 +1,15 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..785cddc8ee6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Xamarin.Test.SomeObject.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/constructor[@name='SomeObject' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + [global::System.Obsolete (@"deprecated")] + public unsafe SomeObject () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/constructor[@name='SomeObject' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniConstructorSignature ("(I)V")] + public unsafe SomeObject (int aint) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "(I)V"; + + if (PeerReference.IsValid) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (aint); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Xamarin.Test.SomeObject2.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Xamarin.Test.SomeObject2.cs new file mode 100644 index 00000000000..a07754a2bca --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/Xamarin.Test.SomeObject2.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject2", GenerateJavaPeer=false)] + public sealed partial class SomeObject2 : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject2", typeof (SomeObject2)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + internal SomeObject2 (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']/constructor[@name='SomeObject2' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniConstructorSignature ("(I)V")] + public unsafe SomeObject2 (int aint) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "(I)V"; + + if (PeerReference.IsValid) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (aint); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/Constructors/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Java.Lang.String.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Java.Lang.String.cs new file mode 100644 index 00000000000..02a9a305e62 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Java.Lang.String.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='String']" + [global::Java.Interop.JniTypeSignature ("java/lang/String", GenerateJavaPeer=false)] + public partial class String : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/String", typeof (String)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected String (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Mono.Android.projitems new file mode 100644 index 00000000000..ea168730bb7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Mono.Android.projitems @@ -0,0 +1,17 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Google.Composable.MyClass.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Google.Composable.MyClass.cs new file mode 100644 index 00000000000..d32fef53f54 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Google.Composable.MyClass.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Google.Composable { + + // Metadata.xml XPath class reference: path="/api/package[@name='com.com.google.compose']/class[@name='MyClass']" + [global::Java.Interop.JniTypeSignature ("com/com/google/compose/MyClass", GenerateJavaPeer=false)] + public partial class MyClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/com/google/compose/MyClass", typeof (MyClass)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected MyClass (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Test.Invalidnames.In.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Test.Invalidnames.In.cs new file mode 100644 index 00000000000..6a75bf7b55f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Test.Invalidnames.In.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test.Invalidnames { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test.invalidnames']/class[@name='in']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/invalidnames/in", GenerateJavaPeer=false)] + public partial class In : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/invalidnames/in", typeof (In)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected In (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Test.Invalidnames.InvalidNameMembers.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Test.Invalidnames.InvalidNameMembers.cs new file mode 100644 index 00000000000..ec5ff2cdbae --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/Xamarin.Test.Invalidnames.InvalidNameMembers.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test.Invalidnames { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test.invalidnames']/class[@name='InvalidNameMembers']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/invalidnames/InvalidNameMembers", GenerateJavaPeer=false)] + public partial class InvalidNameMembers : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/invalidnames/InvalidNameMembers", typeof (InvalidNameMembers)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected InvalidNameMembers (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/api.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/api.xml new file mode 100644 index 00000000000..6289ee40278 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/api.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/metadata.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/metadata.xml new file mode 100644 index 00000000000..fa358dfa52b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_ClassParse/metadata.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.ISpannable.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.ISpannable.cs new file mode 100644 index 00000000000..19a6c44f9f5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.ISpannable.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath interface reference: path="/api/package[@name='android.text']/interface[@name='Spannable']" + [global::Java.Interop.JniTypeSignature ("android/text/Spannable", GenerateJavaPeer=false)] + public partial interface ISpannable : global::Android.Text.ISpanned { + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.ISpanned.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.ISpanned.cs new file mode 100644 index 00000000000..590585eb857 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.ISpanned.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath interface reference: path="/api/package[@name='android.text']/interface[@name='Spanned']" + [global::Java.Interop.JniTypeSignature ("android/text/Spanned", GenerateJavaPeer=false)] + public partial interface ISpanned : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='android.text']/interface[@name='Spanned']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [return:global::Android.Runtime.GeneratedEnum] + global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object tag); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.SpannableString.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.SpannableString.cs new file mode 100644 index 00000000000..d813fff239b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.SpannableString.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath class reference: path="/api/package[@name='android.text']/class[@name='SpannableString']" + [global::Java.Interop.JniTypeSignature ("android/text/SpannableString", GenerateJavaPeer=false)] + public partial class SpannableString : global::Android.Text.SpannableStringInternal, global::Android.Text.ISpannable { + static readonly JniPeerMembers _members = new JniPeerMembers ("android/text/SpannableString", typeof (SpannableString)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SpannableString (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='android.text']/class[@name='SpannableString']/constructor[@name='SpannableString' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + public unsafe SpannableString (global::Java.Lang.ICharSequence source) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (PeerReference.IsValid) + return; + + IntPtr native_source = CharSequence.ToLocalJniHandle (source); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_source); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_source); + global::System.GC.KeepAlive (source); + } + } + + public unsafe SpannableString (string source) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (PeerReference.IsValid) + return; + + IntPtr native_source = CharSequence.ToLocalJniHandle (source); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_source); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_source); + global::System.GC.KeepAlive (source); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='android.text']/class[@name='SpannableString']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + public override unsafe global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object what) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (what); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return (global::Android.Text.SpanTypes) __rm; + } finally { + global::System.GC.KeepAlive (what); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.SpannableStringInternal.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.SpannableStringInternal.cs new file mode 100644 index 00000000000..625020c9bd5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Text.SpannableStringInternal.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath class reference: path="/api/package[@name='android.text']/class[@name='SpannableStringInternal']" + [global::Java.Interop.JniTypeSignature ("android/text/SpannableStringInternal", GenerateJavaPeer=false)] + public abstract partial class SpannableStringInternal : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("android/text/SpannableStringInternal", typeof (SpannableStringInternal)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SpannableStringInternal (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='android.text']/class[@name='SpannableStringInternal']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [return:global::Android.Runtime.GeneratedEnum] + public virtual unsafe global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object p0) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (p0); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return (global::Android.Text.SpanTypes) __rm; + } finally { + global::System.GC.KeepAlive (p0); + } + } + + } + + [global::Java.Interop.JniTypeSignature ("android/text/SpannableStringInternal", GenerateJavaPeer=false)] + internal partial class SpannableStringInternalInvoker : SpannableStringInternal { + public SpannableStringInternalInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("android/text/SpannableStringInternal", typeof (SpannableStringInternalInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Views.View.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Views.View.cs new file mode 100644 index 00000000000..6abf1945ac2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Android.Views.View.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Android.Views { + + // Metadata.xml XPath class reference: path="/api/package[@name='android.view']/class[@name='View']" + [global::Java.Interop.JniTypeSignature ("android/view/View", GenerateJavaPeer=false)] + public partial class View : global::Java.Lang.Object { + // Metadata.xml XPath interface reference: path="/api/package[@name='android.view']/interface[@name='View.OnClickListener']" + [global::Java.Interop.JniTypeSignature ("android/view/View$OnClickListener", GenerateJavaPeer=false)] + public partial interface IOnClickListener : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/interface[@name='View.OnClickListener']/method[@name='onClick' and count(parameter)=1 and parameter[1][@type='android.view.View']]" + void OnClick (global::Android.Views.View v); + + } + + [global::Android.Runtime.Register ("mono/android/view/View_OnClickListenerImplementor")] + internal sealed partial class IOnClickListenerImplementor : global::Java.Lang.Object, IOnClickListener { + public IOnClickListenerImplementor () : base (global::Android.Runtime.JNIEnv.StartCreateInstance ("mono/android/view/View_OnClickListenerImplementor", "()V"), JniHandleOwnership.TransferLocalRef) + { + global::Android.Runtime.JNIEnv.FinishCreateInstance (this.PeerReference, "()V"); + } + + #pragma warning disable 0649 + public EventHandler Handler; + #pragma warning restore 0649 + + public void OnClick (global::Android.Views.View v) + { + var __h = Handler; + if (__h != null) + __h (v, new EventArgs ()); + } + + internal static bool __IsEmpty (IOnClickListenerImplementor value) + { + return value.Handler == null; + } + + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("android/view/View", typeof (View)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected View (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/class[@name='View']/method[@name='setOnClickListener' and count(parameter)=1 and parameter[1][@type='android.view.View.OnClickListener']]" + public virtual unsafe void SetOnClickListener (global::Android.Views.View.IOnClickListener l) + { + const string __id = "setOnClickListener.(Landroid/view/View$OnClickListener;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (l); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (l); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/class[@name='View']/method[@name='setOn123Listener' and count(parameter)=1 and parameter[1][@type='android.view.View.OnClickListener']]" + public virtual unsafe void SetOn123Listener (global::Android.Views.View.IOnClickListener l) + { + const string __id = "setOn123Listener.(Landroid/view/View$OnClickListener;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (l); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (l); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/class[@name='View']/method[@name='addTouchables' and count(parameter)=1 and parameter[1][@type='java.util.ArrayList<android.view.View>']]" + public virtual unsafe void AddTouchables (global::System.Collections.Generic.IList views) + { + const string __id = "addTouchables.(Ljava/util/ArrayList;)V"; + IntPtr native_views = global::Android.Runtime.JavaList.ToLocalJniHandle (views); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_views); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_views); + global::System.GC.KeepAlive (views); + } + } + + #region "Event implementation for Android.Views.View.IOnClickListener" + + public event EventHandler Click { + add { + global::Java.Interop.EventHelper.AddEventHandler( + ref weak_implementor_SetOnClickListener, + __CreateIOnClickListenerImplementor, + SetOnClickListener, + __h => __h.Handler += value); + } + remove { + global::Java.Interop.EventHelper.RemoveEventHandler( + ref weak_implementor_SetOnClickListener, + global::Android.Views.View.IOnClickListenerImplementor.__IsEmpty, + __v => SetOnClickListener (null), + __h => __h.Handler -= value); + } + } + + WeakReference weak_implementor_SetOnClickListener; + + global::Android.Views.View.IOnClickListenerImplementor __CreateIOnClickListenerImplementor () + { + return new global::Android.Views.View.IOnClickListenerImplementor (); + } + + #endregion + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Java.Lang.Object.cs new file mode 100644 index 00000000000..86d0bd17b2b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Java.Lang.Object.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Mono.Android.projitems new file mode 100644 index 00000000000..0bd3f3343a4 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/Mono.Android.projitems @@ -0,0 +1,20 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/api.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/api.xml new file mode 100644 index 00000000000..b979cf7c745 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/api.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/fields.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/fields.xml new file mode 100644 index 00000000000..8c82dea0cc0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/fields.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/methods.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/methods.xml new file mode 100644 index 00000000000..0a92237a8fa --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Core_Jar2Xml/methods.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaDrm.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaDrm.cs new file mode 100644 index 00000000000..dc2f10632da --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaDrm.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Com.Google.Android.Exoplayer.Drm { + + // Metadata.xml XPath class reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaDrm']" + [global::Java.Interop.JniTypeSignature ("com/google/android/exoplayer/drm/FrameworkMediaDrm", GenerateJavaPeer=false)] + public sealed partial class FrameworkMediaDrm : global::Java.Lang.Object, global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm { + static readonly JniPeerMembers _members = new JniPeerMembers ("com/google/android/exoplayer/drm/FrameworkMediaDrm", typeof (FrameworkMediaDrm)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + internal FrameworkMediaDrm (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaDrm']/constructor[@name='FrameworkMediaDrm' and count(parameter)=0]" + public unsafe FrameworkMediaDrm () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaDrm']/method[@name='setOnEventListener' and count(parameter)=1 and parameter[1][@type='com.google.android.exoplayer.drm.ExoMediaDrm.OnEventListener<com.google.android.exoplayer.drm.FrameworkMediaCrypto>']]" + public unsafe void SetOnEventListener (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener p0) + { + const string __id = "setOnEventListener.(Lcom/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (p0); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (p0); + } + } + + // This method is explicitly implemented as a member of an instantiated Com.Google.Android.Exoplayer.Drm.IExoMediaDrm + void global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.SetOnEventListener (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener p0) + { + SetOnEventListener (global::Java.Interop.JavaObjectExtensions.JavaCast(p0)); + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.cs new file mode 100644 index 00000000000..5dd4b571f15 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Com.Google.Android.Exoplayer.Drm { + + // Metadata.xml XPath interface reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm.OnEventListener']" + [global::Java.Interop.JniTypeSignature ("com/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends com.google.android.exoplayer.drm.ExoMediaCrypto"})] + public partial interface IExoMediaDrmOnEventListener : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm.OnEventListener']/method[@name='onEvent' and count(parameter)=5 and parameter[1][@type='com.google.android.exoplayer.drm.ExoMediaDrm<T>'] and parameter[2][@type='byte[]'] and parameter[3][@type='int'] and parameter[4][@type='int'] and parameter[5][@type='byte[]']]" + void OnEvent (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, global::Java.Interop.JavaSByteArray p1, int p2, int p3, global::Java.Interop.JavaSByteArray p4); + + } + + // event args for com.google.android.exoplayer.drm.ExoMediaDrm.OnEventListener.onEvent + public partial class ExoMediaDrmOnEventEventArgs : global::System.EventArgs { + public ExoMediaDrmOnEventEventArgs (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, global::Java.Interop.JavaSByteArray p1, int p2, int p3, global::Java.Interop.JavaSByteArray p4) + { + this.p0 = p0; + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + this.p4 = p4; + } + + global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0; + + public global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm P0 { + get { return p0; } + } + + global::Java.Interop.JavaSByteArray p1; + + public global::Java.Interop.JavaSByteArray P1 { + get { return p1; } + } + + int p2; + + public int P2 { + get { return p2; } + } + + int p3; + + public int P3 { + get { return p3; } + } + + global::Java.Interop.JavaSByteArray p4; + + public global::Java.Interop.JavaSByteArray P4 { + get { return p4; } + } + + } + + [global::Android.Runtime.Register ("mono/com/google/android/exoplayer/drm/ExoMediaDrm_OnEventListenerImplementor")] + internal sealed partial class IExoMediaDrmOnEventListenerImplementor : global::Java.Lang.Object, IExoMediaDrmOnEventListener { + + object sender; + + public IExoMediaDrmOnEventListenerImplementor (object sender) : base (global::Android.Runtime.JNIEnv.StartCreateInstance ("mono/com/google/android/exoplayer/drm/ExoMediaDrm_OnEventListenerImplementor", "()V"), JniHandleOwnership.TransferLocalRef) + { + global::Android.Runtime.JNIEnv.FinishCreateInstance (this.PeerReference, "()V"); + this.sender = sender; + } + + #pragma warning disable 0649 + public EventHandler Handler; + #pragma warning restore 0649 + + public void OnEvent (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, global::Java.Interop.JavaSByteArray p1, int p2, int p3, global::Java.Interop.JavaSByteArray p4) + { + var __h = Handler; + if (__h != null) + __h (sender, new ExoMediaDrmOnEventEventArgs (p0, p1, p2, p3, p4)); + } + + internal static bool __IsEmpty (IExoMediaDrmOnEventListenerImplementor value) + { + return value.Handler == null; + } + + } + + // Metadata.xml XPath interface reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm']" + [global::Java.Interop.JniTypeSignature ("com/google/android/exoplayer/drm/ExoMediaDrm", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends com.google.android.exoplayer.drm.ExoMediaCrypto"})] + public partial interface IExoMediaDrm : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm']/method[@name='setOnEventListener' and count(parameter)=1 and parameter[1][@type='com.google.android.exoplayer.drm.ExoMediaDrm.OnEventListener<T>']]" + void SetOnEventListener (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener p0); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/GenericArguments.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/GenericArguments.xml new file mode 100644 index 00000000000..f9387a080e7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/GenericArguments.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Java.Lang.Object.cs new file mode 100644 index 00000000000..86d0bd17b2b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/GenericArguments/Java.Lang.Object.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/InterfaceMethodsConflict.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/InterfaceMethodsConflict.xml new file mode 100644 index 00000000000..e83a6e37a3a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/InterfaceMethodsConflict.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Mono.Android.projitems new file mode 100644 index 00000000000..a57b6da5dc2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Mono.Android.projitems @@ -0,0 +1,17 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II1.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II1.cs new file mode 100644 index 00000000000..de1e6308d3b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II1.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/I1", GenerateJavaPeer=false, InvokerType=typeof (Xamarin.Test.II1Invoker))] + public partial interface II1 : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']/method[@name='close' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("close", "()V")] + void Close (); + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/I1", GenerateJavaPeer=false)] + internal partial class II1Invoker : global::Java.Lang.Object, II1 { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_I1; } + } + + static readonly JniPeerMembers _members_xamarin_test_I1 = new JniPeerMembers ("xamarin/test/I1", typeof (II1Invoker)); + + public II1Invoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Close () + { + const string __id = "close.()V"; + try { + _members_xamarin_test_I1.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II2.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II2.cs new file mode 100644 index 00000000000..228f6349007 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.II2.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='I2']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/I2", GenerateJavaPeer=false, InvokerType=typeof (Xamarin.Test.II2Invoker))] + public partial interface II2 : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I2']/method[@name='close' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("close", "()V")] + void Close (); + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/I2", GenerateJavaPeer=false)] + internal partial class II2Invoker : global::Java.Lang.Object, II2 { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_I2; } + } + + static readonly JniPeerMembers _members_xamarin_test_I2 = new JniPeerMembers ("xamarin/test/I2", typeof (II2Invoker)); + + public II2Invoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Close () + { + const string __id = "close.()V"; + try { + _members_xamarin_test_I2.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..d28401ffff2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.SomeObject.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object, global::Xamarin.Test.II1, global::Xamarin.Test.II2 { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='close' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("close", "()V")] + public virtual unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.SomeObject2.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.SomeObject2.cs new file mode 100644 index 00000000000..775f0372f7b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/Xamarin.Test.SomeObject2.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject2", GenerateJavaPeer=false, InvokerType=typeof (SomeObject2Invoker))] + public abstract partial class SomeObject2 : global::Java.Lang.Object, global::Xamarin.Test.II1, global::Xamarin.Test.II2 { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject2", typeof (SomeObject2)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject2 (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']/method[@name='irrelevant' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("irrelevant", "()V")] + public virtual unsafe void Irrelevant () + { + const string __id = "irrelevant.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']/method[@name='close' and count(parameter)=0]" + public abstract void Close (); + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject2", GenerateJavaPeer=false)] + internal partial class SomeObject2Invoker : SomeObject2 { + public SomeObject2Invoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject2", typeof (SomeObject2Invoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']/method[@name='close' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("close", "()V")] + public override unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/InterfaceMethodsConflict/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Mono.Android.projitems new file mode 100644 index 00000000000..a5071d7a74f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/NestedTypes.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/NestedTypes.xml new file mode 100644 index 00000000000..c28f0ccd331 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/NestedTypes.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Xamarin.Test.NotificationCompatBase.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Xamarin.Test.NotificationCompatBase.cs new file mode 100644 index 00000000000..8a4e1de3ed0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/Xamarin.Test.NotificationCompatBase.cs @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase", GenerateJavaPeer=false)] + public partial class NotificationCompatBase : global::Java.Lang.Object { + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase.Action']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$Action", GenerateJavaPeer=false, InvokerType=typeof (ActionInvoker))] + public abstract partial class Action : global::Java.Lang.Object { + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='NotificationCompatBase.Action.Factory']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$Action$Factory", GenerateJavaPeer=false, InvokerType=typeof (Xamarin.Test.NotificationCompatBase.Action.IFactoryInvoker))] + public partial interface IFactory : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='NotificationCompatBase.Action.Factory']/method[@name='build' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("build", "(I)Lxamarin/test/NotificationCompatBase$Action;")] + global::Xamarin.Test.NotificationCompatBase.Action Build (int p0); + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$Action$Factory", GenerateJavaPeer=false)] + internal partial class IFactoryInvoker : global::Java.Lang.Object, IFactory { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_NotificationCompatBase_Action_Factory; } + } + + static readonly JniPeerMembers _members_xamarin_test_NotificationCompatBase_Action_Factory = new JniPeerMembers ("xamarin/test/NotificationCompatBase$Action$Factory", typeof (IFactoryInvoker)); + + public IFactoryInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe global::Xamarin.Test.NotificationCompatBase.Action Build (int p0) + { + const string __id = "build.(I)Lxamarin/test/NotificationCompatBase$Action;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (p0); + var __rm = _members_xamarin_test_NotificationCompatBase_Action_Factory.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/NotificationCompatBase$Action", typeof (Action)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected Action (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$Action", GenerateJavaPeer=false)] + internal partial class ActionInvoker : Action { + public ActionInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/NotificationCompatBase$Action", typeof (ActionInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + } + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase.InstanceInner']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$InstanceInner", GenerateJavaPeer=false, InvokerType=typeof (InstanceInnerInvoker))] + public abstract partial class InstanceInner : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/NotificationCompatBase$InstanceInner", typeof (InstanceInner)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected InstanceInner (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase.InstanceInner']/constructor[@name='NotificationCompatBase.InstanceInner' and count(parameter)=1 and parameter[1][@type='xamarin.test.NotificationCompatBase']]" + [global::Java.Interop.JniConstructorSignature ("(Lxamarin/test/NotificationCompatBase;)V")] + public unsafe InstanceInner (global::Xamarin.Test.NotificationCompatBase __self) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + string __id = "(L" + global::Java.Interop.JniEnvironment.Runtime.TypeManager.GetTypeSignature (GetType ().DeclaringType).SimpleReference + ";)V"; + + if (PeerReference.IsValid) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (__self); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + global::System.GC.KeepAlive (__self); + } + } + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$InstanceInner", GenerateJavaPeer=false)] + internal partial class InstanceInnerInvoker : InstanceInner { + public InstanceInnerInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/NotificationCompatBase$InstanceInner", typeof (InstanceInnerInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/NotificationCompatBase", typeof (NotificationCompatBase)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected NotificationCompatBase (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/NestedTypes/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/NonStaticField.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/NonStaticField.xml new file mode 100644 index 00000000000..29e293914a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/NonStaticField.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..0edd8c70f5b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/Xamarin.Test.SomeObject.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='Value']" + public int Value { + get { + const string __id = "Value.I"; + + var __v = _members.InstanceFields.GetInt32Value (__id, this); + return __v; + } + set { + const string __id = "Value.I"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='BooleanValue']" + public bool BooleanValue { + get { + const string __id = "BooleanValue.Z"; + + var __v = _members.InstanceFields.GetBooleanValue (__id, this); + return __v; + } + set { + const string __id = "BooleanValue.Z"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='CharValue']" + public char CharValue { + get { + const string __id = "CharValue.C"; + + var __v = _members.InstanceFields.GetCharValue (__id, this); + return __v; + } + set { + const string __id = "CharValue.C"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/NonStaticFields/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Class.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Class.cs new file mode 100644 index 00000000000..af92b40a9fa --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Class.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Class']" + [global::Java.Interop.JniTypeSignature ("java/lang/Class", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial class Class : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Class", typeof (Class)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected Class (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Integer.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Integer.cs new file mode 100644 index 00000000000..6fdb05d0314 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Integer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Integer']" + [global::Java.Interop.JniTypeSignature ("java/lang/Integer", GenerateJavaPeer=false)] + public partial class Integer : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Integer", typeof (Integer)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected Integer (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Object.cs new file mode 100644 index 00000000000..86d0bd17b2b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Object.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Throwable.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Throwable.cs new file mode 100644 index 00000000000..b04ec6d4abf --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Java.Lang.Throwable.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Throwable']" + [global::Java.Interop.JniTypeSignature ("java/lang/Throwable", GenerateJavaPeer=false)] + public partial class Throwable { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Throwable", typeof (Throwable)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Mono.Android.projitems new file mode 100644 index 00000000000..e1aa69457fa --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Mono.Android.projitems @@ -0,0 +1,19 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/NormalMethods.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/NormalMethods.xml new file mode 100644 index 00000000000..c58efb8a969 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/NormalMethods.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.A.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.A.cs new file mode 100644 index 00000000000..56dec8d68c1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.A.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='A']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/A", GenerateJavaPeer=false)] + public partial class A : global::Java.Lang.Object { + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='A.B']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/A$B", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends xamarin.test.A.B"})] + public partial class B : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/A$B", typeof (B)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected B (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A.B']/method[@name='setCustomDimension' and count(parameter)=1 and parameter[1][@type='int']]" + public virtual unsafe global::Java.Lang.Object SetCustomDimension (int index) + { + const string __id = "setCustomDimension.(I)Lxamarin/test/A$B;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (index); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/A", typeof (A)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected A (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A']/method[@name='getHandle' and count(parameter)=0]" + public virtual unsafe int GetHandle () + { + const string __id = "getHandle.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.C.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.C.cs new file mode 100644 index 00000000000..7c90fe03fac --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.C.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='C']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/C", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends xamarin.test.C"})] + public partial class C : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/C", typeof (C)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected C (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='C']/method[@name='setCustomDimension' and count(parameter)=1 and parameter[1][@type='int']]" + public virtual unsafe global::Java.Lang.Object SetCustomDimension (int index) + { + const string __id = "setCustomDimension.(I)Lxamarin/test/C;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (index); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..d0504b8825f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/Xamarin.Test.SomeObject.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/constructor[@name='SomeObject' and count(parameter)=1 and parameter[1][@type='java.lang.Class<? extends xamarin.test.SomeObject>']]" + public unsafe SomeObject (global::Java.Lang.Class c) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "(Ljava/lang/Class;)V"; + + if (PeerReference.IsValid) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (c); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + global::System.GC.KeepAlive (c); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getType' and count(parameter)=0]" + public new virtual unsafe global::Java.Interop.JavaInt32Array GetType () + { + const string __id = "getType.()[I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='handle' and count(parameter)=2 and parameter[1][@type='java.lang.Object'] and parameter[2][@type='java.lang.Throwable']]" + public new virtual unsafe int Handle (global::Java.Lang.Object o, global::Java.Lang.Throwable t) + { + const string __id = "handle.(Ljava/lang/Object;Ljava/lang/Throwable;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [2]; + __args [0] = new JniArgumentValue (o); + __args [1] = new JniArgumentValue (t); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (o); + global::System.GC.KeepAlive (t); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='IntegerMethod' and count(parameter)=0]" + public virtual unsafe int IntegerMethod () + { + const string __id = "IntegerMethod.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='VoidMethod' and count(parameter)=0]" + public virtual unsafe void VoidMethod () + { + const string __id = "VoidMethod.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='StringMethod' and count(parameter)=0]" + public virtual unsafe string StringMethod () + { + const string __id = "StringMethod.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='ObjectMethod' and count(parameter)=0]" + public virtual unsafe global::Java.Lang.Object ObjectMethod () + { + const string __id = "ObjectMethod.()Ljava/lang/Object;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='VoidMethodWithParams' and count(parameter)=3 and parameter[1][@type='java.lang.String'] and parameter[2][@type='int'] and parameter[3][@type='java.lang.Object']]" + public virtual unsafe void VoidMethodWithParams (string astring, int anint, global::Java.Lang.Object anObject) + { + const string __id = "VoidMethodWithParams.(Ljava/lang/String;ILjava/lang/Object;)V"; + var native_astring = global::Java.Interop.JniEnvironment.Strings.NewString (astring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (native_astring); + __args [1] = new JniArgumentValue (anint); + __args [2] = new JniArgumentValue (anObject); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_astring); + global::System.GC.KeepAlive (anObject); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='ObsoleteMethod' and count(parameter)=0]" + [global::System.Obsolete (@"Deprecated please use IntegerMethod instead")] + public virtual unsafe int ObsoleteMethod () + { + const string __id = "ObsoleteMethod.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='ArrayListTest' and count(parameter)=1 and parameter[1][@type='java.util.ArrayList<java.lang.Integer>']]" + public virtual unsafe void ArrayListTest (global::System.Collections.Generic.IList p0) + { + const string __id = "ArrayListTest.(Ljava/util/ArrayList;)V"; + IntPtr native_p0 = global::Android.Runtime.JavaList.ToLocalJniHandle (p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + global::System.GC.KeepAlive (p0); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalMethods/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/NormalProperties.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/NormalProperties.xml new file mode 100644 index 00000000000..d6a740d99f6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/NormalProperties.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..d65fba4f30a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/Xamarin.Test.SomeObject.cs @@ -0,0 +1,148 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false, InvokerType=typeof (SomeObjectInvoker))] + public abstract partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public abstract int SomeInteger { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeInteger' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("getSomeInteger", "()I")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeInteger' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("setSomeInteger", "(I)V")] + set; + } + + public abstract global::Java.Lang.Object SomeObjectProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeObjectProperty' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("getSomeObjectProperty", "()Ljava/lang/Object;")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeObjectProperty' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [global::Java.Interop.JniMethodSignature ("setSomeObjectProperty", "(Ljava/lang/Object;)V")] + set; + } + + public abstract string SomeString { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeString' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("getSomeString", "()Ljava/lang/String;")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeString' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [global::Java.Interop.JniMethodSignature ("setSomeString", "(Ljava/lang/String;)V")] + set; + } + + } + + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + internal partial class SomeObjectInvoker : SomeObject { + public SomeObjectInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObjectInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + public override unsafe int SomeInteger { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeInteger' and count(parameter)=0]" + get { + const string __id = "getSomeInteger.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeInteger' and count(parameter)=1 and parameter[1][@type='int']]" + set { + const string __id = "setSomeInteger.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public override unsafe global::Java.Lang.Object SomeObjectProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeObjectProperty' and count(parameter)=0]" + get { + const string __id = "getSomeObjectProperty.()Ljava/lang/Object;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeObjectProperty' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + set { + const string __id = "setSomeObjectProperty.(Ljava/lang/Object;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + public override unsafe string SomeString { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeString' and count(parameter)=0]" + get { + const string __id = "getSomeString.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeString' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + set { + const string __id = "setSomeString.(Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/NormalProperties/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Lang.Integer.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Lang.Integer.cs new file mode 100644 index 00000000000..2d1a341953f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Lang.Integer.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Integer']" + [global::Java.Interop.JniTypeSignature ("java/lang/Integer", GenerateJavaPeer=false)] + public partial class Integer : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Integer", typeof (Integer)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected Integer (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Util.IList.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Util.IList.cs new file mode 100644 index 00000000000..3e28a1e0b65 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Java.Util.IList.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='List']" + [global::Java.Interop.JniTypeSignature ("java/util/List", GenerateJavaPeer=false, InvokerType=typeof (Java.Util.IListInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IList : IJavaPeerable { + } + + [global::Java.Interop.JniTypeSignature ("java/util/List", GenerateJavaPeer=false)] + internal partial class IListInvoker : global::Java.Lang.Object, IList { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_List; } + } + + static readonly JniPeerMembers _members_java_util_List = new JniPeerMembers ("java/util/List", typeof (IListInvoker)); + + public IListInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Mono.Android.projitems new file mode 100644 index 00000000000..3b6b7a5dd5e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Mono.Android.projitems @@ -0,0 +1,16 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/ParameterXPath.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/ParameterXPath.xml new file mode 100644 index 00000000000..c7a4c5e570e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/ParameterXPath.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Xamarin.Test.A.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Xamarin.Test.A.cs new file mode 100644 index 00000000000..472dba9621e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/Xamarin.Test.A.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='A']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/A", GenerateJavaPeer=false)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends java.lang.Object"})] + public partial class A : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/A", typeof (A)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected A (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A']/method[@name='setA' and count(parameter)=1 and parameter[1][@type='T']]" + [global::Java.Interop.JniMethodSignature ("setA", "(Ljava/lang/Object;)V")] + public virtual unsafe void SetA (global::Java.Lang.Object adapter) + { + const string __id = "setA.(Ljava/lang/Object;)V"; + var native_adapter = (adapter?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_adapter); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (adapter); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A']/method[@name='listTest' and count(parameter)=1 and parameter[1][@type='java.util.List<java.lang.Integer>']]" + [global::Java.Interop.JniMethodSignature ("listTest", "(Ljava/util/List;)V")] + public virtual unsafe void ListTest (global::Java.Util.IList p0) + { + const string __id = "listTest.(Ljava/util/List;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (p0); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (p0); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/ParameterXPath/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/StaticField.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/StaticField.xml new file mode 100644 index 00000000000..fb810c114f3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/StaticField.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..8d567d71e06 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/Xamarin.Test.SomeObject.cs @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='Value']" + public static int Value { + get { + const string __id = "Value.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='Value2']" + public static int Value2 { + get { + const string __id = "Value2.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + set { + const string __id = "Value2.I"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='BooleanValue']" + public static bool BooleanValue { + get { + const string __id = "BooleanValue.Z"; + + var __v = _members.StaticFields.GetBooleanValue (__id); + return __v; + } + set { + const string __id = "BooleanValue.Z"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='CharValue']" + public static char CharValue { + get { + const string __id = "CharValue.C"; + + var __v = _members.StaticFields.GetCharValue (__id); + return __v; + } + set { + const string __id = "CharValue.C"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticFields/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/StaticMethod.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/StaticMethod.xml new file mode 100644 index 00000000000..913f5e69b27 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/StaticMethod.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..31f27208011 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/Xamarin.Test.SomeObject.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='methodAsInt' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("methodAsInt", "()I")] + public static unsafe int MethodAsInt () + { + const string __id = "methodAsInt.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='methodAsString' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("methodAsString", "()Ljava/lang/String;")] + public static unsafe string MethodAsString () + { + const string __id = "methodAsString.()Ljava/lang/String;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='Obsoletemethod' and count(parameter)=0]" + [global::System.Obsolete (@"Deprecated please use methodAsString")] + [global::Java.Interop.JniMethodSignature ("Obsoletemethod", "()Ljava/lang/String;")] + public static unsafe string Obsoletemethod () + { + const string __id = "Obsoletemethod.()Ljava/lang/String;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticMethods/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/StaticProperties.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/StaticProperties.xml new file mode 100644 index 00000000000..ed21f876b23 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/StaticProperties.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..847372322d1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/Xamarin.Test.SomeObject.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public static unsafe int SomeInteger { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeInteger' and count(parameter)=0]" + get { + const string __id = "getSomeInteger.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeInteger' and count(parameter)=1 and parameter[1][@type='int']]" + set { + const string __id = "setSomeInteger.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + + public static unsafe string SomeString { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeString' and count(parameter)=0]" + get { + const string __id = "getSomeString.()Ljava/lang/String;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeString' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + set { + const string __id = "setSomeString.(Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_value); + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeObject' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("getSomeObject", "()Ljava/lang/Object;")] + public static unsafe global::Java.Lang.Object GetSomeObject () + { + const string __id = "getSomeObject.()Ljava/lang/Object;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeObject' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [global::Java.Interop.JniMethodSignature ("setSomeObject", "(Ljava/lang/Object;)V")] + public static unsafe void SetSomeObject (global::Java.Lang.Object newvalue) + { + const string __id = "setSomeObject.(Ljava/lang/Object;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (newvalue); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + global::System.GC.KeepAlive (newvalue); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/StaticProperties/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.FilterOutputStream.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.FilterOutputStream.cs new file mode 100644 index 00000000000..1269bbc2d31 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.FilterOutputStream.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='FilterOutputStream']" + [global::Java.Interop.JniTypeSignature ("java/io/FilterOutputStream", GenerateJavaPeer=false)] + public partial class FilterOutputStream : global::Java.IO.OutputStream { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/io/FilterOutputStream", typeof (FilterOutputStream)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected FilterOutputStream (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.io']/class[@name='FilterOutputStream']/constructor[@name='FilterOutputStream' and count(parameter)=1 and parameter[1][@type='java.io.OutputStream']]" + [global::Java.Interop.JniConstructorSignature ("(Ljava/io/OutputStream;)V")] + public unsafe FilterOutputStream (global::Java.IO.OutputStream @out) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "(Ljava/io/OutputStream;)V"; + + if (PeerReference.IsValid) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (@out); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + global::System.GC.KeepAlive (@out); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='FilterOutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("write", "(I)V")] + public override unsafe void Write (int oneByte) + { + const string __id = "write.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (oneByte); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.IOException.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.IOException.cs new file mode 100644 index 00000000000..d2d9cd673f8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.IOException.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='IOException']" + [global::Java.Interop.JniTypeSignature ("java/io/IOException", GenerateJavaPeer=false, InvokerType=typeof (IOExceptionInvoker))] + public abstract partial class IOException : global::Java.Lang.Throwable { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/io/IOException", typeof (IOException)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected IOException (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='IOException']/method[@name='printStackTrace' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("printStackTrace", "()V")] + public virtual unsafe void PrintStackTrace () + { + const string __id = "printStackTrace.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } + + [global::Java.Interop.JniTypeSignature ("java/io/IOException", GenerateJavaPeer=false)] + internal partial class IOExceptionInvoker : IOException { + public IOExceptionInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/io/IOException", typeof (IOExceptionInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.InputStream.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.InputStream.cs new file mode 100644 index 00000000000..3b787e704c3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.InputStream.cs @@ -0,0 +1,194 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='InputStream']" + [global::Java.Interop.JniTypeSignature ("java/io/InputStream", GenerateJavaPeer=false, InvokerType=typeof (InputStreamInvoker))] + public abstract partial class InputStream : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/io/InputStream", typeof (InputStream)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected InputStream (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.io']/class[@name='InputStream']/constructor[@name='InputStream' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe InputStream () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='available' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("available", "()I")] + public virtual unsafe int Available () + { + const string __id = "available.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='close' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("close", "()V")] + public virtual unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='mark' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("mark", "(I)V")] + public virtual unsafe void Mark (int readlimit) + { + const string __id = "mark.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (readlimit); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='markSupported' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("markSupported", "()Z")] + public virtual unsafe bool MarkSupported () + { + const string __id = "markSupported.()Z"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualBooleanMethod (__id, this, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=0]" + public abstract int Read (); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=1 and parameter[1][@type='byte[]']]" + [global::Java.Interop.JniMethodSignature ("read", "([B)I")] + public virtual unsafe int Read (global::Java.Interop.JavaSByteArray buffer) + { + const string __id = "read.([B)I"; + var native_buffer = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_buffer); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + if (native_buffer != null) { + native_buffer.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (buffer); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=3 and parameter[1][@type='byte[]'] and parameter[2][@type='int'] and parameter[3][@type='int']]" + [global::Java.Interop.JniMethodSignature ("read", "([BII)I")] + public virtual unsafe int Read (global::Java.Interop.JavaSByteArray buffer, int byteOffset, int byteCount) + { + const string __id = "read.([BII)I"; + var native_buffer = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (native_buffer); + __args [1] = new JniArgumentValue (byteOffset); + __args [2] = new JniArgumentValue (byteCount); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + if (native_buffer != null) { + native_buffer.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (buffer); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='reset' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("reset", "()V")] + public virtual unsafe void Reset () + { + const string __id = "reset.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='skip' and count(parameter)=1 and parameter[1][@type='long']]" + [global::Java.Interop.JniMethodSignature ("skip", "(J)J")] + public virtual unsafe long Skip (long byteCount) + { + const string __id = "skip.(J)J"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (byteCount); + var __rm = _members.InstanceMethods.InvokeVirtualInt64Method (__id, this, __args); + return __rm; + } finally { + } + } + + } + + [global::Java.Interop.JniTypeSignature ("java/io/InputStream", GenerateJavaPeer=false)] + internal partial class InputStreamInvoker : InputStream { + public InputStreamInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/io/InputStream", typeof (InputStreamInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("read", "()I")] + public override unsafe int Read () + { + const string __id = "read.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.OutputStream.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.OutputStream.cs new file mode 100644 index 00000000000..7af6b63e5fb --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.IO.OutputStream.cs @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='OutputStream']" + [global::Java.Interop.JniTypeSignature ("java/io/OutputStream", GenerateJavaPeer=false, InvokerType=typeof (OutputStreamInvoker))] + public abstract partial class OutputStream : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/io/OutputStream", typeof (OutputStream)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected OutputStream (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/constructor[@name='OutputStream' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe OutputStream () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='close' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("close", "()V")] + public virtual unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='flush' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("flush", "()V")] + public virtual unsafe void Flush () + { + const string __id = "flush.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='byte[]']]" + [global::Java.Interop.JniMethodSignature ("write", "([B)V")] + public virtual unsafe void Write (global::Java.Interop.JavaSByteArray buffer) + { + const string __id = "write.([B)V"; + var native_buffer = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_buffer); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (native_buffer != null) { + native_buffer.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (buffer); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=3 and parameter[1][@type='byte[]'] and parameter[2][@type='int'] and parameter[3][@type='int']]" + [global::Java.Interop.JniMethodSignature ("write", "([BII)V")] + public virtual unsafe void Write (global::Java.Interop.JavaSByteArray buffer, int offset, int count) + { + const string __id = "write.([BII)V"; + var native_buffer = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (native_buffer); + __args [1] = new JniArgumentValue (offset); + __args [2] = new JniArgumentValue (count); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (native_buffer != null) { + native_buffer.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (buffer); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='int']]" + public abstract void Write (int oneByte); + + } + + [global::Java.Interop.JniTypeSignature ("java/io/OutputStream", GenerateJavaPeer=false)] + internal partial class OutputStreamInvoker : OutputStream { + public OutputStreamInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/io/OutputStream", typeof (OutputStreamInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='int']]" + [global::Java.Interop.JniMethodSignature ("write", "(I)V")] + public override unsafe void Write (int oneByte) + { + const string __id = "write.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (oneByte); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.Lang.Throwable.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.Lang.Throwable.cs new file mode 100644 index 00000000000..f627b04b98c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Java.Lang.Throwable.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Throwable']" + [global::Java.Interop.JniTypeSignature ("java/lang/Throwable", GenerateJavaPeer=false)] + public partial class Throwable { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Throwable", typeof (Throwable)); + + public new virtual unsafe string Message { + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/class[@name='Throwable']/method[@name='getMessage' and count(parameter)=0]" + get { + const string __id = "getMessage.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Mono.Android.projitems new file mode 100644 index 00000000000..835eac21485 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Mono.Android.projitems @@ -0,0 +1,18 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Streams.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Streams.xml new file mode 100644 index 00000000000..b853aee1ba8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/Streams.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/InputStreamAdapter.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/InputStreamAdapter.cs new file mode 100644 index 00000000000..b20b29151af --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/InputStreamAdapter.cs @@ -0,0 +1,47 @@ +#if !JAVA_INTEROP1 +using System; +using System.IO; + +namespace Android.Runtime { + + [Register ("mono/android/runtime/InputStreamAdapter")] + public sealed class InputStreamAdapter : Java.IO.InputStream { + + public Stream BaseStream {get; private set;} + + public InputStreamAdapter (System.IO.Stream stream) + : base ( + JNIEnv.StartCreateInstance ("mono/android/runtime/InputStreamAdapter", "()V"), + JniHandleOwnership.TransferLocalRef) + { + throw new NotImplementedException (); + } + + public override void Close () + { + throw new NotImplementedException (); + } + + public override int Read () + { + throw new NotImplementedException (); + } + + public override int Read (byte[] bytes) + { + throw new NotImplementedException (); + } + + public override int Read (byte[] bytes, int offset, int length) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (Stream value) + { + throw new NotImplementedException (); + } + } +} +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/InputStreamInvoker.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/InputStreamInvoker.cs new file mode 100644 index 00000000000..ffb26e125c8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/InputStreamInvoker.cs @@ -0,0 +1,64 @@ +#if !JAVA_INTEROP1 +using System; +using System.IO; + +namespace Android.Runtime +{ + public class InputStreamInvoker : Stream + { + public Java.IO.InputStream BaseInputStream {get; private set;} + + public InputStreamInvoker (Java.IO.InputStream stream) + { + throw new NotImplementedException (); + } + + protected override void Dispose (bool disposing) + { + throw new NotImplementedException (); + } + + public override void Flush () + { + // No need to flush an input stream + } + + public override int Read (byte[] buffer, int offset, int count) + { + throw new NotImplementedException (); + } + + public override long Seek (long offset, SeekOrigin origin) + { + throw new NotImplementedException (); + } + + public override void SetLength (long value) + { + throw new NotImplementedException (); + } + + public override void Write (byte[] buffer, int offset, int count) + { + throw new NotImplementedException (); + } + + public override bool CanRead { get { return true; } } + public override bool CanSeek { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override long Length { get { throw new NotImplementedException (); } } + + public override long Position { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + [Preserve (Conditional=true)] + public static Stream FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + } +} +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/OutputStreamAdapter.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/OutputStreamAdapter.cs new file mode 100644 index 00000000000..b2996d073da --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/OutputStreamAdapter.cs @@ -0,0 +1,53 @@ +#if !JAVA_INTEROP1 +using System; +using System.IO; + +namespace Android.Runtime +{ + [Register ("mono/android/runtime/OutputStreamAdapter")] + public class OutputStreamAdapter : Java.IO.OutputStream + { + public Stream BaseStream {get; private set;} + + [Register (".ctor", "()V", "")] + public OutputStreamAdapter (System.IO.Stream stream) + : base ( + JNIEnv.StartCreateInstance ("mono/android/runtime/OutputStreamAdapter", "()V"), + JniHandleOwnership.TransferLocalRef) + { + throw new NotImplementedException (); + } + + public override void Close () + { + throw new NotImplementedException (); + } + + public override void Flush () + { + throw new NotImplementedException (); + } + + public override void Write (byte[] buffer) + { + throw new NotImplementedException (); + } + + public override void Write (byte[] buffer, int offset, int length) + { + throw new NotImplementedException (); + } + + public override void Write (int oneByte) + { + throw new NotImplementedException (); + } + + [Preserve (Conditional=true)] + public static IntPtr ToLocalJniHandle (Stream value) + { + throw new NotImplementedException (); + } + } +} +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/OutputStreamInvoker.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/OutputStreamInvoker.cs new file mode 100644 index 00000000000..1189c1d757a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/SupportFiles/OutputStreamInvoker.cs @@ -0,0 +1,69 @@ +#if !JAVA_INTEROP1 +using System; +using System.IO; + +namespace Android.Runtime +{ + public class OutputStreamInvoker : Stream + { + public Java.IO.OutputStream BaseOutputStream {get; private set;} + + public OutputStreamInvoker (Java.IO.OutputStream stream) + { + throw new NotImplementedException (); + } + + protected override void Dispose (bool disposing) + { + throw new NotImplementedException (); + } + + public override void Flush () + { + throw new NotImplementedException (); + } + + public override int Read (byte[] buffer, int offset, int count) + { + throw new NotImplementedException (); + } + + public override long Seek (long offset, SeekOrigin origin) + { + throw new NotImplementedException (); + } + + public override void SetLength (long value) + { + throw new NotImplementedException (); + } + + public override void Write (byte[] buffer, int offset, int count) + { + throw new NotImplementedException (); + } + + public override bool CanRead { get { return false; } } + public override bool CanSeek { get { return false; } } + public override bool CanWrite { get { return true; } } + + public override long Length { get { throw new NotImplementedException (); } } + + public override long Position { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + [Preserve (Conditional=true)] + public static Stream FromJniHandle (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + + internal static Stream FromNative (IntPtr handle, JniHandleOwnership transfer) + { + throw new NotImplementedException (); + } + } +} +#endif // !JAVA_INTEROP1 diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/Streams/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/ClassWithoutNamespace.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/ClassWithoutNamespace.cs new file mode 100644 index 00000000000..65b44c3e2c1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/ClassWithoutNamespace.cs @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +// Metadata.xml XPath class reference: path="/api/package[@name='']/class[@name='ClassWithoutNamespace']" +[global::Java.Interop.JniTypeSignature ("ClassWithoutNamespace", GenerateJavaPeer=false, InvokerType=typeof (ClassWithoutNamespaceInvoker))] +public abstract partial class ClassWithoutNamespace : global::Java.Lang.Object, IInterfaceWithoutNamespace { + static readonly JniPeerMembers _members = new JniPeerMembers ("ClassWithoutNamespace", typeof (ClassWithoutNamespace)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected ClassWithoutNamespace (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='']/class[@name='ClassWithoutNamespace']/constructor[@name='ClassWithoutNamespace' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe ClassWithoutNamespace () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + public abstract void Foo (); + +} + +[global::Java.Interop.JniTypeSignature ("ClassWithoutNamespace", GenerateJavaPeer=false)] +internal partial class ClassWithoutNamespaceInvoker : ClassWithoutNamespace { + public ClassWithoutNamespaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("ClassWithoutNamespace", typeof (ClassWithoutNamespaceInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("Foo", "()V")] + public override unsafe void Foo () + { + const string __id = "Foo.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/IInterfaceWithoutNamespace.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/IInterfaceWithoutNamespace.cs new file mode 100644 index 00000000000..7a693cfe6de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/IInterfaceWithoutNamespace.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +// Metadata.xml XPath interface reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']" +[global::Java.Interop.JniTypeSignature ("InterfaceWithoutNamespace", GenerateJavaPeer=false, InvokerType=typeof (IInterfaceWithoutNamespaceInvoker))] +public partial interface IInterfaceWithoutNamespace : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("Foo", "()V")] + void Foo (); + +} + +[global::Java.Interop.JniTypeSignature ("InterfaceWithoutNamespace", GenerateJavaPeer=false)] +internal partial class IInterfaceWithoutNamespaceInvoker : global::Java.Lang.Object, IInterfaceWithoutNamespace { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members__InterfaceWithoutNamespace; } + } + + static readonly JniPeerMembers _members__InterfaceWithoutNamespace = new JniPeerMembers ("InterfaceWithoutNamespace", typeof (IInterfaceWithoutNamespaceInvoker)); + + public IInterfaceWithoutNamespaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void Foo () + { + const string __id = "Foo.()V"; + try { + _members__InterfaceWithoutNamespace.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.String.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.String.cs new file mode 100644 index 00000000000..5195f63f5fa --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Lang.String.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='String']" + [global::Java.Interop.JniTypeSignature ("java/lang/String", GenerateJavaPeer=false)] + public sealed partial class String : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/String", typeof (String)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + internal String (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.ICollection.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.ICollection.cs new file mode 100644 index 00000000000..b67ca171c59 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.ICollection.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Collection']" + [global::Java.Interop.JniTypeSignature ("java/util/Collection", GenerateJavaPeer=false, InvokerType=typeof (Java.Util.ICollectionInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface ICollection : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Collection']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [global::Java.Interop.JniMethodSignature ("add", "(Ljava/lang/Object;)Z")] + bool Add (global::Java.Lang.Object e); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Collection']/method[@name='clear' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("clear", "()V")] + void Clear (); + + } + + [global::Java.Interop.JniTypeSignature ("java/util/Collection", GenerateJavaPeer=false)] + internal partial class ICollectionInvoker : global::Java.Lang.Object, ICollection { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Collection; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new JniPeerMembers ("java/util/Collection", typeof (ICollectionInvoker)); + + public ICollectionInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + var native_e = (e?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Collection.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (e); + } + } + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IDeque.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IDeque.cs new file mode 100644 index 00000000000..57186f03e17 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IDeque.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Deque']" + [global::Java.Interop.JniTypeSignature ("java/util/Deque", GenerateJavaPeer=false, InvokerType=typeof (Java.Util.IDequeInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IDeque : global::Java.Util.IQueue { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Deque']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [global::Java.Interop.JniMethodSignature ("add", "(Ljava/lang/Object;)Z")] + bool Add (global::Java.Lang.Object e); + + } + + [global::Java.Interop.JniTypeSignature ("java/util/Deque", GenerateJavaPeer=false)] + internal partial class IDequeInvoker : global::Java.Lang.Object, IDeque { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Deque; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new JniPeerMembers ("java/util/Collection", typeof (IDequeInvoker)); + + static readonly JniPeerMembers _members_java_util_Deque = new JniPeerMembers ("java/util/Deque", typeof (IDequeInvoker)); + + static readonly JniPeerMembers _members_java_util_Queue = new JniPeerMembers ("java/util/Queue", typeof (IDequeInvoker)); + + public IDequeInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + var native_e = (e?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Deque.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (e); + } + } + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IQueue.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IQueue.cs new file mode 100644 index 00000000000..8125f2edbda --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Java.Util.IQueue.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Queue']" + [global::Java.Interop.JniTypeSignature ("java/util/Queue", GenerateJavaPeer=false, InvokerType=typeof (Java.Util.IQueueInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IQueue : global::Java.Util.ICollection { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Queue']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [global::Java.Interop.JniMethodSignature ("add", "(Ljava/lang/Object;)Z")] + bool Add (global::Java.Lang.Object e); + + } + + [global::Java.Interop.JniTypeSignature ("java/util/Queue", GenerateJavaPeer=false)] + internal partial class IQueueInvoker : global::Java.Lang.Object, IQueue { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Queue; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new JniPeerMembers ("java/util/Collection", typeof (IQueueInvoker)); + + static readonly JniPeerMembers _members_java_util_Queue = new JniPeerMembers ("java/util/Queue", typeof (IQueueInvoker)); + + public IQueueInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + var native_e = (e?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Queue.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (e); + } + } + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Mono.Android.projitems new file mode 100644 index 00000000000..579227feeae --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Mono.Android.projitems @@ -0,0 +1,27 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericImplementation.cs new file mode 100644 index 00000000000..f520881a2f5 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericImplementation.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericImplementation']" + [global::Java.Interop.JniTypeSignature ("test/me/GenericImplementation", GenerateJavaPeer=false)] + public partial class GenericImplementation : global::Java.Lang.Object, global::Test.ME.IGenericInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("test/me/GenericImplementation", typeof (GenericImplementation)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected GenericImplementation (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericImplementation']/constructor[@name='GenericImplementation' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe GenericImplementation () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='byte[]']]" + [global::Java.Interop.JniMethodSignature ("SetObject", "([B)V")] + public virtual unsafe void SetObject (global::Java.Interop.JavaSByteArray value) + { + const string __id = "SetObject.([B)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + + // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericInterface + void global::Test.ME.IGenericInterface.SetObject (global::Java.Lang.Object value) + { + SetObject (global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue((value?.PeerReference ?? default).Handle)); + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs new file mode 100644 index 00000000000..9f538e8c3cb --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']" + [global::Java.Interop.JniTypeSignature ("test/me/GenericObjectPropertyImplementation", GenerateJavaPeer=false)] + public partial class GenericObjectPropertyImplementation : global::Java.Lang.Object, global::Test.ME.IGenericPropertyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("test/me/GenericObjectPropertyImplementation", typeof (GenericObjectPropertyImplementation)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected GenericObjectPropertyImplementation (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']/constructor[@name='GenericObjectPropertyImplementation' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe GenericObjectPropertyImplementation () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + public virtual unsafe global::Java.Lang.Object Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']/method[@name='getObject' and count(parameter)=0]" + get { + const string __id = "getObject.()Ljava/lang/Object;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + set { + const string __id = "setObject.(Ljava/lang/Object;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringImplementation.cs new file mode 100644 index 00000000000..7a47fee8210 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringImplementation.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericStringImplementation']" + [global::Java.Interop.JniTypeSignature ("test/me/GenericStringImplementation", GenerateJavaPeer=false)] + public partial class GenericStringImplementation : global::Java.Lang.Object, global::Test.ME.IGenericInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("test/me/GenericStringImplementation", typeof (GenericStringImplementation)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected GenericStringImplementation (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericStringImplementation']/constructor[@name='GenericStringImplementation' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe GenericStringImplementation () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericStringImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='java.lang.String[]']]" + [global::Java.Interop.JniMethodSignature ("SetObject", "([Ljava/lang/String;)V")] + public virtual unsafe void SetObject (global::Java.Interop.JavaObjectArray value) + { + const string __id = "SetObject.([Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Arrays.CreateMarshalObjectArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (native_value != null) { + native_value.DisposeUnlessReferenced (); + } + global::System.GC.KeepAlive (value); + } + } + + // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericInterface + void global::Test.ME.IGenericInterface.SetObject (global::Java.Lang.Object value) + { + SetObject (global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue>((value?.PeerReference ?? default).Handle)); + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs new file mode 100644 index 00000000000..14ccac53892 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']" + [global::Java.Interop.JniTypeSignature ("test/me/GenericStringPropertyImplementation", GenerateJavaPeer=false)] + public partial class GenericStringPropertyImplementation : global::Java.Lang.Object, global::Test.ME.IGenericPropertyInterface { + static readonly JniPeerMembers _members = new JniPeerMembers ("test/me/GenericStringPropertyImplementation", typeof (GenericStringPropertyImplementation)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected GenericStringPropertyImplementation (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']/constructor[@name='GenericStringPropertyImplementation' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe GenericStringPropertyImplementation () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + public virtual unsafe string Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']/method[@name='getObject' and count(parameter)=0]" + get { + const string __id = "getObject.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Strings.ToString (ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + set { + const string __id = "SetObject.(Ljava/lang/String;)V"; + var native_value = global::Java.Interop.JniEnvironment.Strings.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::Java.Interop.JniObjectReference.Dispose (ref native_value); + } + } + } + + // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericPropertyInterface + global::Java.Lang.Object global::Test.ME.IGenericPropertyInterface.Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='getObject' and count(parameter)=0]" + get { return new Java.Lang.String (Object); } + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='T']]" + set { Object = value?.ToString (); } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericInterface.cs new file mode 100644 index 00000000000..5bc81d5c3c6 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericInterface.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath interface reference: path="/api/package[@name='test.me']/interface[@name='GenericInterface']" + [global::Java.Interop.JniTypeSignature ("test/me/GenericInterface", GenerateJavaPeer=false, InvokerType=typeof (Test.ME.IGenericInterfaceInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial interface IGenericInterface : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericInterface']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='T']]" + [global::Java.Interop.JniMethodSignature ("SetObject", "(Ljava/lang/Object;)V")] + void SetObject (global::Java.Lang.Object value); + + } + + [global::Java.Interop.JniTypeSignature ("test/me/GenericInterface", GenerateJavaPeer=false)] + internal partial class IGenericInterfaceInvoker : global::Java.Lang.Object, IGenericInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_GenericInterface; } + } + + static readonly JniPeerMembers _members_test_me_GenericInterface = new JniPeerMembers ("test/me/GenericInterface", typeof (IGenericInterfaceInvoker)); + + public IGenericInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe void SetObject (global::Java.Lang.Object value) + { + const string __id = "SetObject.(Ljava/lang/Object;)V"; + var native_value = (value?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_test_me_GenericInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericPropertyInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericPropertyInterface.cs new file mode 100644 index 00000000000..a9698b97eea --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.IGenericPropertyInterface.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath interface reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']" + [global::Java.Interop.JniTypeSignature ("test/me/GenericPropertyInterface", GenerateJavaPeer=false, InvokerType=typeof (Test.ME.IGenericPropertyInterfaceInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial interface IGenericPropertyInterface : IJavaPeerable { + global::Java.Lang.Object Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='getObject' and count(parameter)=0]" + [global::Java.Interop.JniMethodSignature ("getObject", "()Ljava/lang/Object;")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='T']]" + [global::Java.Interop.JniMethodSignature ("setObject", "(Ljava/lang/Object;)V")] + set; + } + + } + + [global::Java.Interop.JniTypeSignature ("test/me/GenericPropertyInterface", GenerateJavaPeer=false)] + internal partial class IGenericPropertyInterfaceInvoker : global::Java.Lang.Object, IGenericPropertyInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_GenericPropertyInterface; } + } + + static readonly JniPeerMembers _members_test_me_GenericPropertyInterface = new JniPeerMembers ("test/me/GenericPropertyInterface", typeof (IGenericPropertyInterfaceInvoker)); + + public IGenericPropertyInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe global::Java.Lang.Object Object { + get { + const string __id = "getObject.()Ljava/lang/Object;"; + try { + var __rm = _members_test_me_GenericPropertyInterface.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + } + } + set { + const string __id = "setObject.(Ljava/lang/Object;)V"; + var native_value = (value?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_test_me_GenericPropertyInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs new file mode 100644 index 00000000000..a3a7a9c4945 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath interface reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']" + [global::Java.Interop.JniTypeSignature ("test/me/TestInterface", GenerateJavaPeer=false, InvokerType=typeof (Test.ME.ITestInterfaceInvoker))] + public partial interface ITestInterface : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [global::Java.Interop.JniMethodSignature ("getSpanFlags", "(Ljava/lang/Object;)I")] + int GetSpanFlags (global::Java.Lang.Object tag); + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("append", "(Ljava/lang/CharSequence;)V")] + void Append (global::Java.Lang.ICharSequence value); + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;")] + global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + } + + public static partial class ITestInterfaceExtensions { + public static void Append (this Test.ME.ITestInterface self, string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + self.Append (jls_value); + jls_value?.Dispose (); + } + + public static string Identity (this Test.ME.ITestInterface self, string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = self.IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + + } + + [global::Java.Interop.JniTypeSignature ("test/me/TestInterface", GenerateJavaPeer=false)] + internal partial class ITestInterfaceInvoker : global::Java.Lang.Object, ITestInterface { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_TestInterface; } + } + + static readonly JniPeerMembers _members_test_me_TestInterface = new JniPeerMembers ("test/me/TestInterface", typeof (ITestInterfaceInvoker)); + + public ITestInterfaceInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe int GetSpanFlags (global::Java.Lang.Object tag) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (tag); + var __rm = _members_test_me_TestInterface.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (tag); + } + } + + public unsafe void Append (global::Java.Lang.ICharSequence value) + { + const string __id = "append.(Ljava/lang/CharSequence;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members_test_me_TestInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + + public unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + const string __id = "identity.(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members_test_me_TestInterface.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + global::System.GC.KeepAlive (value); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs new file mode 100644 index 00000000000..1dcf2d643ed --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='TestInterfaceImplementation']" + [global::Java.Interop.JniTypeSignature ("test/me/TestInterfaceImplementation", GenerateJavaPeer=false, InvokerType=typeof (TestInterfaceImplementationInvoker))] + public abstract partial class TestInterfaceImplementation : global::Java.Lang.Object, global::Test.ME.ITestInterface { + public static class InterfaceConsts { + // The following are fields from: test.me.TestInterface + + // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='SPAN_COMPOSING']" + public const int SpanComposing = (int) 256; + + + // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='DEFAULT_FOO']" + public static global::Java.Lang.Object DefaultFoo { + get { + const string __id = "DEFAULT_FOO.Ljava/lang/Object;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + } + + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("test/me/TestInterfaceImplementation", typeof (TestInterfaceImplementation)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected TestInterfaceImplementation (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='TestInterfaceImplementation']/constructor[@name='TestInterfaceImplementation' and count(parameter)=0]" + [global::Java.Interop.JniConstructorSignature ("()V")] + public unsafe TestInterfaceImplementation () : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None) + { + const string __id = "()V"; + + if (PeerReference.IsValid) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + public abstract int GetSpanFlags (global::Java.Lang.Object tag); + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + public abstract void Append (global::Java.Lang.ICharSequence value); + + public void Append (string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + Append (jls_value); + jls_value?.Dispose (); + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + public abstract global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + public string Identity (string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + + } + + [global::Java.Interop.JniTypeSignature ("test/me/TestInterfaceImplementation", GenerateJavaPeer=false)] + internal partial class TestInterfaceImplementationInvoker : TestInterfaceImplementation { + public TestInterfaceImplementationInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("test/me/TestInterfaceImplementation", typeof (TestInterfaceImplementationInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [global::Java.Interop.JniMethodSignature ("getSpanFlags", "(Ljava/lang/Object;)I")] + public override unsafe int GetSpanFlags (global::Java.Lang.Object tag) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (tag); + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (tag); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("append", "(Ljava/lang/CharSequence;)V")] + public override unsafe void Append (global::Java.Lang.ICharSequence value) + { + const string __id = "append.(Ljava/lang/CharSequence;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [global::Java.Interop.JniMethodSignature ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;")] + public override unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + const string __id = "identity.(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __rm, JniObjectReferenceOptions.CopyAndDispose); + } finally { + global::System.GC.KeepAlive (value); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/TestInterface.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/TestInterface.xml new file mode 100644 index 00000000000..bbaa4e20739 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/TestInterface.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/TestInterface/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Enum.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Enum.cs new file mode 100644 index 00000000000..846f6c0c69d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Enum.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Enum']" + [global::Java.Interop.JniTypeSignature ("java/lang/Enum", GenerateJavaPeer=false, InvokerType=typeof (EnumInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"E extends java.lang.Enum"})] + public abstract partial class Enum : global::Java.Lang.Object, global::Java.Lang.IComparable { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Enum", typeof (Enum)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected Enum (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/class[@name='Enum']/method[@name='compareTo' and count(parameter)=1 and parameter[1][@type='E']]" + [global::Java.Interop.JniMethodSignature ("compareTo", "(Ljava/lang/Enum;)I")] + public unsafe int CompareTo (global::Java.Lang.Object o) + { + const string __id = "compareTo.(Ljava/lang/Enum;)I"; + var native_o = (o?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_o); + var __rm = _members.InstanceMethods.InvokeNonvirtualInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (o); + } + } + + } + + [global::Java.Interop.JniTypeSignature ("java/lang/Enum", GenerateJavaPeer=false)] + internal partial class EnumInvoker : Enum, global::Java.Lang.IComparable { + public EnumInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Enum", typeof (EnumInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Enum.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Enum.xml new file mode 100644 index 00000000000..9f7df147707 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Enum.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.IComparable.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.IComparable.cs new file mode 100644 index 00000000000..61f341858ee --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.IComparable.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.lang']/interface[@name='Comparable']" + [global::Java.Interop.JniTypeSignature ("java/lang/Comparable", GenerateJavaPeer=false, InvokerType=typeof (Java.Lang.IComparableInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial interface IComparable : IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/interface[@name='Comparable']/method[@name='compareTo' and count(parameter)=1 and parameter[1][@type='T']]" + [global::Java.Interop.JniMethodSignature ("compareTo", "(Ljava/lang/Object;)I")] + int CompareTo (global::Java.Lang.Object another); + + } + + [global::Java.Interop.JniTypeSignature ("java/lang/Comparable", GenerateJavaPeer=false)] + internal partial class IComparableInvoker : global::Java.Lang.Object, IComparable { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_lang_Comparable; } + } + + static readonly JniPeerMembers _members_java_lang_Comparable = new JniPeerMembers ("java/lang/Comparable", typeof (IComparableInvoker)); + + public IComparableInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + public unsafe int CompareTo (global::Java.Lang.Object another) + { + const string __id = "compareTo.(Ljava/lang/Object;)I"; + var native_another = (another?.PeerReference ?? default); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_another); + var __rm = _members_java_lang_Comparable.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (another); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.State.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.State.cs new file mode 100644 index 00000000000..ee78a59c303 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Java.Lang.State.cs @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='State']" + [global::Java.Interop.JniTypeSignature ("java/lang/State", GenerateJavaPeer=false)] + public sealed partial class State : global::Java.Lang.Enum { + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='BLOCKED']" + public static global::Java.Lang.State Blocked { + get { + const string __id = "BLOCKED.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='NEW']" + public static global::Java.Lang.State New { + get { + const string __id = "NEW.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='RUNNABLE']" + public static global::Java.Lang.State Runnable { + get { + const string __id = "RUNNABLE.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='TERMINATED']" + public static global::Java.Lang.State Terminated { + get { + const string __id = "TERMINATED.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='TIMED_WAITING']" + public static global::Java.Lang.State TimedWaiting { + get { + const string __id = "TIMED_WAITING.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='WAITING']" + public static global::Java.Lang.State Waiting { + get { + const string __id = "WAITING.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/State", typeof (State)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + internal State (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Mono.Android.projitems new file mode 100644 index 00000000000..24a983853b1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/Mono.Android.projitems @@ -0,0 +1,16 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/enumlist new file mode 100644 index 00000000000..368c3f7b281 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Enum/enumlist @@ -0,0 +1 @@ +java.lang.State:Java.Lang:State diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/Mono.Android.projitems new file mode 100644 index 00000000000..2ebaae2b77a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/Mono.Android.projitems @@ -0,0 +1,13 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/java.lang.Object.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/java.lang.Object.xml new file mode 100644 index 00000000000..2311996e266 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.lang.Object/java.lang.Object.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Java.Lang.Object.cs new file mode 100644 index 00000000000..47f7f266194 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Java.Lang.Object.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Java.Interop.JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Java.Util.IList.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Java.Util.IList.cs new file mode 100644 index 00000000000..3e28a1e0b65 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Java.Util.IList.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='List']" + [global::Java.Interop.JniTypeSignature ("java/util/List", GenerateJavaPeer=false, InvokerType=typeof (Java.Util.IListInvoker))] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IList : IJavaPeerable { + } + + [global::Java.Interop.JniTypeSignature ("java/util/List", GenerateJavaPeer=false)] + internal partial class IListInvoker : global::Java.Lang.Object, IList { + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_List; } + } + + static readonly JniPeerMembers _members_java_util_List = new JniPeerMembers ("java/util/List", typeof (IListInvoker)); + + public IListInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Mono.Android.projitems new file mode 100644 index 00000000000..1b1e00f7633 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Mono.Android.projitems @@ -0,0 +1,15 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..8b839100199 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/Xamarin.Test.SomeObject.cs @@ -0,0 +1,173 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Java.Interop.JniTypeSignature ("xamarin/test/SomeObject", GenerateJavaPeer=false)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myStrings']" + public global::Java.Util.IList MyStrings { + get { + const string __id = "myStrings.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myStrings.Ljava/util/List;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myInts']" + public global::Java.Util.IList MyInts { + get { + const string __id = "myInts.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myInts.Ljava/util/List;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mybools']" + public global::Java.Util.IList Mybools { + get { + const string __id = "mybools.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "mybools.Ljava/util/List;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myObjects']" + public global::Java.Util.IList MyObjects { + get { + const string __id = "myObjects.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myObjects.Ljava/util/List;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myfloats']" + public global::Java.Util.IList Myfloats { + get { + const string __id = "myfloats.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "myfloats.Ljava/util/List;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mydoubles']" + public global::Java.Util.IList Mydoubles { + get { + const string __id = "mydoubles.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "mydoubles.Ljava/util/List;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mylongs']" + public global::Java.Util.IList Mylongs { + get { + const string __id = "mylongs.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(ref __v, JniObjectReferenceOptions.Copy); + } + set { + const string __id = "mylongs.Ljava/util/List;"; + + try { + _members.InstanceFields.SetValue (__id, this, value?.PeerReference ?? default); + } finally { + GC.KeepAlive (value); + } + } + } + + static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected SomeObject (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/__NamespaceMapping__.cs new file mode 100644 index 00000000000..417caab06e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/__NamespaceMapping__.cs @@ -0,0 +1,2 @@ +using System; + diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/enumlist b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/java.util.List.xml b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/java.util.List.xml new file mode 100644 index 00000000000..57c35adbb2f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.ji/java.util.List/java.util.List.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Mono.Android.projitems new file mode 100644 index 00000000000..cceaf3aec12 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Mono.Android.projitems @@ -0,0 +1,19 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.BasePublicClass.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.BasePublicClass.cs new file mode 100644 index 00000000000..f83bcd5db70 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.BasePublicClass.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='BasePublicClass']" + [global::Android.Runtime.Register ("xamarin/test/BasePublicClass", DoNotGenerateAcw=true)] + public partial class BasePublicClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/BasePublicClass", typeof (BasePublicClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected BasePublicClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_baseMethod_BaseMethod_V; +#pragma warning disable 0169 + static Delegate GetBaseMethodHandler () + { + return cb_baseMethod_BaseMethod_V ??= new _JniMarshal_PP_V (n_BaseMethod); + } + + static void n_BaseMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_BaseMethod); + } + } + private static void __n_BaseMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.BaseMethod (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='BasePublicClass']/method[@name='baseMethod' and count(parameter)=0]" + [Register ("baseMethod", "()V", "GetBaseMethodHandler")] + public virtual unsafe void BaseMethod () + { + const string __id = "baseMethod.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.ExtendPublicClass.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.ExtendPublicClass.cs new file mode 100644 index 00000000000..8ba4146dee1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.ExtendPublicClass.cs @@ -0,0 +1,98 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='ExtendPublicClass']" + [global::Android.Runtime.Register ("xamarin/test/ExtendPublicClass", DoNotGenerateAcw=true)] + public partial class ExtendPublicClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/ExtendPublicClass", typeof (ExtendPublicClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected ExtendPublicClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='ExtendPublicClass']/constructor[@name='ExtendPublicClass' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe ExtendPublicClass () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_foo_Foo_V; +#pragma warning disable 0169 + static Delegate GetFooHandler () + { + return cb_foo_Foo_V ??= new _JniMarshal_PP_V (n_Foo); + } + + static void n_Foo (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Foo); + } + } + private static void __n_Foo (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Foo (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='ExtendPublicClass']/method[@name='foo' and count(parameter)=0]" + [Register ("foo", "()V", "GetFooHandler")] + public virtual unsafe void Foo () + { + const string __id = "foo.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs new file mode 100644 index 00000000000..652e6a115a0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.IExtendedInterface.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='ExtendedInterface']" + [Register ("xamarin/test/ExtendedInterface", "", "Xamarin.Test.IExtendedInterfaceInvoker")] + public partial interface IExtendedInterface : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='ExtendedInterface']/method[@name='extendedMethod' and count(parameter)=0]" + [Register ("extendedMethod", "()V", "GetExtendedMethodHandler:Xamarin.Test.IExtendedInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void ExtendedMethod (); + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='ExtendedInterface']/method[@name='baseMethod' and count(parameter)=0]" + [Register ("baseMethod", "()V", "GetBaseMethodHandler:Xamarin.Test.IExtendedInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void BaseMethod (); + + } + + [global::Android.Runtime.Register ("xamarin/test/ExtendedInterface", DoNotGenerateAcw=true)] + internal partial class IExtendedInterfaceInvoker : global::Java.Lang.Object, IExtendedInterface { + static IntPtr java_class_ref { + get { return _members_xamarin_test_ExtendedInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_ExtendedInterface; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_xamarin_test_ExtendedInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_xamarin_test_ExtendedInterface.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_xamarin_test_BaseInterface = new XAPeerMembers ("xamarin/test/BaseInterface", typeof (IExtendedInterfaceInvoker)); + + static readonly JniPeerMembers _members_xamarin_test_ExtendedInterface = new XAPeerMembers ("xamarin/test/ExtendedInterface", typeof (IExtendedInterfaceInvoker)); + + public IExtendedInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_extendedMethod_ExtendedMethod_V; +#pragma warning disable 0169 + static Delegate GetExtendedMethodHandler () + { + return cb_extendedMethod_ExtendedMethod_V ??= new _JniMarshal_PP_V (n_ExtendedMethod); + } + + static void n_ExtendedMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_ExtendedMethod); + } + } + private static void __n_ExtendedMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.ExtendedMethod (); + } +#pragma warning restore 0169 + + public unsafe void ExtendedMethod () + { + const string __id = "extendedMethod.()V"; + try { + _members_xamarin_test_ExtendedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + static Delegate cb_baseMethod_BaseMethod_V; +#pragma warning disable 0169 + static Delegate GetBaseMethodHandler () + { + return cb_baseMethod_BaseMethod_V ??= new _JniMarshal_PP_V (n_BaseMethod); + } + + static void n_BaseMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_BaseMethod); + } + } + private static void __n_BaseMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.BaseMethod (); + } +#pragma warning restore 0169 + + public unsafe void BaseMethod () + { + const string __id = "baseMethod.()V"; + try { + _members_xamarin_test_ExtendedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicClass.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicClass.cs new file mode 100644 index 00000000000..edf9b90f794 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicClass.cs @@ -0,0 +1,168 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='PublicClass']" + [global::Android.Runtime.Register ("xamarin/test/PublicClass", DoNotGenerateAcw=true)] + public partial class PublicClass : global::Java.Lang.Object { + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='PublicClass.ProtectedInterface']" + [Register ("xamarin/test/PublicClass$ProtectedInterface", "", "Xamarin.Test.PublicClass/IProtectedInterfaceInvoker")] + protected internal partial interface IProtectedInterface : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='PublicClass.ProtectedInterface']/method[@name='foo' and count(parameter)=0]" + [Register ("foo", "()V", "GetFooHandler:Xamarin.Test.PublicClass/IProtectedInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Foo (); + + } + + [global::Android.Runtime.Register ("xamarin/test/PublicClass$ProtectedInterface", DoNotGenerateAcw=true)] + internal partial class IProtectedInterfaceInvoker : global::Java.Lang.Object, IProtectedInterface { + static IntPtr java_class_ref { + get { return _members_xamarin_test_PublicClass_ProtectedInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_PublicClass_ProtectedInterface; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_xamarin_test_PublicClass_ProtectedInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_xamarin_test_PublicClass_ProtectedInterface.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_xamarin_test_PublicClass_ProtectedInterface = new XAPeerMembers ("xamarin/test/PublicClass$ProtectedInterface", typeof (IProtectedInterfaceInvoker)); + + public IProtectedInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_foo_Foo_V; +#pragma warning disable 0169 + static Delegate GetFooHandler () + { + return cb_foo_Foo_V ??= new _JniMarshal_PP_V (n_Foo); + } + + static void n_Foo (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Foo); + } + } + private static void __n_Foo (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Foo (); + } +#pragma warning restore 0169 + + public unsafe void Foo () + { + const string __id = "foo.()V"; + try { + _members_xamarin_test_PublicClass_ProtectedInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/PublicClass", typeof (PublicClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected PublicClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='PublicClass']/constructor[@name='PublicClass' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe PublicClass () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_foo_Foo_V; +#pragma warning disable 0169 + static Delegate GetFooHandler () + { + return cb_foo_Foo_V ??= new _JniMarshal_PP_V (n_Foo); + } + + static void n_Foo (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Foo); + } + } + private static void __n_Foo (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Foo (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicClass']/method[@name='foo' and count(parameter)=0]" + [Register ("foo", "()V", "GetFooHandler")] + public virtual unsafe void Foo () + { + const string __id = "foo.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs new file mode 100644 index 00000000000..f1258d3ecc9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.PublicFinalClass.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']" + [global::Android.Runtime.Register ("xamarin/test/PublicFinalClass", DoNotGenerateAcw=true)] + public sealed partial class PublicFinalClass : global::Xamarin.Test.BasePublicClass { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/PublicFinalClass", typeof (PublicFinalClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + internal PublicFinalClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='publicMethod' and count(parameter)=0]" + [Register ("publicMethod", "()V", "")] + public unsafe void PublicMethod () + { + const string __id = "publicMethod.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodB' and count(parameter)=0]" + [Register ("packageMethodB", "()V", "")] + public unsafe void PackageMethodB () + { + const string __id = "packageMethodB.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='PublicFinalClass']/method[@name='packageMethodA' and count(parameter)=0]" + [Register ("packageMethodA", "()V", "")] + public unsafe void PackageMethodA () + { + const string __id = "packageMethodA.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.TestClass.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.TestClass.cs new file mode 100644 index 00000000000..411928bc99a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/Xamarin.Test.TestClass.cs @@ -0,0 +1,98 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='TestClass']" + [global::Android.Runtime.Register ("xamarin/test/TestClass", DoNotGenerateAcw=true)] + public partial class TestClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/TestClass", typeof (TestClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected TestClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='TestClass']/constructor[@name='TestClass' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe TestClass () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_baseMethod_BaseMethod_V; +#pragma warning disable 0169 + static Delegate GetBaseMethodHandler () + { + return cb_baseMethod_BaseMethod_V ??= new _JniMarshal_PP_V (n_BaseMethod); + } + + static void n_BaseMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_BaseMethod); + } + } + private static void __n_BaseMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.BaseMethod (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='TestClass']/method[@name='baseMethod' and count(parameter)=0]" + [Register ("baseMethod", "()V", "GetBaseMethodHandler")] + public virtual unsafe void BaseMethod () + { + const string __id = "baseMethod.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/__NamespaceMapping__.cs new file mode 100644 index 00000000000..12ae9009a03 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/__NamespaceMapping__.cs @@ -0,0 +1,8 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PP_V (IntPtr jnienv, IntPtr klass); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/AccessModifiers/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Mono.Android.projitems new file mode 100644 index 00000000000..e44fcabbd6e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Mono.Android.projitems @@ -0,0 +1,18 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.AbsSpinner.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.AbsSpinner.cs new file mode 100644 index 00000000000..ab7a8784bd9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.AbsSpinner.cs @@ -0,0 +1,165 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='AbsSpinner']" + [global::Android.Runtime.Register ("xamarin/test/AbsSpinner", DoNotGenerateAcw=true)] + public abstract partial class AbsSpinner : Xamarin.Test.AdapterView { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/AbsSpinner", typeof (AbsSpinner)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected AbsSpinner (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_getAdapter_GetAdapter_Lxamarin_test_SpinnerAdapter_; +#pragma warning disable 0169 + static Delegate GetGetAdapterHandler () + { + return cb_getAdapter_GetAdapter_Lxamarin_test_SpinnerAdapter_ ??= new _JniMarshal_PP_L (n_GetAdapter); + } + + static IntPtr n_GetAdapter (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetAdapter); + } + } + private static IntPtr __n_GetAdapter (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.Adapter); + } +#pragma warning restore 0169 + + static Delegate cb_setAdapter_SetAdapter_Lxamarin_test_SpinnerAdapter__V; +#pragma warning disable 0169 + static Delegate GetSetAdapter_Lxamarin_test_SpinnerAdapter_Handler () + { + return cb_setAdapter_SetAdapter_Lxamarin_test_SpinnerAdapter__V ??= new _JniMarshal_PPL_V (n_SetAdapter_Lxamarin_test_SpinnerAdapter_); + } + + static void n_SetAdapter_Lxamarin_test_SpinnerAdapter_ (IntPtr jnienv, IntPtr native__this, IntPtr native_adapter) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_adapter, &__n_SetAdapter_Lxamarin_test_SpinnerAdapter_); + } + } + private static void __n_SetAdapter_Lxamarin_test_SpinnerAdapter_ (IntPtr jnienv, IntPtr native__this, IntPtr native_adapter) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var adapter = (global::Xamarin.Test.ISpinnerAdapter)global::Java.Lang.Object.GetObject (native_adapter, JniHandleOwnership.DoNotTransfer); + __this.Adapter = adapter; + } +#pragma warning restore 0169 + + public override unsafe global::Xamarin.Test.ISpinnerAdapter Adapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AbsSpinner']/method[@name='getAdapter' and count(parameter)=0]" + [Register ("getAdapter", "()Lxamarin/test/SpinnerAdapter;", "GetGetAdapterHandler")] + get { + const string __id = "getAdapter.()Lxamarin/test/SpinnerAdapter;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AbsSpinner']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='xamarin.test.SpinnerAdapter']]" + [Register ("setAdapter", "(Lxamarin/test/SpinnerAdapter;)V", "GetSetAdapter_Lxamarin_test_SpinnerAdapter_Handler")] + set { + const string __id = "setAdapter.(Lxamarin/test/SpinnerAdapter;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((value == null) ? IntPtr.Zero : ((global::Java.Lang.Object) value).Handle); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } + + [global::Android.Runtime.Register ("xamarin/test/AbsSpinner", DoNotGenerateAcw=true)] + internal partial class AbsSpinnerInvoker : AbsSpinner { + public AbsSpinnerInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/AbsSpinner", typeof (AbsSpinnerInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected override unsafe global::Java.Lang.Object RawAdapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='getAdapter' and count(parameter)=0]" + [Register ("getAdapter", "()Lxamarin/test/Adapter;", "GetGetAdapterHandler")] + get { + const string __id = "getAdapter.()Lxamarin/test/Adapter;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (global::Java.Lang.Object) global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("setAdapter", "(Lxamarin/test/Adapter;)V", "GetSetAdapter_Lxamarin_test_Adapter_Handler")] + set { + const string __id = "setAdapter.(Lxamarin/test/Adapter;)V"; + IntPtr native_value = JNIEnv.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.AdapterView.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.AdapterView.cs new file mode 100644 index 00000000000..06c4c550254 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.AdapterView.cs @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']" + [global::Android.Runtime.Register ("xamarin/test/AdapterView", DoNotGenerateAcw=true)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends xamarin.test.Adapter"})] + public abstract partial class AdapterView : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/AdapterView", typeof (AdapterView)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected AdapterView (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_getAdapter_GetAdapter_Lxamarin_test_Adapter_; +#pragma warning disable 0169 + static Delegate GetGetAdapterHandler () + { + return cb_getAdapter_GetAdapter_Lxamarin_test_Adapter_ ??= new _JniMarshal_PP_L (n_GetAdapter); + } + + static IntPtr n_GetAdapter (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetAdapter); + } + } + private static IntPtr __n_GetAdapter (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.RawAdapter); + } +#pragma warning restore 0169 + + static Delegate cb_setAdapter_SetAdapter_Lxamarin_test_Adapter__V; +#pragma warning disable 0169 + static Delegate GetSetAdapter_Lxamarin_test_Adapter_Handler () + { + return cb_setAdapter_SetAdapter_Lxamarin_test_Adapter__V ??= new _JniMarshal_PPL_V (n_SetAdapter_Lxamarin_test_Adapter_); + } + + static void n_SetAdapter_Lxamarin_test_Adapter_ (IntPtr jnienv, IntPtr native__this, IntPtr native_adapter) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_adapter, &__n_SetAdapter_Lxamarin_test_Adapter_); + } + } + private static void __n_SetAdapter_Lxamarin_test_Adapter_ (IntPtr jnienv, IntPtr native__this, IntPtr native_adapter) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var adapter = global::Java.Lang.Object.GetObject (native_adapter, JniHandleOwnership.DoNotTransfer); + __this.RawAdapter = adapter; + } +#pragma warning restore 0169 + + protected abstract global::Java.Lang.Object RawAdapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='getAdapter' and count(parameter)=0]" + [Register ("getAdapter", "()Lxamarin/test/Adapter;", "GetGetAdapterHandler")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("setAdapter", "(Lxamarin/test/Adapter;)V", "GetSetAdapter_Lxamarin_test_Adapter_Handler")] + set; + } + + } + + [global::Android.Runtime.Register ("xamarin/test/AdapterView", DoNotGenerateAcw=true)] + internal partial class AdapterViewInvoker : AdapterView { + public AdapterViewInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/AdapterView", typeof (AdapterViewInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected override unsafe global::Java.Lang.Object RawAdapter { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='getAdapter' and count(parameter)=0]" + [Register ("getAdapter", "()Lxamarin/test/Adapter;", "GetGetAdapterHandler")] + get { + const string __id = "getAdapter.()Lxamarin/test/Adapter;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (global::Java.Lang.Object) global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='AdapterView']/method[@name='setAdapter' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("setAdapter", "(Lxamarin/test/Adapter;)V", "GetSetAdapter_Lxamarin_test_Adapter_Handler")] + set { + const string __id = "setAdapter.(Lxamarin/test/Adapter;)V"; + IntPtr native_value = JNIEnv.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.GenericReturnObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.GenericReturnObject.cs new file mode 100644 index 00000000000..027de617b7e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.GenericReturnObject.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='GenericReturnObject']" + [global::Android.Runtime.Register ("xamarin/test/GenericReturnObject", DoNotGenerateAcw=true)] + public partial class GenericReturnObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/GenericReturnObject", typeof (GenericReturnObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected GenericReturnObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_GenericReturn_GenericReturn_Lxamarin_test_AdapterView_; +#pragma warning disable 0169 + static Delegate GetGenericReturnHandler () + { + return cb_GenericReturn_GenericReturn_Lxamarin_test_AdapterView_ ??= new _JniMarshal_PP_L (n_GenericReturn); + } + + static IntPtr n_GenericReturn (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GenericReturn); + } + } + private static IntPtr __n_GenericReturn (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.GenericReturn ()); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='GenericReturnObject']/method[@name='GenericReturn' and count(parameter)=0]" + [Register ("GenericReturn", "()Lxamarin/test/AdapterView;", "GetGenericReturnHandler")] + public virtual unsafe global::Xamarin.Test.AdapterView GenericReturn () + { + const string __id = "GenericReturn.()Lxamarin/test/AdapterView;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.IAdapter.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.IAdapter.cs new file mode 100644 index 00000000000..374ab964fde --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.IAdapter.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='Adapter']" + [Register ("xamarin/test/Adapter", "", "Xamarin.Test.IAdapterInvoker")] + public partial interface IAdapter : IJavaObject, IJavaPeerable { + } + + [global::Android.Runtime.Register ("xamarin/test/Adapter", DoNotGenerateAcw=true)] + internal partial class IAdapterInvoker : global::Java.Lang.Object, IAdapter { + static IntPtr java_class_ref { + get { return _members_xamarin_test_Adapter.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_Adapter; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_xamarin_test_Adapter.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_xamarin_test_Adapter.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_xamarin_test_Adapter = new XAPeerMembers ("xamarin/test/Adapter", typeof (IAdapterInvoker)); + + public IAdapterInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.ISpinnerAdapter.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.ISpinnerAdapter.cs new file mode 100644 index 00000000000..18f9641ccfa --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/Xamarin.Test.ISpinnerAdapter.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='SpinnerAdapter']" + [Register ("xamarin/test/SpinnerAdapter", "", "Xamarin.Test.ISpinnerAdapterInvoker")] + public partial interface ISpinnerAdapter : global::Xamarin.Test.IAdapter { + } + + [global::Android.Runtime.Register ("xamarin/test/SpinnerAdapter", DoNotGenerateAcw=true)] + internal partial class ISpinnerAdapterInvoker : global::Java.Lang.Object, ISpinnerAdapter { + static IntPtr java_class_ref { + get { return _members_xamarin_test_SpinnerAdapter.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_SpinnerAdapter; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_xamarin_test_SpinnerAdapter.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_xamarin_test_SpinnerAdapter.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_xamarin_test_Adapter = new XAPeerMembers ("xamarin/test/Adapter", typeof (ISpinnerAdapterInvoker)); + + static readonly JniPeerMembers _members_xamarin_test_SpinnerAdapter = new XAPeerMembers ("xamarin/test/SpinnerAdapter", typeof (ISpinnerAdapterInvoker)); + + public ISpinnerAdapterInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/__NamespaceMapping__.cs new file mode 100644 index 00000000000..9b21c9bc0b7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/__NamespaceMapping__.cs @@ -0,0 +1,10 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/Adapters/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..4a45666913b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/Xamarin.Test.SomeObject.cs @@ -0,0 +1,167 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public abstract partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='backColor']" + [Register ("backColor")] + public global::Android.Graphics.Color BackColor { + get { + const string __id = "backColor.I"; + + var __v = _members.InstanceFields.GetInt32Value (__id, this); + return new global::Android.Graphics.Color (__v); + } + set { + const string __id = "backColor.I"; + + try { + _members.InstanceFields.SetValue (__id, this, value.ToArgb ()); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_getSomeColor_GetSomeColor_I; +#pragma warning disable 0169 + static Delegate GetGetSomeColorHandler () + { + return cb_getSomeColor_GetSomeColor_I ??= new _JniMarshal_PP_I (n_GetSomeColor); + } + + static int n_GetSomeColor (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetSomeColor); + } + } + private static int __n_GetSomeColor (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.SomeColor.ToArgb (); + } +#pragma warning restore 0169 + + static Delegate cb_setSomeColor_SetSomeColor_I_V; +#pragma warning disable 0169 + static Delegate GetSetSomeColor_IHandler () + { + return cb_setSomeColor_SetSomeColor_I_V ??= new _JniMarshal_PPI_V (n_SetSomeColor_I); + } + + static void n_SetSomeColor_I (IntPtr jnienv, IntPtr native__this, int native_newvalue) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_newvalue, &__n_SetSomeColor_I); + } + } + private static void __n_SetSomeColor_I (IntPtr jnienv, IntPtr native__this, int native_newvalue) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var newvalue = new global::Android.Graphics.Color (native_newvalue); + __this.SomeColor = newvalue; + } +#pragma warning restore 0169 + + public abstract global::Android.Graphics.Color SomeColor { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeColor' and count(parameter)=0]" + [Register ("getSomeColor", "()I", "GetGetSomeColorHandler")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeColor' and count(parameter)=1 and parameter[1][@type='Android.Graphics.Color']]" + [Register ("setSomeColor", "(I)V", "GetSetSomeColor_IHandler")] + set; + } + + } + + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + internal partial class SomeObjectInvoker : SomeObject { + public SomeObjectInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObjectInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + public override unsafe global::Android.Graphics.Color SomeColor { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeColor' and count(parameter)=0]" + [Register ("getSomeColor", "()I", "GetGetSomeColorHandler")] + get { + const string __id = "getSomeColor.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return new global::Android.Graphics.Color (__rm); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeColor' and count(parameter)=1 and parameter[1][@type='Android.Graphics.Color']]" + [Register ("setSomeColor", "(I)V", "GetSetSomeColor_IHandler")] + set { + const string __id = "setSomeColor.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value.ToArgb ()); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/__NamespaceMapping__.cs new file mode 100644 index 00000000000..3c8dba5128e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/__NamespaceMapping__.cs @@ -0,0 +1,10 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PP_I (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPI_V (IntPtr jnienv, IntPtr klass, int p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/Android.Graphics.Color/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..92a40e3a2c1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/Xamarin.Test.SomeObject.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myStrings']" + [Register ("myStrings")] + public IList MyStrings { + get { + const string __id = "myStrings.[Ljava/lang/String;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaArray.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myStrings.[Ljava/lang/String;"; + + IntPtr native_value = global::Android.Runtime.JavaArray.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myInts']" + [Register ("myInts")] + public IList MyInts { + get { + const string __id = "myInts.[I"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaArray.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myInts.[I"; + + IntPtr native_value = global::Android.Runtime.JavaArray.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mybools']" + [Register ("mybools")] + public IList Mybools { + get { + const string __id = "mybools.[Z"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaArray.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "mybools.[Z"; + + IntPtr native_value = global::Android.Runtime.JavaArray.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myObjects']" + [Register ("myObjects")] + public IList MyObjects { + get { + const string __id = "myObjects.[Ljava/lang/Object;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaArray.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myObjects.[Ljava/lang/Object;"; + + IntPtr native_value = global::Android.Runtime.JavaArray.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myfloats']" + [Register ("myfloats")] + public IList Myfloats { + get { + const string __id = "myfloats.[F"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaArray.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myfloats.[F"; + + IntPtr native_value = global::Android.Runtime.JavaArray.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mydoubles']" + [Register ("mydoubles")] + public IList Mydoubles { + get { + const string __id = "mydoubles.[D"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaArray.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "mydoubles.[D"; + + IntPtr native_value = global::Android.Runtime.JavaArray.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mylongs']" + [Register ("mylongs")] + public IList Mylongs { + get { + const string __id = "mylongs.[J"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaArray.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "mylongs.[J"; + + IntPtr native_value = global::Android.Runtime.JavaArray.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value); + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/__NamespaceMapping__.cs new file mode 100644 index 00000000000..549748329a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/__NamespaceMapping__.cs @@ -0,0 +1,4 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/Arrays/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/CSharpKeywords.xml b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/CSharpKeywords.xml new file mode 100644 index 00000000000..52d6f43cd55 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/CSharpKeywords.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Java.Lang.Throwable.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Java.Lang.Throwable.cs new file mode 100644 index 00000000000..311c44de33b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Java.Lang.Throwable.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Throwable']" + [global::Android.Runtime.Register ("java/lang/Throwable", DoNotGenerateAcw=true)] + public partial class Throwable { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Throwable", typeof (Throwable)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + static Delegate cb_getMessage_GetMessage_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetGetMessageHandler () + { + return cb_getMessage_GetMessage_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_GetMessage); + } + + static IntPtr n_GetMessage (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetMessage); + } + } + private static IntPtr __n_GetMessage (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Message); + } +#pragma warning restore 0169 + + public new virtual unsafe string Message { + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/class[@name='Throwable']/method[@name='getMessage' and count(parameter)=0]" + [Register ("getMessage", "()Ljava/lang/String;", "GetGetMessageHandler")] + get { + const string __id = "getMessage.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Mono.Android.projitems new file mode 100644 index 00000000000..449fda2e99c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Mono.Android.projitems @@ -0,0 +1,15 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Xamarin.Test.CSharpKeywords.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Xamarin.Test.CSharpKeywords.cs new file mode 100644 index 00000000000..c7d2c3aaba7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/Xamarin.Test.CSharpKeywords.cs @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='CSharpKeywords']" + [global::Android.Runtime.Register ("xamarin/test/CSharpKeywords", DoNotGenerateAcw=true)] + public partial class CSharpKeywords : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/CSharpKeywords", typeof (CSharpKeywords)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected CSharpKeywords (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_usePartial_UsePartial_I_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetUsePartial_IHandler () + { + return cb_usePartial_UsePartial_I_Ljava_lang_String_ ??= new _JniMarshal_PPI_L (n_UsePartial_I); + } + + static IntPtr n_UsePartial_I (IntPtr jnienv, IntPtr native__this, int partial) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, partial, &__n_UsePartial_I); + } + } + private static IntPtr __n_UsePartial_I (IntPtr jnienv, IntPtr native__this, int partial) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.UsePartial (partial)); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='CSharpKeywords']/method[@name='usePartial' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("usePartial", "(I)Ljava/lang/String;", "GetUsePartial_IHandler")] + public virtual unsafe string UsePartial (int partial) + { + const string __id = "usePartial.(I)Ljava/lang/String;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (partial); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='CSharpKeywords']/method[@name='useThis' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("useThis", "(Ljava/lang/String;)Ljava/lang/String;", "")] + public static unsafe string UseThis (string this_) + { + const string __id = "useThis.(Ljava/lang/String;)Ljava/lang/String;"; + IntPtr native_this = JNIEnv.NewString ((string)this_); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_this); + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, __args); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + JNIEnv.DeleteLocalRef (native_this); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/__NamespaceMapping__.cs new file mode 100644 index 00000000000..77617daa227 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/__NamespaceMapping__.cs @@ -0,0 +1,10 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PPI_L (IntPtr jnienv, IntPtr klass, int p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/CSharpKeywords/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Mono.Android.projitems new file mode 100644 index 00000000000..5f74b81c012 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Mono.Android.projitems @@ -0,0 +1,15 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..a5d4dd041e8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Xamarin.Test.SomeObject.cs @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/constructor[@name='SomeObject' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + [global::System.Obsolete (@"deprecated")] + public unsafe SomeObject () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/constructor[@name='SomeObject' and count(parameter)=1 and parameter[1][@type='int']]" + [Register (".ctor", "(I)V", "")] + public unsafe SomeObject (int aint) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(I)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (aint); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Xamarin.Test.SomeObject2.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Xamarin.Test.SomeObject2.cs new file mode 100644 index 00000000000..b8bbda396cd --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/Xamarin.Test.SomeObject2.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject2", DoNotGenerateAcw=true)] + public sealed partial class SomeObject2 : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject2", typeof (SomeObject2)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + internal SomeObject2 (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']/constructor[@name='SomeObject2' and count(parameter)=1 and parameter[1][@type='int']]" + [Register (".ctor", "(I)V", "")] + public unsafe SomeObject2 (int aint) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(I)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (aint); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/__NamespaceMapping__.cs new file mode 100644 index 00000000000..549748329a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/__NamespaceMapping__.cs @@ -0,0 +1,4 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/Constructors/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Java.Lang.String.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Java.Lang.String.cs new file mode 100644 index 00000000000..ddbc5d2734c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Java.Lang.String.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='String']" + [global::Android.Runtime.Register ("java/lang/String", DoNotGenerateAcw=true)] + public partial class String : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/String", typeof (String)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected String (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Mono.Android.projitems new file mode 100644 index 00000000000..ea168730bb7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Mono.Android.projitems @@ -0,0 +1,17 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Google.Composable.MyClass.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Google.Composable.MyClass.cs new file mode 100644 index 00000000000..67d3c554b0e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Google.Composable.MyClass.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Google.Composable { + + // Metadata.xml XPath class reference: path="/api/package[@name='com.com.google.compose']/class[@name='MyClass']" + [global::Android.Runtime.Register ("com/com/google/compose/MyClass", DoNotGenerateAcw=true)] + public partial class MyClass : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/com/google/compose/MyClass", typeof (MyClass)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Test.Invalidnames.In.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Test.Invalidnames.In.cs new file mode 100644 index 00000000000..f1f70a0ba3b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Test.Invalidnames.In.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test.Invalidnames { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test.invalidnames']/class[@name='in']" + [global::Android.Runtime.Register ("xamarin/test/invalidnames/in", DoNotGenerateAcw=true)] + public partial class In : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/invalidnames/in", typeof (In)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected In (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Test.Invalidnames.InvalidNameMembers.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Test.Invalidnames.InvalidNameMembers.cs new file mode 100644 index 00000000000..e62398fc240 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/Xamarin.Test.Invalidnames.InvalidNameMembers.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test.Invalidnames { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test.invalidnames']/class[@name='InvalidNameMembers']" + [global::Android.Runtime.Register ("xamarin/test/invalidnames/InvalidNameMembers", DoNotGenerateAcw=true)] + public partial class InvalidNameMembers : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/invalidnames/InvalidNameMembers", typeof (InvalidNameMembers)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected InvalidNameMembers (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/__NamespaceMapping__.cs new file mode 100644 index 00000000000..5642c5ff9df --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/__NamespaceMapping__.cs @@ -0,0 +1,5 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test.invalidnames", Managed="Xamarin.Test.Invalidnames")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "com.com.google.compose", Managed="Xamarin.Google.Composable")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_ClassParse/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.ISpannable.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.ISpannable.cs new file mode 100644 index 00000000000..3ac495bb5c7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.ISpannable.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath interface reference: path="/api/package[@name='android.text']/interface[@name='Spannable']" + [Register ("android/text/Spannable", "", "Android.Text.ISpannableInvoker")] + public partial interface ISpannable : global::Android.Text.ISpanned { + } + + [global::Android.Runtime.Register ("android/text/Spannable", DoNotGenerateAcw=true)] + internal partial class ISpannableInvoker : global::Java.Lang.Object, ISpannable { + static IntPtr java_class_ref { + get { return _members_android_text_Spannable.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_android_text_Spannable; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_android_text_Spannable.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_android_text_Spannable.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_android_text_Spannable = new XAPeerMembers ("android/text/Spannable", typeof (ISpannableInvoker)); + + static readonly JniPeerMembers _members_android_text_Spanned = new XAPeerMembers ("android/text/Spanned", typeof (ISpannableInvoker)); + + public ISpannableInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I; +#pragma warning disable 0169 + static Delegate GetGetSpanFlags_Ljava_lang_Object_Handler () + { + return cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I ??= new _JniMarshal_PPL_I (n_GetSpanFlags_Ljava_lang_Object_); + } + + static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_tag, &__n_GetSpanFlags_Ljava_lang_Object_); + } + } + private static int __n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var tag = global::Java.Lang.Object.GetObject (native_tag, JniHandleOwnership.DoNotTransfer); + int __ret = (int) __this.GetSpanFlags (tag); + return __ret; + } +#pragma warning restore 0169 + + public unsafe global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object tag) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((tag == null) ? IntPtr.Zero : ((global::Java.Lang.Object) tag).Handle); + var __rm = _members_android_text_Spanned.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return (global::Android.Text.SpanTypes) __rm; + } finally { + global::System.GC.KeepAlive (tag); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.ISpanned.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.ISpanned.cs new file mode 100644 index 00000000000..37abfa63214 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.ISpanned.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath interface reference: path="/api/package[@name='android.text']/interface[@name='Spanned']" + [Register ("android/text/Spanned", "", "Android.Text.ISpannedInvoker")] + public partial interface ISpanned : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='android.text']/interface[@name='Spanned']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [return:global::Android.Runtime.GeneratedEnum] + [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler:Android.Text.ISpannedInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object tag); + + } + + [global::Android.Runtime.Register ("android/text/Spanned", DoNotGenerateAcw=true)] + internal partial class ISpannedInvoker : global::Java.Lang.Object, ISpanned { + static IntPtr java_class_ref { + get { return _members_android_text_Spanned.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_android_text_Spanned; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_android_text_Spanned.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_android_text_Spanned.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_android_text_Spanned = new XAPeerMembers ("android/text/Spanned", typeof (ISpannedInvoker)); + + public ISpannedInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I; +#pragma warning disable 0169 + static Delegate GetGetSpanFlags_Ljava_lang_Object_Handler () + { + return cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I ??= new _JniMarshal_PPL_I (n_GetSpanFlags_Ljava_lang_Object_); + } + + static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_tag, &__n_GetSpanFlags_Ljava_lang_Object_); + } + } + private static int __n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var tag = global::Java.Lang.Object.GetObject (native_tag, JniHandleOwnership.DoNotTransfer); + int __ret = (int) __this.GetSpanFlags (tag); + return __ret; + } +#pragma warning restore 0169 + + public unsafe global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object tag) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((tag == null) ? IntPtr.Zero : ((global::Java.Lang.Object) tag).Handle); + var __rm = _members_android_text_Spanned.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return (global::Android.Text.SpanTypes) __rm; + } finally { + global::System.GC.KeepAlive (tag); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.SpannableString.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.SpannableString.cs new file mode 100644 index 00000000000..f101c2f3c6c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.SpannableString.cs @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath class reference: path="/api/package[@name='android.text']/class[@name='SpannableString']" + [global::Android.Runtime.Register ("android/text/SpannableString", DoNotGenerateAcw=true)] + public partial class SpannableString : global::Android.Text.SpannableStringInternal, global::Android.Text.ISpannable { + static readonly JniPeerMembers _members = new XAPeerMembers ("android/text/SpannableString", typeof (SpannableString)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SpannableString (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='android.text']/class[@name='SpannableString']/constructor[@name='SpannableString' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + public unsafe SpannableString (global::Java.Lang.ICharSequence source) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_source = CharSequence.ToLocalJniHandle (source); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_source); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_source); + global::System.GC.KeepAlive (source); + } + } + + [Register (".ctor", "(Ljava/lang/CharSequence;)V", "")] + public unsafe SpannableString (string source) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(Ljava/lang/CharSequence;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native_source = CharSequence.ToLocalJniHandle (source); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_source); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_source); + global::System.GC.KeepAlive (source); + } + } + + static Delegate cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I; +#pragma warning disable 0169 + static Delegate GetGetSpanFlags_Ljava_lang_Object_Handler () + { + return cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I ??= new _JniMarshal_PPL_I (n_GetSpanFlags_Ljava_lang_Object_); + } + + static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_what) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_what, &__n_GetSpanFlags_Ljava_lang_Object_); + } + } + private static int __n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_what) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var what = global::Java.Lang.Object.GetObject (native_what, JniHandleOwnership.DoNotTransfer); + int __ret = (int) __this.GetSpanFlags (what); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='android.text']/class[@name='SpannableString']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler")] + public override unsafe global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object what) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((what == null) ? IntPtr.Zero : ((global::Java.Lang.Object) what).Handle); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return (global::Android.Text.SpanTypes) __rm; + } finally { + global::System.GC.KeepAlive (what); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.SpannableStringInternal.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.SpannableStringInternal.cs new file mode 100644 index 00000000000..0985ee1b062 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Text.SpannableStringInternal.cs @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Android.Text { + + // Metadata.xml XPath class reference: path="/api/package[@name='android.text']/class[@name='SpannableStringInternal']" + [global::Android.Runtime.Register ("android/text/SpannableStringInternal", DoNotGenerateAcw=true)] + public abstract partial class SpannableStringInternal : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("android/text/SpannableStringInternal", typeof (SpannableStringInternal)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SpannableStringInternal (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I; +#pragma warning disable 0169 + static Delegate GetGetSpanFlags_Ljava_lang_Object_Handler () + { + return cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I ??= new _JniMarshal_PPL_I (n_GetSpanFlags_Ljava_lang_Object_); + } + + static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_p0, &__n_GetSpanFlags_Ljava_lang_Object_); + } + } + private static int __n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var p0 = global::Java.Lang.Object.GetObject (native_p0, JniHandleOwnership.DoNotTransfer); + int __ret = (int) __this.GetSpanFlags (p0); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='android.text']/class[@name='SpannableStringInternal']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [return:global::Android.Runtime.GeneratedEnum] + [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler")] + public virtual unsafe global::Android.Text.SpanTypes GetSpanFlags (global::Java.Lang.Object p0) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((p0 == null) ? IntPtr.Zero : ((global::Java.Lang.Object) p0).Handle); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return (global::Android.Text.SpanTypes) __rm; + } finally { + global::System.GC.KeepAlive (p0); + } + } + + } + + [global::Android.Runtime.Register ("android/text/SpannableStringInternal", DoNotGenerateAcw=true)] + internal partial class SpannableStringInternalInvoker : SpannableStringInternal { + public SpannableStringInternalInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("android/text/SpannableStringInternal", typeof (SpannableStringInternalInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Views.View.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Views.View.cs new file mode 100644 index 00000000000..3a1c6b7f821 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Android.Views.View.cs @@ -0,0 +1,289 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Android.Views { + + // Metadata.xml XPath class reference: path="/api/package[@name='android.view']/class[@name='View']" + [global::Android.Runtime.Register ("android/view/View", DoNotGenerateAcw=true)] + public partial class View : global::Java.Lang.Object { + // Metadata.xml XPath interface reference: path="/api/package[@name='android.view']/interface[@name='View.OnClickListener']" + [Register ("android/view/View$OnClickListener", "", "Android.Views.View/IOnClickListenerInvoker")] + public partial interface IOnClickListener : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/interface[@name='View.OnClickListener']/method[@name='onClick' and count(parameter)=1 and parameter[1][@type='android.view.View']]" + [Register ("onClick", "(Landroid/view/View;)V", "GetOnClick_Landroid_view_View_Handler:Android.Views.View/IOnClickListenerInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void OnClick (global::Android.Views.View v); + + } + + [global::Android.Runtime.Register ("android/view/View$OnClickListener", DoNotGenerateAcw=true)] + internal partial class IOnClickListenerInvoker : global::Java.Lang.Object, IOnClickListener { + static IntPtr java_class_ref { + get { return _members_android_view_View_OnClickListener.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_android_view_View_OnClickListener; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_android_view_View_OnClickListener.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_android_view_View_OnClickListener.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_android_view_View_OnClickListener = new XAPeerMembers ("android/view/View$OnClickListener", typeof (IOnClickListenerInvoker)); + + public IOnClickListenerInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_onClick_OnClick_Landroid_view_View__V; +#pragma warning disable 0169 + static Delegate GetOnClick_Landroid_view_View_Handler () + { + return cb_onClick_OnClick_Landroid_view_View__V ??= new _JniMarshal_PPL_V (n_OnClick_Landroid_view_View_); + } + + static void n_OnClick_Landroid_view_View_ (IntPtr jnienv, IntPtr native__this, IntPtr native_v) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_v, &__n_OnClick_Landroid_view_View_); + } + } + private static void __n_OnClick_Landroid_view_View_ (IntPtr jnienv, IntPtr native__this, IntPtr native_v) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var v = global::Java.Lang.Object.GetObject (native_v, JniHandleOwnership.DoNotTransfer); + __this.OnClick (v); + } +#pragma warning restore 0169 + + public unsafe void OnClick (global::Android.Views.View v) + { + const string __id = "onClick.(Landroid/view/View;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((v == null) ? IntPtr.Zero : ((global::Java.Lang.Object) v).Handle); + _members_android_view_View_OnClickListener.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (v); + } + } + + } + + [global::Android.Runtime.Register ("mono/android/view/View_OnClickListenerImplementor")] + internal sealed partial class IOnClickListenerImplementor : global::Java.Lang.Object, IOnClickListener { + public unsafe IOnClickListenerImplementor () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + var h = JniPeerMembers.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (h.Handle, JniHandleOwnership.TransferLocalRef); + JniPeerMembers.InstanceMethods.FinishCreateInstance (__id, this, null); + } + + #pragma warning disable 0649 + public EventHandler Handler; + #pragma warning restore 0649 + + public void OnClick (global::Android.Views.View v) + { + var __h = Handler; + if (__h != null) + __h (v, new EventArgs ()); + } + + internal static bool __IsEmpty (IOnClickListenerImplementor value) + { + return value.Handler == null; + } + + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("android/view/View", typeof (View)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected View (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_setOnClickListener_SetOnClickListener_Landroid_view_View_OnClickListener__V; +#pragma warning disable 0169 + static Delegate GetSetOnClickListener_Landroid_view_View_OnClickListener_Handler () + { + return cb_setOnClickListener_SetOnClickListener_Landroid_view_View_OnClickListener__V ??= new _JniMarshal_PPL_V (n_SetOnClickListener_Landroid_view_View_OnClickListener_); + } + + static void n_SetOnClickListener_Landroid_view_View_OnClickListener_ (IntPtr jnienv, IntPtr native__this, IntPtr native_l) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_l, &__n_SetOnClickListener_Landroid_view_View_OnClickListener_); + } + } + private static void __n_SetOnClickListener_Landroid_view_View_OnClickListener_ (IntPtr jnienv, IntPtr native__this, IntPtr native_l) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var l = (global::Android.Views.View.IOnClickListener)global::Java.Lang.Object.GetObject (native_l, JniHandleOwnership.DoNotTransfer); + __this.SetOnClickListener (l); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/class[@name='View']/method[@name='setOnClickListener' and count(parameter)=1 and parameter[1][@type='android.view.View.OnClickListener']]" + [Register ("setOnClickListener", "(Landroid/view/View$OnClickListener;)V", "GetSetOnClickListener_Landroid_view_View_OnClickListener_Handler")] + public virtual unsafe void SetOnClickListener (global::Android.Views.View.IOnClickListener l) + { + const string __id = "setOnClickListener.(Landroid/view/View$OnClickListener;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((l == null) ? IntPtr.Zero : ((global::Java.Lang.Object) l).Handle); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (l); + } + } + + static Delegate cb_setOn123Listener_SetOn123Listener_Landroid_view_View_OnClickListener__V; +#pragma warning disable 0169 + static Delegate GetSetOn123Listener_Landroid_view_View_OnClickListener_Handler () + { + return cb_setOn123Listener_SetOn123Listener_Landroid_view_View_OnClickListener__V ??= new _JniMarshal_PPL_V (n_SetOn123Listener_Landroid_view_View_OnClickListener_); + } + + static void n_SetOn123Listener_Landroid_view_View_OnClickListener_ (IntPtr jnienv, IntPtr native__this, IntPtr native_l) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_l, &__n_SetOn123Listener_Landroid_view_View_OnClickListener_); + } + } + private static void __n_SetOn123Listener_Landroid_view_View_OnClickListener_ (IntPtr jnienv, IntPtr native__this, IntPtr native_l) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var l = (global::Android.Views.View.IOnClickListener)global::Java.Lang.Object.GetObject (native_l, JniHandleOwnership.DoNotTransfer); + __this.SetOn123Listener (l); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/class[@name='View']/method[@name='setOn123Listener' and count(parameter)=1 and parameter[1][@type='android.view.View.OnClickListener']]" + [Register ("setOn123Listener", "(Landroid/view/View$OnClickListener;)V", "GetSetOn123Listener_Landroid_view_View_OnClickListener_Handler")] + public virtual unsafe void SetOn123Listener (global::Android.Views.View.IOnClickListener l) + { + const string __id = "setOn123Listener.(Landroid/view/View$OnClickListener;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((l == null) ? IntPtr.Zero : ((global::Java.Lang.Object) l).Handle); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (l); + } + } + + static Delegate cb_addTouchables_AddTouchables_Ljava_util_ArrayList__V; +#pragma warning disable 0169 + static Delegate GetAddTouchables_Ljava_util_ArrayList_Handler () + { + return cb_addTouchables_AddTouchables_Ljava_util_ArrayList__V ??= new _JniMarshal_PPL_V (n_AddTouchables_Ljava_util_ArrayList_); + } + + static void n_AddTouchables_Ljava_util_ArrayList_ (IntPtr jnienv, IntPtr native__this, IntPtr native_views) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_views, &__n_AddTouchables_Ljava_util_ArrayList_); + } + } + private static void __n_AddTouchables_Ljava_util_ArrayList_ (IntPtr jnienv, IntPtr native__this, IntPtr native_views) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var views = global::Android.Runtime.JavaList.FromJniHandle (native_views, JniHandleOwnership.DoNotTransfer); + __this.AddTouchables (views); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='android.view']/class[@name='View']/method[@name='addTouchables' and count(parameter)=1 and parameter[1][@type='java.util.ArrayList<android.view.View>']]" + [Register ("addTouchables", "(Ljava/util/ArrayList;)V", "GetAddTouchables_Ljava_util_ArrayList_Handler")] + public virtual unsafe void AddTouchables (global::System.Collections.Generic.IList views) + { + const string __id = "addTouchables.(Ljava/util/ArrayList;)V"; + IntPtr native_views = global::Android.Runtime.JavaList.ToLocalJniHandle (views); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_views); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_views); + global::System.GC.KeepAlive (views); + } + } + + #region "Event implementation for Android.Views.View.IOnClickListener" + + public event EventHandler Click { + add { + global::Java.Interop.EventHelper.AddEventHandler( + ref weak_implementor_SetOnClickListener, + __CreateIOnClickListenerImplementor, + SetOnClickListener, + __h => __h.Handler += value); + } + remove { + global::Java.Interop.EventHelper.RemoveEventHandler( + ref weak_implementor_SetOnClickListener, + global::Android.Views.View.IOnClickListenerImplementor.__IsEmpty, + __v => SetOnClickListener (null), + __h => __h.Handler -= value); + } + } + + WeakReference weak_implementor_SetOnClickListener; + + global::Android.Views.View.IOnClickListenerImplementor __CreateIOnClickListenerImplementor () + { + return new global::Android.Views.View.IOnClickListenerImplementor (); + } + + #endregion + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Mono.Android.projitems new file mode 100644 index 00000000000..0bd3f3343a4 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/Mono.Android.projitems @@ -0,0 +1,20 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/__NamespaceMapping__.cs new file mode 100644 index 00000000000..4077cbc3a75 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/__NamespaceMapping__.cs @@ -0,0 +1,11 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "android.view", Managed="Android.Views")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "android.text", Managed="Android.Text")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PPL_I (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/Core_Jar2Xml/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaCrypto.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaCrypto.cs new file mode 100644 index 00000000000..e3268911c23 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaCrypto.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Com.Google.Android.Exoplayer.Drm { + + // Metadata.xml XPath class reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaCrypto']" + [global::Android.Runtime.Register ("com/google/android/exoplayer/drm/FrameworkMediaCrypto", DoNotGenerateAcw=true)] + public sealed partial class FrameworkMediaCrypto : global::Java.Lang.Object, global::Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/google/android/exoplayer/drm/FrameworkMediaCrypto", typeof (FrameworkMediaCrypto)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + internal FrameworkMediaCrypto (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaCrypto']/constructor[@name='FrameworkMediaCrypto' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe FrameworkMediaCrypto () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaCrypto']/method[@name='requiresSecureDecoderComponent' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("requiresSecureDecoderComponent", "(Ljava/lang/String;)Z", "")] + public unsafe bool RequiresSecureDecoderComponent (string p0) + { + const string __id = "requiresSecureDecoderComponent.(Ljava/lang/String;)Z"; + IntPtr native_p0 = JNIEnv.NewString ((string)p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __rm = _members.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_p0); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaDrm.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaDrm.cs new file mode 100644 index 00000000000..4e00d036000 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.FrameworkMediaDrm.cs @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Com.Google.Android.Exoplayer.Drm { + + // Metadata.xml XPath class reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaDrm']" + [global::Android.Runtime.Register ("com/google/android/exoplayer/drm/FrameworkMediaDrm", DoNotGenerateAcw=true)] + public sealed partial class FrameworkMediaDrm : global::Java.Lang.Object, global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm { + static readonly JniPeerMembers _members = new XAPeerMembers ("com/google/android/exoplayer/drm/FrameworkMediaDrm", typeof (FrameworkMediaDrm)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + internal FrameworkMediaDrm (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaDrm']/constructor[@name='FrameworkMediaDrm' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe FrameworkMediaDrm () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/class[@name='FrameworkMediaDrm']/method[@name='setOnEventListener' and count(parameter)=1 and parameter[1][@type='com.google.android.exoplayer.drm.ExoMediaDrm.OnEventListener<com.google.android.exoplayer.drm.FrameworkMediaCrypto>']]" + [Register ("setOnEventListener", "(Lcom/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener;)V", "")] + public unsafe void SetOnEventListener (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener p0) + { + const string __id = "setOnEventListener.(Lcom/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((p0 == null) ? IntPtr.Zero : ((global::Java.Lang.Object) p0).Handle); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (p0); + } + } + + // This method is explicitly implemented as a member of an instantiated Com.Google.Android.Exoplayer.Drm.IExoMediaDrm + void global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.SetOnEventListener (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener p0) + { + SetOnEventListener (global::Java.Interop.JavaObjectExtensions.JavaCast(p0)); + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto.cs new file mode 100644 index 00000000000..21f300fe034 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Com.Google.Android.Exoplayer.Drm { + + // Metadata.xml XPath interface reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaCrypto']" + [Register ("com/google/android/exoplayer/drm/ExoMediaCrypto", "", "Com.Google.Android.Exoplayer.Drm.IExoMediaCryptoInvoker")] + public partial interface IExoMediaCrypto : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaCrypto']/method[@name='requiresSecureDecoderComponent' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("requiresSecureDecoderComponent", "(Ljava/lang/String;)Z", "GetRequiresSecureDecoderComponent_Ljava_lang_String_Handler:Com.Google.Android.Exoplayer.Drm.IExoMediaCryptoInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + bool RequiresSecureDecoderComponent (string p0); + + } + + [global::Android.Runtime.Register ("com/google/android/exoplayer/drm/ExoMediaCrypto", DoNotGenerateAcw=true)] + internal partial class IExoMediaCryptoInvoker : global::Java.Lang.Object, IExoMediaCrypto { + static IntPtr java_class_ref { + get { return _members_com_google_android_exoplayer_drm_ExoMediaCrypto.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_com_google_android_exoplayer_drm_ExoMediaCrypto; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_com_google_android_exoplayer_drm_ExoMediaCrypto.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_com_google_android_exoplayer_drm_ExoMediaCrypto.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_com_google_android_exoplayer_drm_ExoMediaCrypto = new XAPeerMembers ("com/google/android/exoplayer/drm/ExoMediaCrypto", typeof (IExoMediaCryptoInvoker)); + + public IExoMediaCryptoInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_requiresSecureDecoderComponent_RequiresSecureDecoderComponent_Ljava_lang_String__Z; +#pragma warning disable 0169 + static Delegate GetRequiresSecureDecoderComponent_Ljava_lang_String_Handler () + { + return cb_requiresSecureDecoderComponent_RequiresSecureDecoderComponent_Ljava_lang_String__Z ??= new _JniMarshal_PPL_B (n_RequiresSecureDecoderComponent_Ljava_lang_String_); + } + + static sbyte n_RequiresSecureDecoderComponent_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_p0, &__n_RequiresSecureDecoderComponent_Ljava_lang_String_); + } + } + private static sbyte __n_RequiresSecureDecoderComponent_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var p0 = JNIEnv.GetString (native_p0, JniHandleOwnership.DoNotTransfer); + sbyte __ret = __this.RequiresSecureDecoderComponent (p0) ? (sbyte)1 : (sbyte)0; + return __ret; + } +#pragma warning restore 0169 + + public unsafe bool RequiresSecureDecoderComponent (string p0) + { + const string __id = "requiresSecureDecoderComponent.(Ljava/lang/String;)Z"; + IntPtr native_p0 = JNIEnv.NewString ((string)p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + var __rm = _members_com_google_android_exoplayer_drm_ExoMediaCrypto.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_p0); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.cs new file mode 100644 index 00000000000..e5e00d5f16b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Com.Google.Android.Exoplayer.Drm { + + // Metadata.xml XPath interface reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm.OnEventListener']" + [Register ("com/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener", "", "Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListenerInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends com.google.android.exoplayer.drm.ExoMediaCrypto"})] + public partial interface IExoMediaDrmOnEventListener : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm.OnEventListener']/method[@name='onEvent' and count(parameter)=5 and parameter[1][@type='com.google.android.exoplayer.drm.ExoMediaDrm<T>'] and parameter[2][@type='byte[]'] and parameter[3][@type='int'] and parameter[4][@type='int'] and parameter[5][@type='byte[]']]" + [Register ("onEvent", "(Lcom/google/android/exoplayer/drm/ExoMediaDrm;[BII[B)V", "GetOnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayBHandler:Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListenerInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void OnEvent (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, byte[] p1, int p2, int p3, byte[] p4); + + } + + [global::Android.Runtime.Register ("com/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener", DoNotGenerateAcw=true)] + internal partial class IExoMediaDrmOnEventListenerInvoker : global::Java.Lang.Object, IExoMediaDrmOnEventListener { + static IntPtr java_class_ref { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_com_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener = new XAPeerMembers ("com/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener", typeof (IExoMediaDrmOnEventListenerInvoker)); + + public IExoMediaDrmOnEventListenerInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_onEvent_OnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayB_V; +#pragma warning disable 0169 + static Delegate GetOnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayBHandler () + { + return cb_onEvent_OnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayB_V ??= new _JniMarshal_PPLLIIL_V (n_OnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayB); + } + + static void n_OnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_p0, IntPtr native_p1, int p2, int p3, IntPtr native_p4) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_p0, native_p1, p2, p3, native_p4, &__n_OnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayB); + } + } + private static void __n_OnEvent_Lcom_google_android_exoplayer_drm_ExoMediaDrm_arrayBIIarrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_p0, IntPtr native_p1, int p2, int p3, IntPtr native_p4) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var p0 = (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm)global::Java.Lang.Object.GetObject (native_p0, JniHandleOwnership.DoNotTransfer); + var p1 = (byte[]) JNIEnv.GetArray (native_p1, JniHandleOwnership.DoNotTransfer, typeof (byte)); + var p4 = (byte[]) JNIEnv.GetArray (native_p4, JniHandleOwnership.DoNotTransfer, typeof (byte)); + __this.OnEvent (p0, p1, p2, p3, p4); + if (p1 != null) + JNIEnv.CopyArray (p1, native_p1); + if (p4 != null) + JNIEnv.CopyArray (p4, native_p4); + } +#pragma warning restore 0169 + + public unsafe void OnEvent (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, byte[] p1, int p2, int p3, byte[] p4) + { + const string __id = "onEvent.(Lcom/google/android/exoplayer/drm/ExoMediaDrm;[BII[B)V"; + IntPtr native_p1 = JNIEnv.NewArray (p1); + IntPtr native_p4 = JNIEnv.NewArray (p4); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [5]; + __args [0] = new JniArgumentValue ((p0 == null) ? IntPtr.Zero : ((global::Java.Lang.Object) p0).Handle); + __args [1] = new JniArgumentValue (native_p1); + __args [2] = new JniArgumentValue (p2); + __args [3] = new JniArgumentValue (p3); + __args [4] = new JniArgumentValue (native_p4); + _members_com_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (p1 != null) { + JNIEnv.CopyArray (native_p1, p1); + JNIEnv.DeleteLocalRef (native_p1); + } + if (p4 != null) { + JNIEnv.CopyArray (native_p4, p4); + JNIEnv.DeleteLocalRef (native_p4); + } + global::System.GC.KeepAlive (p0); + global::System.GC.KeepAlive (p1); + global::System.GC.KeepAlive (p4); + } + } + + } + + // event args for com.google.android.exoplayer.drm.ExoMediaDrm.OnEventListener.onEvent + public partial class ExoMediaDrmOnEventEventArgs : global::System.EventArgs { + public ExoMediaDrmOnEventEventArgs (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, byte[] p1, int p2, int p3, byte[] p4) + { + this.p0 = p0; + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + this.p4 = p4; + } + + global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0; + + public global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm P0 { + get { return p0; } + } + + byte[] p1; + + public byte[] P1 { + get { return p1; } + } + + int p2; + + public int P2 { + get { return p2; } + } + + int p3; + + public int P3 { + get { return p3; } + } + + byte[] p4; + + public byte[] P4 { + get { return p4; } + } + + } + + [global::Android.Runtime.Register ("mono/com/google/android/exoplayer/drm/ExoMediaDrm_OnEventListenerImplementor")] + internal sealed partial class IExoMediaDrmOnEventListenerImplementor : global::Java.Lang.Object, IExoMediaDrmOnEventListener { + + object sender; + + public unsafe IExoMediaDrmOnEventListenerImplementor (object sender) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + var h = JniPeerMembers.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (h.Handle, JniHandleOwnership.TransferLocalRef); + JniPeerMembers.InstanceMethods.FinishCreateInstance (__id, this, null); + this.sender = sender; + } + + #pragma warning disable 0649 + public EventHandler Handler; + #pragma warning restore 0649 + + public void OnEvent (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, byte[] p1, int p2, int p3, byte[] p4) + { + var __h = Handler; + if (__h != null) + __h (sender, new ExoMediaDrmOnEventEventArgs (p0, p1, p2, p3, p4)); + } + + internal static bool __IsEmpty (IExoMediaDrmOnEventListenerImplementor value) + { + return value.Handler == null; + } + + } + + // Metadata.xml XPath interface reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm']" + [Register ("com/google/android/exoplayer/drm/ExoMediaDrm", "", "Com.Google.Android.Exoplayer.Drm.IExoMediaDrmInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends com.google.android.exoplayer.drm.ExoMediaCrypto"})] + public partial interface IExoMediaDrm : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='com.google.android.exoplayer.drm']/interface[@name='ExoMediaDrm']/method[@name='setOnEventListener' and count(parameter)=1 and parameter[1][@type='com.google.android.exoplayer.drm.ExoMediaDrm.OnEventListener<T>']]" + [Register ("setOnEventListener", "(Lcom/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener;)V", "GetSetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener_Handler:Com.Google.Android.Exoplayer.Drm.IExoMediaDrmInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void SetOnEventListener (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener p0); + + } + + [global::Android.Runtime.Register ("com/google/android/exoplayer/drm/ExoMediaDrm", DoNotGenerateAcw=true)] + internal partial class IExoMediaDrmInvoker : global::Java.Lang.Object, IExoMediaDrm { + static IntPtr java_class_ref { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_com_google_android_exoplayer_drm_ExoMediaDrm.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_com_google_android_exoplayer_drm_ExoMediaDrm = new XAPeerMembers ("com/google/android/exoplayer/drm/ExoMediaDrm", typeof (IExoMediaDrmInvoker)); + + public IExoMediaDrmInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_setOnEventListener_SetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener__V; +#pragma warning disable 0169 + static Delegate GetSetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener_Handler () + { + return cb_setOnEventListener_SetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener__V ??= new _JniMarshal_PPL_V (n_SetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener_); + } + + static void n_SetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_p0, &__n_SetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener_); + } + } + private static void __n_SetOnEventListener_Lcom_google_android_exoplayer_drm_ExoMediaDrm_OnEventListener_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var p0 = (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener)global::Java.Lang.Object.GetObject (native_p0, JniHandleOwnership.DoNotTransfer); + __this.SetOnEventListener (p0); + } +#pragma warning restore 0169 + + public unsafe void SetOnEventListener (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrmOnEventListener p0) + { + const string __id = "setOnEventListener.(Lcom/google/android/exoplayer/drm/ExoMediaDrm$OnEventListener;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((p0 == null) ? IntPtr.Zero : ((global::Java.Lang.Object) p0).Handle); + _members_com_google_android_exoplayer_drm_ExoMediaDrm.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (p0); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/GenericArguments.xml b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/GenericArguments.xml new file mode 100644 index 00000000000..f9387a080e7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/GenericArguments.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Mono.Android.projitems new file mode 100644 index 00000000000..6270ae72799 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/Mono.Android.projitems @@ -0,0 +1,17 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/__NamespaceMapping__.cs new file mode 100644 index 00000000000..9d289a020ef --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/__NamespaceMapping__.cs @@ -0,0 +1,12 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "com.google.android.exoplayer.drm", Managed="Com.Google.Android.Exoplayer.Drm")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate sbyte _JniMarshal_PPL_B (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPLLIIL_V (IntPtr jnienv, IntPtr klass, IntPtr p0, IntPtr p1, int p2, int p3, IntPtr p4); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/GenericArguments/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/InterfaceMethodsConflict.xml b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/InterfaceMethodsConflict.xml new file mode 100644 index 00000000000..703f91b2476 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/InterfaceMethodsConflict.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Mono.Android.projitems new file mode 100644 index 00000000000..a57b6da5dc2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Mono.Android.projitems @@ -0,0 +1,17 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.II1.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.II1.cs new file mode 100644 index 00000000000..57cfad2d233 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.II1.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']" + [Register ("xamarin/test/I1", "", "Xamarin.Test.II1Invoker")] + public partial interface II1 : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']/method[@name='close' and count(parameter)=0]" + [Register ("close", "()V", "GetCloseHandler:Xamarin.Test.II1Invoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Close (); + + } + + [global::Android.Runtime.Register ("xamarin/test/I1", DoNotGenerateAcw=true)] + internal partial class II1Invoker : global::Java.Lang.Object, II1 { + static IntPtr java_class_ref { + get { return _members_xamarin_test_I1.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_I1; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_xamarin_test_I1.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_xamarin_test_I1.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_xamarin_test_I1 = new XAPeerMembers ("xamarin/test/I1", typeof (II1Invoker)); + + public II1Invoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_close_Close_V; +#pragma warning disable 0169 + static Delegate GetCloseHandler () + { + return cb_close_Close_V ??= new _JniMarshal_PP_V (n_Close); + } + + static void n_Close (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Close); + } + } + private static void __n_Close (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Close (); + } +#pragma warning restore 0169 + + public unsafe void Close () + { + const string __id = "close.()V"; + try { + _members_xamarin_test_I1.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.II2.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.II2.cs new file mode 100644 index 00000000000..3ff1c74b146 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.II2.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='I2']" + [Register ("xamarin/test/I2", "", "Xamarin.Test.II2Invoker")] + public partial interface II2 : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I2']/method[@name='close' and count(parameter)=0]" + [Register ("close", "()V", "GetCloseHandler:Xamarin.Test.II2Invoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Close (); + + } + + [global::Android.Runtime.Register ("xamarin/test/I2", DoNotGenerateAcw=true)] + internal partial class II2Invoker : global::Java.Lang.Object, II2 { + static IntPtr java_class_ref { + get { return _members_xamarin_test_I2.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_I2; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_xamarin_test_I2.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_xamarin_test_I2.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_xamarin_test_I2 = new XAPeerMembers ("xamarin/test/I2", typeof (II2Invoker)); + + public II2Invoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_close_Close_V; +#pragma warning disable 0169 + static Delegate GetCloseHandler () + { + return cb_close_Close_V ??= new _JniMarshal_PP_V (n_Close); + } + + static void n_Close (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Close); + } + } + private static void __n_Close (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Close (); + } +#pragma warning restore 0169 + + public unsafe void Close () + { + const string __id = "close.()V"; + try { + _members_xamarin_test_I2.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..ad0b3332cf0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.SomeObject.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object, global::Xamarin.Test.II1, global::Xamarin.Test.II2 { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_close_Close_V; +#pragma warning disable 0169 + static Delegate GetCloseHandler () + { + return cb_close_Close_V ??= new _JniMarshal_PP_V (n_Close); + } + + static void n_Close (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Close); + } + } + private static void __n_Close (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Close (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='close' and count(parameter)=0]" + [Register ("close", "()V", "GetCloseHandler")] + public virtual unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.SomeObject2.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.SomeObject2.cs new file mode 100644 index 00000000000..e0d1154188b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/Xamarin.Test.SomeObject2.cs @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject2", DoNotGenerateAcw=true)] + public abstract partial class SomeObject2 : global::Java.Lang.Object, global::Xamarin.Test.II1, global::Xamarin.Test.II2 { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject2", typeof (SomeObject2)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject2 (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_irrelevant_Irrelevant_V; +#pragma warning disable 0169 + static Delegate GetIrrelevantHandler () + { + return cb_irrelevant_Irrelevant_V ??= new _JniMarshal_PP_V (n_Irrelevant); + } + + static void n_Irrelevant (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Irrelevant); + } + } + private static void __n_Irrelevant (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Irrelevant (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']/method[@name='irrelevant' and count(parameter)=0]" + [Register ("irrelevant", "()V", "GetIrrelevantHandler")] + public virtual unsafe void Irrelevant () + { + const string __id = "irrelevant.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + static Delegate cb_close_Close_V; +#pragma warning disable 0169 + static Delegate GetCloseHandler () + { + return cb_close_Close_V ??= new _JniMarshal_PP_V (n_Close); + } + + static void n_Close (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Close); + } + } + private static void __n_Close (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Close (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']/method[@name='close' and count(parameter)=0]" + [Register ("close", "()V", "GetCloseHandler")] + public abstract void Close (); + + } + + [global::Android.Runtime.Register ("xamarin/test/SomeObject2", DoNotGenerateAcw=true)] + internal partial class SomeObject2Invoker : SomeObject2 { + public SomeObject2Invoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject2", typeof (SomeObject2Invoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='I1']/method[@name='close' and count(parameter)=0]" + [Register ("close", "()V", "GetCloseHandler")] + public override unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/__NamespaceMapping__.cs new file mode 100644 index 00000000000..12ae9009a03 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/__NamespaceMapping__.cs @@ -0,0 +1,8 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PP_V (IntPtr jnienv, IntPtr klass); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/InterfaceMethodsConflict/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Mono.Android.projitems new file mode 100644 index 00000000000..a5071d7a74f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Xamarin.Test.NotificationCompatBase.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Xamarin.Test.NotificationCompatBase.cs new file mode 100644 index 00000000000..ec8493f5cf0 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/Xamarin.Test.NotificationCompatBase.cs @@ -0,0 +1,253 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase']" + [global::Android.Runtime.Register ("xamarin/test/NotificationCompatBase", DoNotGenerateAcw=true)] + public partial class NotificationCompatBase : global::Java.Lang.Object { + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase.Action']" + [global::Android.Runtime.Register ("xamarin/test/NotificationCompatBase$Action", DoNotGenerateAcw=true)] + public abstract partial class Action : global::Java.Lang.Object { + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='NotificationCompatBase.Action.Factory']" + [Register ("xamarin/test/NotificationCompatBase$Action$Factory", "", "Xamarin.Test.NotificationCompatBase/Action/IFactoryInvoker")] + public partial interface IFactory : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='NotificationCompatBase.Action.Factory']/method[@name='build' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("build", "(I)Lxamarin/test/NotificationCompatBase$Action;", "GetBuild_IHandler:Xamarin.Test.NotificationCompatBase/Action/IFactoryInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + global::Xamarin.Test.NotificationCompatBase.Action Build (int p0); + + } + + [global::Android.Runtime.Register ("xamarin/test/NotificationCompatBase$Action$Factory", DoNotGenerateAcw=true)] + internal partial class IFactoryInvoker : global::Java.Lang.Object, IFactory { + static IntPtr java_class_ref { + get { return _members_xamarin_test_NotificationCompatBase_Action_Factory.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_xamarin_test_NotificationCompatBase_Action_Factory; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_xamarin_test_NotificationCompatBase_Action_Factory.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_xamarin_test_NotificationCompatBase_Action_Factory.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_xamarin_test_NotificationCompatBase_Action_Factory = new XAPeerMembers ("xamarin/test/NotificationCompatBase$Action$Factory", typeof (IFactoryInvoker)); + + public IFactoryInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_build_Build_I_Lxamarin_test_NotificationCompatBase_Action_; +#pragma warning disable 0169 + static Delegate GetBuild_IHandler () + { + return cb_build_Build_I_Lxamarin_test_NotificationCompatBase_Action_ ??= new _JniMarshal_PPI_L (n_Build_I); + } + + static IntPtr n_Build_I (IntPtr jnienv, IntPtr native__this, int p0) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, p0, &__n_Build_I); + } + } + private static IntPtr __n_Build_I (IntPtr jnienv, IntPtr native__this, int p0) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.Build (p0)); + } +#pragma warning restore 0169 + + public unsafe global::Xamarin.Test.NotificationCompatBase.Action Build (int p0) + { + const string __id = "build.(I)Lxamarin/test/NotificationCompatBase$Action;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (p0); + var __rm = _members_xamarin_test_NotificationCompatBase_Action_Factory.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/NotificationCompatBase$Action", typeof (Action)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Action (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } + + [global::Android.Runtime.Register ("xamarin/test/NotificationCompatBase$Action", DoNotGenerateAcw=true)] + internal partial class ActionInvoker : Action { + public ActionInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/NotificationCompatBase$Action", typeof (ActionInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + } + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase.InstanceInner']" + [global::Android.Runtime.Register ("xamarin/test/NotificationCompatBase$InstanceInner", DoNotGenerateAcw=true)] + public abstract partial class InstanceInner : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/NotificationCompatBase$InstanceInner", typeof (InstanceInner)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected InstanceInner (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase.InstanceInner']/constructor[@name='NotificationCompatBase.InstanceInner' and count(parameter)=1 and parameter[1][@type='xamarin.test.NotificationCompatBase']]" + [Register (".ctor", "(Lxamarin/test/NotificationCompatBase;)V", "")] + public unsafe InstanceInner (global::Xamarin.Test.NotificationCompatBase __self) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + string __id = "(L" + global::Android.Runtime.JNIEnv.GetJniName (GetType ().DeclaringType) + ";)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((__self == null) ? IntPtr.Zero : ((global::Java.Lang.Object) __self).Handle); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + global::System.GC.KeepAlive (__self); + } + } + + } + + [global::Android.Runtime.Register ("xamarin/test/NotificationCompatBase$InstanceInner", DoNotGenerateAcw=true)] + internal partial class InstanceInnerInvoker : InstanceInner { + public InstanceInnerInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/NotificationCompatBase$InstanceInner", typeof (InstanceInnerInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/NotificationCompatBase", typeof (NotificationCompatBase)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected NotificationCompatBase (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/__NamespaceMapping__.cs new file mode 100644 index 00000000000..1707f26a680 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/__NamespaceMapping__.cs @@ -0,0 +1,8 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PPI_L (IntPtr jnienv, IntPtr klass, int p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/NestedTypes/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..3fa463e60cd --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/Xamarin.Test.SomeObject.cs @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='Value']" + [Register ("Value")] + public int Value { + get { + const string __id = "Value.I"; + + var __v = _members.InstanceFields.GetInt32Value (__id, this); + return __v; + } + set { + const string __id = "Value.I"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='BooleanValue']" + [Register ("BooleanValue")] + public bool BooleanValue { + get { + const string __id = "BooleanValue.Z"; + + var __v = _members.InstanceFields.GetBooleanValue (__id, this); + return __v; + } + set { + const string __id = "BooleanValue.Z"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='CharValue']" + [Register ("CharValue")] + public char CharValue { + get { + const string __id = "CharValue.C"; + + var __v = _members.InstanceFields.GetCharValue (__id, this); + return __v; + } + set { + const string __id = "CharValue.C"; + + try { + _members.InstanceFields.SetValue (__id, this, value); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/__NamespaceMapping__.cs new file mode 100644 index 00000000000..549748329a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/__NamespaceMapping__.cs @@ -0,0 +1,4 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/NonStaticFields/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Class.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Class.cs new file mode 100644 index 00000000000..5647ba8371b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Class.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Class']" + [global::Android.Runtime.Register ("java/lang/Class", DoNotGenerateAcw=true)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial class Class : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Class", typeof (Class)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Class (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Integer.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Integer.cs new file mode 100644 index 00000000000..1889e90d7ff --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Integer.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Integer']" + [global::Android.Runtime.Register ("java/lang/Integer", DoNotGenerateAcw=true)] + public partial class Integer : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Integer", typeof (Integer)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Integer (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Throwable.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Throwable.cs new file mode 100644 index 00000000000..cc7579be940 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Java.Lang.Throwable.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Throwable']" + [global::Android.Runtime.Register ("java/lang/Throwable", DoNotGenerateAcw=true)] + public partial class Throwable { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Throwable", typeof (Throwable)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Mono.Android.projitems new file mode 100644 index 00000000000..f2657c4aea3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Mono.Android.projitems @@ -0,0 +1,21 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.A.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.A.cs new file mode 100644 index 00000000000..e246519bf0c --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.A.cs @@ -0,0 +1,150 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='A']" + [global::Android.Runtime.Register ("xamarin/test/A", DoNotGenerateAcw=true)] + public partial class A : global::Java.Lang.Object { + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='A.B']" + [global::Android.Runtime.Register ("xamarin/test/A$B", DoNotGenerateAcw=true)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends xamarin.test.A.B"})] + public partial class B : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/A$B", typeof (B)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected B (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_setCustomDimension_SetCustomDimension_I_Lxamarin_test_A_B_; +#pragma warning disable 0169 + static Delegate GetSetCustomDimension_IHandler () + { + return cb_setCustomDimension_SetCustomDimension_I_Lxamarin_test_A_B_ ??= new _JniMarshal_PPI_L (n_SetCustomDimension_I); + } + + static IntPtr n_SetCustomDimension_I (IntPtr jnienv, IntPtr native__this, int index) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, index, &__n_SetCustomDimension_I); + } + } + private static IntPtr __n_SetCustomDimension_I (IntPtr jnienv, IntPtr native__this, int index) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.SetCustomDimension (index)); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A.B']/method[@name='setCustomDimension' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("setCustomDimension", "(I)Lxamarin/test/A$B;", "GetSetCustomDimension_IHandler")] + public virtual unsafe global::Java.Lang.Object SetCustomDimension (int index) + { + const string __id = "setCustomDimension.(I)Lxamarin/test/A$B;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (index); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return (global::Java.Lang.Object) global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/A", typeof (A)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected A (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_getHandle_GetHandle_I; +#pragma warning disable 0169 + static Delegate GetGetHandleHandler () + { + return cb_getHandle_GetHandle_I ??= new _JniMarshal_PP_I (n_GetHandle); + } + + static int n_GetHandle (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetHandle); + } + } + private static int __n_GetHandle (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.GetHandle (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A']/method[@name='getHandle' and count(parameter)=0]" + [Register ("getHandle", "()I", "GetGetHandleHandler")] + public virtual unsafe int GetHandle () + { + const string __id = "getHandle.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.C.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.C.cs new file mode 100644 index 00000000000..7b98e3a88ac --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.C.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='C']" + [global::Android.Runtime.Register ("xamarin/test/C", DoNotGenerateAcw=true)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends xamarin.test.C"})] + public partial class C : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/C", typeof (C)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected C (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_setCustomDimension_SetCustomDimension_I_Lxamarin_test_C_; +#pragma warning disable 0169 + static Delegate GetSetCustomDimension_IHandler () + { + return cb_setCustomDimension_SetCustomDimension_I_Lxamarin_test_C_ ??= new _JniMarshal_PPI_L (n_SetCustomDimension_I); + } + + static IntPtr n_SetCustomDimension_I (IntPtr jnienv, IntPtr native__this, int index) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, index, &__n_SetCustomDimension_I); + } + } + private static IntPtr __n_SetCustomDimension_I (IntPtr jnienv, IntPtr native__this, int index) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.SetCustomDimension (index)); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='C']/method[@name='setCustomDimension' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("setCustomDimension", "(I)Lxamarin/test/C;", "GetSetCustomDimension_IHandler")] + public virtual unsafe global::Java.Lang.Object SetCustomDimension (int index) + { + const string __id = "setCustomDimension.(I)Lxamarin/test/C;"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (index); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + return (global::Java.Lang.Object) global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..d47f6641753 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/Xamarin.Test.SomeObject.cs @@ -0,0 +1,382 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/constructor[@name='SomeObject' and count(parameter)=1 and parameter[1][@type='java.lang.Class<? extends xamarin.test.SomeObject>']]" + [Register (".ctor", "(Ljava/lang/Class;)V", "")] + public unsafe SomeObject (global::Java.Lang.Class c) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(Ljava/lang/Class;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((c == null) ? IntPtr.Zero : ((global::Java.Lang.Object) c).Handle); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + global::System.GC.KeepAlive (c); + } + } + + static Delegate cb_getType_GetType_arrayI; +#pragma warning disable 0169 + static Delegate GetGetTypeHandler () + { + return cb_getType_GetType_arrayI ??= new _JniMarshal_PP_L (n_GetType); + } + + static IntPtr n_GetType (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetType); + } + } + private static IntPtr __n_GetType (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewArray (__this.GetType ()); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getType' and count(parameter)=0]" + [Register ("getType", "()[I", "GetGetTypeHandler")] + public new virtual unsafe int[] GetType () + { + const string __id = "getType.()[I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return (int[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (int)); + } finally { + } + } + + static Delegate cb_handle_Handle_Ljava_lang_Object_Ljava_lang_Throwable__I; +#pragma warning disable 0169 + static Delegate GetHandle_Ljava_lang_Object_Ljava_lang_Throwable_Handler () + { + return cb_handle_Handle_Ljava_lang_Object_Ljava_lang_Throwable__I ??= new _JniMarshal_PPLL_I (n_Handle_Ljava_lang_Object_Ljava_lang_Throwable_); + } + + static int n_Handle_Ljava_lang_Object_Ljava_lang_Throwable_ (IntPtr jnienv, IntPtr native__this, IntPtr native_o, IntPtr native_t) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_o, native_t, &__n_Handle_Ljava_lang_Object_Ljava_lang_Throwable_); + } + } + private static int __n_Handle_Ljava_lang_Object_Ljava_lang_Throwable_ (IntPtr jnienv, IntPtr native__this, IntPtr native_o, IntPtr native_t) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var o = global::Java.Lang.Object.GetObject (native_o, JniHandleOwnership.DoNotTransfer); + var t = global::Java.Lang.Object.GetObject (native_t, JniHandleOwnership.DoNotTransfer); + int __ret = __this.Handle (o, t); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='handle' and count(parameter)=2 and parameter[1][@type='java.lang.Object'] and parameter[2][@type='java.lang.Throwable']]" + [Register ("handle", "(Ljava/lang/Object;Ljava/lang/Throwable;)I", "GetHandle_Ljava_lang_Object_Ljava_lang_Throwable_Handler")] + public new virtual unsafe int Handle (global::Java.Lang.Object o, global::Java.Lang.Throwable t) + { + const string __id = "handle.(Ljava/lang/Object;Ljava/lang/Throwable;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [2]; + __args [0] = new JniArgumentValue ((o == null) ? IntPtr.Zero : ((global::Java.Lang.Object) o).Handle); + __args [1] = new JniArgumentValue ((t == null) ? IntPtr.Zero : ((global::Java.Lang.Throwable) t).Handle); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (o); + global::System.GC.KeepAlive (t); + } + } + + static Delegate cb_IntegerMethod_IntegerMethod_I; +#pragma warning disable 0169 + static Delegate GetIntegerMethodHandler () + { + return cb_IntegerMethod_IntegerMethod_I ??= new _JniMarshal_PP_I (n_IntegerMethod); + } + + static int n_IntegerMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_IntegerMethod); + } + } + private static int __n_IntegerMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.IntegerMethod (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='IntegerMethod' and count(parameter)=0]" + [Register ("IntegerMethod", "()I", "GetIntegerMethodHandler")] + public virtual unsafe int IntegerMethod () + { + const string __id = "IntegerMethod.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + static Delegate cb_VoidMethod_VoidMethod_V; +#pragma warning disable 0169 + static Delegate GetVoidMethodHandler () + { + return cb_VoidMethod_VoidMethod_V ??= new _JniMarshal_PP_V (n_VoidMethod); + } + + static void n_VoidMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_VoidMethod); + } + } + private static void __n_VoidMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.VoidMethod (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='VoidMethod' and count(parameter)=0]" + [Register ("VoidMethod", "()V", "GetVoidMethodHandler")] + public virtual unsafe void VoidMethod () + { + const string __id = "VoidMethod.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + static Delegate cb_StringMethod_StringMethod_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetStringMethodHandler () + { + return cb_StringMethod_StringMethod_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_StringMethod); + } + + static IntPtr n_StringMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_StringMethod); + } + } + private static IntPtr __n_StringMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.StringMethod ()); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='StringMethod' and count(parameter)=0]" + [Register ("StringMethod", "()Ljava/lang/String;", "GetStringMethodHandler")] + public virtual unsafe string StringMethod () + { + const string __id = "StringMethod.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + static Delegate cb_ObjectMethod_ObjectMethod_Ljava_lang_Object_; +#pragma warning disable 0169 + static Delegate GetObjectMethodHandler () + { + return cb_ObjectMethod_ObjectMethod_Ljava_lang_Object_ ??= new _JniMarshal_PP_L (n_ObjectMethod); + } + + static IntPtr n_ObjectMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_ObjectMethod); + } + } + private static IntPtr __n_ObjectMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.ObjectMethod ()); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='ObjectMethod' and count(parameter)=0]" + [Register ("ObjectMethod", "()Ljava/lang/Object;", "GetObjectMethodHandler")] + public virtual unsafe global::Java.Lang.Object ObjectMethod () + { + const string __id = "ObjectMethod.()Ljava/lang/Object;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + static Delegate cb_VoidMethodWithParams_VoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object__V; +#pragma warning disable 0169 + static Delegate GetVoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object_Handler () + { + return cb_VoidMethodWithParams_VoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object__V ??= new _JniMarshal_PPLIL_V (n_VoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object_); + } + + static void n_VoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_astring, int anint, IntPtr native_anObject) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_astring, anint, native_anObject, &__n_VoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object_); + } + } + private static void __n_VoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_astring, int anint, IntPtr native_anObject) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var astring = JNIEnv.GetString (native_astring, JniHandleOwnership.DoNotTransfer); + var anObject = global::Java.Lang.Object.GetObject (native_anObject, JniHandleOwnership.DoNotTransfer); + __this.VoidMethodWithParams (astring, anint, anObject); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='VoidMethodWithParams' and count(parameter)=3 and parameter[1][@type='java.lang.String'] and parameter[2][@type='int'] and parameter[3][@type='java.lang.Object']]" + [Register ("VoidMethodWithParams", "(Ljava/lang/String;ILjava/lang/Object;)V", "GetVoidMethodWithParams_Ljava_lang_String_ILjava_lang_Object_Handler")] + public virtual unsafe void VoidMethodWithParams (string astring, int anint, global::Java.Lang.Object anObject) + { + const string __id = "VoidMethodWithParams.(Ljava/lang/String;ILjava/lang/Object;)V"; + IntPtr native_astring = JNIEnv.NewString ((string)astring); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (native_astring); + __args [1] = new JniArgumentValue (anint); + __args [2] = new JniArgumentValue ((anObject == null) ? IntPtr.Zero : ((global::Java.Lang.Object) anObject).Handle); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_astring); + global::System.GC.KeepAlive (anObject); + } + } + + static Delegate cb_ObsoleteMethod_ObsoleteMethod_I; +#pragma warning disable 0169 + [global::System.Obsolete] + static Delegate GetObsoleteMethodHandler () + { + return cb_ObsoleteMethod_ObsoleteMethod_I ??= new _JniMarshal_PP_I (n_ObsoleteMethod); + } + + [global::System.Obsolete] + static int n_ObsoleteMethod (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_ObsoleteMethod); + } + } + [global::System.Obsolete] + private static int __n_ObsoleteMethod (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.ObsoleteMethod (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='ObsoleteMethod' and count(parameter)=0]" + [global::System.Obsolete (@"Deprecated please use IntegerMethod instead")] + [Register ("ObsoleteMethod", "()I", "GetObsoleteMethodHandler")] + public virtual unsafe int ObsoleteMethod () + { + const string __id = "ObsoleteMethod.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + static Delegate cb_ArrayListTest_ArrayListTest_Ljava_util_ArrayList__V; +#pragma warning disable 0169 + static Delegate GetArrayListTest_Ljava_util_ArrayList_Handler () + { + return cb_ArrayListTest_ArrayListTest_Ljava_util_ArrayList__V ??= new _JniMarshal_PPL_V (n_ArrayListTest_Ljava_util_ArrayList_); + } + + static void n_ArrayListTest_Ljava_util_ArrayList_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_p0, &__n_ArrayListTest_Ljava_util_ArrayList_); + } + } + private static void __n_ArrayListTest_Ljava_util_ArrayList_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var p0 = global::Android.Runtime.JavaList.FromJniHandle (native_p0, JniHandleOwnership.DoNotTransfer); + __this.ArrayListTest (p0); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='ArrayListTest' and count(parameter)=1 and parameter[1][@type='java.util.ArrayList<java.lang.Integer>']]" + [Register ("ArrayListTest", "(Ljava/util/ArrayList;)V", "GetArrayListTest_Ljava_util_ArrayList_Handler")] + public virtual unsafe void ArrayListTest (global::System.Collections.Generic.IList p0) + { + const string __id = "ArrayListTest.(Ljava/util/ArrayList;)V"; + IntPtr native_p0 = global::Android.Runtime.JavaList.ToLocalJniHandle (p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + global::System.GC.KeepAlive (p0); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/__NamespaceMapping__.cs new file mode 100644 index 00000000000..9a0e0b9b123 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/__NamespaceMapping__.cs @@ -0,0 +1,21 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.util", Managed="Java.Util")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PP_I (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PP_V (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PPI_L (IntPtr jnienv, IntPtr klass, int p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPLIL_V (IntPtr jnienv, IntPtr klass, IntPtr p0, int p1, IntPtr p2); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PPLL_I (IntPtr jnienv, IntPtr klass, IntPtr p0, IntPtr p1); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalMethods/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..09989862c02 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/Xamarin.Test.SomeObject.cs @@ -0,0 +1,299 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public abstract partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_getSomeInteger_GetSomeInteger_I; +#pragma warning disable 0169 + static Delegate GetGetSomeIntegerHandler () + { + return cb_getSomeInteger_GetSomeInteger_I ??= new _JniMarshal_PP_I (n_GetSomeInteger); + } + + static int n_GetSomeInteger (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetSomeInteger); + } + } + private static int __n_GetSomeInteger (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.SomeInteger; + } +#pragma warning restore 0169 + + static Delegate cb_setSomeInteger_SetSomeInteger_I_V; +#pragma warning disable 0169 + static Delegate GetSetSomeInteger_IHandler () + { + return cb_setSomeInteger_SetSomeInteger_I_V ??= new _JniMarshal_PPI_V (n_SetSomeInteger_I); + } + + static void n_SetSomeInteger_I (IntPtr jnienv, IntPtr native__this, int newvalue) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, newvalue, &__n_SetSomeInteger_I); + } + } + private static void __n_SetSomeInteger_I (IntPtr jnienv, IntPtr native__this, int newvalue) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.SomeInteger = newvalue; + } +#pragma warning restore 0169 + + public abstract int SomeInteger { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeInteger' and count(parameter)=0]" + [Register ("getSomeInteger", "()I", "GetGetSomeIntegerHandler")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeInteger' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("setSomeInteger", "(I)V", "GetSetSomeInteger_IHandler")] + set; + } + + static Delegate cb_getSomeObjectProperty_GetSomeObjectProperty_Ljava_lang_Object_; +#pragma warning disable 0169 + static Delegate GetGetSomeObjectPropertyHandler () + { + return cb_getSomeObjectProperty_GetSomeObjectProperty_Ljava_lang_Object_ ??= new _JniMarshal_PP_L (n_GetSomeObjectProperty); + } + + static IntPtr n_GetSomeObjectProperty (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetSomeObjectProperty); + } + } + private static IntPtr __n_GetSomeObjectProperty (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.SomeObjectProperty); + } +#pragma warning restore 0169 + + static Delegate cb_setSomeObjectProperty_SetSomeObjectProperty_Ljava_lang_Object__V; +#pragma warning disable 0169 + static Delegate GetSetSomeObjectProperty_Ljava_lang_Object_Handler () + { + return cb_setSomeObjectProperty_SetSomeObjectProperty_Ljava_lang_Object__V ??= new _JniMarshal_PPL_V (n_SetSomeObjectProperty_Ljava_lang_Object_); + } + + static void n_SetSomeObjectProperty_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_newvalue) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_newvalue, &__n_SetSomeObjectProperty_Ljava_lang_Object_); + } + } + private static void __n_SetSomeObjectProperty_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_newvalue) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var newvalue = global::Java.Lang.Object.GetObject (native_newvalue, JniHandleOwnership.DoNotTransfer); + __this.SomeObjectProperty = newvalue; + } +#pragma warning restore 0169 + + public abstract global::Java.Lang.Object SomeObjectProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeObjectProperty' and count(parameter)=0]" + [Register ("getSomeObjectProperty", "()Ljava/lang/Object;", "GetGetSomeObjectPropertyHandler")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeObjectProperty' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("setSomeObjectProperty", "(Ljava/lang/Object;)V", "GetSetSomeObjectProperty_Ljava_lang_Object_Handler")] + set; + } + + static Delegate cb_getSomeString_GetSomeString_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetGetSomeStringHandler () + { + return cb_getSomeString_GetSomeString_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_GetSomeString); + } + + static IntPtr n_GetSomeString (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetSomeString); + } + } + private static IntPtr __n_GetSomeString (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.SomeString); + } +#pragma warning restore 0169 + + static Delegate cb_setSomeString_SetSomeString_Ljava_lang_String__V; +#pragma warning disable 0169 + static Delegate GetSetSomeString_Ljava_lang_String_Handler () + { + return cb_setSomeString_SetSomeString_Ljava_lang_String__V ??= new _JniMarshal_PPL_V (n_SetSomeString_Ljava_lang_String_); + } + + static void n_SetSomeString_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_newvalue) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_newvalue, &__n_SetSomeString_Ljava_lang_String_); + } + } + private static void __n_SetSomeString_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_newvalue) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var newvalue = JNIEnv.GetString (native_newvalue, JniHandleOwnership.DoNotTransfer); + __this.SomeString = newvalue; + } +#pragma warning restore 0169 + + public abstract string SomeString { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeString' and count(parameter)=0]" + [Register ("getSomeString", "()Ljava/lang/String;", "GetGetSomeStringHandler")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeString' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("setSomeString", "(Ljava/lang/String;)V", "GetSetSomeString_Ljava_lang_String_Handler")] + set; + } + + } + + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + internal partial class SomeObjectInvoker : SomeObject { + public SomeObjectInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObjectInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + public override unsafe int SomeInteger { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeInteger' and count(parameter)=0]" + [Register ("getSomeInteger", "()I", "GetGetSomeIntegerHandler")] + get { + const string __id = "getSomeInteger.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeInteger' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("setSomeInteger", "(I)V", "GetSetSomeInteger_IHandler")] + set { + const string __id = "setSomeInteger.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public override unsafe global::Java.Lang.Object SomeObjectProperty { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeObjectProperty' and count(parameter)=0]" + [Register ("getSomeObjectProperty", "()Ljava/lang/Object;", "GetGetSomeObjectPropertyHandler")] + get { + const string __id = "getSomeObjectProperty.()Ljava/lang/Object;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeObjectProperty' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("setSomeObjectProperty", "(Ljava/lang/Object;)V", "GetSetSomeObjectProperty_Ljava_lang_Object_Handler")] + set { + const string __id = "setSomeObjectProperty.(Ljava/lang/Object;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((value == null) ? IntPtr.Zero : ((global::Java.Lang.Object) value).Handle); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + public override unsafe string SomeString { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeString' and count(parameter)=0]" + [Register ("getSomeString", "()Ljava/lang/String;", "GetGetSomeStringHandler")] + get { + const string __id = "getSomeString.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeString' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("setSomeString", "(Ljava/lang/String;)V", "GetSetSomeString_Ljava_lang_String_Handler")] + set { + const string __id = "setSomeString.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString ((string)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/__NamespaceMapping__.cs new file mode 100644 index 00000000000..8154d6b2f14 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/__NamespaceMapping__.cs @@ -0,0 +1,14 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PP_I (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPI_V (IntPtr jnienv, IntPtr klass, int p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/NormalProperties/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Lang.Integer.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Lang.Integer.cs new file mode 100644 index 00000000000..1889e90d7ff --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Lang.Integer.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Integer']" + [global::Android.Runtime.Register ("java/lang/Integer", DoNotGenerateAcw=true)] + public partial class Integer : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Integer", typeof (Integer)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Integer (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Util.IList.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Util.IList.cs new file mode 100644 index 00000000000..039257aa573 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Java.Util.IList.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='List']" + [Register ("java/util/List", "", "Java.Util.IListInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IList : IJavaObject, IJavaPeerable { + } + + [global::Android.Runtime.Register ("java/util/List", DoNotGenerateAcw=true)] + internal partial class IListInvoker : global::Java.Lang.Object, IList { + static IntPtr java_class_ref { + get { return _members_java_util_List.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_List; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_java_util_List.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_java_util_List.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_java_util_List = new XAPeerMembers ("java/util/List", typeof (IListInvoker)); + + public IListInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Mono.Android.projitems new file mode 100644 index 00000000000..3b6b7a5dd5e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Mono.Android.projitems @@ -0,0 +1,16 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Xamarin.Test.A.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Xamarin.Test.A.cs new file mode 100644 index 00000000000..4973df61a85 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/Xamarin.Test.A.cs @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='A']" + [global::Android.Runtime.Register ("xamarin/test/A", DoNotGenerateAcw=true)] + [global::Java.Interop.JavaTypeParameters (new string [] {"T extends java.lang.Object"})] + public partial class A : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/A", typeof (A)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected A (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_setA_SetA_Ljava_lang_Object__V; +#pragma warning disable 0169 + static Delegate GetSetA_Ljava_lang_Object_Handler () + { + return cb_setA_SetA_Ljava_lang_Object__V ??= new _JniMarshal_PPL_V (n_SetA_Ljava_lang_Object_); + } + + static void n_SetA_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_adapter) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_adapter, &__n_SetA_Ljava_lang_Object_); + } + } + private static void __n_SetA_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_adapter) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var adapter = global::Java.Lang.Object.GetObject (native_adapter, JniHandleOwnership.DoNotTransfer); + __this.SetA (adapter); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A']/method[@name='setA' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("setA", "(Ljava/lang/Object;)V", "GetSetA_Ljava_lang_Object_Handler")] + public virtual unsafe void SetA (global::Java.Lang.Object adapter) + { + const string __id = "setA.(Ljava/lang/Object;)V"; + IntPtr native_adapter = JNIEnv.ToLocalJniHandle (adapter); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_adapter); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_adapter); + global::System.GC.KeepAlive (adapter); + } + } + + static Delegate cb_listTest_ListTest_Ljava_util_List__V; +#pragma warning disable 0169 + static Delegate GetListTest_Ljava_util_List_Handler () + { + return cb_listTest_ListTest_Ljava_util_List__V ??= new _JniMarshal_PPL_V (n_ListTest_Ljava_util_List_); + } + + static void n_ListTest_Ljava_util_List_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_p0, &__n_ListTest_Ljava_util_List_); + } + } + private static void __n_ListTest_Ljava_util_List_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var p0 = global::Android.Runtime.JavaList.FromJniHandle (native_p0, JniHandleOwnership.DoNotTransfer); + __this.ListTest (p0); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='A']/method[@name='listTest' and count(parameter)=1 and parameter[1][@type='java.util.List<java.lang.Integer>']]" + [Register ("listTest", "(Ljava/util/List;)V", "GetListTest_Ljava_util_List_Handler")] + public virtual unsafe void ListTest (global::System.Collections.Generic.IList p0) + { + const string __id = "listTest.(Ljava/util/List;)V"; + IntPtr native_p0 = global::Android.Runtime.JavaList.ToLocalJniHandle (p0); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_p0); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_p0); + global::System.GC.KeepAlive (p0); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/__NamespaceMapping__.cs new file mode 100644 index 00000000000..0995fa455fb --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/__NamespaceMapping__.cs @@ -0,0 +1,9 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.util", Managed="Java.Util")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/ParameterXPath/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..261590db72d --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/Xamarin.Test.SomeObject.cs @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='Value']" + [Register ("Value")] + public static int Value { + get { + const string __id = "Value.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='Value2']" + [Register ("Value2")] + public static int Value2 { + get { + const string __id = "Value2.I"; + + var __v = _members.StaticFields.GetInt32Value (__id); + return __v; + } + set { + const string __id = "Value2.I"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='BooleanValue']" + [Register ("BooleanValue")] + public static bool BooleanValue { + get { + const string __id = "BooleanValue.Z"; + + var __v = _members.StaticFields.GetBooleanValue (__id); + return __v; + } + set { + const string __id = "BooleanValue.Z"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='CharValue']" + [Register ("CharValue")] + public static char CharValue { + get { + const string __id = "CharValue.C"; + + var __v = _members.StaticFields.GetCharValue (__id); + return __v; + } + set { + const string __id = "CharValue.C"; + + try { + _members.StaticFields.SetValue (__id, value); + } finally { + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/__NamespaceMapping__.cs new file mode 100644 index 00000000000..549748329a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/__NamespaceMapping__.cs @@ -0,0 +1,4 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticFields/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..59976149b9a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/Xamarin.Test.SomeObject.cs @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='methodAsInt' and count(parameter)=0]" + [Register ("methodAsInt", "()I", "")] + public static unsafe int MethodAsInt () + { + const string __id = "methodAsInt.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='methodAsString' and count(parameter)=0]" + [Register ("methodAsString", "()Ljava/lang/String;", "")] + public static unsafe string MethodAsString () + { + const string __id = "methodAsString.()Ljava/lang/String;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='Obsoletemethod' and count(parameter)=0]" + [global::System.Obsolete (@"Deprecated please use methodAsString")] + [Register ("Obsoletemethod", "()Ljava/lang/String;", "")] + public static unsafe string Obsoletemethod () + { + const string __id = "Obsoletemethod.()Ljava/lang/String;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/__NamespaceMapping__.cs new file mode 100644 index 00000000000..549748329a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/__NamespaceMapping__.cs @@ -0,0 +1,4 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticMethods/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Mono.Android.projitems new file mode 100644 index 00000000000..c47692f39de --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Mono.Android.projitems @@ -0,0 +1,14 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..80cffc22b59 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/Xamarin.Test.SomeObject.cs @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + public static unsafe int SomeInteger { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeInteger' and count(parameter)=0]" + [Register ("getSomeInteger", "()I", "")] + get { + const string __id = "getSomeInteger.()I"; + try { + var __rm = _members.StaticMethods.InvokeInt32Method (__id, null); + return __rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeInteger' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("setSomeInteger", "(I)V", "")] + set { + const string __id = "setSomeInteger.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + } + } + } + + public static unsafe string SomeString { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeString' and count(parameter)=0]" + [Register ("getSomeString", "()Ljava/lang/String;", "")] + get { + const string __id = "getSomeString.()Ljava/lang/String;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeString' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("setSomeString", "(Ljava/lang/String;)V", "")] + set { + const string __id = "setSomeString.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString ((string)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='getSomeObject' and count(parameter)=0]" + [Register ("getSomeObject", "()Ljava/lang/Object;", "")] + public static unsafe global::Java.Lang.Object GetSomeObject () + { + const string __id = "getSomeObject.()Ljava/lang/Object;"; + try { + var __rm = _members.StaticMethods.InvokeObjectMethod (__id, null); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/method[@name='setSomeObject' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("setSomeObject", "(Ljava/lang/Object;)V", "")] + public static unsafe void SetSomeObject (global::Java.Lang.Object newvalue) + { + const string __id = "setSomeObject.(Ljava/lang/Object;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((newvalue == null) ? IntPtr.Zero : ((global::Java.Lang.Object) newvalue).Handle); + _members.StaticMethods.InvokeVoidMethod (__id, __args); + } finally { + global::System.GC.KeepAlive (newvalue); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/__NamespaceMapping__.cs new file mode 100644 index 00000000000..549748329a3 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/__NamespaceMapping__.cs @@ -0,0 +1,4 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/StaticProperties/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.FilterOutputStream.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.FilterOutputStream.cs new file mode 100644 index 00000000000..82fa1d65700 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.FilterOutputStream.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='FilterOutputStream']" + [global::Android.Runtime.Register ("java/io/FilterOutputStream", DoNotGenerateAcw=true)] + public partial class FilterOutputStream : global::Java.IO.OutputStream { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/io/FilterOutputStream", typeof (FilterOutputStream)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected FilterOutputStream (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.io']/class[@name='FilterOutputStream']/constructor[@name='FilterOutputStream' and count(parameter)=1 and parameter[1][@type='java.io.OutputStream']]" + [Register (".ctor", "(Ljava/io/OutputStream;)V", "")] + public unsafe FilterOutputStream (global::System.IO.Stream @out) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "(Ljava/io/OutputStream;)V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + IntPtr native__out = global::Android.Runtime.OutputStreamAdapter.ToLocalJniHandle (@out); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native__out); + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), __args); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native__out); + global::System.GC.KeepAlive (@out); + } + } + + static Delegate cb_write_Write_I_V; +#pragma warning disable 0169 + static Delegate GetWrite_IHandler () + { + return cb_write_Write_I_V ??= new _JniMarshal_PPI_V (n_Write_I); + } + + static void n_Write_I (IntPtr jnienv, IntPtr native__this, int oneByte) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, oneByte, &__n_Write_I); + } + } + private static void __n_Write_I (IntPtr jnienv, IntPtr native__this, int oneByte) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Write (oneByte); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='FilterOutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("write", "(I)V", "GetWrite_IHandler")] + public override unsafe void Write (int oneByte) + { + const string __id = "write.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (oneByte); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.IOException.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.IOException.cs new file mode 100644 index 00000000000..96a5f1c7cd2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.IOException.cs @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='IOException']" + [global::Android.Runtime.Register ("java/io/IOException", DoNotGenerateAcw=true)] + public abstract partial class IOException : global::Java.Lang.Throwable { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/io/IOException", typeof (IOException)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected IOException (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + static Delegate cb_printStackTrace_PrintStackTrace_V; +#pragma warning disable 0169 + static Delegate GetPrintStackTraceHandler () + { + return cb_printStackTrace_PrintStackTrace_V ??= new _JniMarshal_PP_V (n_PrintStackTrace); + } + + static void n_PrintStackTrace (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_PrintStackTrace); + } + } + private static void __n_PrintStackTrace (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.PrintStackTrace (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='IOException']/method[@name='printStackTrace' and count(parameter)=0]" + [Register ("printStackTrace", "()V", "GetPrintStackTraceHandler")] + public virtual unsafe void PrintStackTrace () + { + const string __id = "printStackTrace.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + } + + [global::Android.Runtime.Register ("java/io/IOException", DoNotGenerateAcw=true)] + internal partial class IOExceptionInvoker : IOException { + public IOExceptionInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/io/IOException", typeof (IOExceptionInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.InputStream.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.InputStream.cs new file mode 100644 index 00000000000..16afe2e40ce --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.InputStream.cs @@ -0,0 +1,408 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='InputStream']" + [global::Android.Runtime.Register ("java/io/InputStream", DoNotGenerateAcw=true)] + public abstract partial class InputStream : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/io/InputStream", typeof (InputStream)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected InputStream (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.io']/class[@name='InputStream']/constructor[@name='InputStream' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe InputStream () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_available_Available_I; +#pragma warning disable 0169 + static Delegate GetAvailableHandler () + { + return cb_available_Available_I ??= new _JniMarshal_PP_I (n_Available); + } + + static int n_Available (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_Available); + } + } + private static int __n_Available (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Available (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='available' and count(parameter)=0]" + [Register ("available", "()I", "GetAvailableHandler")] + public virtual unsafe int Available () + { + const string __id = "available.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + static Delegate cb_close_Close_V; +#pragma warning disable 0169 + static Delegate GetCloseHandler () + { + return cb_close_Close_V ??= new _JniMarshal_PP_V (n_Close); + } + + static void n_Close (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Close); + } + } + private static void __n_Close (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Close (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='close' and count(parameter)=0]" + [Register ("close", "()V", "GetCloseHandler")] + public virtual unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + static Delegate cb_mark_Mark_I_V; +#pragma warning disable 0169 + static Delegate GetMark_IHandler () + { + return cb_mark_Mark_I_V ??= new _JniMarshal_PPI_V (n_Mark_I); + } + + static void n_Mark_I (IntPtr jnienv, IntPtr native__this, int readlimit) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, readlimit, &__n_Mark_I); + } + } + private static void __n_Mark_I (IntPtr jnienv, IntPtr native__this, int readlimit) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Mark (readlimit); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='mark' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("mark", "(I)V", "GetMark_IHandler")] + public virtual unsafe void Mark (int readlimit) + { + const string __id = "mark.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (readlimit); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + } + } + + static Delegate cb_markSupported_MarkSupported_Z; +#pragma warning disable 0169 + static Delegate GetMarkSupportedHandler () + { + return cb_markSupported_MarkSupported_Z ??= new _JniMarshal_PP_B (n_MarkSupported); + } + + static sbyte n_MarkSupported (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_MarkSupported); + } + } + private static sbyte __n_MarkSupported (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.MarkSupported () ? (sbyte)1 : (sbyte)0; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='markSupported' and count(parameter)=0]" + [Register ("markSupported", "()Z", "GetMarkSupportedHandler")] + public virtual unsafe bool MarkSupported () + { + const string __id = "markSupported.()Z"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualBooleanMethod (__id, this, null); + return __rm; + } finally { + } + } + + static Delegate cb_read_Read_I; +#pragma warning disable 0169 + static Delegate GetReadHandler () + { + return cb_read_Read_I ??= new _JniMarshal_PP_I (n_Read); + } + + static int n_Read (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_Read); + } + } + private static int __n_Read (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Read (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=0]" + [Register ("read", "()I", "GetReadHandler")] + public abstract int Read (); + + static Delegate cb_read_Read_arrayB_I; +#pragma warning disable 0169 + static Delegate GetRead_arrayBHandler () + { + return cb_read_Read_arrayB_I ??= new _JniMarshal_PPL_I (n_Read_arrayB); + } + + static int n_Read_arrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_buffer, &__n_Read_arrayB); + } + } + private static int __n_Read_arrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var buffer = (byte[]) JNIEnv.GetArray (native_buffer, JniHandleOwnership.DoNotTransfer, typeof (byte)); + int __ret = __this.Read (buffer); + if (buffer != null) + JNIEnv.CopyArray (buffer, native_buffer); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=1 and parameter[1][@type='byte[]']]" + [Register ("read", "([B)I", "GetRead_arrayBHandler")] + public virtual unsafe int Read (byte[] buffer) + { + const string __id = "read.([B)I"; + IntPtr native_buffer = JNIEnv.NewArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_buffer); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + if (buffer != null) { + JNIEnv.CopyArray (native_buffer, buffer); + JNIEnv.DeleteLocalRef (native_buffer); + } + global::System.GC.KeepAlive (buffer); + } + } + + static Delegate cb_read_Read_arrayBII_I; +#pragma warning disable 0169 + static Delegate GetRead_arrayBIIHandler () + { + return cb_read_Read_arrayBII_I ??= new _JniMarshal_PPLII_I (n_Read_arrayBII); + } + + static int n_Read_arrayBII (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer, int byteOffset, int byteCount) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_buffer, byteOffset, byteCount, &__n_Read_arrayBII); + } + } + private static int __n_Read_arrayBII (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer, int byteOffset, int byteCount) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var buffer = (byte[]) JNIEnv.GetArray (native_buffer, JniHandleOwnership.DoNotTransfer, typeof (byte)); + int __ret = __this.Read (buffer, byteOffset, byteCount); + if (buffer != null) + JNIEnv.CopyArray (buffer, native_buffer); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=3 and parameter[1][@type='byte[]'] and parameter[2][@type='int'] and parameter[3][@type='int']]" + [Register ("read", "([BII)I", "GetRead_arrayBIIHandler")] + public virtual unsafe int Read (byte[] buffer, int byteOffset, int byteCount) + { + const string __id = "read.([BII)I"; + IntPtr native_buffer = JNIEnv.NewArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (native_buffer); + __args [1] = new JniArgumentValue (byteOffset); + __args [2] = new JniArgumentValue (byteCount); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args); + return __rm; + } finally { + if (buffer != null) { + JNIEnv.CopyArray (native_buffer, buffer); + JNIEnv.DeleteLocalRef (native_buffer); + } + global::System.GC.KeepAlive (buffer); + } + } + + static Delegate cb_reset_Reset_V; +#pragma warning disable 0169 + static Delegate GetResetHandler () + { + return cb_reset_Reset_V ??= new _JniMarshal_PP_V (n_Reset); + } + + static void n_Reset (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Reset); + } + } + private static void __n_Reset (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Reset (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='reset' and count(parameter)=0]" + [Register ("reset", "()V", "GetResetHandler")] + public virtual unsafe void Reset () + { + const string __id = "reset.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + static Delegate cb_skip_Skip_J_J; +#pragma warning disable 0169 + static Delegate GetSkip_JHandler () + { + return cb_skip_Skip_J_J ??= new _JniMarshal_PPJ_J (n_Skip_J); + } + + static long n_Skip_J (IntPtr jnienv, IntPtr native__this, long byteCount) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, byteCount, &__n_Skip_J); + } + } + private static long __n_Skip_J (IntPtr jnienv, IntPtr native__this, long byteCount) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Skip (byteCount); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='skip' and count(parameter)=1 and parameter[1][@type='long']]" + [Register ("skip", "(J)J", "GetSkip_JHandler")] + public virtual unsafe long Skip (long byteCount) + { + const string __id = "skip.(J)J"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (byteCount); + var __rm = _members.InstanceMethods.InvokeVirtualInt64Method (__id, this, __args); + return __rm; + } finally { + } + } + + } + + [global::Android.Runtime.Register ("java/io/InputStream", DoNotGenerateAcw=true)] + internal partial class InputStreamInvoker : InputStream { + public InputStreamInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/io/InputStream", typeof (InputStreamInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='InputStream']/method[@name='read' and count(parameter)=0]" + [Register ("read", "()I", "GetReadHandler")] + public override unsafe int Read () + { + const string __id = "read.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return __rm; + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.OutputStream.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.OutputStream.cs new file mode 100644 index 00000000000..8a6959ec7f2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.IO.OutputStream.cs @@ -0,0 +1,274 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.IO { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.io']/class[@name='OutputStream']" + [global::Android.Runtime.Register ("java/io/OutputStream", DoNotGenerateAcw=true)] + public abstract partial class OutputStream : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/io/OutputStream", typeof (OutputStream)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected OutputStream (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/constructor[@name='OutputStream' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe OutputStream () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_close_Close_V; +#pragma warning disable 0169 + static Delegate GetCloseHandler () + { + return cb_close_Close_V ??= new _JniMarshal_PP_V (n_Close); + } + + static void n_Close (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Close); + } + } + private static void __n_Close (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Close (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='close' and count(parameter)=0]" + [Register ("close", "()V", "GetCloseHandler")] + public virtual unsafe void Close () + { + const string __id = "close.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + static Delegate cb_flush_Flush_V; +#pragma warning disable 0169 + static Delegate GetFlushHandler () + { + return cb_flush_Flush_V ??= new _JniMarshal_PP_V (n_Flush); + } + + static void n_Flush (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Flush); + } + } + private static void __n_Flush (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Flush (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='flush' and count(parameter)=0]" + [Register ("flush", "()V", "GetFlushHandler")] + public virtual unsafe void Flush () + { + const string __id = "flush.()V"; + try { + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, null); + } finally { + } + } + + static Delegate cb_write_Write_arrayB_V; +#pragma warning disable 0169 + static Delegate GetWrite_arrayBHandler () + { + return cb_write_Write_arrayB_V ??= new _JniMarshal_PPL_V (n_Write_arrayB); + } + + static void n_Write_arrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_buffer, &__n_Write_arrayB); + } + } + private static void __n_Write_arrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var buffer = (byte[]) JNIEnv.GetArray (native_buffer, JniHandleOwnership.DoNotTransfer, typeof (byte)); + __this.Write (buffer); + if (buffer != null) + JNIEnv.CopyArray (buffer, native_buffer); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='byte[]']]" + [Register ("write", "([B)V", "GetWrite_arrayBHandler")] + public virtual unsafe void Write (byte[] buffer) + { + const string __id = "write.([B)V"; + IntPtr native_buffer = JNIEnv.NewArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_buffer); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (buffer != null) { + JNIEnv.CopyArray (native_buffer, buffer); + JNIEnv.DeleteLocalRef (native_buffer); + } + global::System.GC.KeepAlive (buffer); + } + } + + static Delegate cb_write_Write_arrayBII_V; +#pragma warning disable 0169 + static Delegate GetWrite_arrayBIIHandler () + { + return cb_write_Write_arrayBII_V ??= new _JniMarshal_PPLII_V (n_Write_arrayBII); + } + + static void n_Write_arrayBII (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer, int offset, int count) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_buffer, offset, count, &__n_Write_arrayBII); + } + } + private static void __n_Write_arrayBII (IntPtr jnienv, IntPtr native__this, IntPtr native_buffer, int offset, int count) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var buffer = (byte[]) JNIEnv.GetArray (native_buffer, JniHandleOwnership.DoNotTransfer, typeof (byte)); + __this.Write (buffer, offset, count); + if (buffer != null) + JNIEnv.CopyArray (buffer, native_buffer); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=3 and parameter[1][@type='byte[]'] and parameter[2][@type='int'] and parameter[3][@type='int']]" + [Register ("write", "([BII)V", "GetWrite_arrayBIIHandler")] + public virtual unsafe void Write (byte[] buffer, int offset, int count) + { + const string __id = "write.([BII)V"; + IntPtr native_buffer = JNIEnv.NewArray (buffer); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (native_buffer); + __args [1] = new JniArgumentValue (offset); + __args [2] = new JniArgumentValue (count); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (buffer != null) { + JNIEnv.CopyArray (native_buffer, buffer); + JNIEnv.DeleteLocalRef (native_buffer); + } + global::System.GC.KeepAlive (buffer); + } + } + + static Delegate cb_write_Write_I_V; +#pragma warning disable 0169 + static Delegate GetWrite_IHandler () + { + return cb_write_Write_I_V ??= new _JniMarshal_PPI_V (n_Write_I); + } + + static void n_Write_I (IntPtr jnienv, IntPtr native__this, int oneByte) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, oneByte, &__n_Write_I); + } + } + private static void __n_Write_I (IntPtr jnienv, IntPtr native__this, int oneByte) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Write (oneByte); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("write", "(I)V", "GetWrite_IHandler")] + public abstract void Write (int oneByte); + + } + + [global::Android.Runtime.Register ("java/io/OutputStream", DoNotGenerateAcw=true)] + internal partial class OutputStreamInvoker : OutputStream { + public OutputStreamInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/io/OutputStream", typeof (OutputStreamInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.io']/class[@name='OutputStream']/method[@name='write' and count(parameter)=1 and parameter[1][@type='int']]" + [Register ("write", "(I)V", "GetWrite_IHandler")] + public override unsafe void Write (int oneByte) + { + const string __id = "write.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (oneByte); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.Lang.Throwable.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.Lang.Throwable.cs new file mode 100644 index 00000000000..311c44de33b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Java.Lang.Throwable.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Throwable']" + [global::Android.Runtime.Register ("java/lang/Throwable", DoNotGenerateAcw=true)] + public partial class Throwable { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Throwable", typeof (Throwable)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + static Delegate cb_getMessage_GetMessage_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetGetMessageHandler () + { + return cb_getMessage_GetMessage_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_GetMessage); + } + + static IntPtr n_GetMessage (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetMessage); + } + } + private static IntPtr __n_GetMessage (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Message); + } +#pragma warning restore 0169 + + public new virtual unsafe string Message { + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/class[@name='Throwable']/method[@name='getMessage' and count(parameter)=0]" + [Register ("getMessage", "()Ljava/lang/String;", "GetGetMessageHandler")] + get { + const string __id = "getMessage.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Mono.Android.projitems new file mode 100644 index 00000000000..835eac21485 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/Mono.Android.projitems @@ -0,0 +1,18 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/__NamespaceMapping__.cs new file mode 100644 index 00000000000..811271d72d7 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/__NamespaceMapping__.cs @@ -0,0 +1,26 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.io", Managed="Java.IO")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate sbyte _JniMarshal_PP_B (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PP_I (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PP_V (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPI_V (IntPtr jnienv, IntPtr klass, int p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate long _JniMarshal_PPJ_J (IntPtr jnienv, IntPtr klass, long p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PPL_I (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PPLII_I (IntPtr jnienv, IntPtr klass, IntPtr p0, int p1, int p2); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPLII_V (IntPtr jnienv, IntPtr klass, IntPtr p0, int p1, int p2); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/Streams/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/ClassWithoutNamespace.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/ClassWithoutNamespace.cs new file mode 100644 index 00000000000..613ab546dd9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/ClassWithoutNamespace.cs @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +// Metadata.xml XPath class reference: path="/api/package[@name='']/class[@name='ClassWithoutNamespace']" +[global::Android.Runtime.Register ("ClassWithoutNamespace", DoNotGenerateAcw=true)] +public abstract partial class ClassWithoutNamespace : global::Java.Lang.Object, IInterfaceWithoutNamespace { + static readonly JniPeerMembers _members = new XAPeerMembers ("ClassWithoutNamespace", typeof (ClassWithoutNamespace)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected ClassWithoutNamespace (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='']/class[@name='ClassWithoutNamespace']/constructor[@name='ClassWithoutNamespace' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe ClassWithoutNamespace () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_Foo_Foo_V; +#pragma warning disable 0169 + static Delegate GetFooHandler () + { + return cb_Foo_Foo_V ??= new _JniMarshal_PP_V (n_Foo); + } + + static void n_Foo (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Foo); + } + } + private static void __n_Foo (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Foo (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + [Register ("Foo", "()V", "GetFooHandler")] + public abstract void Foo (); + +} + +[global::Android.Runtime.Register ("ClassWithoutNamespace", DoNotGenerateAcw=true)] +internal partial class ClassWithoutNamespaceInvoker : ClassWithoutNamespace { + public ClassWithoutNamespaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("ClassWithoutNamespace", typeof (ClassWithoutNamespaceInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + [Register ("Foo", "()V", "GetFooHandler")] + public override unsafe void Foo () + { + const string __id = "Foo.()V"; + try { + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/IInterfaceWithoutNamespace.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/IInterfaceWithoutNamespace.cs new file mode 100644 index 00000000000..4b9ea61616b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/IInterfaceWithoutNamespace.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +// Metadata.xml XPath interface reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']" +[Register ("InterfaceWithoutNamespace", "", "IInterfaceWithoutNamespaceInvoker")] +public partial interface IInterfaceWithoutNamespace : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='']/interface[@name='InterfaceWithoutNamespace']/method[@name='Foo' and count(parameter)=0]" + [Register ("Foo", "()V", "GetFooHandler:IInterfaceWithoutNamespaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Foo (); + +} + +[global::Android.Runtime.Register ("InterfaceWithoutNamespace", DoNotGenerateAcw=true)] +internal partial class IInterfaceWithoutNamespaceInvoker : global::Java.Lang.Object, IInterfaceWithoutNamespace { + static IntPtr java_class_ref { + get { return _members__InterfaceWithoutNamespace.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members__InterfaceWithoutNamespace; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members__InterfaceWithoutNamespace.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members__InterfaceWithoutNamespace.ManagedPeerType; } + } + + static readonly JniPeerMembers _members__InterfaceWithoutNamespace = new XAPeerMembers ("InterfaceWithoutNamespace", typeof (IInterfaceWithoutNamespaceInvoker)); + + public IInterfaceWithoutNamespaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_Foo_Foo_V; +#pragma warning disable 0169 + static Delegate GetFooHandler () + { + return cb_Foo_Foo_V ??= new _JniMarshal_PP_V (n_Foo); + } + + static void n_Foo (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Foo); + } + } + private static void __n_Foo (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Foo (); + } +#pragma warning restore 0169 + + public unsafe void Foo () + { + const string __id = "Foo.()V"; + try { + _members__InterfaceWithoutNamespace.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Lang.String.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Lang.String.cs new file mode 100644 index 00000000000..f9d26ceef45 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Lang.String.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='String']" + [global::Android.Runtime.Register ("java/lang/String", DoNotGenerateAcw=true)] + public sealed partial class String : global::Java.Lang.Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/String", typeof (String)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + internal String (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs new file mode 100644 index 00000000000..5f366be2722 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Collection']" + [Register ("java/util/Collection", "", "Java.Util.ICollectionInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface ICollection : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Collection']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [Register ("add", "(Ljava/lang/Object;)Z", "GetAdd_Ljava_lang_Object_Handler:Java.Util.ICollectionInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + bool Add (global::Java.Lang.Object e); + + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Collection']/method[@name='clear' and count(parameter)=0]" + [Register ("clear", "()V", "GetClearHandler:Java.Util.ICollectionInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Clear (); + + } + + [global::Android.Runtime.Register ("java/util/Collection", DoNotGenerateAcw=true)] + internal partial class ICollectionInvoker : global::Java.Lang.Object, ICollection { + static IntPtr java_class_ref { + get { return _members_java_util_Collection.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Collection; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_java_util_Collection.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_java_util_Collection.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new XAPeerMembers ("java/util/Collection", typeof (ICollectionInvoker)); + + public ICollectionInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_add_Add_Ljava_lang_Object__Z; +#pragma warning disable 0169 + static Delegate GetAdd_Ljava_lang_Object_Handler () + { + return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_B (n_Add_Ljava_lang_Object_); + } + + static sbyte n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_e, &__n_Add_Ljava_lang_Object_); + } + } + private static sbyte __n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var e = global::Java.Lang.Object.GetObject (native_e, JniHandleOwnership.DoNotTransfer); + sbyte __ret = __this.Add (e) ? (sbyte)1 : (sbyte)0; + return __ret; + } +#pragma warning restore 0169 + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + IntPtr native_e = JNIEnv.ToLocalJniHandle (e); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Collection.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_e); + global::System.GC.KeepAlive (e); + } + } + + static Delegate cb_clear_Clear_V; +#pragma warning disable 0169 + static Delegate GetClearHandler () + { + return cb_clear_Clear_V ??= new _JniMarshal_PP_V (n_Clear); + } + + static void n_Clear (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Clear); + } + } + private static void __n_Clear (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Clear (); + } +#pragma warning restore 0169 + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs new file mode 100644 index 00000000000..0e38e3ef14a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Deque']" + [Register ("java/util/Deque", "", "Java.Util.IDequeInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IDeque : global::Java.Util.IQueue { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Deque']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [Register ("add", "(Ljava/lang/Object;)Z", "GetAdd_Ljava_lang_Object_Handler:Java.Util.IDequeInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + bool Add (global::Java.Lang.Object e); + + } + + [global::Android.Runtime.Register ("java/util/Deque", DoNotGenerateAcw=true)] + internal partial class IDequeInvoker : global::Java.Lang.Object, IDeque { + static IntPtr java_class_ref { + get { return _members_java_util_Deque.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Deque; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_java_util_Deque.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_java_util_Deque.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new XAPeerMembers ("java/util/Collection", typeof (IDequeInvoker)); + + static readonly JniPeerMembers _members_java_util_Deque = new XAPeerMembers ("java/util/Deque", typeof (IDequeInvoker)); + + static readonly JniPeerMembers _members_java_util_Queue = new XAPeerMembers ("java/util/Queue", typeof (IDequeInvoker)); + + public IDequeInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_add_Add_Ljava_lang_Object__Z; +#pragma warning disable 0169 + static Delegate GetAdd_Ljava_lang_Object_Handler () + { + return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_B (n_Add_Ljava_lang_Object_); + } + + static sbyte n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_e, &__n_Add_Ljava_lang_Object_); + } + } + private static sbyte __n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var e = global::Java.Lang.Object.GetObject (native_e, JniHandleOwnership.DoNotTransfer); + sbyte __ret = __this.Add (e) ? (sbyte)1 : (sbyte)0; + return __ret; + } +#pragma warning restore 0169 + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + IntPtr native_e = JNIEnv.ToLocalJniHandle (e); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Deque.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_e); + global::System.GC.KeepAlive (e); + } + } + + static Delegate cb_clear_Clear_V; +#pragma warning disable 0169 + static Delegate GetClearHandler () + { + return cb_clear_Clear_V ??= new _JniMarshal_PP_V (n_Clear); + } + + static void n_Clear (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Clear); + } + } + private static void __n_Clear (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Clear (); + } +#pragma warning restore 0169 + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs new file mode 100644 index 00000000000..6aea8ff7537 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='Queue']" + [Register ("java/util/Queue", "", "Java.Util.IQueueInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IQueue : global::Java.Util.ICollection { + // Metadata.xml XPath method reference: path="/api/package[@name='java.util']/interface[@name='Queue']/method[@name='add' and count(parameter)=1 and parameter[1][@type='E']]" + [Register ("add", "(Ljava/lang/Object;)Z", "GetAdd_Ljava_lang_Object_Handler:Java.Util.IQueueInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + bool Add (global::Java.Lang.Object e); + + } + + [global::Android.Runtime.Register ("java/util/Queue", DoNotGenerateAcw=true)] + internal partial class IQueueInvoker : global::Java.Lang.Object, IQueue { + static IntPtr java_class_ref { + get { return _members_java_util_Queue.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_Queue; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_java_util_Queue.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_java_util_Queue.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_java_util_Collection = new XAPeerMembers ("java/util/Collection", typeof (IQueueInvoker)); + + static readonly JniPeerMembers _members_java_util_Queue = new XAPeerMembers ("java/util/Queue", typeof (IQueueInvoker)); + + public IQueueInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_add_Add_Ljava_lang_Object__Z; +#pragma warning disable 0169 + static Delegate GetAdd_Ljava_lang_Object_Handler () + { + return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_B (n_Add_Ljava_lang_Object_); + } + + static sbyte n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_e, &__n_Add_Ljava_lang_Object_); + } + } + private static sbyte __n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var e = global::Java.Lang.Object.GetObject (native_e, JniHandleOwnership.DoNotTransfer); + sbyte __ret = __this.Add (e) ? (sbyte)1 : (sbyte)0; + return __ret; + } +#pragma warning restore 0169 + + public unsafe bool Add (global::Java.Lang.Object e) + { + const string __id = "add.(Ljava/lang/Object;)Z"; + IntPtr native_e = JNIEnv.ToLocalJniHandle (e); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_e); + var __rm = _members_java_util_Queue.InstanceMethods.InvokeAbstractBooleanMethod (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_e); + global::System.GC.KeepAlive (e); + } + } + + static Delegate cb_clear_Clear_V; +#pragma warning disable 0169 + static Delegate GetClearHandler () + { + return cb_clear_Clear_V ??= new _JniMarshal_PP_V (n_Clear); + } + + static void n_Clear (IntPtr jnienv, IntPtr native__this) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, &__n_Clear); + } + } + private static void __n_Clear (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + __this.Clear (); + } +#pragma warning restore 0169 + + public unsafe void Clear () + { + const string __id = "clear.()V"; + try { + _members_java_util_Collection.InstanceMethods.InvokeAbstractVoidMethod (__id, this, null); + } finally { + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Mono.Android.projitems new file mode 100644 index 00000000000..579227feeae --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Mono.Android.projitems @@ -0,0 +1,27 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericImplementation.cs new file mode 100644 index 00000000000..885f1f0e816 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericImplementation.cs @@ -0,0 +1,115 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericImplementation']" + [global::Android.Runtime.Register ("test/me/GenericImplementation", DoNotGenerateAcw=true)] + public partial class GenericImplementation : global::Java.Lang.Object, global::Test.ME.IGenericInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("test/me/GenericImplementation", typeof (GenericImplementation)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected GenericImplementation (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericImplementation']/constructor[@name='GenericImplementation' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe GenericImplementation () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_SetObject_SetObject_arrayB_V; +#pragma warning disable 0169 + static Delegate GetSetObject_arrayBHandler () + { + return cb_SetObject_SetObject_arrayB_V ??= new _JniMarshal_PPL_V (n_SetObject_arrayB); + } + + static void n_SetObject_arrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_SetObject_arrayB); + } + } + private static void __n_SetObject_arrayB (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = (byte[]) JNIEnv.GetArray (native_value, JniHandleOwnership.DoNotTransfer, typeof (byte)); + __this.SetObject (value); + if (value != null) + JNIEnv.CopyArray (value, native_value); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='byte[]']]" + [Register ("SetObject", "([B)V", "GetSetObject_arrayBHandler")] + public virtual unsafe void SetObject (byte[] value) + { + const string __id = "SetObject.([B)V"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + + // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericInterface + void global::Test.ME.IGenericInterface.SetObject (global::Java.Lang.Object value) + { + SetObject (value.ToArray ()); + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs new file mode 100644 index 00000000000..8ea79c2e21b --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericObjectPropertyImplementation.cs @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']" + [global::Android.Runtime.Register ("test/me/GenericObjectPropertyImplementation", DoNotGenerateAcw=true)] + public partial class GenericObjectPropertyImplementation : global::Java.Lang.Object, global::Test.ME.IGenericPropertyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("test/me/GenericObjectPropertyImplementation", typeof (GenericObjectPropertyImplementation)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected GenericObjectPropertyImplementation (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']/constructor[@name='GenericObjectPropertyImplementation' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe GenericObjectPropertyImplementation () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_getObject_GetObject_Ljava_lang_Object_; +#pragma warning disable 0169 + static Delegate GetGetObjectHandler () + { + return cb_getObject_GetObject_Ljava_lang_Object_ ??= new _JniMarshal_PP_L (n_GetObject); + } + + static IntPtr n_GetObject (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetObject); + } + } + private static IntPtr __n_GetObject (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.Object); + } +#pragma warning restore 0169 + + static Delegate cb_setObject_SetObject_Ljava_lang_Object__V; +#pragma warning disable 0169 + static Delegate GetSetObject_Ljava_lang_Object_Handler () + { + return cb_setObject_SetObject_Ljava_lang_Object__V ??= new _JniMarshal_PPL_V (n_SetObject_Ljava_lang_Object_); + } + + static void n_SetObject_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native__object) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native__object, &__n_SetObject_Ljava_lang_Object_); + } + } + private static void __n_SetObject_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native__object) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var @object = global::Java.Lang.Object.GetObject (native__object, JniHandleOwnership.DoNotTransfer); + __this.Object = @object; + } +#pragma warning restore 0169 + + public virtual unsafe global::Java.Lang.Object Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']/method[@name='getObject' and count(parameter)=0]" + [Register ("getObject", "()Ljava/lang/Object;", "GetGetObjectHandler")] + get { + const string __id = "getObject.()Ljava/lang/Object;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericObjectPropertyImplementation']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("setObject", "(Ljava/lang/Object;)V", "GetSetObject_Ljava_lang_Object_Handler")] + set { + const string __id = "setObject.(Ljava/lang/Object;)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((value == null) ? IntPtr.Zero : ((global::Java.Lang.Object) value).Handle); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericStringImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericStringImplementation.cs new file mode 100644 index 00000000000..151f245abd9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericStringImplementation.cs @@ -0,0 +1,115 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericStringImplementation']" + [global::Android.Runtime.Register ("test/me/GenericStringImplementation", DoNotGenerateAcw=true)] + public partial class GenericStringImplementation : global::Java.Lang.Object, global::Test.ME.IGenericInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("test/me/GenericStringImplementation", typeof (GenericStringImplementation)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected GenericStringImplementation (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericStringImplementation']/constructor[@name='GenericStringImplementation' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe GenericStringImplementation () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_SetObject_SetObject_arrayLjava_lang_String__V; +#pragma warning disable 0169 + static Delegate GetSetObject_arrayLjava_lang_String_Handler () + { + return cb_SetObject_SetObject_arrayLjava_lang_String__V ??= new _JniMarshal_PPL_V (n_SetObject_arrayLjava_lang_String_); + } + + static void n_SetObject_arrayLjava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_SetObject_arrayLjava_lang_String_); + } + } + private static void __n_SetObject_arrayLjava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = (string[]) JNIEnv.GetArray (native_value, JniHandleOwnership.DoNotTransfer, typeof (string)); + __this.SetObject (value); + if (value != null) + JNIEnv.CopyArray (value, native_value); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericStringImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='java.lang.String[]']]" + [Register ("SetObject", "([Ljava/lang/String;)V", "GetSetObject_arrayLjava_lang_String_Handler")] + public virtual unsafe void SetObject (string[] value) + { + const string __id = "SetObject.([Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + global::System.GC.KeepAlive (value); + } + } + + // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericInterface + void global::Test.ME.IGenericInterface.SetObject (global::Java.Lang.Object value) + { + SetObject (value.ToArray ()); + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs new file mode 100644 index 00000000000..dc9859f3695 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.GenericStringPropertyImplementation.cs @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']" + [global::Android.Runtime.Register ("test/me/GenericStringPropertyImplementation", DoNotGenerateAcw=true)] + public partial class GenericStringPropertyImplementation : global::Java.Lang.Object, global::Test.ME.IGenericPropertyInterface { + static readonly JniPeerMembers _members = new XAPeerMembers ("test/me/GenericStringPropertyImplementation", typeof (GenericStringPropertyImplementation)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected GenericStringPropertyImplementation (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']/constructor[@name='GenericStringPropertyImplementation' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe GenericStringPropertyImplementation () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_getObject_GetObject_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetGetObjectHandler () + { + return cb_getObject_GetObject_Ljava_lang_String_ ??= new _JniMarshal_PP_L (n_GetObject); + } + + static IntPtr n_GetObject (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetObject); + } + } + private static IntPtr __n_GetObject (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.Object); + } +#pragma warning restore 0169 + + static Delegate cb_SetObject_SetObject_Ljava_lang_String__V; +#pragma warning disable 0169 + static Delegate GetSetObject_Ljava_lang_String_Handler () + { + return cb_SetObject_SetObject_Ljava_lang_String__V ??= new _JniMarshal_PPL_V (n_SetObject_Ljava_lang_String_); + } + + static void n_SetObject_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native__object) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native__object, &__n_SetObject_Ljava_lang_String_); + } + } + private static void __n_SetObject_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native__object) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var @object = JNIEnv.GetString (native__object, JniHandleOwnership.DoNotTransfer); + __this.Object = @object; + } +#pragma warning restore 0169 + + public virtual unsafe string Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']/method[@name='getObject' and count(parameter)=0]" + [Register ("getObject", "()Ljava/lang/String;", "GetGetObjectHandler")] + get { + const string __id = "getObject.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/class[@name='GenericStringPropertyImplementation']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("SetObject", "(Ljava/lang/String;)V", "GetSetObject_Ljava_lang_String_Handler")] + set { + const string __id = "SetObject.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString ((string)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + // This method is explicitly implemented as a member of an instantiated Test.ME.IGenericPropertyInterface + global::Java.Lang.Object global::Test.ME.IGenericPropertyInterface.Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='getObject' and count(parameter)=0]" + [Register ("getObject", "()Ljava/lang/Object;", "GetGetObjectHandler:Test.ME.IGenericPropertyInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + get { return Object; } + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("setObject", "(Ljava/lang/Object;)V", "GetSetObject_Ljava_lang_Object_Handler:Test.ME.IGenericPropertyInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + set { Object = value?.ToString (); } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.IGenericInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.IGenericInterface.cs new file mode 100644 index 00000000000..ea85904ea7f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.IGenericInterface.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath interface reference: path="/api/package[@name='test.me']/interface[@name='GenericInterface']" + [Register ("test/me/GenericInterface", "", "Test.ME.IGenericInterfaceInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial interface IGenericInterface : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericInterface']/method[@name='SetObject' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("SetObject", "(Ljava/lang/Object;)V", "GetSetObject_Ljava_lang_Object_Handler:Test.ME.IGenericInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void SetObject (global::Java.Lang.Object value); + + } + + [global::Android.Runtime.Register ("test/me/GenericInterface", DoNotGenerateAcw=true)] + internal partial class IGenericInterfaceInvoker : global::Java.Lang.Object, IGenericInterface { + static IntPtr java_class_ref { + get { return _members_test_me_GenericInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_GenericInterface; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_test_me_GenericInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_test_me_GenericInterface.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_test_me_GenericInterface = new XAPeerMembers ("test/me/GenericInterface", typeof (IGenericInterfaceInvoker)); + + public IGenericInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_SetObject_SetObject_Ljava_lang_Object__V; +#pragma warning disable 0169 + static Delegate GetSetObject_Ljava_lang_Object_Handler () + { + return cb_SetObject_SetObject_Ljava_lang_Object__V ??= new _JniMarshal_PPL_V (n_SetObject_Ljava_lang_Object_); + } + + static void n_SetObject_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_SetObject_Ljava_lang_Object_); + } + } + private static void __n_SetObject_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + __this.SetObject (value); + } +#pragma warning restore 0169 + + public unsafe void SetObject (global::Java.Lang.Object value) + { + const string __id = "SetObject.(Ljava/lang/Object;)V"; + IntPtr native_value = JNIEnv.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_test_me_GenericInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.IGenericPropertyInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.IGenericPropertyInterface.cs new file mode 100644 index 00000000000..9c40dc51df9 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.IGenericPropertyInterface.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath interface reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']" + [Register ("test/me/GenericPropertyInterface", "", "Test.ME.IGenericPropertyInterfaceInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial interface IGenericPropertyInterface : IJavaObject, IJavaPeerable { + global::Java.Lang.Object Object { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='getObject' and count(parameter)=0]" + [Register ("getObject", "()Ljava/lang/Object;", "GetGetObjectHandler:Test.ME.IGenericPropertyInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + get; + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='GenericPropertyInterface']/method[@name='setObject' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("setObject", "(Ljava/lang/Object;)V", "GetSetObject_Ljava_lang_Object_Handler:Test.ME.IGenericPropertyInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + set; + } + + } + + [global::Android.Runtime.Register ("test/me/GenericPropertyInterface", DoNotGenerateAcw=true)] + internal partial class IGenericPropertyInterfaceInvoker : global::Java.Lang.Object, IGenericPropertyInterface { + static IntPtr java_class_ref { + get { return _members_test_me_GenericPropertyInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_GenericPropertyInterface; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_test_me_GenericPropertyInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_test_me_GenericPropertyInterface.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_test_me_GenericPropertyInterface = new XAPeerMembers ("test/me/GenericPropertyInterface", typeof (IGenericPropertyInterfaceInvoker)); + + public IGenericPropertyInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_getObject_GetObject_Ljava_lang_Object_; +#pragma warning disable 0169 + static Delegate GetGetObjectHandler () + { + return cb_getObject_GetObject_Ljava_lang_Object_ ??= new _JniMarshal_PP_L (n_GetObject); + } + + static IntPtr n_GetObject (IntPtr jnienv, IntPtr native__this) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, &__n_GetObject); + } + } + private static IntPtr __n_GetObject (IntPtr jnienv, IntPtr native__this) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.ToLocalJniHandle (__this.Object); + } +#pragma warning restore 0169 + + static Delegate cb_setObject_SetObject_Ljava_lang_Object__V; +#pragma warning disable 0169 + static Delegate GetSetObject_Ljava_lang_Object_Handler () + { + return cb_setObject_SetObject_Ljava_lang_Object__V ??= new _JniMarshal_PPL_V (n_SetObject_Ljava_lang_Object_); + } + + static void n_SetObject_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native__object) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native__object, &__n_SetObject_Ljava_lang_Object_); + } + } + private static void __n_SetObject_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native__object) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var @object = global::Java.Lang.Object.GetObject (native__object, JniHandleOwnership.DoNotTransfer); + __this.Object = @object; + } +#pragma warning restore 0169 + + public unsafe global::Java.Lang.Object Object { + get { + const string __id = "getObject.()Ljava/lang/Object;"; + try { + var __rm = _members_test_me_GenericPropertyInterface.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (global::Java.Lang.Object) global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + set { + const string __id = "setObject.(Ljava/lang/Object;)V"; + IntPtr native_value = JNIEnv.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_test_me_GenericPropertyInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.ITestInterface.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.ITestInterface.cs new file mode 100644 index 00000000000..5df4d25ee9e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.ITestInterface.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + [Register ("mono/internal/test/me/TestInterface", DoNotGenerateAcw=true)] + public abstract class TestInterface : Java.Lang.Object { + internal TestInterface () + { + } + + // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='SPAN_COMPOSING']" + [Register ("SPAN_COMPOSING")] + public const int SpanComposing = (int) 256; + + + // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='DEFAULT_FOO']" + [Register ("DEFAULT_FOO")] + public static global::Java.Lang.Object DefaultFoo { + get { + const string __id = "DEFAULT_FOO.Ljava/lang/Object;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("test/me/TestInterface", typeof (TestInterface)); + + } + + [Register ("mono/internal/test/me/TestInterface", DoNotGenerateAcw=true)] + [global::System.Obsolete (@"Use the 'TestInterface' type. This type will be removed in a future release.", error: true)] + public abstract class TestInterfaceConsts : TestInterface { + private TestInterfaceConsts () + { + } + + } + + // Metadata.xml XPath interface reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']" + [Register ("test/me/TestInterface", "", "Test.ME.ITestInterfaceInvoker")] + public partial interface ITestInterface : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + int GetSpanFlags (global::Java.Lang.Object tag); + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Append (global::Java.Lang.ICharSequence value); + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + } + + public static partial class ITestInterfaceExtensions { + public static void Append (this Test.ME.ITestInterface self, string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + self.Append (jls_value); + jls_value?.Dispose (); + } + + public static string Identity (this Test.ME.ITestInterface self, string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = self.IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + + } + + [global::Android.Runtime.Register ("test/me/TestInterface", DoNotGenerateAcw=true)] + internal partial class ITestInterfaceInvoker : global::Java.Lang.Object, ITestInterface { + static IntPtr java_class_ref { + get { return _members_test_me_TestInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_test_me_TestInterface; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_test_me_TestInterface.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_test_me_TestInterface.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_test_me_TestInterface = new XAPeerMembers ("test/me/TestInterface", typeof (ITestInterfaceInvoker)); + + public ITestInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I; +#pragma warning disable 0169 + static Delegate GetGetSpanFlags_Ljava_lang_Object_Handler () + { + return cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I ??= new _JniMarshal_PPL_I (n_GetSpanFlags_Ljava_lang_Object_); + } + + static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_tag, &__n_GetSpanFlags_Ljava_lang_Object_); + } + } + private static int __n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var tag = global::Java.Lang.Object.GetObject (native_tag, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetSpanFlags (tag); + return __ret; + } +#pragma warning restore 0169 + + public unsafe int GetSpanFlags (global::Java.Lang.Object tag) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((tag == null) ? IntPtr.Zero : ((global::Java.Lang.Object) tag).Handle); + var __rm = _members_test_me_TestInterface.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (tag); + } + } + + static Delegate cb_append_Append_Ljava_lang_CharSequence__V; +#pragma warning disable 0169 + static Delegate GetAppend_Ljava_lang_CharSequence_Handler () + { + return cb_append_Append_Ljava_lang_CharSequence__V ??= new _JniMarshal_PPL_V (n_Append_Ljava_lang_CharSequence_); + } + + static void n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_Append_Ljava_lang_CharSequence_); + } + } + private static void __n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + __this.Append (value); + } +#pragma warning restore 0169 + + public unsafe void Append (global::Java.Lang.ICharSequence value) + { + const string __id = "append.(Ljava/lang/CharSequence;)V"; + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members_test_me_TestInterface.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + + static Delegate cb_identity_Identity_Ljava_lang_CharSequence__Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetIdentity_Ljava_lang_CharSequence_Handler () + { + return cb_identity_Identity_Ljava_lang_CharSequence__Ljava_lang_CharSequence_ ??= new _JniMarshal_PPL_L (n_Identity_Ljava_lang_CharSequence_); + } + + static IntPtr n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_value, &__n_Identity_Ljava_lang_CharSequence_); + } + } + private static IntPtr __n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + IntPtr __ret = CharSequence.ToLocalJniHandle (__this.IdentityFormatted (value)); + return __ret; + } +#pragma warning restore 0169 + + public unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + const string __id = "identity.(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"; + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members_test_me_TestInterface.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.TestInterfaceImplementation.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.TestInterfaceImplementation.cs new file mode 100644 index 00000000000..ad4e1e4d659 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/Test.ME.TestInterfaceImplementation.cs @@ -0,0 +1,251 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Test.ME { + + // Metadata.xml XPath class reference: path="/api/package[@name='test.me']/class[@name='TestInterfaceImplementation']" + [global::Android.Runtime.Register ("test/me/TestInterfaceImplementation", DoNotGenerateAcw=true)] + public abstract partial class TestInterfaceImplementation : global::Java.Lang.Object, global::Test.ME.ITestInterface { + public static class InterfaceConsts { + // The following are fields from: test.me.TestInterface + + // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='SPAN_COMPOSING']" + [Register ("SPAN_COMPOSING")] + public const int SpanComposing = (int) 256; + + + // Metadata.xml XPath field reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/field[@name='DEFAULT_FOO']" + [Register ("DEFAULT_FOO")] + public static global::Java.Lang.Object DefaultFoo { + get { + const string __id = "DEFAULT_FOO.Ljava/lang/Object;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("test/me/TestInterfaceImplementation", typeof (TestInterfaceImplementation)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected TestInterfaceImplementation (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath constructor reference: path="/api/package[@name='test.me']/class[@name='TestInterfaceImplementation']/constructor[@name='TestInterfaceImplementation' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe TestInterfaceImplementation () : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + static Delegate cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I; +#pragma warning disable 0169 + static Delegate GetGetSpanFlags_Ljava_lang_Object_Handler () + { + return cb_getSpanFlags_GetSpanFlags_Ljava_lang_Object__I ??= new _JniMarshal_PPL_I (n_GetSpanFlags_Ljava_lang_Object_); + } + + static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_tag, &__n_GetSpanFlags_Ljava_lang_Object_); + } + } + private static int __n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_tag) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var tag = global::Java.Lang.Object.GetObject (native_tag, JniHandleOwnership.DoNotTransfer); + int __ret = __this.GetSpanFlags (tag); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler")] + public abstract int GetSpanFlags (global::Java.Lang.Object tag); + + static Delegate cb_append_Append_Ljava_lang_CharSequence__V; +#pragma warning disable 0169 + static Delegate GetAppend_Ljava_lang_CharSequence_Handler () + { + return cb_append_Append_Ljava_lang_CharSequence__V ??= new _JniMarshal_PPL_V (n_Append_Ljava_lang_CharSequence_); + } + + static void n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + global::Java.Interop.JniMarshal.SafeInvokeAction (jnienv, native__this, native_value, &__n_Append_Ljava_lang_CharSequence_); + } + } + private static void __n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + __this.Append (value); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler")] + public abstract void Append (global::Java.Lang.ICharSequence value); + + public void Append (string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + Append (jls_value); + jls_value?.Dispose (); + } + + static Delegate cb_identity_Identity_Ljava_lang_CharSequence__Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetIdentity_Ljava_lang_CharSequence_Handler () + { + return cb_identity_Identity_Ljava_lang_CharSequence__Ljava_lang_CharSequence_ ??= new _JniMarshal_PPL_L (n_Identity_Ljava_lang_CharSequence_); + } + + static IntPtr n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_value, &__n_Identity_Ljava_lang_CharSequence_); + } + } + private static IntPtr __n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + IntPtr __ret = CharSequence.ToLocalJniHandle (__this.IdentityFormatted (value)); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler")] + public abstract global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + public string Identity (string value) + { + var jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + + } + + [global::Android.Runtime.Register ("test/me/TestInterfaceImplementation", DoNotGenerateAcw=true)] + internal partial class TestInterfaceImplementationInvoker : TestInterfaceImplementation { + public TestInterfaceImplementationInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("test/me/TestInterfaceImplementation", typeof (TestInterfaceImplementationInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='getSpanFlags' and count(parameter)=1 and parameter[1][@type='java.lang.Object']]" + [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler")] + public override unsafe int GetSpanFlags (global::Java.Lang.Object tag) + { + const string __id = "getSpanFlags.(Ljava/lang/Object;)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue ((tag == null) ? IntPtr.Zero : ((global::Java.Lang.Object) tag).Handle); + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return __rm; + } finally { + global::System.GC.KeepAlive (tag); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler")] + public override unsafe void Append (global::Java.Lang.ICharSequence value) + { + const string __id = "append.(Ljava/lang/CharSequence;)V"; + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler")] + public override unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + const string __id = "identity.(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"; + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + JNIEnv.DeleteLocalRef (native_value); + global::System.GC.KeepAlive (value); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/__NamespaceMapping__.cs new file mode 100644 index 00000000000..42243b9747e --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/__NamespaceMapping__.cs @@ -0,0 +1,20 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.util", Managed="Java.Util")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "test.me", Managed="Test.ME")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "", Managed="")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PP_V (IntPtr jnienv, IntPtr klass); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate sbyte _JniMarshal_PPL_B (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PPL_I (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate IntPtr _JniMarshal_PPL_L (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/TestInterface/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.Enum.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.Enum.cs new file mode 100644 index 00000000000..d5792caca14 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.Enum.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Enum']" + [global::Android.Runtime.Register ("java/lang/Enum", DoNotGenerateAcw=true)] + [global::Java.Interop.JavaTypeParameters (new string [] {"E extends java.lang.Enum"})] + public abstract partial class Enum : global::Java.Lang.Object, global::Java.Lang.IComparable { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Enum", typeof (Enum)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Enum (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/class[@name='Enum']/method[@name='compareTo' and count(parameter)=1 and parameter[1][@type='E']]" + [Register ("compareTo", "(Ljava/lang/Enum;)I", "")] + public unsafe int CompareTo (global::Java.Lang.Object o) + { + const string __id = "compareTo.(Ljava/lang/Enum;)I"; + IntPtr native_o = JNIEnv.ToLocalJniHandle (o); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_o); + var __rm = _members.InstanceMethods.InvokeNonvirtualInt32Method (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_o); + global::System.GC.KeepAlive (o); + } + } + + } + + [global::Android.Runtime.Register ("java/lang/Enum", DoNotGenerateAcw=true)] + internal partial class EnumInvoker : Enum, global::Java.Lang.IComparable { + public EnumInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Enum", typeof (EnumInvoker)); + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.IComparable.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.IComparable.cs new file mode 100644 index 00000000000..8667c2f003f --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.IComparable.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.lang']/interface[@name='Comparable']" + [Register ("java/lang/Comparable", "", "Java.Lang.IComparableInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"T"})] + public partial interface IComparable : IJavaObject, IJavaPeerable { + // Metadata.xml XPath method reference: path="/api/package[@name='java.lang']/interface[@name='Comparable']/method[@name='compareTo' and count(parameter)=1 and parameter[1][@type='T']]" + [Register ("compareTo", "(Ljava/lang/Object;)I", "GetCompareTo_Ljava_lang_Object_Handler:Java.Lang.IComparableInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + int CompareTo (global::Java.Lang.Object another); + + } + + [global::Android.Runtime.Register ("java/lang/Comparable", DoNotGenerateAcw=true)] + internal partial class IComparableInvoker : global::Java.Lang.Object, IComparable { + static IntPtr java_class_ref { + get { return _members_java_lang_Comparable.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_lang_Comparable; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_java_lang_Comparable.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_java_lang_Comparable.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_java_lang_Comparable = new XAPeerMembers ("java/lang/Comparable", typeof (IComparableInvoker)); + + public IComparableInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + static Delegate cb_compareTo_CompareTo_Ljava_lang_Object__I; +#pragma warning disable 0169 + static Delegate GetCompareTo_Ljava_lang_Object_Handler () + { + return cb_compareTo_CompareTo_Ljava_lang_Object__I ??= new _JniMarshal_PPL_I (n_CompareTo_Ljava_lang_Object_); + } + + static int n_CompareTo_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_another) + { + unsafe { + return global::Java.Interop.JniMarshal.SafeInvokeFunc (jnienv, native__this, native_another, &__n_CompareTo_Ljava_lang_Object_); + } + } + private static int __n_CompareTo_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_another) + { + var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + var another = global::Java.Lang.Object.GetObject (native_another, JniHandleOwnership.DoNotTransfer); + int __ret = __this.CompareTo (another); + return __ret; + } +#pragma warning restore 0169 + + public unsafe int CompareTo (global::Java.Lang.Object another) + { + const string __id = "compareTo.(Ljava/lang/Object;)I"; + IntPtr native_another = JNIEnv.ToLocalJniHandle (another); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_another); + var __rm = _members_java_lang_Comparable.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return __rm; + } finally { + JNIEnv.DeleteLocalRef (native_another); + global::System.GC.KeepAlive (another); + } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.State.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.State.cs new file mode 100644 index 00000000000..994daa84876 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Java.Lang.State.cs @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='State']" + [global::Android.Runtime.Register ("java/lang/State", DoNotGenerateAcw=true)] + public sealed partial class State : global::Java.Lang.Enum { + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='BLOCKED']" + [Register ("BLOCKED")] + public static global::Java.Lang.State Blocked { + get { + const string __id = "BLOCKED.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='NEW']" + [Register ("NEW")] + public static global::Java.Lang.State New { + get { + const string __id = "NEW.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='RUNNABLE']" + [Register ("RUNNABLE")] + public static global::Java.Lang.State Runnable { + get { + const string __id = "RUNNABLE.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='TERMINATED']" + [Register ("TERMINATED")] + public static global::Java.Lang.State Terminated { + get { + const string __id = "TERMINATED.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='TIMED_WAITING']" + [Register ("TIMED_WAITING")] + public static global::Java.Lang.State TimedWaiting { + get { + const string __id = "TIMED_WAITING.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='java.lang']/class[@name='State']/field[@name='WAITING']" + [Register ("WAITING")] + public static global::Java.Lang.State Waiting { + get { + const string __id = "WAITING.Ljava/lang/State;"; + + var __v = _members.StaticFields.GetObjectValue (__id); + return global::Java.Lang.Object.GetObject (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/State", typeof (State)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + internal State (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Mono.Android.projitems new file mode 100644 index 00000000000..24a983853b1 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/Mono.Android.projitems @@ -0,0 +1,16 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/__NamespaceMapping__.cs new file mode 100644 index 00000000000..cd49d90a790 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/__NamespaceMapping__.cs @@ -0,0 +1,7 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] + +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate int _JniMarshal_PPL_I (IntPtr jnienv, IntPtr klass, IntPtr p0); + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/enumlist new file mode 100644 index 00000000000..368c3f7b281 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Enum/enumlist @@ -0,0 +1 @@ +java.lang.State:Java.Lang:State diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/Java.Lang.Object.cs new file mode 100644 index 00000000000..5744963dc57 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/Java.Lang.Object.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new JniPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/Mono.Android.projitems new file mode 100644 index 00000000000..2ebaae2b77a --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/Mono.Android.projitems @@ -0,0 +1,13 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/__NamespaceMapping__.cs new file mode 100644 index 00000000000..01ebfbe27d8 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/__NamespaceMapping__.cs @@ -0,0 +1,4 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] + diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.lang.Object/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Java.Lang.Object.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Java.Lang.Object.cs new file mode 100644 index 00000000000..e7029b8f7e2 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Java.Lang.Object.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Lang { + + // Metadata.xml XPath class reference: path="/api/package[@name='java.lang']/class[@name='Object']" + [global::Android.Runtime.Register ("java/lang/Object", DoNotGenerateAcw=true)] + public partial class Object { + static readonly JniPeerMembers _members = new XAPeerMembers ("java/lang/Object", typeof (Object)); + + internal static IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Java.Util.IList.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Java.Util.IList.cs new file mode 100644 index 00000000000..039257aa573 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Java.Util.IList.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Java.Util { + + // Metadata.xml XPath interface reference: path="/api/package[@name='java.util']/interface[@name='List']" + [Register ("java/util/List", "", "Java.Util.IListInvoker")] + [global::Java.Interop.JavaTypeParameters (new string [] {"E"})] + public partial interface IList : IJavaObject, IJavaPeerable { + } + + [global::Android.Runtime.Register ("java/util/List", DoNotGenerateAcw=true)] + internal partial class IListInvoker : global::Java.Lang.Object, IList { + static IntPtr java_class_ref { + get { return _members_java_util_List.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members_java_util_List; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members_java_util_List.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members_java_util_List.ManagedPeerType; } + } + + static readonly JniPeerMembers _members_java_util_List = new XAPeerMembers ("java/util/List", typeof (IListInvoker)); + + public IListInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Mono.Android.projitems b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Mono.Android.projitems new file mode 100644 index 00000000000..1b1e00f7633 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Mono.Android.projitems @@ -0,0 +1,15 @@ + + + + $(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4 + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Xamarin.Test.SomeObject.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Xamarin.Test.SomeObject.cs new file mode 100644 index 00000000000..242dfcc2d09 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/Xamarin.Test.SomeObject.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nullable restore +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']" + [global::Android.Runtime.Register ("xamarin/test/SomeObject", DoNotGenerateAcw=true)] + public partial class SomeObject : global::Java.Lang.Object { + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myStrings']" + [Register ("myStrings")] + public global::System.Collections.Generic.IList MyStrings { + get { + const string __id = "myStrings.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaList.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myStrings.Ljava/util/List;"; + + IntPtr native_value = global::Android.Runtime.JavaList.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myInts']" + [Register ("myInts")] + public global::System.Collections.Generic.IList MyInts { + get { + const string __id = "myInts.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaList.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myInts.Ljava/util/List;"; + + IntPtr native_value = global::Android.Runtime.JavaList.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mybools']" + [Register ("mybools")] + public global::System.Collections.Generic.IList Mybools { + get { + const string __id = "mybools.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaList.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "mybools.Ljava/util/List;"; + + IntPtr native_value = global::Android.Runtime.JavaList.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myObjects']" + [Register ("myObjects")] + public global::System.Collections.Generic.IList MyObjects { + get { + const string __id = "myObjects.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaList.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myObjects.Ljava/util/List;"; + + IntPtr native_value = global::Android.Runtime.JavaList.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='myfloats']" + [Register ("myfloats")] + public global::System.Collections.Generic.IList Myfloats { + get { + const string __id = "myfloats.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaList.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "myfloats.Ljava/util/List;"; + + IntPtr native_value = global::Android.Runtime.JavaList.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mydoubles']" + [Register ("mydoubles")] + public global::System.Collections.Generic.IList Mydoubles { + get { + const string __id = "mydoubles.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaList.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "mydoubles.Ljava/util/List;"; + + IntPtr native_value = global::Android.Runtime.JavaList.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + + // Metadata.xml XPath field reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject']/field[@name='mylongs']" + [Register ("mylongs")] + public global::System.Collections.Generic.IList Mylongs { + get { + const string __id = "mylongs.Ljava/util/List;"; + + var __v = _members.InstanceFields.GetObjectValue (__id, this); + return global::Android.Runtime.JavaList.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef); + } + set { + const string __id = "mylongs.Ljava/util/List;"; + + IntPtr native_value = global::Android.Runtime.JavaList.ToLocalJniHandle (value); + try { + _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value)); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + static readonly JniPeerMembers _members = new XAPeerMembers ("xamarin/test/SomeObject", typeof (SomeObject)); + + internal static new IntPtr class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + [global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)] + [global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)] + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected SomeObject (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) + { + } + + } +} diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/__NamespaceMapping__.cs b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/__NamespaceMapping__.cs new file mode 100644 index 00000000000..6604853f318 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/__NamespaceMapping__.cs @@ -0,0 +1,5 @@ +using System; + +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "java.util", Managed="Java.Util")] +[assembly:global::Android.Runtime.NamespaceMapping (Java = "xamarin.test", Managed="Xamarin.Test")] diff --git a/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/enumlist b/external/Java.Interop/tests/generator-Tests/expected.xaji/java.util.List/enumlist new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tests/generator-Tests/generator-Tests.csproj b/external/Java.Interop/tests/generator-Tests/generator-Tests.csproj new file mode 100644 index 00000000000..fb2b84c7338 --- /dev/null +++ b/external/Java.Interop/tests/generator-Tests/generator-Tests.csproj @@ -0,0 +1,75 @@ + + + + $(DotNetTargetFramework) + false + true + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/GrefsTest.cs b/external/Java.Interop/tests/logcat-parse-Tests/GrefsTest.cs new file mode 100644 index 00000000000..9dd065baf1a --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/GrefsTest.cs @@ -0,0 +1,474 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; + +using Xamarin.Android.Tools.LogcatParse; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.LogcatParse.Tests { + + [TestFixture] + public class GrefsTest { + + [Test] + public void Instances_GrefToWgrefToCollected () + { + using (var source = GetResourceStream ("logcat-gwd.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (0, info.AlivePeers.Count ()); + Assert.AreEqual (0, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsTrue (peer.Collected); + Assert.AreEqual ("android/widget/ProgressBar", peer.JniType); + Assert.AreEqual ("Android.Widget.ProgressBar", peer.McwType); + Assert.AreEqual ("0x41f008f8", peer.KeyHandle); + Assert.AreEqual (0, peer.Handles.Count); + Assert.AreEqual (3, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x41f008f8/L"); + Assert.IsTrue (peer.RemovedHandles [1] == "0x1d20046a/G"); + Assert.IsTrue (peer.RemovedHandles [2] == "0x1d200003/W"); + + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)\n" + + " at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)\n" + + " at Android.Widget.ProgressBar..ctor(Android.Content.Context context, IAttributeSet attrs, Int32 defStyle)\n" + + " at Android.Support.V4.App.Fragment.n_OnCreateView_Landroid_view_LayoutInflater_Landroid_view_ViewGroup_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, ", + peer.GetStackTraceForHandle ("0x1d20046a")); + Assert.AreEqual ( + "take_weak_global_ref_jni", + peer.GetStackTraceForHandle ("0x1d200003")); + } + } + + [Test] + public void Instances_GrefToDisposed () + { + using (var source = GetResourceStream ("logcat-disposed.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (0, info.AlivePeers.Count ()); + Assert.AreEqual (0, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsTrue (peer.Collected); + Assert.IsTrue (peer.Disposed); + Assert.AreEqual ("java/lang/String", peer.JniType); + Assert.AreEqual ("Java.Lang.String", peer.McwType); + Assert.AreEqual ("0x41e29778", peer.KeyHandle); + Assert.AreEqual (0, peer.Handles.Count); + Assert.AreEqual (2, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x41e29778/L"); + Assert.IsTrue (peer.RemovedHandles [1] == "0x1d200282/G"); + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)\n" + + " at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)\n" + + " at Java.Lang.String..ctor(System.String string)\n" + + " at Android.App.ProgressDialog.Show(Android.Content.Context context, System.String title, System.String message, Boolean indeterminate, Boolean cancelable)\n" + + " at Java.Lang.Thread+RunnableImplementor.Run()\n" + + " at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)\n" + + " at System.Object.015d773b-4c56-4e22-ab21-e971886ef628(IntPtr , IntPtr )\n" + + " at System.Object.wrapper_native_0x408f48fd(IntPtr , IntPtr , IntPtr , Android.Runtime.JValue[] )\n" + + " at Android.Runtime.JNIEnv.CallVoidMethod(IntPtr jobject, IntPtr jmethod, Android.Runtime.JValue[] parms)\n" + + " at Android.App", + peer.GetStackTraceForHandle ("0x1d200282")); + } + } + + [Test] + public void Instances_Resurrection () + { + using (var source = GetResourceStream ("logcat-resurrection.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (1, info.AlivePeers.Count ()); + Assert.AreEqual (1, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsFalse (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.AreEqual ("android/widget/LinearLayout", peer.JniType); + Assert.AreEqual ("Android.Widget.LinearLayout", peer.McwType); + Assert.AreEqual ("0x41ff8758", peer.KeyHandle); + Assert.AreEqual (1, peer.Handles.Count); + Assert.IsTrue (peer.Handles [0] == "0x1d300eea"); + Assert.AreEqual (3, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x41ff8758/L"); + Assert.IsTrue (peer.RemovedHandles [1] == "0x1d200f1e/G"); + Assert.IsTrue (peer.RemovedHandles [2] == "0x1d9000cb/W"); + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)\n" + + " at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)\n" + + " at Android.Widget.LinearLayout..ctor(Android.Content.Context context)\n" + + " at Android.Support.V4.App.Fragment.n_OnCreateView_Landroid_view_LayoutInflater_Landroid_view_ViewGroup_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native", + peer.GetStackTraceForHandle ("0x1d200f1e")); + Assert.AreEqual ( + "take_weak_global_ref_jni", + peer.GetStackTraceForHandle ("0x1d9000cb")); + Assert.AreEqual ( + "take_global_ref_jni", + peer.GetStackTraceForHandle ("0x1d300eea")); + } + } + + void Instances_CreateAndDestroy (string resource) + { + using (var source = GetResourceStream (resource)) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (0, info.AlivePeers.Count ()); + Assert.AreEqual (0, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsTrue (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.AreEqual ("Java.Lang.Thread+RunnableImplementor.class", peer.JniType); + Assert.AreEqual ("typeof(Java.Lang.Thread+RunnableImplementor)", peer.McwType); + Assert.AreEqual (0, peer.Handles.Count); + Assert.AreEqual (2, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x41e29370/L"); + Assert.IsTrue (peer.RemovedHandles [1] == "0x1d200276/G"); + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Android.Runtime.JNIEnv.FindClass(System.String classname)\n" + + " at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters)\n" + + " at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable)\n" + + " at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)\n" + + " at Android.App.Activity.RunOnUiThread(System.Action action)\n" + + " at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState)\n" + + " at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr ", + peer.GetStackTraceForHandle ("0x1d200276")); + } + } + + [Test] + public void Instances_CreateAndDestroy () + { + Instances_CreateAndDestroy ("logcat-ag-rg.txt"); + } + + [Test] + public void Instances_CreateAndDestroy_Stdout () + { + Instances_CreateAndDestroy ("stdout-ag-rg.txt"); + } + + [Test] + public void Instances_CreateAndDestroy_Timestamp () + { + Instances_CreateAndDestroy ("timestamp-ag-rg.txt"); + } + + [Test] + public void Instances_CreateAndDestroy_Stdio () + { + Instances_CreateAndDestroy ("stdio-ag-rg.txt"); + } + + [Test] + public void Instances_Alias () + { + using (var source = GetResourceStream ("logcat-alias.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (1, info.AlivePeers.Count ()); + Assert.AreEqual (2, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsFalse (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.AreEqual ("android/widget/NewButton", peer.JniType); + Assert.AreEqual ("Android.Widget.NewButton", peer.McwType); + Assert.AreEqual (2, peer.Handles.Count); + Assert.IsTrue (peer.Handles.Contains ("0x100456")); + Assert.IsTrue (peer.Handles.Contains ("0x100472")); + Assert.AreEqual (1, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0xbecdf114/L"); + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer, IntPtr ByRef handle)\n" + + " at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)\n" + + " at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)\n" + + " at Android.Views.View..ctor(IntPtr javaReference, JniHandleOwnership transfer)\n" + + " at Android.Widget.TextView..ctor(IntPtr javaReference, JniHandleOwnership transfer)\n" + + " at Android.Widget.Button..ctor(IntPtr javaReference, JniHandleOwnership transfer)\n" + + " at Android.Widget.NewButton..ctor(IntPtr jr, JniHandleOwnership tr)\n" + + " at System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod , System.Object , System.Object[] , System.Exception ByRef )\n" + + " at System.Reflection.MonoCMethod.InternalInvoke(System.Object obj, System.Object[] parameters)\n" + + " at System.Reflection.MonoCMethod.DoInvoke(Syste", + peer.GetStackTraceForHandle ("0x100456")); + } + } + + [Test] + public void GetClassRef () + { + using (var source = GetResourceStream ("logcat-get_class_ref.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (1, info.AlivePeers.Count ()); + Assert.AreEqual (1, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsFalse (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.AreEqual ("Android.Widget.Button.class", peer.JniType); + Assert.AreEqual ("typeof(Android.Widget.Button)", peer.McwType); + Assert.AreEqual (1, peer.Handles.Count); + Assert.IsTrue (peer.Handles [0] == "0x10046a"); + Assert.AreEqual (1, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x7830001d/L"); + + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Android.Runtime.JNIEnv.FindClass(System.String classname)\n" + + " at Android.Runtime.JNIEnv.FindClass(System.String className, IntPtr ByRef cachedJniClassHandle)\n" + + " at Android.Widget.Button.get_class_ref()\n" + + " at Android.Widget.Button.get_ThresholdClass()\n" + + " at Android.Views.View.SetLayerType(LayerType layerType, Android.Graphics.Paint paint)", + peer.GetStackTraceForHandle ("0x10046a")); + } + } + + [Test] + public void InvokerJavaClassRef () + { + using (var source = GetResourceStream ("logcat-Invoker-java_class_ref.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (1, info.AlivePeers.Count ()); + Assert.AreEqual (1, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsFalse (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.AreEqual ("Android.Views.View+IOnClickListenerInvoker.class", peer.JniType); + Assert.AreEqual ("typeof(Android.Views.View+IOnClickListenerInvoker)", peer.McwType); + Assert.AreEqual (1, peer.Handles.Count); + Assert.IsTrue (peer.Handles [0] == "0x100476"); + Assert.AreEqual (1, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x78b0001d/L"); + + + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Android.Runtime.JNIEnv.FindClass(System.String classname)\n" + + " at Android.Views.View+IOnClickListenerInvoker..cctor()\n" + + " at Android.Runtime.JNIEnv.RegisterJniNatives(IntPtr typeName_ptr, Int32 typeName_len, IntPtr jniClass, IntPtr methods_ptr, Int32 methods_len)\n" + + " at System.Object.wrapper_native_0xb4dd21a1(IntPtr , IntPtr )\n" + + " at Android.Runtime.JNIEnv.AllocObject(IntPtr jclass)\n" + + " at Android.Runtime.JNIEnv.AllocObject(System.String jniClassName)\n" + + " at Android.Runtime.JNIEnv.StartCreateInstance(System.String jniClassName, System.String jniCtorSignature, Android.Runtime.JValue[] constructorParameters)\n" + + " at Android.Views.View+IOnClickListenerImplementor..ctor()\n" + + " at Android.Views.View.__CreateIOnClickListenerImplementor()\n" + + " at Java.Interop.EventHelper.AddEventHandler(System.WeakReference ByRef implementor, System.Func`1 creator, System.Action`1 setListener, System.Action`1 add)\n" + + " at Android.Views.View.add_Click(System.EventHandler value)\n" + + " at System.Object.1beb6483-abe9-4bc4-b75a-e21a3e26c5a1(IntPtr , IntPtr , IntPtr )", + peer.GetStackTraceForHandle ("0x100476")); + } + } + + [Test] + public void JavaListClassRef () + { + using (var source = GetResourceStream ("stdio-JavaList.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (1, info.AlivePeers.Count ()); + Assert.AreEqual (1, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsFalse (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.IsFalse (peer.Finalized); + Assert.AreEqual ("Android.Runtime.JavaList.class", peer.JniType); + Assert.AreEqual ("typeof(Android.Runtime.JavaList)", peer.McwType); + Assert.IsTrue (peer.Handles.Contains ("0x19004aa")); + Assert.AreEqual (1, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x4a00009/L"); + + + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Android.Runtime.JNIEnv.FindClass(System.String classname)\n" + + " at Android.Runtime.JavaList..cctor()\n" + + " at Java.Interop.JavaConvert.FromJniHandle(IntPtr handle, JniHandleOwnership transfer, Boolean ByRef set)\n" + + " at Java.Interop.JavaConvert.FromJniHandle(IntPtr handle, JniHandleOwnership transfer)\n" + + " at Android.Runtime.JavaDictionary`2[[System.String, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Get(System.String key)\n" + + " at Android.Runtime.JavaDictionary`2[[System.String, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryGetValue(System.String key, System.Object ByRef value)\n" + + " at Xamarin.Android.RuntimeTests.JavaConvertTest.Conversions()\n" + + " at System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod , System.Object , System.Object[] , System.Exception ByRef )\n" + + " at System.Reflection.MonoMethod.Invoke(System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)\n" + + " at System.Reflection.MethodBase.Invoke(System.Object obj, System.Object[] parameters)\n" + + " at NUnit.Framework.Internal.Reflect.InvokeMethod(System.Reflection.MethodInfo method, System.Object fixture, System.Object[] args)\n" + + " at NUnit.Framework.Internal.Commands.TestMethodCommand.RunNonAsyncTestMethod(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.Commands.SetUpTearDownCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.SimpleWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren()\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren()\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren()\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test)\n" + + " at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test, Android.Content.Context context)\n" + + " at Xamarin.Android.NUnitLite.TestSuiteInstrumentation.OnStart()\n" + + " at Android.App.Instrumentation.n_OnStart(IntPtr jnienv, IntPtr native__this)\n" + + " at System.Object.b7ee1212-364f-405b-bebd-08a60608685f(IntPtr , IntPtr )", + peer.GetStackTraceForHandle ("0x19004aa")); + } + } + + [Test] + public void TrackThreadInformation () + { + using (var source = GetResourceStream ("stdio-Finalized-threads.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (1, info.AllocatedPeers.Count); + Assert.AreEqual (0, info.AlivePeers.Count ()); + Assert.AreEqual (0, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers.First (); + Assert.IsTrue (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.IsFalse (peer.Finalized); + Assert.AreEqual ("java/lang/Boolean", peer.JniType); + Assert.AreEqual ("Java.Lang.Boolean", peer.McwType); + + Assert.AreEqual ("'(null)'(3)", peer.CreatedOnThread); + Assert.AreEqual ("'finalizer'(20660)", peer.DestroyedOnThread); + + Assert.AreEqual ("0x39bcfcb7", peer.KeyHandle); + Assert.AreEqual (0, peer.Handles.Count); + Assert.AreEqual (3, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x9500001/L"); + Assert.IsTrue (peer.RemovedHandles [1] == "0x100492/G"); + Assert.IsTrue (peer.RemovedHandles [2] == "0x700003/W"); + + Assert.AreEqual ( + " at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject)\n" + + " at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer, IntPtr ByRef handle)\n" + + " at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)\n" + + " at Java.Lang.Boolean..ctor(Boolean value)\n" + + " at Xamarin.Android.RuntimeTests.JavaConvertTest.Conversions()\n" + + " at System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod , System.Object , System.Object[] , System.Exception ByRef )\n" + + " at System.Reflection.MonoMethod.Invoke(System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)\n" + + " at System.Reflection.MethodBase.Invoke(System.Object obj, System.Object[] parameters)\n" + + " at NUnit.Framework.Internal.Reflect.InvokeMethod(System.Reflection.MethodInfo method, System.Object fixture, System.Object[] args)\n" + + " at NUnit.Framework.Internal.Commands.TestMethodCommand.RunNonAsyncTestMethod(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.Commands.SetUpTearDownCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.SimpleWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren()\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren()\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren()\n" + + " at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest()\n" + + " at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context)\n" + + " at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test)\n" + + " at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test, Android.Content.Context context)\n" + + " at Xamarin.Android.NUnitLite.TestSuiteInstrumentation.OnStart()\n" + + " at Android.App.Instrumentation.n_OnStart(IntPtr jnienv, IntPtr native__this)\n" + + " at System.Object.b7ee1212-364f-405b-bebd-08a60608685f(IntPtr , IntPtr )", + peer.GetStackTraceForHandle ("0x100492/G")); + } + } + + [Test] + public void RepeatedThreadHandles () + { + using (var source = GetResourceStream ("stdio-repeated-handles.txt")) { + var info = Grefs.Parse (source, options: GrefParseOptions.ThrowOnCountMismatch); + Assert.AreEqual (2, info.AllocatedPeers.Count); + Assert.AreEqual (1, info.AlivePeers.Count ()); + Assert.AreEqual (1, info.GrefCount); + Assert.AreEqual (0, info.WeakGrefCount); + + var peer = info.AllocatedPeers [0]; + Assert.IsTrue (peer.Collected); + Assert.IsTrue (peer.Disposed); + Assert.IsFalse (peer.Finalized); + Assert.AreEqual ("java/lang/String", peer.JniType); + Assert.AreEqual ("Java.Lang.String", peer.McwType); + + Assert.AreEqual ("'(null)'(3)", peer.CreatedOnThread); + Assert.AreEqual ("'(null)'(3)", peer.DestroyedOnThread); + + Assert.AreEqual ("0x41e29778", peer.KeyHandle); + Assert.AreEqual (0, peer.Handles.Count); + Assert.AreEqual (2, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x4a00009/L"); + Assert.IsTrue (peer.RemovedHandles [1] == "0x19004aa/G"); + + Assert.AreEqual ( + " at Doesn't Matter", + peer.GetStackTraceForHandle ("0x19004aa/G")); + + peer = info.AllocatedPeers [1]; + Assert.IsFalse (peer.Collected); + Assert.IsFalse (peer.Disposed); + Assert.IsFalse (peer.Finalized); + Assert.AreEqual ("java/lang/String", peer.JniType); + Assert.AreEqual ("Java.Lang.String", peer.McwType); + + Assert.AreEqual ("'(null)'(3)", peer.CreatedOnThread); + Assert.AreEqual (null, peer.DestroyedOnThread); + + Assert.AreEqual ("0x41e29778", peer.KeyHandle); + Assert.AreEqual (1, peer.Handles.Count); + Assert.IsTrue (peer.Handles [0] == "0x19004aa/G"); + Assert.AreEqual (1, peer.RemovedHandles.Count); + Assert.IsTrue (peer.RemovedHandles [0] == "0x4a00009/L"); + + Assert.AreEqual ( + " at Doesn't Matter", + peer.GetStackTraceForHandle ("0x19004aa/G")); + } + } + + StreamReader GetResourceStream (string resource) + { + // Look for resources that end with our name, this allows us to + // avoid the LogicalName stuff + var assembly = Assembly.GetExecutingAssembly (); + var name = assembly.GetManifestResourceNames ().FirstOrDefault (n => n.EndsWith ("." + resource, StringComparison.OrdinalIgnoreCase)) ?? resource; + + return new StreamReader (assembly.GetManifestResourceStream (name)); + } + } +} + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/JniHandleInfoTests.cs b/external/Java.Interop/tests/logcat-parse-Tests/JniHandleInfoTests.cs new file mode 100644 index 00000000000..ea4da2285d1 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/JniHandleInfoTests.cs @@ -0,0 +1,25 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; + +using Xamarin.Android.Tools.LogcatParse; + +using NUnit.Framework; + +namespace Xamarin.Android.Tools.LogcatParse.Tests { + + [TestFixture] + public class JniHandleInfoTests { + + [Test] + public void ImplicitFromString () + { + JniHandleInfo h = "0x1234/G"; + + Assert.AreEqual ("0x1234", h.Handle); + Assert.AreEqual (JniHandleType.Global, h.Type); + } + } +} + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-Invoker-java_class_ref.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-Invoker-java_class_ref.txt new file mode 100644 index 00000000000..dcf97167564 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-Invoker-java_class_ref.txt @@ -0,0 +1,15 @@ +# Interface invokers require a GREF for the jclass of the interface they're invoking. +I/monodroid-gref(11718): +g+ grefc 1 gwrefc 0 obj-handle 0x78b0001d/L -> new-handle 0x100476/G from thread '(null)'(1) +I/monodroid-gref(11718): at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +I/monodroid-gref(11718): at Android.Runtime.JNIEnv.FindClass(System.String classname) +I/monodroid-gref(11718): at Android.Views.View+IOnClickListenerInvoker..cctor() +I/monodroid-gref(11718): at Android.Runtime.JNIEnv.RegisterJniNatives(IntPtr typeName_ptr, Int32 typeName_len, IntPtr jniClass, IntPtr methods_ptr, Int32 methods_len) +I/monodroid-gref(11718): at System.Object.wrapper_native_0xb4dd21a1(IntPtr , IntPtr ) +I/monodroid-gref(11718): at Android.Runtime.JNIEnv.AllocObject(IntPtr jclass) +I/monodroid-gref(11718): at Android.Runtime.JNIEnv.AllocObject(System.String jniClassName) +I/monodroid-gref(11718): at Android.Runtime.JNIEnv.StartCreateInstance(System.String jniClassName, System.String jniCtorSignature, Android.Runtime.JValue[] constructorParameters) +I/monodroid-gref(11718): at Android.Views.View+IOnClickListenerImplementor..ctor() +I/monodroid-gref(11718): at Android.Views.View.__CreateIOnClickListenerImplementor() +I/monodroid-gref(11718): at Java.Interop.EventHelper.AddEventHandler(System.WeakReference ByRef implementor, System.Func`1 creator, System.Action`1 setListener, System.Action`1 add) +I/monodroid-gref(11718): at Android.Views.View.add_Click(System.EventHandler value) +I/monodroid-gref(11718): at System.Object.1beb6483-abe9-4bc4-b75a-e21a3e26c5a1(IntPtr , IntPtr , IntPtr ) diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-ag-rg.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-ag-rg.txt new file mode 100644 index 00000000000..b2dfb0194be --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-ag-rg.txt @@ -0,0 +1,17 @@ +# Add gref, remove gref, no intermediary messages +I/monodroid-gref(23777): +g+ grefc 1 gwrefc 0 obj-handle 0x41e29370/L -> new-handle 0x1d200276/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +I/monodroid-gref(23777): at Android.Runtime.JNIEnv.FindClass(System.String classname) +I/monodroid-gref(23777): at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) +I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) +I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) +I/monodroid-gref(23777): at Android.App.Activity.RunOnUiThread(System.Action action) +I/monodroid-gref(23777): at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) +I/monodroid-gref(23777): at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr +I/monodroid-gref(23777): -g- grefc 0 gwrefc 0 handle 0x1d200276/G from at Android.Runtime.JNIEnv.DeleteGlobalRef(IntPtr jobject) +I/monodroid-gref(23777): at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) +I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) +I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) +I/monodroid-gref(23777): at Android.App.Activity.RunOnUiThread(System.Action action) +I/monodroid-gref(23777): at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) +I/monodroid-gref(23777): at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr ) + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-alias.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-alias.txt new file mode 100644 index 00000000000..f1b5c9c1351 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-alias.txt @@ -0,0 +1,22 @@ +I/monodroid-gref(19858): +g+ grefc 1 gwrefc 0 obj-handle 0xbecdf114/L -> new-handle 0x100456/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +I/monodroid-gref(19858): at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer, IntPtr ByRef handle) +I/monodroid-gref(19858): at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Android.Views.View..ctor(IntPtr javaReference, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Android.Widget.TextView..ctor(IntPtr javaReference, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Android.Widget.Button..ctor(IntPtr javaReference, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Android.Widget.NewButton..ctor(IntPtr jr, JniHandleOwnership tr) +I/monodroid-gref(19858): at System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod , System.Object , System.Object[] , System.Exception ByRef ) +I/monodroid-gref(19858): at System.Reflection.MonoCMethod.InternalInvoke(System.Object obj, System.Object[] parameters) +I/monodroid-gref(19858): at System.Reflection.MonoCMethod.DoInvoke(Syste +I/monodroid-gref(19858): handle 0x100456; key_handle 0x655615a0: Java Type: `android/widget/NewButton`; MCW type: `Android.Widget.NewButton` +I/monodroid-gref(19858): +g+ grefc 2 gwrefc 0 obj-handle 0x100456/G -> new-handle 0x100472/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +I/monodroid-gref(19858): at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer, IntPtr ByRef handle) +I/monodroid-gref(19858): at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Android.Views.View..ctor(IntPtr javaReference, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Android.Widget.TextView..ctor(IntPtr javaReference, JniHandleOwnership transfer) +I/monodroid-gref(19858): at Android.Widget.Button..ctor(Android.Content.Context context, IAttributeSet attrs) +I/monodroid-gref(19858): at Android.Widget.NewButton..ctor(Android.Content.Context context, IAttributeSet attrs) in /Users/jon/Downloads/bxc-18641/MemoryLeakTest/MemoryLeakTest/NewButton.cs:line 19 +I/monodroid-gref(19858): at System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod , System.Object , System.Object[] , System.Exception ByRef ) +I/monodroid-gref(19858): at System.Reflection.MonoCMethod.Inter diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-disposed.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-disposed.txt new file mode 100644 index 00000000000..667dc06606b --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-disposed.txt @@ -0,0 +1,27 @@ +# gref created, explicitly disposed +I/monodroid-gref(23777): +g+ grefc 1 gwrefc 0 obj-handle 0x41e29778/L -> new-handle 0x1d200282/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +I/monodroid-gref(23777): at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(23777): at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(23777): at Java.Lang.String..ctor(System.String string) +I/monodroid-gref(23777): at Android.App.ProgressDialog.Show(Android.Content.Context context, System.String title, System.String message, Boolean indeterminate, Boolean cancelable) +I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor.Run() +I/monodroid-gref(23777): at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this) +I/monodroid-gref(23777): at System.Object.015d773b-4c56-4e22-ab21-e971886ef628(IntPtr , IntPtr ) +I/monodroid-gref(23777): at System.Object.wrapper_native_0x408f48fd(IntPtr , IntPtr , IntPtr , Android.Runtime.JValue[] ) +I/monodroid-gref(23777): at Android.Runtime.JNIEnv.CallVoidMethod(IntPtr jobject, IntPtr jmethod, Android.Runtime.JValue[] parms) +I/monodroid-gref(23777): at Android.App +I/monodroid-gref(23777): handle 0x1d200282; key_handle 0x41e29778: Java Type: `java/lang/String`; MCW type: `Java.Lang.String` +I/monodroid-gref(23777): Disposing handle 0x1d200282 +I/monodroid-gref(23777): -g- grefc 0 gwrefc 0 handle 0x1d200282/G from at Android.Runtime.JNIEnv.DeleteGlobalRef(IntPtr jobject) +I/monodroid-gref(23777): at Java.Lang.Object.Dispose(System.Object instance, IntPtr handle, IntPtr key_handle, JObjectRefType handle_type) +I/monodroid-gref(23777): at Java.Lang.Object.Dispose() +I/monodroid-gref(23777): at Android.App.ProgressDialog.Show(Android.Content.Context context, System.String title, System.String message, Boolean indeterminate, Boolean cancelable) +I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor.Run() +I/monodroid-gref(23777): at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this) +I/monodroid-gref(23777): at System.Object.015d773b-4c56-4e22-ab21-e971886ef628(IntPtr , IntPtr ) +I/monodroid-gref(23777): at System.Object.wrapper_native_0x408f48fd(IntPtr , IntPtr , IntPtr , Android.Runtime.JValue[] ) +I/monodroid-gref(23777): at Android.Runtime.JNIEnv.CallVoidMethod(IntPtr jobject, IntPtr jmethod, Android.Runtime.JValue[] parms) +I/monodroid-gref(23777): at Android.App.Activity.RunOnUiThread(IRunnable action) +I/monodroid-gref(23777): at Android.App.Activity.RunOnUiThread(System.Action action) +I/monodroid-gref(23777): at + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-get_class_ref.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-get_class_ref.txt new file mode 100644 index 00000000000..7caea9e0e39 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-get_class_ref.txt @@ -0,0 +1,9 @@ +# If get_class_ref() is in the callstack, this is a "burned" GREF which references +# a jclass for the specified type; it can never be collected. +06-15 14:29:12.360 11718 11718 I monodroid-gref: +g+ grefc 1 gwrefc 0 obj-handle 0x7830001d/L -> new-handle 0x10046a/G from thread '(null)'(1) +06-15 14:29:12.360 11718 11718 I monodroid-gref: at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +06-15 14:29:12.360 11718 11718 I monodroid-gref: at Android.Runtime.JNIEnv.FindClass(System.String classname) +06-15 14:29:12.360 11718 11718 I monodroid-gref: at Android.Runtime.JNIEnv.FindClass(System.String className, IntPtr ByRef cachedJniClassHandle) +06-15 14:29:12.360 11718 11718 I monodroid-gref: at Android.Widget.Button.get_class_ref() +06-15 14:29:12.360 11718 11718 I monodroid-gref: at Android.Widget.Button.get_ThresholdClass() +06-15 14:29:12.360 11718 11718 I monodroid-gref: at Android.Views.View.SetLayerType(LayerType layerType, Android.Graphics.Paint paint) diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-gwd.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-gwd.txt new file mode 100644 index 00000000000..bb5a45d5455 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-gwd.txt @@ -0,0 +1,13 @@ +# logcat: gref > wgref > dead +I/monodroid-gref(23777): +g+ grefc 1 gwrefc 0 obj-handle 0x41f008f8/L -> new-handle 0x1d20046a/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +I/monodroid-gref(23777): at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(23777): at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(23777): at Android.Widget.ProgressBar..ctor(Android.Content.Context context, IAttributeSet attrs, Int32 defStyle) +I/monodroid-gref(23777): at Android.Support.V4.App.Fragment.n_OnCreateView_Landroid_view_LayoutInflater_Landroid_view_ViewGroup_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, +I/monodroid-gref(23777): handle 0x1d20046a; key_handle 0x41f008f8: Java Type: `android/widget/ProgressBar`; MCW type: `Android.Widget.ProgressBar` +I/monodroid-gref(23777): *take_weak obj=0x73702428 -> wref=0x1d200003 handle=0x1d20046a +I/monodroid-gref(23777): +w+ grefc 1 gwrefc 1 obj-handle 0x1d20046a/G -> new-handle 0x1d200003/W from take_weak_global_ref_jni +I/monodroid-gref(23777): -g- grefc 0 gwrefc 1 handle 0x1d20046a/G from take_weak_global_ref_jni +I/monodroid-gref(23777): *try_take_global obj=0x73702428 -> wref=0x1d200003 handle=0x0 +I/monodroid-gref(23777): -w- grefc 0 gwrefc 0 handle 0x1d200003/W from take_global_ref_jni + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-resurrection.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-resurrection.txt new file mode 100644 index 00000000000..bb496a49a4f --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/logcat-resurrection.txt @@ -0,0 +1,13 @@ +# Create gref > wgref > gref; not disposed +I/monodroid-gref(23777): +g+ grefc 1 gwrefc 0 obj-handle 0x41ff8758/L -> new-handle 0x1d200f1e/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +I/monodroid-gref(23777): at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(23777): at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer) +I/monodroid-gref(23777): at Android.Widget.LinearLayout..ctor(Android.Content.Context context) +I/monodroid-gref(23777): at Android.Support.V4.App.Fragment.n_OnCreateView_Landroid_view_LayoutInflater_Landroid_view_ViewGroup_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native +I/monodroid-gref(23777): handle 0x1d200f1e; key_handle 0x41ff8758: Java Type: `android/widget/LinearLayout`; MCW type: `Android.Widget.LinearLayout` +I/monodroid-gref(23777): *take_weak obj=0x79a78748 -> wref=0x1d9000cb handle=0x1d200f1e +I/monodroid-gref(23777): +w+ grefc 1 gwrefc 1 obj-handle 0x1d200f1e/G -> new-handle 0x1d9000cb/W from take_weak_global_ref_jni +I/monodroid-gref(23777): -g- grefc 0 gwrefc 1 handle 0x1d200f1e/G from take_weak_global_ref_jni +I/monodroid-gref(23777): *try_take_global obj=0x79a78748 -> wref=0x1d9000cb handle=0x1d300eea +I/monodroid-gref(23777): +g+ grefc 1 gwrefc 1 obj-handle 0x1d9000cb/W -> new-handle 0x1d300eea/G from take_global_ref_jni +I/monodroid-gref(23777): -w- grefc 1 gwrefc 0 handle 0x1d9000cb/W from take_global_ref_jni diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-Finalized-threads.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-Finalized-threads.txt new file mode 100644 index 00000000000..20d98376a01 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-Finalized-threads.txt @@ -0,0 +1,44 @@ +# For storing thread names within JniHandleInfo! +# Note that handle lifetime messages have a "thread" identifier; this is present as of +# Xamarin.Android 4.14/commit 2e9a4e66. ++g+ grefc 1 gwrefc 0 obj-handle 0x9500001/L -> new-handle 0x100492/G from thread '(null)'(3) + at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) + at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer, IntPtr ByRef handle) + at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer) + at Java.Lang.Boolean..ctor(Boolean value) + at Xamarin.Android.RuntimeTests.JavaConvertTest.Conversions() + at System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod , System.Object , System.Object[] , System.Exception ByRef ) + at System.Reflection.MonoMethod.Invoke(System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) + at System.Reflection.MethodBase.Invoke(System.Object obj, System.Object[] parameters) + at NUnit.Framework.Internal.Reflect.InvokeMethod(System.Reflection.MethodInfo method, System.Object fixture, System.Object[] args) + at NUnit.Framework.Internal.Commands.TestMethodCommand.RunNonAsyncTestMethod(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.Commands.SetUpTearDownCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.SimpleWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren() + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren() + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren() + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test) + at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test, Android.Content.Context context) + at Xamarin.Android.NUnitLite.TestSuiteInstrumentation.OnStart() + at Android.App.Instrumentation.n_OnStart(IntPtr jnienv, IntPtr native__this) + at System.Object.b7ee1212-364f-405b-bebd-08a60608685f(IntPtr , IntPtr ) +handle 0x100492; key_handle 0x39bcfcb7: Java Type: `java/lang/Boolean`; MCW type: `Java.Lang.Boolean` +*take_weak obj=0xa432fcc0 -> wref=0x700003 handle=0x100492 ++w+ grefc 1 gwrefc 1 obj-handle 0x100492/G -> new-handle 0x700003/W from thread 'finalizer'(20660) +take_weak_global_ref_jni +-g- grefc 0 gwrefc 1 handle 0x100492/G from thread 'finalizer'(20660) +*try_take_global obj=0xa432fcc0 -> wref=0x700003 handle=0x0 +-w- grefc 0 gwrefc 0 handle 0x700003/W from thread 'finalizer'(20660) diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-JavaList.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-JavaList.txt new file mode 100644 index 00000000000..4c85b4845c7 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-JavaList.txt @@ -0,0 +1,37 @@ ++g+ grefc 1 gwrefc 0 obj-handle 0x4a00009/L -> new-handle 0x19004aa/G from thread '(null)'(3) + at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) + at Android.Runtime.JNIEnv.FindClass(System.String classname) + at Android.Runtime.JavaList..cctor() + at Java.Interop.JavaConvert.FromJniHandle(IntPtr handle, JniHandleOwnership transfer, Boolean ByRef set) + at Java.Interop.JavaConvert.FromJniHandle(IntPtr handle, JniHandleOwnership transfer) + at Android.Runtime.JavaDictionary`2[[System.String, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Get(System.String key) + at Android.Runtime.JavaDictionary`2[[System.String, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryGetValue(System.String key, System.Object ByRef value) + at Xamarin.Android.RuntimeTests.JavaConvertTest.Conversions() + at System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod , System.Object , System.Object[] , System.Exception ByRef ) + at System.Reflection.MonoMethod.Invoke(System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) + at System.Reflection.MethodBase.Invoke(System.Object obj, System.Object[] parameters) + at NUnit.Framework.Internal.Reflect.InvokeMethod(System.Reflection.MethodInfo method, System.Object fixture, System.Object[] args) + at NUnit.Framework.Internal.Commands.TestMethodCommand.RunNonAsyncTestMethod(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.Commands.SetUpTearDownCommand.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.SimpleWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren() + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren() + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.RunChildren() + at NUnit.Framework.Internal.WorkItems.CompositeWorkItem.PerformWork() + at NUnit.Framework.Internal.WorkItems.WorkItem.RunTest() + at NUnit.Framework.Internal.WorkItems.WorkItem.Execute(NUnit.Framework.Internal.TestExecutionContext context) + at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test) + at Xamarin.Android.NUnitLite.AndroidRunner.Run(NUnit.Framework.Internal.Test test, Android.Content.Context context) + at Xamarin.Android.NUnitLite.TestSuiteInstrumentation.OnStart() + at Android.App.Instrumentation.n_OnStart(IntPtr jnienv, IntPtr native__this) + at System.Object.b7ee1212-364f-405b-bebd-08a60608685f(IntPtr , IntPtr ) diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-ag-rg.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-ag-rg.txt new file mode 100644 index 00000000000..386ea200f28 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-ag-rg.txt @@ -0,0 +1,18 @@ +# Output as written to the "new" fopen(3)-based GREF logging. +# Add gref, remove gref, no intermediary messages ++g+ grefc 1 gwrefc 0 obj-handle 0x41e29370/L -> new-handle 0x1d200276/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) + at Android.Runtime.JNIEnv.FindClass(System.String classname) + at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) + at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) + at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) + at Android.App.Activity.RunOnUiThread(System.Action action) + at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) + at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr +-g- grefc 0 gwrefc 0 handle 0x1d200276/G from at Android.Runtime.JNIEnv.DeleteGlobalRef(IntPtr jobject) + at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) + at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) + at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) + at Android.App.Activity.RunOnUiThread(System.Action action) + at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) + at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr ) + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-repeated-handles.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-repeated-handles.txt new file mode 100644 index 00000000000..fe1611c05bb --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdio-repeated-handles.txt @@ -0,0 +1,9 @@ ++g+ grefc 1 gwrefc 0 obj-handle 0x4a00009/L -> new-handle 0x19004aa/G from thread '(null)'(3) + at Doesn't Matter +handle 0x19004aa; key_handle 0x41e29778: Java Type: `java/lang/String`; MCW type: `Java.Lang.String` +Disposing handle 0x19004aa +-g- grefc 0 gwrefc 0 handle 0x19004aa/G from thread '(null)'(3) + at Doesn't Matter ++g+ grefc 1 gwrefc 0 obj-handle 0x4a00009/L -> new-handle 0x19004aa/G from thread '(null)'(3) + at Doesn't Matter +handle 0x19004aa; key_handle 0x41e29778: Java Type: `java/lang/String`; MCW type: `Java.Lang.String` diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdout-ag-rg.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdout-ag-rg.txt new file mode 100644 index 00000000000..2b8ec9df1ed --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/stdout-ag-rg.txt @@ -0,0 +1,19 @@ +# Output as written to the Output panel within Xamarin Studio +# Add gref, remove gref, no intermediary messages +[monodroid-gref] +g+ grefc 1 gwrefc 0 obj-handle 0x41e29370/L -> new-handle 0x1d200276/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +[monodroid-gref] at Android.Runtime.JNIEnv.FindClass(System.String classname) +[monodroid-gref] at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) +[monodroid-gref] at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) +[monodroid-gref] at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) +[monodroid-gref] at Android.App.Activity.RunOnUiThread(System.Action action) +[monodroid-gref] at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) +[monodroid-gref] at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr +[monodroid-gref] -g- grefc 0 gwrefc 0 handle 0x1d200276/G from at Android.Runtime.JNIEnv.DeleteGlobalRef(IntPtr jobject) +[monodroid-gref] at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) +[monodroid-gref] at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) +[monodroid-gref] at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) +[monodroid-gref] at Android.App.Activity.RunOnUiThread(System.Action action) +[monodroid-gref] at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) +[monodroid-gref] at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr ) + + diff --git a/external/Java.Interop/tests/logcat-parse-Tests/Resources/timestamp-ag-rg.txt b/external/Java.Interop/tests/logcat-parse-Tests/Resources/timestamp-ag-rg.txt new file mode 100644 index 00000000000..164c2dff9f4 --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/Resources/timestamp-ag-rg.txt @@ -0,0 +1,17 @@ +logcat w/ timestamps, as seen at: https://bugzilla.xamarin.com/attachment.cgi?id=5374 +# Add gref, remove gref, no intermediary messages +11-08 15:25:46.516: I/monodroid-gref(23777): +g+ grefc 1 gwrefc 0 obj-handle 0x41e29370/L -> new-handle 0x1d200276/G from at Android.Runtime.JNIEnv.NewGlobalRef(IntPtr jobject) +11-08 15:25:46.516: I/monodroid-gref(23777): at Android.Runtime.JNIEnv.FindClass(System.String classname) +11-08 15:25:46.516: I/monodroid-gref(23777): at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) +11-08 15:25:46.516: I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) +11-08 15:25:46.516: I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) +11-08 15:25:46.516: I/monodroid-gref(23777): at Android.App.Activity.RunOnUiThread(System.Action action) +11-08 15:25:46.516: I/monodroid-gref(23777): at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) +11-08 15:25:46.516: I/monodroid-gref(23777): at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr +11-08 15:25:46.516: I/monodroid-gref(23777): -g- grefc 0 gwrefc 0 handle 0x1d200276/G from at Android.Runtime.JNIEnv.DeleteGlobalRef(IntPtr jobject) +11-08 15:25:46.516: I/monodroid-gref(23777): at Android.Runtime.JNIEnv.CreateInstance(System.String jniClassName, System.String signature, Android.Runtime.JValue[] constructorParameters) +11-08 15:25:46.516: I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable) +11-08 15:25:46.516: I/monodroid-gref(23777): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler) +11-08 15:25:46.516: I/monodroid-gref(23777): at Android.App.Activity.RunOnUiThread(System.Action action) +11-08 15:25:46.516: I/monodroid-gref(23777): at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) +11-08 15:25:46.516: I/monodroid-gref(23777): at System.Object.71bca0f9-d145-4b62-90c1-4e9ad52c866a(IntPtr , IntPtr , IntPtr ) diff --git a/external/Java.Interop/tests/logcat-parse-Tests/logcat-parse-Tests.csproj b/external/Java.Interop/tests/logcat-parse-Tests/logcat-parse-Tests.csproj new file mode 100644 index 00000000000..962348d5e9a --- /dev/null +++ b/external/Java.Interop/tests/logcat-parse-Tests/logcat-parse-Tests.csproj @@ -0,0 +1,28 @@ + + + + $(DotNetTargetFramework) + false + + + + + + $(TestOutputFullPath) + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/class-parse/Program.cs b/external/Java.Interop/tools/class-parse/Program.cs new file mode 100644 index 00000000000..bf3b2f17813 --- /dev/null +++ b/external/Java.Interop/tools/class-parse/Program.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Text; + +using Mono.Options; + +using Xamarin.Android.Tools.Bytecode; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Xamarin.Android.Tools { + + class App { + + public static void Main (string[] args) + { + bool dump = false; + bool help = false; + bool docsType = false; + int verbosity = 0; + bool autorename = false; + var outputFile = (string) null; + string platform = null; + var docsPaths = new List (); + var p = new OptionSet () { + "usage: class-dump [-dump] FILES [@RESPONSE-FILES]", + "", + "View the metadata contents of a Java .class or .jar file.", + "", + "Options:", + { "dump", + "Dump out .class metadata, including constant pool.\nDefault is XML output.", + v => dump = v != null }, + { "o=", + "Write output to {PATH}.", + v => outputFile = v }, + { "docspath=", + "Documentation {PATH} for parameter fixup", + doc => docsPaths.Add (doc) }, + { "parameter-names=", + "{PATH} for Java method parameter name information", + doc => docsPaths.Add (doc) }, + { "docstype=", + "OBSOLETE: Previously used to specify a doc type (now auto detected).", + t => docsType = t != null }, + { "v|verbose:", + "See stack traces on error.", + (int? v) => verbosity = v.HasValue ? v.Value : verbosity + 1 }, + { "autorename", + "Renames parameter names in the interfaces by derived classes.", + v => autorename = v != null }, + { "platform=", + "(Internal use only) specify Android framework platform ID", + v => platform = v }, + { "h|?|help", + "Show this message and exit.", + v => help = v != null }, + new ResponseFileSource (), + }; + var files = p.Parse (args); + if (help) { + p.WriteOptionDescriptions (Console.Out); + return; + } + if (docsType) + Console.WriteLine ("class-parse: --docstype is obsolete and no longer a valid option."); + var output = outputFile == null + ? Console.Out + : (TextWriter) new StreamWriter (outputFile, append: false, encoding: new UTF8Encoding (encoderShouldEmitUTF8Identifier: false)); + Log.OnLog = (t, v, m, a) => { + Console.Error.WriteLine(m, a); + }; + var globalClassPath = CreateClassPath (platform, docsPaths, autorename); + var classPaths = new List (); + foreach (var file in files) { + try { + if (ClassPath.IsJmodFile (file) || ClassPath.IsJarFile (file)) { + var cp = CreateClassPath (platform, docsPaths, autorename); + cp.Load (file); + classPaths.Add (cp); + continue; + } + using (var s = File.OpenRead (file)) { + if (!ClassFile.IsClassFile (s)) { + Console.Error.WriteLine ($"class-parse: Unable to read file '{file}': Unknown file format."); + Environment.ExitCode = 1; + continue; + } + s.Position = 0; + globalClassPath.Add (new ClassFile (s)); + } + } catch (Exception e) { + Console.Error.WriteLine ("class-parse: Unable to read file '{0}': {1}", + file, verbosity == 0 ? e.Message : e.ToString ()); + Environment.ExitCode = 1; + } + } + globalClassPath.FixupModuleVisibility (removeModules: !dump); + foreach (var cp in classPaths) { + globalClassPath.Add (cp, removeModules: !dump); + } + if (!dump) { + globalClassPath.SaveXmlDescription (output); + } else { + bool first = true; + foreach (var c in globalClassPath.GetClassFiles ()) { + if (!first) { + output.WriteLine (); + } + first = false; + DumpClassFile (c, output); + } + } + if (outputFile != null) + output.Close (); + } + + static ClassPath CreateClassPath (string platform, List docsPaths, bool autoRename) + { + return new ClassPath () { + ApiSource = "class-parse", + AndroidFrameworkPlatform = platform, + DocumentationPaths = docsPaths.Count == 0 ? null : docsPaths, + AutoRename = autoRename + }; + } + + static void DumpClassFile (ClassFile c, TextWriter output) + { + output.WriteLine ($"-- Begin {c.FullJniName} --"); + output.WriteLine (".class version: {0}.{1}", c.MajorVersion, c.MinorVersion); + output.WriteLine ("ConstantPool Count: {0}", c.ConstantPool.Count); + for (int i = 0; i < c.ConstantPool.Count; ++i) { + output.WriteLine ("\t{0}: {1}", i, c.ConstantPool [i]); + } + output.WriteLine ("ThisClass: {0}", c.ThisClass.Name); + output.WriteLine ("SuperClass: {0}", c.SuperClass?.Name); + output.WriteLine ("AccessFlags: {0}", c.AccessFlags); + output.WriteLine ("Attributes Count: {0}", c.Attributes.Count); + for (int i = 0; i < c.Attributes.Count; ++i) { + output.WriteLine ("\t{0}: {1}", i, c.Attributes [i]); + } + output.WriteLine ("Interfaces Count: {0}", c.Interfaces.Count); + for (int i = 0; i < c.Interfaces.Count; ++i) { + output.WriteLine ("\t{0}: {1}", i, c.Interfaces [i].Name.Value); + } + output.WriteLine ("Fields Count: {0}", c.Fields.Count); + for (int i = 0; i < c.Fields.Count; ++i) { + output.WriteLine ("\t{0}: {1} {2} {3}", i, c.Fields [i].Name, c.Fields [i].Descriptor, c.Fields [i].AccessFlags); + foreach (var attr in c.Fields [i].Attributes) { + output.WriteLine ("\t\t{0}", attr); + } + } + output.WriteLine ("Methods Count: {0}", c.Methods.Count); + for (int i = 0; i < c.Methods.Count; ++i) { + output.WriteLine ("\t{0}: {1} {2} {3}", i, c.Methods [i].Name, c.Methods [i].Descriptor, c.Methods [i].AccessFlags); + foreach (var attr in c.Methods [i].Attributes) { + output.WriteLine ("\t\t{0}", attr); + } + } + + // Output Kotlin metadata if it exists + var kotlin_metadata = c.Attributes.OfType () + .FirstOrDefault ()?.Annotations + .FirstOrDefault (a => a.Type == "Lkotlin/Metadata;"); + + if (kotlin_metadata is not null) { + var meta = KotlinMetadata.FromAnnotation (kotlin_metadata); + var jopt = new JsonSerializerOptions { + ReferenceHandler = ReferenceHandler.Preserve, + WriteIndented = true, + }; + + if (meta.AsClassMetadata () is KotlinClass kc) { + output.WriteLine (); + var json = JsonSerializer.Serialize (kc, jopt); + output.WriteLine ($"Kotlin Class Metadata [{meta.MetadataVersion}]: {json}"); + } else if (meta.AsFileMetadata () is KotlinFile kf) { + output.WriteLine (); + var json = JsonSerializer.Serialize (kf, jopt); + output.WriteLine ($"Kotlin File Metadata [{meta.MetadataVersion}]: {json}"); + } + + output.WriteLine (); + output.WriteLine ($"Kotlin Metadata String Table: {JsonSerializer.Serialize (meta.Data2, jopt)}"); + } + } + } +} diff --git a/external/Java.Interop/tools/class-parse/class-parse.csproj b/external/Java.Interop/tools/class-parse/class-parse.csproj new file mode 100644 index 00000000000..c8b80244cbc --- /dev/null +++ b/external/Java.Interop/tools/class-parse/class-parse.csproj @@ -0,0 +1,23 @@ + + + + $(DotNetTargetFramework) + Exe + + + + + + $(UtilityOutputFullPath) + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/generator/ApiVersionsProvider.cs b/external/Java.Interop/tools/generator/ApiVersionsProvider.cs new file mode 100644 index 00000000000..3bd1c8fd704 --- /dev/null +++ b/external/Java.Interop/tools/generator/ApiVersionsProvider.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using System.Linq; +using Java.Interop.Tools.Generator; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class ApiVersionsProvider + { + public void Parse (string apiVersionsFilePath) + { + using (var reader = XmlReader.Create (apiVersionsFilePath, new XmlReaderSettings { XmlResolver = null })) + Parse (reader); + } + + void Parse (XmlReader reader) + { + // read api + reader.MoveToContent (); // -> api + reader.Read (); // -> (next) + reader.MoveToContent (); // -> class + for (; reader.LocalName == "class"; reader.ReadToNextSibling ("class")) { + + AndroidSdkVersion tmpi; + var name = reader.GetAttribute ("name").Replace ('/', '.').Replace ('$', '.'); + var since = AndroidSdkVersion.Parse (reader.GetAttribute ("since")); + var deprecated = AndroidSdkVersion.TryParse (reader.GetAttribute ("deprecated"), out tmpi) ? tmpi : default; + + ClassDefinition klass; + if (!Versions.TryGetValue (name, out klass)) { + klass = new ClassDefinition { Name = name, Since = since }; + Versions.Add (name, klass); + } + + reader.Read (); + reader.MoveToContent (); + for (; reader.NodeType != XmlNodeType.EndElement; reader.Skip (), reader.MoveToContent ()) { + if (reader.NodeType != XmlNodeType.Element) + continue; + + var csince = reader.GetAttribute ("since"); + if (csince == null) + continue; + var cdeprecated = AndroidSdkVersion.TryParse (reader.GetAttribute ("deprecated"), out tmpi) ? tmpi : default; + + var cname = reader.GetAttribute ("name"); + switch (reader.LocalName) { + case "field": + klass.Fields.Add (new Definition { Name = cname, Since = AndroidSdkVersion.Parse (csince), Deprecated = cdeprecated }); + break; + case "method": + klass.Methods.Add (new Definition { Name = cname, Since = AndroidSdkVersion.Parse (csince), Deprecated = cdeprecated }); + break; + } + } + } + } + + public class Definition + { + public string Name; // it is name + JNI signature for methods. + public AndroidSdkVersion Since; + public AndroidSdkVersion Deprecated; + + string method; +#if !GENERATOR + string [] args; +#endif // !GENERATOR + + public string MethodName { + get { + EnsureParsed (); + return method; + } + } + public string [] Args { + get { + EnsureParsed (); +#if GENERATOR + throw new NotSupportedException ("Not supported as embedded in generator."); +#else // !GENERATOR + return args; +#endif // !GENERATOR + } + } + + void EnsureParsed () + { + bool isCtor = Name == ""; + int braceAt = Name.IndexOf ('('); + method = Name.Substring (0, braceAt); + string jni = Name.Substring (braceAt); +#if !GENERATOR + args = ManagedTypeFinder.ParseJniMethodArgumentsSignature (jni); +#endif + } + } + + public class ClassDefinition : Definition + { + public IList Fields { get; private set; } = new List (); + public IList Methods { get; private set; } = new List (); + } + + public IDictionary Versions { get; private set; } = new Dictionary (); + } +} + diff --git a/external/Java.Interop/tools/generator/ApiVersionsSupport.cs b/external/Java.Interop/tools/generator/ApiVersionsSupport.cs new file mode 100644 index 00000000000..d512a40270a --- /dev/null +++ b/external/Java.Interop/tools/generator/ApiVersionsSupport.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using Xamarin.AndroidTools.AnnotationSupport; +using System.Linq; + +using Java.Interop.Tools.Generator; + +namespace MonoDroid.Generation +{ + static class IApiAvailabilityExtensions + { + public static string AdditionalAttributeString (this ApiVersionsSupport.IApiAvailability a) + { + return a.ApiAvailableSince.ApiLevel == 0 ? null : ", ApiSince = " + a.ApiAvailableSince.ApiLevel; + } + } + + public static class ApiVersionsSupport + { + public interface IApiAvailability + { + AndroidSdkVersion ApiAvailableSince { get; set; } + AndroidSdkVersion ApiRemovedSince { get; set; } + } + + static IEnumerable FlattenGens (IEnumerable gens) + { + foreach (var g in gens) { + yield return g; + foreach (var nt in FlattenGens (g.NestedTypes)) + yield return nt; + } + } + + public static void AssignApiLevels (IList gens, string apiVersionsXml) + { + var flattenGens = FlattenGens (gens).ToLookup (g => g.JavaName); + var versions = new ApiVersionsProvider (); + versions.Parse (apiVersionsXml); + foreach (var type in versions.Versions.Values) { + var matchedGens = flattenGens [type.Name]; + if (!matchedGens.Any ()) + // There are known missing types, and it's going to be too noisy to report missing ones here. + // That task should be done elsewhere. + continue; + foreach (var gen in matchedGens) + gen.ApiAvailableSince = type.Since; + foreach (var field in type.Fields) { + var genf = matchedGens.SelectMany (g => g.Fields).FirstOrDefault (f => f.JavaName == field.Name); + // it might be moved to the corresponding class. + if (genf != null) + genf.ApiAvailableSince = field.Since > 0 ? field.Since : type.Since; + } + Func methodMatch = + (m, method) => m.JavaName == method.MethodName && m.JniSignature == method.Name.Substring (method.MethodName.Length); + Func ctorMatch = + (m, method) => m.JniSignature == method.Name.Substring (method.MethodName.Length); + foreach (var method in type.Methods) { + var genm = method.MethodName == "" ? + (MethodBase) matchedGens.OfType ().SelectMany (g => g.Ctors).FirstOrDefault (m => ctorMatch (m, method)) : + matchedGens.SelectMany (g => GetAllMethods (g)).FirstOrDefault (m => methodMatch (m, method)); + if (genm != null) + genm.ApiAvailableSince = method.Since > 0 ? method.Since : type.Since; + } + } + } + + static IEnumerable GetAllMethods (GenBase g) + { + foreach (var m in g.Properties) { + if (m.Getter != null) + yield return m.Getter; + if (m.Setter != null) + yield return m.Setter; + } + foreach (var m in g.Methods) + yield return m; + } + } +} + diff --git a/external/Java.Interop/tools/generator/CodeGenerationOptions.cs b/external/Java.Interop/tools/generator/CodeGenerationOptions.cs new file mode 100644 index 00000000000..d3c50a254e3 --- /dev/null +++ b/external/Java.Interop/tools/generator/CodeGenerationOptions.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.JavaCallableWrappers; + +using Xamarin.Android.Binder; +using Xamarin.AndroidTools.AnnotationSupport; + +namespace MonoDroid.Generation +{ + public class CodeGenerationOptions + { + CodeGenerationTarget codeGenerationTarget; + public CodeGenerationTarget CodeGenerationTarget { + get { return codeGenerationTarget; } + set { + switch (value) { + case CodeGenerationTarget.XAJavaInterop1: + case CodeGenerationTarget.JavaInterop1: + codeGenerationTarget = value; + break; + default: + throw new NotSupportedException ("Don't know what to do for target '" + value + "'."); + } + } + } + + internal JavaInteropCodeGenerator CreateCodeGenerator (TextWriter writer) + { + switch (codeGenerationTarget) { + case CodeGenerationTarget.XAJavaInterop1: + return new XAJavaInteropCodeGenerator (writer, this); + case CodeGenerationTarget.JavaInterop1: + default: + return new JavaInteropCodeGenerator (writer, this); + } + } + + SymbolTable symbolTable; + public SymbolTable SymbolTable { + get { + if (symbolTable != null) + return symbolTable; + return symbolTable = new SymbolTable (CodeGenerationTarget); + } + } + + readonly SortedSet jni_marshal_delegates = new SortedSet (); + readonly object jni_marshal_delegates_lock = new object (); + + public string ApiXmlFile { get; set; } + public bool EmitLegacyInterfaceInvokers { get; set; } + public bool UseGlobal { get; set; } + public bool IgnoreNonPublicType { get; set; } + public string AssemblyName { get; set; } + public bool UseShortFileNames { get; set; } + public int ProductVersion { get; set; } + public bool SupportInterfaceConstants { get; set; } + public bool SupportDefaultInterfaceMethods { get; set; } + public bool SupportNestedInterfaceTypes { get; set; } + public bool SupportNullableReferenceTypes { get; set; } + public bool UseShallowReferencedTypes { get; set; } + public bool UseObsoletedOSPlatformAttributes { get; set; } + public bool UseRestrictToAttributes { get; set; } + public bool FixObsoleteOverrides { get; set; } + public bool RemoveConstSugar => BuildingCoreAssembly; + + bool? buildingCoreAssembly; + // Basically this means "Are we building Mono.Android.dll?" + public bool BuildingCoreAssembly { + get { + return buildingCoreAssembly ?? (buildingCoreAssembly = (SymbolTable.Lookup ("java.lang.Object") is ClassGen gen && gen.FromXml)).Value; + } + } + + public string NullableOperator => SupportNullableReferenceTypes ? "?" : string.Empty; + + public string NullForgivingOperator => SupportNullableReferenceTypes ? "!" : string.Empty; + + public List NamespaceTransforms { get; } = new List (); + + public string GetTypeReferenceName (Field field) + { + var name = GetOutputName (field.Symbol.FullName); + + if (field.NotNull || field.Symbol.IsEnum) + return name; + + return name + GetNullable (field.Symbol.FullName); + } + + public string GetTypeReferenceName (Parameter symbol) + { + var name = GetOutputName (symbol.Type); + + if (symbol.NotNull || symbol.Symbol.IsEnum) + return name; + + return name + GetNullable (symbol.Type); + } + + public string GetTypeReferenceName (ReturnValue symbol) + { + var name = GetOutputName (symbol.FullName); + + if (symbol.NotNull || symbol.Symbol.IsEnum) + return name; + + return name + GetNullable (symbol.FullName); + } + + public string GetTypeReferenceName (Property symbol) + { + if (symbol.Getter != null) + return GetTypeReferenceName (symbol.Getter.RetVal); + + return GetTypeReferenceName (symbol.Setter.Parameters [0]); + } + + + public string GetNullForgiveness (Field field) + { + if (field.NotNull || field.Symbol.IsEnum) + return NullForgivingOperator; + + return string.Empty; + } + + public string GetNullForgiveness (ReturnValue symbol) + { + if (symbol.NotNull || symbol.Symbol.IsEnum) + return NullForgivingOperator; + + return string.Empty; + } + + public string GetNullForgiveness (Parameter symbol) + { + if (symbol.NotNull || symbol.Symbol.IsEnum) + return NullForgivingOperator; + + return string.Empty; + } + + string GetNullable (string s) + { + switch (s) { + case "void": + case "int": + case "bool": + case "float": + case "sbyte": + case "long": + case "char": + case "double": + case "short": + case "uint": + case "ushort": + case "ulong": + case "byte": + case "System.Boolean": + case "System.Byte": + case "System.Char": + case "System.Double": + case "System.Int16": + case "System.Int32": + case "System.Int64": + case "System.Single": + case "System.SByte": + case "System.UInt16": + case "System.UInt32": + case "System.UInt64": + case "System.Void": + case "Android.Graphics.Color": + return string.Empty; + } + + return NullableOperator; + } + + // Encoding format: + // - Type name prefix: _JniMarshal_PP + // - Parameter types, using JNI encoding, e.g. Z is boolean, I is int, etc. + // - Exception: Reference types, normally encoded as L…;, are instead just L. + // - Lowercase JNI encoding indicates unsigned type, e.g. i is uint. + // - Another _. + // - Return type, encoded as with parameters. A void return type is V. + internal string GetJniMarshalDelegate (Method method) + { + var sb = new StringBuilder ("_JniMarshal_PP"); + + foreach (var p in method.Parameters) + sb.Append (GetJniTypeCode (p.Symbol)); + + sb.Append ("_"); + sb.Append (GetJniTypeCode (method.RetVal.Symbol)); + + var result = sb.ToString (); + + lock (jni_marshal_delegates_lock) + jni_marshal_delegates.Add (result); + + return result; + } + + string GetJniTypeCode (ISymbol symbol) + { + // The JniName for our Kotlin unsigned types is the same + // as the Java signed types, so check the original symbol + // name and encode lowercase for unsigned version. + switch (symbol.JavaName) { + case "ubyte": return "b"; + case "uint": return "i"; + case "ulong": return "j"; + case "ushort": return "s"; + case "boolean": return "B"; // We marshal boolean (Z) as byte (B) + case "char": return "s"; // We marshal char (C) as ushort (s) + } + + var jni_name = symbol.JniName; + + if (jni_name.StartsWith ("L", StringComparison.Ordinal) || jni_name.StartsWith ("[", StringComparison.Ordinal)) + return "L"; + + return symbol.JniName; + } + + internal IEnumerable GetJniMarshalDelegates () + { + lock (jni_marshal_delegates_lock) + return jni_marshal_delegates; + } + + public string GetOutputName (string type) + { + // Handle a few special cases + if (type == "System.Void") + return "void"; + if (type.StartsWith ("params ", StringComparison.Ordinal)) + return "params " + GetOutputName (type.Substring ("params ".Length)); + if (type.StartsWith ("global::", StringComparison.Ordinal)) + Report.LogCodedErrorAndExit (Report.ErrorUnexpectedGlobal); + if (!UseGlobal) + return type; + + // Add "global::" in front of types + return ParsedType.Parse (type).ToString (UseGlobal); + } + + public string GetSafeIdentifier (string name) + { + if (string.IsNullOrEmpty (name)) + return name; + + // NOTE: "partial" differs in behavior on macOS vs. Windows, Windows reports "partial" as a valid identifier + // This check ensures the same output on both platforms + switch (name) { + case "partial": return name; + // `this` isn't in TypeNameUtilities.reserved_keywords; special-case. + case "this": return "this_"; + } + + // In the ideal world, it should not be applied twice. + // Sadly that is not true in reality, so we need to exclude non-symbols + // when replacing the argument name with a valid identifier. + // (ReturnValue.ToNative() takes an argument which could be either an expression or mere symbol.) + if (name [name.Length-1] != ')' && !name.Contains ('.') && !name.StartsWith ("@", StringComparison.Ordinal)) { + if (!IdentifierValidator.IsValidIdentifier (name) || + Array.BinarySearch (TypeNameUtilities.reserved_keywords, name, StringComparer.Ordinal) >= 0) { + name = name + "_"; + } + } + return name.Replace ('$', '_'); + } + + readonly Dictionary short_file_names = new Dictionary (); + + public string GetFileName (string fullName) + { + if (!UseShortFileNames) + return fullName; + + lock (short_file_names) { + if (short_file_names.TryGetValue (fullName, out var s)) + return s; + + s = short_file_names.Count.ToString (); + short_file_names [fullName] = s; + + return s; + } + } + + public string GetTransformedNamespace (string value) + { + if (!value.HasValue () || !NamespaceTransforms.Any ()) + return value; + + foreach (var nt in NamespaceTransforms) + value = nt.Apply (value); + + return value; + } + + public string GetStringArrayToCharSequenceArrayMethodName () + { + return CodeGenerationTarget == CodeGenerationTarget.JavaInterop1 + ? "ICharSequenceExtensions.ToCharSequenceArray" + : "CharSequence.ArrayFromStringArray"; + } + } +} + diff --git a/external/Java.Interop/tools/generator/CodeGenerationTarget.cs b/external/Java.Interop/tools/generator/CodeGenerationTarget.cs new file mode 100644 index 00000000000..e8624ac114b --- /dev/null +++ b/external/Java.Interop/tools/generator/CodeGenerationTarget.cs @@ -0,0 +1,8 @@ +namespace Xamarin.Android.Binder +{ + public enum CodeGenerationTarget + { + XAJavaInterop1, + JavaInterop1, + } +} diff --git a/external/Java.Interop/tools/generator/CodeGenerator.cs b/external/Java.Interop/tools/generator/CodeGenerator.cs new file mode 100644 index 00000000000..60703aa9061 --- /dev/null +++ b/external/Java.Interop/tools/generator/CodeGenerator.cs @@ -0,0 +1,480 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using Mono.Cecil; +using MonoDroid.Generation; +using Xamarin.AndroidTools.AnnotationSupport; +using Xamarin.Android.Tools.ApiXmlAdjuster; + +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Diagnostics; +using Java.Interop.Tools.TypeNameMappings; +using MonoDroid.Generation.Utilities; +using Java.Interop.Tools.Generator.Transformation; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.JavaTypeSystem; +using System.Text; +using generator; + +namespace Xamarin.Android.Binder +{ + public class CodeGenerator + { + public static int Main (string[] args) + { + try { + var options = CodeGeneratorOptions.Parse (args); + if (options == null) + return 1; + + Run (options); + } catch (BindingGeneratorException) { + return 1; + } catch (Exception ex) { + Console.Error.WriteLine (Report.Format (true, 0, null, -1, -1, ex.ToString ())); + return 1; + } + + return 0; + } + + public static void Run (CodeGeneratorOptions options) + { + if (options == null) + throw new ArgumentNullException ("options"); + + using (var resolver = new DirectoryAssemblyResolver (Diagnostic.CreateConsoleLogger (), loadDebugSymbols: false)) { + Run (options, resolver); + } + } + + static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolver) + { + string assemblyQN = options.AssemblyQualifiedName; + string api_level = options.ApiLevel; + int product_version = options.ProductVersion; + bool preserve_enums = options.PreserveEnums; + string csdir = options.ManagedCallableWrapperSourceOutputDirectory ?? "cs"; + string javadir = "java"; + string enumdir = options.EnumOutputDirectory ?? "enum"; + string enum_metadata = options.EnumMetadataOutputFile ?? "enummetadata"; + var references = options.AssemblyReferences; + string enum_fields_map = options.EnumFieldsMapFile; + string enum_flags = options.EnumFlagsFile; + string enum_methods_map = options.EnumMethodsMapFile; + var fixups = options.FixupFiles; + var annotations_zips = options.AnnotationsZipFiles; + string filename = options.ApiDescriptionFile; + string mapping_file = options.MappingReportFile; + bool only_xml_adjuster = options.OnlyRunApiXmlAdjuster; + string api_xml_adjuster_output = options.ApiXmlAdjusterOutput; + var apiSource = ""; + var opt = new CodeGenerationOptions () { + ApiXmlFile = options.ApiDescriptionFile, + CodeGenerationTarget = options.CodeGenerationTarget, + UseGlobal = options.GlobalTypeNames, + IgnoreNonPublicType = true, + UseShortFileNames = options.UseShortFileNames, + ProductVersion = options.ProductVersion, + SupportInterfaceConstants = options.SupportInterfaceConstants, + SupportDefaultInterfaceMethods = options.SupportDefaultInterfaceMethods, + SupportNestedInterfaceTypes = options.SupportNestedInterfaceTypes, + SupportNullableReferenceTypes = options.SupportNullableReferenceTypes, + UseObsoletedOSPlatformAttributes = options.UseObsoletedOSPlatformAttributes, + UseRestrictToAttributes = options.UseRestrictToAttributes, + EmitLegacyInterfaceInvokers = options.EmitLegacyInterfaceInvokers, + FixObsoleteOverrides = options.FixObsoleteOverrides, + }; + var resolverCache = new TypeDefinitionCache (); + + // Load reference libraries + + foreach (var lib in options.LibraryPaths) { + resolver.SearchDirectories.Add (lib); + } + foreach (var reference in references) { + resolver.SearchDirectories.Add (Path.GetDirectoryName (reference)); + } + + // Figure out if this is class-parse + string apiXmlFile = filename; + string apiSourceAttr = null; + + using (var xr = XmlReader.Create (filename, new XmlReaderSettings { XmlResolver = null })) { + xr.MoveToContent (); + apiSourceAttr = xr.GetAttribute ("api-source"); + } + + var is_classparse = apiSourceAttr == "class-parse"; + + // Resolve types using Java.Interop.Tools.JavaTypeSystem + if (is_classparse && !options.UseLegacyJavaResolver) { + var output_xml = api_xml_adjuster_output ?? Path.Combine (Path.GetDirectoryName (filename), Path.GetFileName (filename) + ".adjusted"); + JavaTypeResolutionFixups.Fixup (filename, output_xml, resolver, references.Distinct ().ToArray (), resolverCache, options); + + if (only_xml_adjuster) + return; + + // Use this output for future steps + filename = output_xml; + apiXmlFile = filename; + is_classparse = false; + } + + // We don't use shallow referenced types with class-parse because the Adjuster process + // enumerates every ctor/method/property/field to build its model, so we will need + // every type to be fully populated. + opt.UseShallowReferencedTypes = !is_classparse; + + foreach (var reference in references.Distinct ()) { + try { + Report.Verbose (0, "resolving assembly {0}.", reference); + var assembly = resolver.Load (reference); + foreach (var md in assembly.Modules) + foreach (var td in md.Types) { + // FIXME: at some stage we want to import generic types. + // For now generator fails to load generic types that have conflicting type e.g. + // AdapterView`1 and AdapterView cannot co-exist. + // It is mostly because generator primarily targets jar (no real generics land). + var nonGenericOverload = td.HasGenericParameters + ? md.GetType (td.FullName.Substring (0, td.FullName.IndexOf ('`'))) + : null; + if (BindSameType (td, nonGenericOverload, resolverCache)) + continue; + ProcessReferencedType (td, opt); + } + } catch (Exception ex) { + Report.LogCodedWarning (0, Report.WarningAssemblyParseFailure, ex, reference, ex.Message); + } + } + + // For class-parse API description, transform it to jar2xml style. + // Resolve types using ApiXmlAdjuster + if (is_classparse && options.UseLegacyJavaResolver) { + apiXmlFile = api_xml_adjuster_output ?? Path.Combine (Path.GetDirectoryName (filename), Path.GetFileName (filename) + ".adjusted"); + new Adjuster ().Process (filename, opt, opt.SymbolTable.AllRegisteredSymbols (opt).OfType ().ToArray (), apiXmlFile, Report.Verbosity ?? 0); + } + + if (only_xml_adjuster) + return; + + // load XML API definition with fixups. + + Dictionary enums = null; + + EnumMappings enummap = null; + + if (enum_fields_map != null || enum_methods_map != null) { + enummap = new EnumMappings (enumdir, enum_metadata, api_level, preserve_enums); + enums = enummap.Process (enum_fields_map, enum_flags, enum_methods_map); + fixups.Add (enum_metadata); + } + + // Load the API XML document + var api = ApiXmlDocument.Load (apiXmlFile, api_level, product_version); + + if (api is null) + return; + + // Apply metadata fixups + foreach (var fixup in fixups) { + if (FixupXmlDocument.Load (fixup) is FixupXmlDocument f) { + api.ApplyFixupFile (f); + opt.NamespaceTransforms.AddRange (f.GetNamespaceTransforms ()); + } + } + + api.ApiDocument.Save (apiXmlFile + ".fixed"); + + // Parse API XML + var gens = XmlApiImporter.Parse (api.ApiDocument, opt); + + if (gens is null) + return; + + apiSource = api.ApiSource; + + // disable interface default methods here, especially before validation. + gens = gens.Where (g => !g.IsObfuscated && g.Visibility != "private").ToList (); + foreach (var gen in gens) { + gen.StripNonBindables (opt); + if (gen.IsGeneratable) + AddTypeToTable (opt, gen); + } + + // Apply fixups + KotlinFixups.Fixup (gens); + + Validate (gens, opt, new CodeGeneratorContext ()); + + foreach (var api_versions_xml in options.ApiVersionsXmlFiles) { + ApiVersionsSupport.AssignApiLevels (gens, api_versions_xml); + } + + foreach (GenBase gen in gens) + gen.FillProperties (); + + var cache = new AncestorDescendantCache (gens); + + foreach (var gen in gens) + gen.UpdateEnums (opt, cache); + + foreach (GenBase gen in gens) + gen.FixupMethodOverrides (opt); + + foreach (GenBase gen in gens) + gen.FixupExplicitImplementation (); + + SealedProtectedFixups.Fixup (gens); + + GenerateAnnotationAttributes (gens, annotations_zips); + JavadocFixups.Fixup (gens, options); + + //SymbolTable.Dump (); + + GenerationInfo gen_info = new GenerationInfo (csdir, javadir, assemblyQN); + opt.AssemblyName = gen_info.Assembly; + + if (mapping_file != null) + GenerateMappingReportFile (gens, mapping_file); + + foreach (IGeneratable gen in gens) + if (gen.IsGeneratable) + gen.Generate (opt, gen_info); + + new NamespaceMapping (gens).Generate (opt, gen_info); + + ClassGen.GenerateEnumList (gen_info); + + // Create the .cs files for the enums + var enumFiles = enums == null + ? null + : enummap.WriteEnumerations (enumdir, enums, FlattenNestedTypes (gens).ToArray (), opt); + + gen_info.GenerateLibraryProjectFile (options, enumFiles); + } + + static void AddTypeToTable (CodeGenerationOptions opt, GenBase gb) + { + opt.SymbolTable.AddType (gb); + foreach (var nt in gb.NestedTypes) + AddTypeToTable (opt, nt); + } + + static bool BindSameType (TypeDefinition a, TypeDefinition b, TypeDefinitionCache cache) + { + if (a == null || b == null) + return false; + if (!a.ImplementsInterface ("Android.Runtime.IJavaObject", cache) || !b.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) + return false; + return JavaNativeTypeManager.ToJniName (a, cache) == JavaNativeTypeManager.ToJniName (b, cache); + } + + static IEnumerable FlattenNestedTypes (IEnumerable gens) + { + foreach (var g in gens) { + yield return g; + foreach (var gg in FlattenNestedTypes (g.NestedTypes)) + yield return gg; + } + } + + static void Validate (List gens, CodeGenerationOptions opt, CodeGeneratorContext context) + { + //int cycle = 1; + List removed = new List (); + var nested_removes = new List (); + + // This loop is required because we cannot really split type validation and member + // validation apart (unlike C# compiler), because invalidated members will result + // in the entire interface invalidation (since we cannot implement it), and use of + // those invalidated interfaces must be eliminated in members in turn again. + do { + //Console.WriteLine ("Validation cycle " + cycle++); + removed.Clear (); + foreach (GenBase gen in gens) + gen.ResetValidation (); + foreach (GenBase gen in gens) + gen.FixupAccessModifiers (opt); + foreach (GenBase gen in gens) + if ((opt.IgnoreNonPublicType && + (gen.RawVisibility != "public" && gen.RawVisibility != "internal")) + || !gen.Validate (opt, null, context)) { + foreach (GenBase nest in gen.NestedTypes) { + foreach (var nt in nest.Invalidate ()) + removed.Add (nt); + } + removed.Add (gen); + } + + // Remove any nested types that are package-private + foreach (var gen in gens) { + foreach (var nest in gen.NestedTypes) + if (opt.IgnoreNonPublicType && (nest.RawVisibility != "public" && nest.RawVisibility != "internal" && nest.RawVisibility != "protected internal")) { + // We still add it to "removed" even though the removal + // code later won't work, so that it triggers a new cycle + removed.Add (nest); + nested_removes.Add (nest); + } + + foreach (var nest in nested_removes) + gen.NestedTypes.Remove (nest); + + nested_removes.Clear (); + } + + foreach (GenBase gen in removed) + gens.Remove (gen); + } while (removed.Count > 0); + } + +#if HAVE_CECIL + internal static void ProcessReferencedType (TypeDefinition td, CodeGenerationOptions opt) + { + if (!td.IsPublic && !td.IsNested) + return; + + // We want to exclude "IBlahInvoker" types from this type registration. + if (td.Name.EndsWith ("Invoker", StringComparison.Ordinal)) { + string n = td.FullName; + n = n.Substring (0, n.Length - 7); + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + if (types.Any (t => t.FullName == n)) + return; + //Console.Error.WriteLine ("WARNING: " + td.FullName + " survived"); + } + if (td.Name.EndsWith ("Implementor", StringComparison.Ordinal)) { + string n = td.FullName; + n = n.Substring (0, n.Length - 11); + var types = td.DeclaringType != null ? td.DeclaringType.Resolve ().NestedTypes : td.Module.Types; + if (types.Any (t => t.FullName == n)) + return; + //Console.Error.WriteLine ("WARNING: " + td.FullName + " survived"); + } + + ISymbol gb = td.IsEnum ? (ISymbol)new EnumSymbol (td.FullNameCorrected ()) : td.IsInterface ? (ISymbol)CecilApiImporter.CreateInterface (td, opt) : CecilApiImporter.CreateClass (td, opt); + opt.SymbolTable.AddType (gb); + + foreach (var nt in td.NestedTypes) + ProcessReferencedType (nt, opt); + } +#endif // HAVE_CECIL + + static void GenerateAnnotationAttributes (List gens, IEnumerable zips) + { + if (zips == null || !zips.Any ()) + return; + var annotations = new AndroidAnnotationsSupport (); + annotations.Extensions.Add (new ManagedTypeFinderGeneratorTypeSystem (gens.ToArray ())); + foreach (var z in zips) + annotations.Load (z); + + foreach (var item in annotations.Data.SelectMany (d => d.Value)) { + if (!item.Annotations.Any (a => a.Name == "RequiresPermission")) + continue; + var cx = item.GetExtension (); + if (cx == null) + continue; + string annotation = null; + foreach (var value in cx.Values) + annotation += string.Format ("[global::Android.Runtime.RequiresPermission (\"{0}\")]", value); + + AddAnnotationTo (item, annotation); + } + + foreach (var item in annotations.Data.SelectMany (d => d.Value)) { + if (!item.Annotations.Any (a => a.Name == "IntDef" || a.Name == "StringDef")) + continue; + foreach (var ann in item.Annotations) { + var cx = ann.GetExtension (); + if (cx == null || cx.IsTargetAlreadyEnumified) + continue; + + var groups = cx.ManagedConstants.GroupBy (m => m.Type.FullName); + string annotation = null; + // Generate [IntDef(Type = ..., Fields = ...)] possibly multiple times for each type of the fields, grouped + // (mostly 1, except for things like PendingIntent flags, which is not covered here because it's already enumified). + // ditto for StringDef. + foreach (var grp in groups) + annotation += "[global::Android.Runtime." + ann.Name + " (" + (cx.Flag ? "Flag = true, " : null) + + "Type = \"" + grp.Key + + "\", Fields = new string [] {" + string.Join (", ", grp.Select (mav => '"' + mav.MemberName + '"')) + "})]"; + + AddAnnotationTo (item, annotation); + } + } + } + + static void AddAnnotationTo (AnnotatedItem item, string annotation) + { + if (item.ManagedInfo.PropertyObject != null) + item.ManagedInfo.PropertyObject.Value ().Annotation += annotation; + else if (item.ManagedInfo.MethodObject != null) { + if (item.ParameterIndex < 0) + item.ManagedInfo.MethodObject.Value ().Annotation += annotation; + else + item.ManagedInfo.MethodObject.Value ().Parameters [item.ParameterIndex].Annotation += annotation; + } + } + + // generate mapping report file. + static void GenerateMappingReportFile (List gens, string mapping_file) + { + using (var fs = File.CreateText (mapping_file)) { + foreach (var gen in gens.OrderBy (g => g.JniName)) { + fs.Write (gen.JniName.Substring (1, gen.JniName.Length - 2)); // skip 'L' and ';' at head and tail. + fs.Write (" = "); + fs.WriteLine (gen.FullName); + + var cls = gen as ClassGen; + if (cls != null) { + foreach (var m in cls.Ctors.OrderBy (_ => _.JniSignature)) { + fs.Write (" "); + fs.Write (""); + fs.Write (m.JniSignature); + fs.Write (" = "); + fs.Write (".ctor"); + fs.WriteLine ("(" + string.Join (", ", m.Parameters.Select (p => p.Type)) + ")"); + } + } + + foreach (var f in gen.Fields.OrderBy (f => f.Name)) { + fs.Write (" "); + fs.Write (f.JavaName); + fs.Write (" = "); + fs.WriteLine (f.Name); + } + + foreach (var p in gen.Properties.OrderBy (_ => _.Name)) { + if (p.Getter != null) { + fs.Write (" "); + fs.Write (p.Getter.JavaName); + fs.Write (p.Getter.JniSignature); + fs.Write (" = "); + fs.WriteLine (p.Name); + } + if (p.Setter != null) { + fs.Write (" "); + fs.Write (p.Setter.JavaName); + fs.Write (p.Setter.JniSignature); + fs.Write (" = "); + fs.WriteLine (p.Name); + } + } + + foreach (var m in gen.Methods.OrderBy (_ => _.AdjustedName)) { + fs.Write (" "); + fs.Write (m.JavaName); + fs.Write (m.JniSignature); + fs.Write (" = "); + fs.Write (m.AdjustedName); + fs.WriteLine ("(" + string.Join (", ", m.Parameters.Select (p => p.Type)) + ")"); + } + } + } + } + } +} diff --git a/external/Java.Interop/tools/generator/CodeGeneratorContext.cs b/external/Java.Interop/tools/generator/CodeGeneratorContext.cs new file mode 100644 index 00000000000..4bc80d6e714 --- /dev/null +++ b/external/Java.Interop/tools/generator/CodeGeneratorContext.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MonoDroid.Generation +{ + public class CodeGeneratorContext + { + public Stack ContextTypes { get; } = new Stack (); + public List ContextGeneratedMethods { get; set; } = new List (); + public Field ContextField { get; set; } + public MethodBase ContextMethod { get; set; } + + public GenBase ContextType => ContextTypes.Any () ? ContextTypes.Peek () : null; + string ContextFieldString => ContextField != null ? "in field " + ContextField.Name + " " : null; + string ContextMethodString => ContextMethod != null ? "in method " + ContextMethod.Name + " " : null; + string ContextTypeString => ContextType != null ? "in managed type " + ContextType.FullName : null; + public string ContextString => ContextFieldString + ContextMethodString + ContextTypeString; + + public string GetContextTypeMember () + { + var parts = new List (); + + // Type name + if (!string.IsNullOrEmpty (ContextType?.FullName)) + parts.Add (ContextType?.FullName); + + // Member name + if (ContextMethod != null) + parts.Add ($"{ContextMethod.Name} ({string.Join (", ", ContextMethod?.Parameters.Select (p => p.InternalType).ToArray ())})"); + else if (ContextField != null) + parts.Add (ContextField.Name); + + return string.Join (".", parts); + } + } +} diff --git a/external/Java.Interop/tools/generator/CodeGeneratorOptions.cs b/external/Java.Interop/tools/generator/CodeGeneratorOptions.cs new file mode 100644 index 00000000000..317f8b93a17 --- /dev/null +++ b/external/Java.Interop/tools/generator/CodeGeneratorOptions.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.ObjectModel; +using Mono.Cecil; +using Mono.Options; + +using Java.Interop.Tools.JavaSource; + +using MonoDroid.Generation; +using Java.Interop.Tools.Generator; + +namespace Xamarin.Android.Binder +{ + public class CodeGeneratorOptions + { + public CodeGeneratorOptions () + { + ApiVersionsXmlFiles = new Collection (); + AssemblyReferences = new Collection (); + FixupFiles = new Collection (); + LibraryPaths = new Collection (); + AnnotationsZipFiles = new Collection (); + JavadocXmlFiles = new Collection (); + } + + public string ApiLevel {get; set;} + public CodeGenerationTarget CodeGenerationTarget {get; set;} + public string ManagedCallableWrapperSourceOutputDirectory {get; set;} + public string AssemblyQualifiedName {get; set;} + public Collection AssemblyReferences {get; private set;} + public Collection FixupFiles {get; private set;} + public Collection LibraryPaths {get; private set;} + public Collection JavadocXmlFiles {get; private set;} + public bool GlobalTypeNames {get; set;} + public bool OnlyBindPublicTypes {get; set;} + public string ApiDescriptionFile {get; set;} + [Obsolete ("Use ApiVersionsXmlFiles")] + public string ApiVersionsXmlFile {get; set;} + public Collection ApiVersionsXmlFiles {get; set;} + public Collection AnnotationsZipFiles {get; set;} + public bool EmitLegacyInterfaceInvokers { get; set; } + public string EnumFieldsMapFile {get; set;} + public string EnumFlagsFile {get; set;} + public string EnumMethodsMapFile {get; set;} + public string EnumOutputDirectory {get; set;} + public string EnumMetadataOutputFile {get; set;} + public bool PreserveEnums {get; set;} + public bool UseShortFileNames {get; set;} + public int ProductVersion { get; set; } + public string MappingReportFile { get; set; } + public bool OnlyRunApiXmlAdjuster { get; set; } + public string ApiXmlAdjusterOutput { get; set; } + public bool SupportInterfaceConstants { get; set; } + public bool SupportDefaultInterfaceMethods { get; set; } + public bool SupportNestedInterfaceTypes { get; set; } + public bool SupportNullableReferenceTypes { get; set; } + public bool UseRestrictToAttributes { get; set; } + public bool FixObsoleteOverrides { get; set;} = true; + public bool UseLegacyJavaResolver { get; set; } + public bool UseObsoletedOSPlatformAttributes { get; set; } + + public XmldocStyle XmldocStyle { get; set; } = XmldocStyle.IntelliSense; + + public static CodeGeneratorOptions Parse (string[] args) + { + var opts = new CodeGeneratorOptions (); + + bool show_help = false; + + var parser = new OptionSet { + "Usage: generator.exe OPTIONS+ API_DESCRIPTION [@RESPONSE-FILES]", + "", + "Generates C# source files to bind Java code described by API_DESCRIPTION.", + "", + "Copyright 2012 Xamarin, Inc.", + "", + "Options:", + { "assembly=", + "Fully Qualified Assembly Name ({FQAN}) of the eventual assembly (.dll) that will be built.", + v => opts.AssemblyQualifiedName = v }, + { "codegen-target=", + "{STYLE} of Binding Assembly to generate", + v => opts.CodeGenerationTarget = ParseCodeGenerationTarget (v) }, + { "fixup=", + "XML {FILE} controlling the generated API.\n" + + "http://www.mono-project.com/GAPI#Altering_and_Extending_the_API_File", + v => opts.FixupFiles.Add (v) }, + { "global", + "Prefix type names with `global::`.", + v => opts.GlobalTypeNames = v != null }, + { "javadir=", + "Ignored; for compatibility.", + v => {} }, + { "L=", + "{PATH} to look for referenced assemblies..", + v => opts.LibraryPaths.Add (v) }, + { "o|csdir=", + "{DIRECTORY} to place C# source into.", + v => opts.ManagedCallableWrapperSourceOutputDirectory = v }, + { "public", + "Obsolete option. It binds only public types now", + v => opts.OnlyBindPublicTypes = v != null }, + { "r|ref=", + "{ASSEMBLY} to reference.", + v => opts.AssemblyReferences.Add (v) }, + { "sdk-platform|api-level=", + "SDK Platform {VERSION}/API level.", + v => opts.ApiLevel = v }, + { "lang-features=", + "For internal use. (Flags: interface-constants,default-interface-methods,nested-interface-types,nullable-reference-types,obsoleted-platform-attributes,restrict-to-attributes,do-not-fix-obsolete-overrides,emit-legacy-interface-invokers)", + v => { + opts.EmitLegacyInterfaceInvokers = v?.Contains ("emit-legacy-interface-invokers") == true; + opts.SupportInterfaceConstants = v?.Contains ("interface-constants") == true; + opts.SupportDefaultInterfaceMethods = v?.Contains ("default-interface-methods") == true; + opts.SupportNestedInterfaceTypes = v?.Contains ("nested-interface-types") == true; + opts.SupportNullableReferenceTypes = v?.Contains ("nullable-reference-types") == true; + opts.UseObsoletedOSPlatformAttributes = v?.Contains ("obsoleted-platform-attributes") == true; + opts.UseRestrictToAttributes = v?.Contains ("restrict-to-attributes") == true; + opts.FixObsoleteOverrides = v?.Contains ("do-not-fix-obsolete-overrides") == false; + }}, + { "preserve-enums", + "For internal use.", + v => opts.PreserveEnums = v != null }, + { "use-short-file-names", + "Generates short file name.", + v => opts.UseShortFileNames = v != null }, + { "product-version=", + "Xamarin.Android Major Product Version", + (int? v) => opts.ProductVersion = v.HasValue ? v.Value : 0 }, + { "v:", + "Logging Verbosity", + (int? v) => Report.Verbosity = v.HasValue ? v.Value : (Report.Verbosity ?? 0) + 1 }, + { "type-map-report=", + "Java-Managed Mapping report file.", + v => opts.MappingReportFile = v }, + { "only-xml-adjuster", + "Run only API XML adjuster for class-parse input.", + v => opts.OnlyRunApiXmlAdjuster = v != null }, + { "xml-adjuster-output=", + "specify API XML adjuster output XML for class-parse input.", + v => opts.ApiXmlAdjusterOutput = v }, + { "h|?|help", + "Show this message and exit.", + v => show_help = v != null }, + "", + "Javadoc to C# Documentation Comments Support:", + { "doc-comment-verbosity=", + "{STYLE} of C# documentation comments to emit.\n" + + "Defaults to `full`. {STYLE} may be:\n" + + " * `intellisense`: emit

    , ,\n" + + " , .\n" + + " * `full`: plus , , ...", + v => opts.XmldocStyle = ParseXmldocStyle (v) }, + { "with-javadoc-xml=", + "{PATH} to `api.xml` containing Javadoc docs in\n`` elements", + v => opts.JavadocXmlFiles.Add (v) }, + "", + "C# Enumeration Support:", + { "enumdir=", + "{DIRECTORY} to write enumeration declarations.", + v => opts.EnumOutputDirectory = v }, + { "enumfields=", + "For internal use.", + v => opts.EnumFieldsMapFile = v }, + { "enumflags=", + "For internal use.", + v => opts.EnumFlagsFile = v }, + { "enummetadata=", + "XML {FILENAME} to create.", + v => opts.EnumMetadataOutputFile = v }, + { "enummethods=", + "For internal use.", + v => opts.EnumMethodsMapFile = v }, + { "apiversions=", + "For internal use.", + v => opts.ApiVersionsXmlFiles.Add (v) }, + { "annotations=", + "For internal use.", + v => opts.AnnotationsZipFiles.Add (v) }, + { "use-legacy-java-resolver", + "Uses the legacy ApiXmlAdjuster to resolve Java types, this is a *temporary* fallback in case there are unknown issues with JavaTypeSystem.", + v => opts.UseLegacyJavaResolver = v != null }, + new ResponseFileSource (), + }; + + var apis = parser.Parse (args); + + if (args.Length < 2 || show_help) { + parser.WriteOptionDescriptions (Console.Out); + return null; + } + + if (apis.Count == 0) + throw new InvalidOperationException ("A .xml file must be specified."); + if (apis.Count != 1) { + Console.Error.WriteLine ("generator: Found {0} API descriptions; only one is supported", apis.Count); + foreach (var api in apis) { + Console.Error.WriteLine ("generator: API description: {0}", api); + } + throw new InvalidOperationException ("Only one .xml file may be specified."); + } + + opts.ApiDescriptionFile = apis [0]; + + return opts; + } + + static CodeGenerationTarget ParseCodeGenerationTarget (string value) + { + switch (value.ToLowerInvariant ()) { + case "xajavainterop1": + return CodeGenerationTarget.XAJavaInterop1; + case "javainterop1": + return CodeGenerationTarget.JavaInterop1; + } + throw new NotSupportedException ($"Don't know how to convert '{value}' to a CodeGenerationTarget value!"); + } + + static XmldocStyle ParseXmldocStyle (string style) => style?.ToLowerInvariant () switch { + "intellisense" => XmldocStyle.IntelliSense, + "intellisense+extraremarks" => XmldocStyle.IntelliSenseAndExtraRemarks, + "full" => XmldocStyle.Full, + _ => XmldocStyle.Full, + }; + } +} diff --git a/external/Java.Interop/tools/generator/Extensions/GenBaseExtensions.cs b/external/Java.Interop/tools/generator/Extensions/GenBaseExtensions.cs new file mode 100644 index 00000000000..cae65c976fe --- /dev/null +++ b/external/Java.Interop/tools/generator/Extensions/GenBaseExtensions.cs @@ -0,0 +1,92 @@ +#if GENERATOR +using System; +using System.Collections.Generic; +using System.Linq; +using MonoDroid.Generation; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public static class GenBaseExtensions + { + public static IEnumerable FlattenTypes (this GenBase t) + { + yield return t; + foreach (var x in t.NestedTypes.SelectMany (nt => nt.FlattenTypes ())) + yield return x; + } + + public static IEnumerable GetSelfAndAncestors (this GenBase t) + { + yield return t; + if (t.BaseGen != null) + foreach (var a in t.BaseGen.GetSelfAndAncestors ()) + yield return t; + } + + public static IEnumerable GetMethods (this GenBase t) + { + if (t is ClassGen) + foreach (var m in ((ClassGen) t).Ctors) + yield return m; + foreach (var m in t.Methods) + yield return m; + foreach (var p in t.Properties) { + if (p.Getter != null) + yield return p.Getter; + if (p.Setter != null) + yield return p.Setter; + } + if (t.BaseGen != null) + foreach (var m in t.BaseGen.GetMethods ()) + yield return m; + if (t is InterfaceGen) + foreach (var it in ((InterfaceGen) t).GetAllDerivedInterfaces ()) + foreach (var m in it.GetMethods ()) + yield return m; + } + + public static IEnumerable GetFields (this GenBase t) + { + return t.BaseGen == null ? t.Fields : t.Fields.Concat (t.BaseGen.GetFields ()); + } + + #region conversion between general interfaces + + public static GenBase Value (this ManagedTypeFinder.IType t) + { + return ((ManagedTypeFinderGeneratorTypeSystem.TType) t)?.Value; + } + public static Field Value (this ManagedTypeFinder.IProperty p) + { + return ((ManagedTypeFinderGeneratorTypeSystem.TProperty) p)?.Value; + } + public static Field Value (this ManagedTypeFinder.IDefinition t) + { + return ((ManagedTypeFinderGeneratorTypeSystem.TDefinition) t)?.Value; + } + public static MethodBase Value (this ManagedTypeFinder.IMethodBase t) + { + return ((ManagedTypeFinderGeneratorTypeSystem.TMethodBase) t)?.Value; + } + + public static ManagedTypeFinder.IType Wrap (this GenBase t) + { + return t == null ? null : new ManagedTypeFinderGeneratorTypeSystem.TType () { Value = t }; + } + public static ManagedTypeFinder.IProperty WrapAsProperty (this Field t) + { + return t == null ? null : new ManagedTypeFinderGeneratorTypeSystem.TProperty () { Value = t }; + } + public static ManagedTypeFinder.IDefinition WrapAsDefinition (this Field t) + { + return t == null ? null : new ManagedTypeFinderGeneratorTypeSystem.TDefinition () { Value = t }; + } + public static ManagedTypeFinder.IMethodBase Wrap (this MethodBase t) + { + return t == null ? null : new ManagedTypeFinderGeneratorTypeSystem.TMethodBase () { Value = t }; + } + + #endregion + } +} +#endif diff --git a/external/Java.Interop/tools/generator/Extensions/JavaApiDllLoaderExtensions.cs b/external/Java.Interop/tools/generator/Extensions/JavaApiDllLoaderExtensions.cs new file mode 100644 index 00000000000..58e3b7cbfeb --- /dev/null +++ b/external/Java.Interop/tools/generator/Extensions/JavaApiDllLoaderExtensions.cs @@ -0,0 +1,172 @@ +#if GENERATOR +using System; +using System.Collections.Generic; +using System.Linq; +using MonoDroid.Generation; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiDllLoaderExtensions + { + public static void LoadReferences (this JavaApi api, CodeGenerationOptions opt, IEnumerable gens) + { + JavaPackage pkg = null; + foreach (var gen in gens.Where (_ => _.IsAcw)) { + if (!api.Packages.TryGetValue (gen.PackageName, out pkg)) { + pkg = new JavaPackage (api) { Name = gen.PackageName }; + api.Packages.Add (pkg.Name, pkg); + } + + if (gen is InterfaceGen iface_gen) { + var iface = new JavaInterface (pkg); + iface.Load (iface_gen); + + pkg.AddType (iface); + } else if (gen is ClassGen class_gen) { + var kls = new JavaClass (pkg); + kls.Load (opt, class_gen); + + pkg.AddType (kls); + } + else + throw new InvalidOperationException (); + api.LoadReferences (opt, gen.NestedTypes); + } + } + + static void Load (this JavaType type, GenBase gen) + { + type.IsReferenceOnly = true; + + type.Name = gen.JavaSimpleName; + type.ExtendedJniSignature = gen.JniName; + type.Deprecated = gen.DeprecatedComment; + type.Visibility = gen.RawVisibility; + type.Implements = gen.Interfaces.Select (_ => new JavaImplements () { + Name = _.JavaName, + ExtendedJniType = _.JniName, + }).ToArray (); + if (gen.TypeParameters != null && gen.TypeParameters.Any ()) { + type.TypeParameters = new JavaTypeParameters (type); + type.TypeParameters.Load (gen.TypeParameters); + } + foreach (var f in gen.Fields.Where (_ => _.IsAcw)) { + var fld = new JavaField (type); + fld.Load (f); + type.Members.Add (fld); + } + foreach (var p in gen.Properties) { + if (p.Getter != null && p.Getter.IsAcw) { + var getter = new JavaMethod (type); + getter.Load (p.Getter); + type.Members.Add (getter); + } + if (p.Setter != null && p.Setter.IsAcw) { + var setter = new JavaMethod (type); + setter.Load (p.Setter); + type.Members.Add (setter); + } + } + foreach (var m in gen.Methods.Where (_ => _.IsAcw)) { + var method = new JavaMethod (type); + method.Load (m); + type.Members.Add (method); + } + } + + static void Load (this JavaInterface iface, InterfaceGen gen) + { + ((JavaType) iface).Load (gen); + } + + static string ExpandTypeParameters (ISymbol [] tps) + { + if (tps == null) + return null; + return '<' + string.Join (", ", tps.Select (_ => _.JavaName)) + '>'; + } + + static void Load (this JavaClass kls, CodeGenerationOptions opt, ClassGen gen) + { + ((JavaType) kls).Load (gen); + + kls.Abstract = gen.IsAbstract; + kls.Final = gen.IsFinal; + var baseGen = gen.BaseType != null ? opt.SymbolTable.Lookup (gen.BaseType) : null; + + if (baseGen != null) { + kls.Extends = baseGen.JavaName; + var gs = baseGen as GenericSymbol; + kls.ExtendsGeneric = gs != null ? gs.JavaName + ExpandTypeParameters (gs.TypeParams) : baseGen.JavaName; + kls.ExtendedJniExtends = baseGen.JniName; + } + foreach (var c in gen.Ctors) { + var ctor = new JavaConstructor (kls); + ctor.Load (c); + kls.Members.Add (ctor); + } + } + + static void Load (this JavaField field, Field gf) + { + field.Deprecated = gf.DeprecatedComment; + field.Final = gf.IsFinal; + field.Name = gf.JavaName; + field.Static = gf.IsStatic; + field.Visibility = gf.Visibility; + field.Type = gf.TypeName; // FIXME: this is managed name. Should there be Java typename? + field.TypeGeneric = gf.TypeName; // FIXME: this is NOT generic. + field.Value = gf.Value; + } + + static void Load (this JavaMethodBase method, MethodBase gm) + { + method.Deprecated = gm.Deprecated; + method.Visibility = gm.Visibility; + method.Parameters = gm.Parameters.Select (_ => new JavaParameter (method) { + Name = _.JavaName, + Type = _.RawNativeType, + }).ToArray (); + } + + static void Load (this JavaMethod method, Method gm) + { + ((JavaMethodBase) method).Load (gm); + + if (gm.RetVal.RawJavaType == "System.Boolean") throw new Exception (method.Parent.FullName + "." + gm.JavaName); + + method.Final = gm.IsFinal; + method.Name = gm.JavaName; + method.Static = gm.IsStatic; + //method.ExtendedJniSignature = gm.JniSignature; + if (gm.GenericArguments != null && gm.GenericArguments.Any ()) { + method.TypeParameters = new JavaTypeParameters (method); + method.TypeParameters.Load (gm.GenericArguments); + } + method.Abstract = gm.IsAbstract; + method.Return = gm.RetVal.RawJavaType; + // FIXME: get ExtendedJniReturn? + } + + static void Load (this JavaConstructor ctor, Ctor gc) + { + ((JavaMethodBase) ctor).Load (gc); + } + + static void Load (this JavaTypeParameters tps, GenericParameterDefinitionList gtps) + { + foreach (var stp in gtps) { + var tp = new JavaTypeParameter (tps) { + Name = stp.Name, + }; + if (stp.Constraints != null) + tp.GenericConstraints = new JavaGenericConstraints () { + BoundsType = stp.Name, + GenericConstraints = stp.Constraints.Select (_ => new JavaGenericConstraint () { Type = _.JavaName }).ToArray ()}; + tps.TypeParameters.Add (tp); + } + } + } +} + +#endif diff --git a/external/Java.Interop/tools/generator/Extensions/ManagedExtensions.cs b/external/Java.Interop/tools/generator/Extensions/ManagedExtensions.cs new file mode 100644 index 00000000000..b5e94c9c315 --- /dev/null +++ b/external/Java.Interop/tools/generator/Extensions/ManagedExtensions.cs @@ -0,0 +1,92 @@ +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.TypeNameMappings; +using Mono.Cecil; +using System.Collections.Generic; +using System.Linq; + +namespace MonoDroid.Generation +{ +#if HAVE_CECIL + internal static class ManagedExtensions + { + public static string FullNameCorrected (this TypeReference t) => t.FullName.Replace ('/', '.'); + + public static GenericParameterDefinitionList GenericArguments (this MethodDefinition m) => + m.HasGenericParameters ? GenericParameterDefinitionList.FromMetadata (m.GenericParameters) : null; + + public static string Deprecated (this MethodDefinition m) + { + var v = m.CustomAttributes.FirstOrDefault (a => a.AttributeType.FullName == "System.ObsoleteAttribute"); + return v != null ? (string)v.ConstructorArguments [0].Value ?? "deprecated" : null; + } + + public static string Visibility (this MethodDefinition m) => + m.IsPublic ? "public" : m.IsFamilyOrAssembly ? "protected internal" : m.IsFamily ? "protected" : m.IsAssembly ? "internal" : "private"; + + public static IEnumerable GetParameters (this MethodDefinition m, CustomAttribute regatt) + { + var jnisig = (string)(regatt.ConstructorArguments.Count > 1 ? regatt.ConstructorArguments [1].Value : regatt.Properties.First (p => p.Name == "JniSignature").Argument.Value); + var types = jnisig == null ? null : JavaNativeTypeManager.FromSignature (jnisig); + var e = types?.GetEnumerator (); + + foreach (var p in m.Parameters) { + if (e != null && !e.MoveNext ()) + e = null; + // Here we do some tricky thing: + // Both java.io.InputStream and java.io.OutputStream could be mapped to + // System.IO.Stream. And when there is Stream in parameters, we have to + // determine which direction of the Stream it was - in or out. + // To do that, we inspect JNI Signature to handle that. + // + // We could *always* use this JNI information, *IF* there were no + // int->enum conversion. Sadly this is not true, we still have to expect + // custom enum types and cannot simply use JNI signature here. + var rawtype = e?.Current.Type; + var type = p.ParameterType.FullName == "System.IO.Stream" && e != null ? e.Current.Type : null; + var isNotNull = p.GetTypeNullability (m) == Nullability.NotNull; + + yield return CecilApiImporter.CreateParameter (p, type, rawtype, isNotNull); + } + } + + public static string StripArity (this string type) + { + if (string.IsNullOrWhiteSpace (type)) + return type; + + int tick_index; + + // Need to loop for things like List`1> + while ((tick_index = type.IndexOf ('`')) >= 0) { + var less_than_index = type.IndexOf ('<', tick_index); + + if (less_than_index == -1) + return type; + + type = type.Substring (0, tick_index) + type.Substring (less_than_index); + } + + return type; + } + + // Convert a fully qualified type like "System.Void" to the primitive type "void" if applicable + public static string FilterPrimitive (this string type) + { + return type switch { + "System.Boolean" => "bool", + "System.Char" => "char", + "System.Byte" => "byte", + "System.SByte" => "byte", + "System.Int16" => "short", + "System.Int32" => "int", + "System.Int64" => "long", + "System.Single" => "float", + "System.Double" => "double", + "System.Void" => "void", + "System.String" => "string", + _ => type + }; + } + } +#endif +} diff --git a/external/Java.Interop/tools/generator/Extensions/StringExtensions.cs b/external/Java.Interop/tools/generator/Extensions/StringExtensions.cs new file mode 100644 index 00000000000..3ba6bce0a26 --- /dev/null +++ b/external/Java.Interop/tools/generator/Extensions/StringExtensions.cs @@ -0,0 +1,45 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace generator +{ + static class StringExtensions + { + /// + /// Shortcut for !string.IsNullOrWhiteSpace (s) + /// + public static bool HasValue (this string s) => !string.IsNullOrWhiteSpace (s); + + /// + /// Removes the final subset of a delimited string. ("127.0.0.1" -> "127.0.0") + /// + public static string ChompLast (this string s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return string.Empty; + + return s.Substring (0, index); + } + + /// + /// Returns the final subset of a delimited string. ("127.0.0.1" -> "1") + /// + public static string LastSubset (this string s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return s; + + return s.Substring (index + 1); + } + } +} diff --git a/external/Java.Interop/tools/generator/Extensions/XmlExtensions.cs b/external/Java.Interop/tools/generator/Extensions/XmlExtensions.cs new file mode 100644 index 00000000000..cd567a9c7da --- /dev/null +++ b/external/Java.Interop/tools/generator/Extensions/XmlExtensions.cs @@ -0,0 +1,22 @@ +using System.Xml.Linq; +using Xamarin.Android.Tools; + +namespace MonoDroid.Generation +{ + internal static class XmlExtensions + { + public static string Deprecated (this XElement elem) + { + var deprecated = elem.XGetAttribute ("deprecated"); + return deprecated != "not deprecated" ? deprecated : null; + } + + public static string Visibility (this XElement elem) => elem.XGetAttribute ("visibility"); + + public static GenericParameterDefinitionList GenericArguments (this XElement elem) + { + var tps = elem.Element ("typeParameters"); + return tps != null ? GenericParameterDefinitionList.FromXml (tps) : null; + } + } +} diff --git a/external/Java.Interop/tools/generator/GenerationInfo.cs b/external/Java.Interop/tools/generator/GenerationInfo.cs new file mode 100644 index 00000000000..1f737f45377 --- /dev/null +++ b/external/Java.Interop/tools/generator/GenerationInfo.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using Xamarin.Android.Binder; + +namespace MonoDroid.Generation { + + public class GenerationInfo { + + public GenerationInfo (string csdir, string javadir, string assembly) + { + CSharpDir = csdir; + JavaDir = javadir; + Assembly = assembly; + } + + public string Assembly { get; } + public string CSharpDir { get; } + public string JavaDir { get; } + public ConcurrentBag GeneratedFiles { get; } = new ConcurrentBag (); + public ConcurrentBag Enums { get; } = new ConcurrentBag (); + + public StreamWriter OpenStream (string name) + { + if (!Directory.Exists (CSharpDir)) + Directory.CreateDirectory (CSharpDir); + string filename = Path.Combine (CSharpDir, name + ".cs"); + + var sw = new StreamWriter (File.Create (filename)); + GeneratedFiles.Add (filename); + return sw; + } + + internal void GenerateLibraryProjectFile (CodeGeneratorOptions options, IEnumerable enumFiles, string path = null) + { + if (path == null) { + var name = Assembly ?? "GeneratedFiles"; + int idx = name.IndexOf (','); + name = idx < 0 ? name : name.Substring (0, idx); + path = Path.Combine (CSharpDir, name + ".projitems"); + } + + var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); + var compile = msbuild + "Compile"; + var project = new XElement ( + msbuild + "Project", + ToDefineConstants (options, msbuild), + new XComment (" Classes "), + new XElement ( + msbuild + "ItemGroup", + GeneratedFiles + .OrderBy (f => f, StringComparer.OrdinalIgnoreCase) + .Select (f => ToCompileElement (compile, f))), + new XComment (" Enums "), + new XElement ( + msbuild + "ItemGroup", + enumFiles + ?.OrderBy (f => f, StringComparer.OrdinalIgnoreCase) + ?.Select (f => ToCompileElement (compile, f)))); + + project.Save (path); + } + + XElement ToDefineConstants (CodeGeneratorOptions options, XNamespace msbuild) + { + if (options.ApiLevel == null) + return null; + AndroidSdkVersion level; + if (!AndroidSdkVersion.TryParse (options.ApiLevel, out level)) + return null; + var defines = new StringBuilder () + .Append ("$(DefineConstants);ANDROID_1"); + for (int i = 2; i <= level.ApiLevel; ++i) { + defines.AppendFormat (";ANDROID_{0}", i.ToString ()); + } + // ASSUME one minor release per major release starting with API-36.1 + for (int i = 36; i < level.ApiLevel; ++i) { + defines.Append ($";ANDROID_{i}_1"); + } + if (level.MinorRelease != 0) { + for (int i = 1; i < level.MinorRelease + 1; ++i) { + defines.Append ($";ANDROID_{level.ApiLevel}_{i}"); + } + } + return new XElement ( + msbuild + "PropertyGroup", + new XElement ( + msbuild + "DefineConstants", + defines)); + } + + XElement ToCompileElement (XName compile, string path) + { + path = path.Replace (CSharpDir, "$(MSBuildThisFileDirectory)") + .Replace ('/', '\\') + .Replace ("$(MSBuildThisFileDirectory)\\", "$(MSBuildThisFileDirectory)"); + + return new XElement (compile, new XAttribute ("Include", path)); + } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/EnumGenerator.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/EnumGenerator.cs new file mode 100644 index 00000000000..16a9f6e069b --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/EnumGenerator.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using generator.SourceWriters; +using Java.Interop.Tools.Generator.Enumification; +using Xamarin.SourceWriter; +using static MonoDroid.Generation.EnumMappings; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation +{ + class EnumGenerator + { + protected TextWriter sw; + + public EnumGenerator (TextWriter writer) + { + sw = writer; + } + + public void WriteEnumeration (CodeGenerationOptions opt, KeyValuePair enu, GenBase [] gens) + { + var ns = enu.Key.Substring (0, enu.Key.LastIndexOf ('.')).Trim (); + var cw = new CodeWriter (sw); + + cw.WriteLine ($"namespace {ns}"); + cw.WriteLine ("{"); + + var enoom = CreateWriter (opt, enu, gens); + enoom.Write (cw); + + cw.WriteLine ("}"); + } + + EnumWriter CreateWriter (CodeGenerationOptions opt, KeyValuePair enu, GenBase [] gens) + { + var enoom = new EnumWriter { + Name = enu.Key.Substring (enu.Key.LastIndexOf ('.') + 1).Trim (), + IsPublic = true + }; + + if (enu.Value.BitField) + enoom.Attributes.Add (new FlagsAttr ()); + + foreach (var member in enu.Value.Members) { + var m = new EnumMemberWriter { + Name = member.EnumMember.Trim (), + Value = member.Value.Trim (), + }; + + // Try to find the original field in our model + var managedMember = FindManagedMember (enu.Value, member, gens); + var managedMemberName = managedMember != null ? $"{managedMember.Value.Cls.FullName}.{managedMember.Value.Field.Name}" : null; + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) + m.Attributes.Add (new IntDefinitionAttr (managedMemberName, StripExtraInterfaceSpec (member.JavaSignature))); + + SourceWriterExtensions.AddSupportedOSPlatform (m.Attributes, member.ApiLevel, opt); + + if (member.DeprecatedSince.HasValue) { + // If we've manually marked it as obsolete in map.csv, that takes precedence + var msg = member.DeprecatedSince.Value == -1 ? "This value was incorrectly added to the enumeration and is not a valid value" : "deprecated"; + SourceWriterExtensions.AddObsolete (m.Attributes, msg, opt, deprecatedSince: member.DeprecatedSince); + } else if (managedMember != null && managedMember.Value.Field?.DeprecatedComment?.Contains ("enum directly instead of this field") == false) { + // Some of our source fields may have been marked with: + // "This constant will be removed in the future version. Use XXX enum directly instead of this field." + // We don't want this message to propogate to the enum. + SourceWriterExtensions.AddObsolete (m.Attributes, managedMember.Value.Field.DeprecatedComment, opt, deprecatedSince: managedMember.Value.Field.DeprecatedSince); + } + + enoom.Members.Add (m); + } + + return enoom; + } + + WeakReference cache_found_class; + + (GenBase Cls, Field Field)? FindManagedMember (EnumDescription desc, ConstantEntry constant, IEnumerable gens) + { + if (desc.FieldsRemoved) + return null; + + var jniMember = constant.JavaSignature; + + if (string.IsNullOrWhiteSpace (jniMember)) { + // enum values like "None" falls here. + return null; + } + + ParseJniMember (jniMember, out var package, out var type, out var member); + + var fullJavaType = (string.IsNullOrEmpty (package) ? "" : package + ".") + type; + + var cls = cache_found_class != null ? cache_found_class.Target as GenBase : null; + if (cls == null || cls.JniName != fullJavaType) { + cls = gens.FirstOrDefault (g => g.JavaName == fullJavaType); + if (cls == null) { + // The class was not found e.g. removed by metadata fixup. + return null; + } + cache_found_class = new WeakReference (cls); + } + var fld = cls.Fields.FirstOrDefault (f => f.JavaName == member); + if (fld == null) { + // The field was not found e.g. removed by metadata fixup. + return null; + } + return (cls, fld); + } + + internal void ParseJniMember (string jniMember, out string package, out string type, out string member) + { + try { + DoParseJniMember (jniMember, out package, out type, out member); + } catch (Exception ex) { + throw new Exception (string.Format ("failed to parse enum mapping: JNI member: {0}", jniMember, ex)); + } + } + + static void DoParseJniMember (string jniMember, out string package, out string type, out string member) + { + int endPackage = jniMember.LastIndexOf ('/'); + int endClass = jniMember.LastIndexOf ('.'); + + package = jniMember.Substring (0, endPackage).Replace ('/', '.'); + if (package.StartsWith ("I:", StringComparison.Ordinal)) + package = package.Substring (2); + + if (endClass >= 0) { + type = jniMember.Substring (endPackage + 1, endClass - endPackage - 1).Replace ('$', '.'); + member = jniMember.Substring (endClass + 1); + } else { + type = jniMember.Substring (endPackage + 1).Replace ('$', '.'); + member = ""; + } + } + + string StripExtraInterfaceSpec (string jniFieldSpec) + { + return jniFieldSpec.StartsWith ("I:", StringComparison.Ordinal) ? jniFieldSpec.Substring (2) : jniFieldSpec; + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/JavaInteropCodeGenerator.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/JavaInteropCodeGenerator.cs new file mode 100644 index 00000000000..e820f4d403d --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/JavaInteropCodeGenerator.cs @@ -0,0 +1,62 @@ +using System; +using System.IO; +using generator.SourceWriters; +using Xamarin.SourceWriter; + +namespace MonoDroid.Generation +{ + class JavaInteropCodeGenerator + { + protected TextWriter writer; + protected CodeGenerationOptions opt; + + public CodeGeneratorContext Context { get; } = new CodeGeneratorContext (); + + public JavaInteropCodeGenerator (TextWriter writer, CodeGenerationOptions options) + { + this.writer = writer; + opt = options; + } + + public static string GetInvokeType (string type) + { + return type switch + { + "Bool" => "Boolean", + "Byte" => "SByte", + "Int" => "Int32", + "Short" => "Int16", + "Long" => "Int64", + "Float" => "Single", + "UInt" => "Int32", + "UShort" => "Int16", + "ULong" => "Int64", + "UByte" => "SByte", + _ => type, + }; + } + + public virtual void WriteType (GenBase gen, string indent, GenerationInfo gen_info) + { + TypeWriter type_writer; + + if (gen is InterfaceGen iface) + type_writer = new BoundInterface (iface, opt, Context, gen_info); + else if (gen is ClassGen klass) { + if (klass.IsKotlinInlineClass) + type_writer = new KotlinInlineClassStruct (klass, opt); + else + type_writer = new BoundClass (klass, opt, Context, gen_info); + } else + throw new InvalidOperationException ("Unknown GenBase type"); + + // We do this here because we only want to check for top-level types, + // we should not check types nested in other types. + SourceWriterExtensions.WarnIfTypeNameMatchesNamespace (type_writer, gen); + + var cw = new CodeWriter (writer, indent); + type_writer.Write (cw); + } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/XAJavaInteropCodeGenerator.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/XAJavaInteropCodeGenerator.cs new file mode 100644 index 00000000000..6d34c0dc119 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/XAJavaInteropCodeGenerator.cs @@ -0,0 +1,13 @@ +using System; +using System.IO; + +namespace MonoDroid.Generation +{ + class XAJavaInteropCodeGenerator : JavaInteropCodeGenerator + { + public XAJavaInteropCodeGenerator (TextWriter writer, CodeGenerationOptions options) : base (writer, options) + { + } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Importers/CecilApiImporter.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Importers/CecilApiImporter.cs new file mode 100644 index 00000000000..7a718448cb0 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Importers/CecilApiImporter.cs @@ -0,0 +1,278 @@ +using System; +using System.Linq; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.TypeNameMappings; +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace MonoDroid.Generation +{ + class CecilApiImporter + { + public static ClassGen CreateClass (TypeDefinition t, CodeGenerationOptions opt) + { + var klass = new ClassGen (CreateGenBaseSupport (t, opt)) { + IsAbstract = t.IsAbstract, + IsFinal = t.IsSealed, + IsShallow = opt.UseShallowReferencedTypes, + }; + + foreach (var ifaceImpl in t.Interfaces) { + var iface = ifaceImpl.InterfaceType; + var def = ifaceImpl.InterfaceType.Resolve (); + + if (def != null && def.IsNotPublic) + continue; + + klass.AddImplementedInterface (iface.FullNameCorrected ()); + } + + Action populate = () => { + var implements_charsequence = t.Interfaces.Any (it => it.InterfaceType.FullName == "Java.Lang.CharSequence"); + + foreach (var m in t.Methods) { + if (m.IsPrivate || m.IsAssembly || GetRegisterAttribute (m.CustomAttributes, opt) == null) + continue; + if (implements_charsequence && t.Methods.Any (mm => mm.Name == m.Name + "Formatted")) + continue; + if (m.IsConstructor) + klass.Ctors.Add (CreateCtor (klass, m, opt)); + else + klass.AddMethod (CreateMethod (klass, m, opt)); + } + + foreach (var f in t.Fields) + if (!f.IsPrivate && GetRegisterAttribute (f.CustomAttributes, opt) == null) + klass.AddField (CreateField (f, opt)); + }; + + if (klass.IsShallow) + klass.PopulateAction = populate; + else + populate (); + + TypeReference nominal_base_type; + + for (nominal_base_type = t.BaseType; nominal_base_type != null && (nominal_base_type.HasGenericParameters || nominal_base_type.IsGenericInstance); nominal_base_type = nominal_base_type.Resolve ().BaseType) + ; // iterate up to non-generic type, at worst System.Object. + + klass.BaseType = nominal_base_type?.FullNameCorrected (); + + return klass; + } + + public static Ctor CreateCtor (GenBase declaringType, MethodDefinition m, CodeGenerationOptions opt) + { + var reg_attr = GetRegisterAttribute (m.CustomAttributes, opt); + + var ctor = new Ctor (declaringType) { + AssemblyName = m.DeclaringType.Module.Assembly.FullName, + Deprecated = m.Deprecated (), + GenericArguments = m.GenericArguments (), + IsAcw = reg_attr != null, + // not a beautiful way to check static type, yes :| + IsNonStaticNestedType = m.DeclaringType.IsNested && !(m.DeclaringType.IsAbstract && m.DeclaringType.IsSealed), + Name = m.Name, + Visibility = m.Visibility () + }; + + // If 'elem' is a constructor for a non-static nested type, then + // the type of the containing class must be inserted as the first + // argument + if (ctor.IsNonStaticNestedType) + ctor.Parameters.AddFirst (CreateParameter (m.DeclaringType.DeclaringType.FullName, ctor.DeclaringType.JavaName)); + + foreach (var p in m.GetParameters (reg_attr)) + ctor.Parameters.Add (p); + + return ctor; + } + + public static Field CreateField (FieldDefinition f, CodeGenerationOptions opt) + { + var obs_attr = GetObsoleteAttribute (f.CustomAttributes); + var reg_attr = GetRegisterAttribute (f.CustomAttributes, opt); + + var field = new Field { + DeprecatedComment = GetObsoleteComment (obs_attr), + IsAcw = reg_attr != null, + IsDeprecated = obs_attr != null, + IsEnumified = GetGeneratedEnumAttribute (f.CustomAttributes) != null, + IsFinal = f.Constant != null, + IsStatic = f.IsStatic, + JavaName = reg_attr != null ? ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.') : f.Name, + Name = f.Name, + NotNull = f.GetTypeNullability () == Nullability.NotNull, + TypeName = f.FieldType.FullNameCorrected ().StripArity (), + Value = f.Constant == null ? null : f.FieldType.FullName == "System.String" ? '"' + f.Constant.ToString () + '"' : f.Constant.ToString (), + Visibility = f.IsPublic ? "public" : f.IsFamilyOrAssembly ? "protected internal" : f.IsFamily ? "protected" : f.IsAssembly ? "internal" : "private" + }; + + var field_parameter_type = f.FieldType.Resolve () ?? f.FieldType; + field.SetterParameter = CreateParameter (field_parameter_type.FullNameCorrected ().StripArity (), null); + field.SetterParameter.Name = "value"; + + return field; + } + + public static GenBaseSupport CreateGenBaseSupport (TypeDefinition t, CodeGenerationOptions opt) + { + var obs_attr = GetObsoleteAttribute (t.CustomAttributes); + var reg_attr = GetRegisterAttribute (t.CustomAttributes, opt); + + var jn = reg_attr != null ? ((string) reg_attr.ConstructorArguments [0].Value).Replace ('/', '.') : t.FullNameCorrected (); + var idx = jn.LastIndexOf ('.'); + + var support = new GenBaseSupport { + IsAcw = reg_attr != null, + IsDeprecated = obs_attr != null, + IsGeneratable = false, + IsGeneric = t.HasGenericParameters, + IsObfuscated = false, // obfuscated types have no chance to be already bound in managed types. + Name = t.Name, + Namespace = t.Namespace, + PackageName = idx < 0 ? string.Empty : jn.Substring (0, idx), + TypeParameters = GenericParameterDefinitionList.FromMetadata (t.GenericParameters), + Visibility = t.IsPublic || t.IsNestedPublic ? "public" : "protected internal" + }; + + support.JavaSimpleName = TypeNameUtilities.FilterPrimitiveFullName (t.FullNameCorrected ()); + + if (support.JavaSimpleName == null) { + support.JavaSimpleName = idx < 0 ? jn : jn.Substring (idx + 1); + support.FullName = t.FullNameCorrected (); + } else { + var sym = opt.SymbolTable.Lookup (support.JavaSimpleName); + support.FullName = sym != null ? sym.FullName : t.FullNameCorrected (); + } + + support.JavaSimpleName = support.JavaSimpleName.Replace ('$', '.'); + + if (support.IsDeprecated) + support.DeprecatedComment = GetObsoleteComment (obs_attr) ?? "This class is obsoleted in this android platform"; + + return support; + } + + public static InterfaceGen CreateInterface (TypeDefinition t, CodeGenerationOptions opt) + { + var iface = new InterfaceGen (CreateGenBaseSupport (t, opt)) { + IsShallow = opt.UseShallowReferencedTypes, + }; + + foreach (var ifaceImpl in t.Interfaces) + iface.AddImplementedInterface (ifaceImpl.InterfaceType.FullNameCorrected ()); + + Action populate = () => { + foreach (var m in t.Methods) { + if (m.IsPrivate || m.IsAssembly || GetRegisterAttribute (m.CustomAttributes, opt) == null) + continue; + + iface.AddMethod (CreateMethod (iface, m, opt)); + } + }; + + if (iface.IsShallow) + iface.PopulateAction = populate; + else + populate (); + + iface.MayHaveManagedGenericArguments = !iface.IsAcw; + + return iface; + } + + public static Method CreateMethod (GenBase declaringType, MethodDefinition m, CodeGenerationOptions opt) + { + var reg_attr = GetRegisterAttribute (m.CustomAttributes, opt); + + var method = new Method (declaringType) { + AssemblyName = m.DeclaringType.Module.Assembly.FullName, + Deprecated = m.Deprecated (), + GenerateAsyncWrapper = false, + GenericArguments = m.GenericArguments (), + IsAbstract = m.IsAbstract, + IsAcw = reg_attr != null, + IsFinal = m.IsFinal, + IsInterfaceDefaultMethod = IsDefaultInterfaceMethod (declaringType, m), + IsReturnEnumified = GetGeneratedEnumAttribute (m.MethodReturnType.CustomAttributes) != null, + IsStatic = m.IsStatic, + IsVirtual = m.IsVirtual, + JavaName = reg_attr != null ? ((string) reg_attr.ConstructorArguments [0].Value) : m.Name, + ManagedReturn = m.ReturnType.FullNameCorrected ().StripArity ().FilterPrimitive (), + Return = m.ReturnType.FullNameCorrected ().StripArity ().FilterPrimitive (), + ReturnNotNull = m.GetReturnTypeNullability () == Nullability.NotNull, + Visibility = m.Visibility () + }; + + foreach (var p in m.GetParameters (reg_attr)) + method.Parameters.Add (p); + + if (reg_attr != null) { + var jnisig = (string) (reg_attr.ConstructorArguments.Count > 1 ? reg_attr.ConstructorArguments [1].Value : reg_attr.Properties.First (p => p.Name == "JniSignature").Argument.Value); + var rt = JavaNativeTypeManager.ReturnTypeFromSignature (jnisig); + if (rt?.Type != null) + method.Return = rt.Type; + } + + method.FillReturnType (); + + // Strip "Formatted" from ICharSequence-based method. + var name_base = method.IsReturnCharSequence ? m.Name.Substring (0, m.Name.Length - "Formatted".Length) : m.Name; + + method.Name = m.IsGetter ? (m.Name.StartsWith ("get_Is", StringComparison.Ordinal) && m.Name.Length > 6 && char.IsUpper (m.Name [6]) ? string.Empty : "Get") + name_base.Substring (4) : m.IsSetter ? (m.Name.StartsWith ("set_Is", StringComparison.Ordinal) && m.Name.Length > 6 && char.IsUpper (m.Name [6]) ? string.Empty : "Set") + name_base.Substring (4) : name_base; + + return method; + } + + public static Parameter CreateParameter (ParameterDefinition p, string jnitype, string rawtype, bool isNotNull) + { + // FIXME: safe to use CLR type name? assuming yes as we often use it in metadatamap. + // FIXME: IsSender? + var isEnumType = GetGeneratedEnumAttribute (p.CustomAttributes) != null; + return new Parameter (TypeNameUtilities.MangleName (p.Name), jnitype ?? p.ParameterType.FullNameCorrected ().StripArity (), null, isEnumType, rawtype, isNotNull); + } + + public static Parameter CreateParameter (string managedType, string javaType) + { + return new Parameter ("__self", javaType ?? managedType, managedType, false); + } + + static CustomAttribute GetJavaDefaultInterfaceMethodAttribute (Collection attributes) => + attributes.FirstOrDefault (a => a.AttributeType.FullName == "Java.Interop.JavaInterfaceDefaultMethodAttribute"); + + static CustomAttribute GetGeneratedEnumAttribute (Collection attributes) => + attributes.FirstOrDefault (a => a.AttributeType.FullName == "Android.Runtime.GeneratedEnumAttribute"); + + static CustomAttribute GetObsoleteAttribute (Collection attributes) => + attributes.FirstOrDefault (a => a.AttributeType.FullNameCorrected () == "System.ObsoleteAttribute"); + + static string GetObsoleteComment (CustomAttribute attribute) => + attribute?.ConstructorArguments.Any () == true ? (string) attribute.ConstructorArguments [0].Value : null; + + static CustomAttribute GetRegisterAttribute (Collection attributes, CodeGenerationOptions opt) => + attributes.FirstOrDefault (a => { + var attrType = a.AttributeType.FullNameCorrected (); + + if (opt.CodeGenerationTarget == Xamarin.Android.Binder.CodeGenerationTarget.JavaInterop1) { + return attrType == "Java.Interop.JniTypeSignatureAttribute"; + } + + if (attrType == "Android.Runtime.RegisterAttribute") + return true; + + return false; + }); + + static bool IsDefaultInterfaceMethod (GenBase declaringType, MethodDefinition method) + { + if (!(declaringType is InterfaceGen)) + return false; + + if (GetJavaDefaultInterfaceMethodAttribute (method.CustomAttributes) != null) + return true; + + return !method.IsAbstract && !method.IsStatic; + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs new file mode 100644 index 00000000000..ffc3dd60265 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Importers/XmlApiImporter.cs @@ -0,0 +1,586 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.JavaCallableWrappers; +using MonoDroid.Utils; +using Xamarin.Android.Tools; + +namespace MonoDroid.Generation +{ + class XmlApiImporter + { + static readonly Regex api_level = new Regex (@"api-(\d+).xml"); + + public static List Parse (XDocument doc, CodeGenerationOptions options) + { + if (doc is null) + return null; + + var root = doc.Root; + + if ((root == null) || !root.HasElements) { + Report.LogCodedWarning (0, Report.WarningNoPackageElements); + return null; + } + + var gens = new List (); + + foreach (var elem in root.Elements ()) { + switch (elem.Name.LocalName) { + case "package": + gens.AddRange (ParsePackage (elem, options)); + break; + case "enum": + var name = elem.XGetAttribute ("name"); + var sym = new EnumSymbol (name); + options.SymbolTable.AddType (name, sym); + continue; + default: + Report.LogCodedWarning (0, Report.WarningUnexpectedRootChildNode, elem.Name.ToString ()); + break; + } + } + + return gens; + } + + public static List ParsePackage (XElement ns, CodeGenerationOptions options) + { + var result = new List (); + var nested = new Dictionary (); + var by_name = new Dictionary (); + + foreach (var elem in ns.Elements ()) { + + var name = elem.XGetAttribute ("name"); + GenBase gen = null; + + switch (elem.Name.LocalName) { + case "class": + if (ShouldBind (elem)) + gen = CreateClass (ns, elem, options); + break; + case "interface": + if (ShouldBind (elem)) + gen = CreateInterface (ns, elem, options); + break; + default: + Report.LogCodedWarning (0, Report.WarningUnexpectedPackageChildNode, elem.Name.ToString ()); + break; + } + + if (gen is null) + continue; + + var idx = name.IndexOf ('<'); + + if (idx > 0) + name = name.Substring (0, idx); + + by_name [name] = gen; + + if (name.IndexOf ('.') > 0) + nested [name] = gen; + else + result.Add (gen); + } + + foreach (var name in nested.Keys) { + var top_ancestor = name.Substring (0, name.IndexOf ('.')); + + if (by_name.ContainsKey (top_ancestor)) + by_name [top_ancestor].AddNestedType (nested [name]); + else { + Report.LogCodedWarning (0, Report.WarningNestedTypeAncestorNotFound, top_ancestor, nested [name].FullName); + nested [name].Invalidate (); + } + } + + return result; + } + + public static ClassGen CreateClass (XElement pkg, XElement elem, CodeGenerationOptions options) + { + var klass = new ClassGen (CreateGenBaseSupport (pkg, elem, options, false)) { + BaseType = elem.XGetAttribute ("extends"), + FromXml = true, + IsAbstract = elem.XGetAttribute ("abstract") == "true", + IsFinal = elem.XGetAttribute ("final") == "true", + IsKotlinInlineClass = elem.XGetAttribute ("kotlin-inline-class") == "true", + KotlinInlineClassUnderlyingJniType = elem.XGetAttribute ("kotlin-inline-class-underlying-jni-type"), + PeerConstructorPartialMethod = elem.XGetAttribute ("peerConstructorPartialMethod"), + // Only use an explicitly set XML attribute + Unnest = elem.XGetAttribute ("unnest") == "true" ? true : + elem.XGetAttribute ("unnest") == "false" ? false : + !options.SupportNestedInterfaceTypes + }; + + FillApiSince (klass, pkg, elem); + SetLineInfo (klass, elem, options); + + foreach (var child in elem.Elements ()) { + switch (child.Name.LocalName) { + case "implements": + var iname = child.XGetAttribute ("name-generic-aware"); + iname = iname.Length > 0 ? iname : child.XGetAttribute ("name"); + klass.AddImplementedInterface (iname); + break; + case "method": + if (child.XGetAttribute ("visibility") != "kotlin-internal") + klass.AddMethod (CreateMethod (klass, child, options)); + break; + case "constructor": + if (child.XGetAttribute ("visibility") != "kotlin-internal") + klass.Ctors.Add (CreateCtor (klass, child, options)); + break; + case "field": + if (child.XGetAttribute ("visibility") != "kotlin-internal") + klass.AddField (CreateField (klass, child, options)); + break; + case "typeParameters": + break; // handled at GenBaseSupport + default: + Report.LogCodedWarning (0, Report.WarningUnexpectedChild, klass, child.Name.ToString ()); + break; + } + } + + if (elem.Attribute ("skipInterfaceMethods")?.Value is string skip) + foreach (var m in skip.Split (new char [] { ',', ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)) + klass.SkippedInterfaceMethods.Add (m); + + return klass; + } + + public static Ctor CreateCtor (GenBase declaringType, XElement elem, CodeGenerationOptions options = null) + { + var ctor = new Ctor (declaringType) { + AnnotatedVisibility = elem.XGetAttribute ("annotated-visibility"), + ApiAvailableSince = declaringType.ApiAvailableSince, + ApiRemovedSince = declaringType.ApiRemovedSince, + CustomAttributes = elem.XGetAttribute ("customAttributes"), + Deprecated = elem.Deprecated (), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), + GenericArguments = elem.GenericArguments (), + Name = elem.XGetAttribute ("name"), + Visibility = elem.Visibility () + }; + + SetLineInfo (ctor, elem, options); + + var idx = ctor.Name.LastIndexOf ('.'); + + if (idx > 0) + ctor.Name = ctor.Name.Substring (idx + 1); + + // If 'elem' is a constructor for a non-static nested type, then + // the type of the containing class must be inserted as the first argument + ctor.IsNonStaticNestedType = idx > 0 && elem.Parent.Attribute ("static").Value == "false"; + + if (ctor.IsNonStaticNestedType) { + string declName = elem.Parent.XGetAttribute ("name"); + string expectedEnclosingName = declName.Substring (0, idx); + XElement enclosingType = GetPreviousClass (elem.Parent.PreviousNode, expectedEnclosingName); + + if (enclosingType == null) { + ctor.MissingEnclosingClass = true; + Report.LogCodedWarning (0, Report.WarningMissingClassForConstructor, ctor, ctor.Name, expectedEnclosingName); + } else + ctor.Parameters.AddFirst (CreateParameterFromClassElement (enclosingType, options)); + } + + foreach (var child in elem.Elements ()) { + if (child.Name == "parameter") + ctor.Parameters.Add (CreateParameter (child, options)); + } + + ctor.Name = EnsureValidIdentifer (ctor.Name); + + // If declaring type was deprecated earlier than member, use the type's deprecated-since + if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince < ctor.DeprecatedSince.GetValueOrDefault (default)) + ctor.DeprecatedSince = declaringType.DeprecatedSince; + + FillApiSince (ctor, elem); + + return ctor; + } + + public static Field CreateField (GenBase declaringType, XElement elem, CodeGenerationOptions options = null) + { + var field = new Field { + AnnotatedVisibility = elem.XGetAttribute ("annotated-visibility"), + ApiAvailableSince = declaringType.ApiAvailableSince, + ApiRemovedSince = declaringType.ApiRemovedSince, + DeprecatedComment = elem.XGetAttribute ("deprecated"), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), + IsAcw = true, + IsDeprecated = elem.XGetAttribute ("deprecated") != "not deprecated", + IsDeprecatedError = elem.XGetAttribute ("deprecated-error") == "true", + IsFinal = elem.XGetAttribute ("final") == "true", + IsStatic = elem.XGetAttribute ("static") == "true", + JavaName = elem.XGetAttribute ("name"), + JniSignature = elem.XGetAttribute ("jni-signature"), + NotNull = elem.XGetAttribute ("not-null") == "true", + SetterParameter = CreateParameter (elem, options), + TypeName = elem.XGetAttribute ("type"), + Value = elem.XGetAttribute ("value"), // do not trim + Visibility = elem.XGetAttribute ("visibility") + }; + + field.SetterParameter.Name = "value"; + + if (elem.XGetAttribute ("enumType") != null) { + field.IsEnumified = true; + field.TypeName = elem.XGetAttribute ("enumType"); + } + + if (elem.Attribute ("managedName") != null) + field.Name = elem.XGetAttribute ("managedName"); + else { + field.Name = TypeNameUtilities.StudlyCase (char.IsLower (field.JavaName [0]) || field.JavaName.ToLowerInvariant ().ToUpperInvariant () != field.JavaName ? field.JavaName : field.JavaName.ToLowerInvariant ()); + field.Name = EnsureValidIdentifer (field.Name); + } + + // If declaring type was deprecated earlier than member, use the type's deprecated-since + if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince < field.DeprecatedSince.GetValueOrDefault (default)) + field.DeprecatedSince = declaringType.DeprecatedSince; + + FillApiSince (field, elem); + SetLineInfo (field, elem, options); + + return field; + } + + public static GenBaseSupport CreateGenBaseSupport (XElement pkg, XElement elem, CodeGenerationOptions opt, bool isInterface) + { + var support = new GenBaseSupport { + AnnotatedVisibility = elem.XGetAttribute ("annotated-visibility"), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), + IsAcw = true, + IsDeprecated = elem.XGetAttribute ("deprecated") != "not deprecated", + IsGeneratable = true, + JavaSimpleName = elem.XGetAttribute ("name"), + PackageName = pkg.XGetAttribute ("name"), + Visibility = elem.XGetAttribute ("visibility") + }; + + if (elem.Attribute ("skipInvokerMethods")?.Value is string skip) + foreach (var m in skip.Split (new char [] { ',', ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)) + support.SkippedInvokerMethods.Add (m); + + if (support.IsDeprecated) { + support.DeprecatedComment = elem.XGetAttribute ("deprecated"); + + if (support.DeprecatedComment == "deprecated") + support.DeprecatedComment = "This class is obsoleted in this android platform"; + } + + if (support.Visibility == "protected") + support.Visibility = "protected internal"; + + if (pkg.Attribute ("managedName") != null) + support.Namespace = pkg.XGetAttribute ("managedName"); + else + support.Namespace = opt.GetTransformedNamespace (StringRocks.PackageToPascalCase (support.PackageName)); + + var tpn = elem.Element ("typeParameters"); + + if (tpn != null) { + support.TypeParameters = GenericParameterDefinitionList.FromXml (tpn); + support.IsGeneric = true; + int idx = support.JavaSimpleName.IndexOf ('<'); + if (idx > 0) + support.JavaSimpleName = support.JavaSimpleName.Substring (0, idx); + } else { + int idx = support.JavaSimpleName.IndexOf ('<'); + if (idx > 0) + throw new NotSupportedException ("Looks like old API XML is used, which we don't support anymore."); + } + + string raw_name; + + if (elem.Attribute ("managedName") != null) { + support.Name = elem.XGetAttribute ("managedName"); + support.FullName = string.IsNullOrWhiteSpace(support.Namespace) ? support.Name : $"{support.Namespace}.{support.Name}"; + int idx = support.Name.LastIndexOf ('.'); + support.Name = idx > 0 ? support.Name.Substring (idx + 1) : support.Name; + raw_name = support.Name; + } else { + int idx = support.JavaSimpleName.LastIndexOf ('.'); + support.Name = idx > 0 ? support.JavaSimpleName.Substring (idx + 1) : support.JavaSimpleName; + if (char.IsLower (support.Name [0])) + support.Name = StringRocks.TypeToPascalCase (support.Name); + raw_name = support.Name; + support.TypeNamePrefix = isInterface ? IsPrefixableName (raw_name) ? "I" : string.Empty : string.Empty; + support.Name = EnsureValidIdentifer (support.TypeNamePrefix + raw_name); + var supportNamespace = string.IsNullOrWhiteSpace (support.Namespace) ? string.Empty : $"{support.Namespace}."; + var supportSimpleName = idx > 0 ? StringRocks.TypeToPascalCase (support.JavaSimpleName.Substring (0, idx + 1)) : string.Empty; + support.FullName = string.Format ("{0}{1}{2}", supportNamespace, supportSimpleName, support.Name); + } + + support.IsObfuscated = IsObfuscatedName (pkg.Elements ().Count (), support.JavaSimpleName) && elem.XGetAttribute ("obfuscated") != "false"; + + return support; + } + + public static InterfaceGen CreateInterface (XElement pkg, XElement elem, CodeGenerationOptions options) + { + var iface = new InterfaceGen (CreateGenBaseSupport (pkg, elem, options, true)) { + ArgsType = elem.XGetAttribute ("argsType"), + HasManagedName = elem.Attribute ("managedName") != null, + NoAlternatives = elem.XGetAttribute ("no-alternatives") == "true", + // Only use an explicitly set XML attribute + Unnest = elem.XGetAttribute ("unnest") == "true" ? true : + elem.XGetAttribute ("unnest") == "false" ? false : + !options.SupportNestedInterfaceTypes + }; + + FillApiSince (iface, pkg, elem); + SetLineInfo (iface, elem, options); + + foreach (var child in elem.Elements ()) { + switch (child.Name.LocalName) { + case "implements": + string iname = child.XGetAttribute ("name-generic-aware"); + iname = iname.Length > 0 ? iname : child.XGetAttribute ("name"); + iface.AddImplementedInterface (iname); + break; + case "method": + if (child.XGetAttribute ("visibility") != "kotlin-internal") + iface.AddMethod (CreateMethod (iface, child, options)); + break; + case "field": + if (child.XGetAttribute ("visibility") != "kotlin-internal") + iface.AddField (CreateField (iface, child, options)); + break; + case "typeParameters": + break; // handled at GenBaseSupport + default: + Report.LogCodedWarning (0, Report.WarningUnexpectedInterfaceChild, iface, child.ToString ()); + break; + } + } + + return iface; + } + + public static Method CreateMethod (GenBase declaringType, XElement elem, CodeGenerationOptions options = null) + { + var method = new Method (declaringType) { + AnnotatedVisibility = elem.XGetAttribute ("annotated-visibility"), + ApiAvailableSince = declaringType.ApiAvailableSince, + ApiRemovedSince = declaringType.ApiRemovedSince, + ArgsType = elem.Attribute ("argsType")?.Value, + CustomAttributes = elem.XGetAttribute ("customAttributes"), + Deprecated = elem.Deprecated (), + DeprecatedSince = elem.XGetAttributeAsAndroidSdkVersionOrNull ("deprecated-since"), + ExplicitInterface = elem.XGetAttribute ("explicitInterface"), + EventName = elem.Attribute ("eventName")?.Value, + GenerateAsyncWrapper = elem.Attribute ("generateAsyncWrapper") != null, + GenerateDispatchingSetter = elem.Attribute ("generateDispatchingSetter") != null, + GenericArguments = elem.GenericArguments (), + IsAbstract = elem.XGetAttribute ("abstract") == "true", + IsAcw = true, + IsCompatVirtualMethod = elem.XGetAttribute ("compatVirtualMethod") == "true", + IsFinal = elem.XGetAttribute ("final") == "true", + IsReturnEnumified = elem.Attribute ("enumReturn") != null, + IsStatic = elem.XGetAttribute ("static") == "true", + JavaName = elem.XGetAttribute ("name"), + ManagedOverride = elem.XGetAttribute ("managedOverride"), + ManagedReturn = elem.XGetAttribute ("managedReturn"), + KotlinInlineClassReturnJniType = elem.Attribute ("kotlin-inline-class-return-jni-type") != null ? elem.XGetAttribute ("kotlin-inline-class-return-jni-type") : null, + PropertyNameOverride = elem.XGetAttribute ("propertyName"), + Return = elem.XGetAttribute ("return"), + ReturnNotNull = elem.XGetAttribute ("return-not-null") == "true", + SourceApiLevel = GetApiLevel (elem.XGetAttribute ("merge.SourceFile")), + Visibility = elem.Visibility () + }; + + // CompatVirtualMethods aren't abstract + if (method.IsCompatVirtualMethod) + method.IsAbstract = false; + + method.IsVirtual = !method.IsStatic && elem.XGetAttribute ("final") == "false"; + + if (elem.Attribute ("managedName") != null) + method.Name = elem.XGetAttribute ("managedName"); + else + method.Name = StringRocks.MemberToPascalCase (method.JavaName); + + if (method.IsReturnEnumified) { + method.ManagedReturn = elem.XGetAttribute ("enumReturn"); + + // FIXME: this should not require enumReturn. Somewhere in generator uses this property improperly. + method.Return = method.ManagedReturn; + } + + if (declaringType is InterfaceGen) + method.IsInterfaceDefaultMethod = !method.IsAbstract && !method.IsStatic; + + foreach (var child in elem.Elements ()) { + if (child.Name == "parameter") + method.Parameters.Add (CreateParameter (child, options)); + } + + method.Name = EnsureValidIdentifer (method.Name); + + method.FillReturnType (); + + // If declaring type was deprecated earlier than member, use the type's deprecated-since + if (declaringType.DeprecatedSince.HasValue && declaringType.DeprecatedSince < method.DeprecatedSince.GetValueOrDefault (default)) + method.DeprecatedSince = declaringType.DeprecatedSince; + + FillApiSince (method, elem); + SetLineInfo (method, elem, options); + + return method; + } + + public static Parameter CreateParameter (XElement elem, CodeGenerationOptions options = null) + { + string managedName = elem.XGetAttribute ("managedName"); + string name = !string.IsNullOrEmpty (managedName) ? managedName : TypeNameUtilities.MangleName (EnsureValidIdentifer (elem.XGetAttribute ("name"))); + string java_type = elem.XGetAttribute ("type"); + string enum_type = elem.Attribute ("enumType") != null ? elem.XGetAttribute ("enumType") : null; + string managed_type = elem.Attribute ("managedType") != null ? elem.XGetAttribute ("managedType") : null; + var not_null = elem.XGetAttribute ("not-null") == "true"; + string kotlin_inline_jni = elem.Attribute ("kotlin-inline-class-jni-type") != null ? elem.XGetAttribute ("kotlin-inline-class-jni-type") : null; + // FIXME: "enum_type ?? java_type" should be extraneous. Somewhere in generator uses it improperly. + var result = new Parameter (name, enum_type ?? java_type, enum_type ?? managed_type, enum_type != null, java_type, not_null) { + KotlinInlineClassJniType = kotlin_inline_jni, + }; + if (elem.Attribute ("sender") != null) + result.IsSender = true; + SetLineInfo (result, elem, options); + return result; + } + + public static Parameter CreateParameterFromClassElement (XElement elem, CodeGenerationOptions options) + { + string name = "__self"; + string java_type = elem.XGetAttribute ("name"); + string java_package = elem.Parent.XGetAttribute ("name"); + var p = new Parameter (name, java_package + "." + java_type, null, false); + + SetLineInfo (p, elem, options); + return p; + } + + static string EnsureValidIdentifer (string name) + { + if (string.IsNullOrWhiteSpace (name)) + return name; + + name = IdentifierValidator.CreateValidIdentifier (name); + + if (char.IsNumber (name [0])) + name = $"_{name}"; + + return name; + } + + static int GetApiLevel (string source) + { + if (source == null) + return 0; + + var m = api_level.Match (source); + + if (!m.Success) + return 0; + + if (int.TryParse (m.Groups [1].Value, out var api)) + return api; + + return 0; + } + + static XElement GetPreviousClass (XNode n, string nameValue) + { + XElement e = null; + + while (n != null && + ((e = n as XElement) == null || + e.Name != "class" || + !e.XGetAttribute ("name").StartsWith (nameValue, StringComparison.Ordinal) || + // this complicated check (instead of simple name string equivalence match) is required for nested class inside a generic class e.g. android.content.Loader.ForceLoadContentObserver. + (e.XGetAttribute ("name") != nameValue && e.XGetAttribute ("name").IndexOf ('<') < 0))) { + n = n.PreviousNode; + } + + return e; + } + + // The array here allows members to inherit defaults from their parent, but + // override them if they were added later. + // For example: + // - + // - + // - + // Elements need to be passed in the above order. (package, class, member) + static void FillApiSince (ApiVersionsSupport.IApiAvailability model, params XElement[] elems) + { + foreach (var elem in elems) { + if (AndroidSdkVersion.TryParse (elem.XGetAttribute ("api-since"), out var result)) + model.ApiAvailableSince = result; + if (AndroidSdkVersion.TryParse (elem.XGetAttribute ("removed-since"), out var removed)) + model.ApiRemovedSince = removed; + } + } + + static bool IsObfuscatedName (int threshold, string name) + { + if (name.StartsWith ("R.", StringComparison.Ordinal)) + return false; + int idx = name.LastIndexOf ('.'); + string last = idx < 0 ? name : name.Substring (idx + 1); + // probably new proguard within Gradle tasks, used in recent GooglePlayServices in 2016 or later. + if (last.StartsWith ("zz", StringComparison.Ordinal)) + return true; + // do not expect any name with more than 3 letters is an 'obfuscated' one. + if (last.Length > 3) + return false; + // Only short ones ('a', 'b', 'c' ... 'aa', 'ab', ... 'zzz') are the targets. + if (!(last.Length == 3 && threshold > 26 * 26 || last.Length == 2 && threshold > 26 || last.Length == 1)) + return false; + if (last.Any (c => (c < 'a' || 'z' < c) && (c < '0' || '9' < c))) + return false; + return true; + } + + static bool IsPrefixableName (string name) + { + // IBlahBlah is not prefixed with 'I' + return name.Length <= 2 || name [0] != 'I' || !char.IsUpper (name [1]); + } + + static void SetLineInfo (ISourceLineInfo model, XNode node, CodeGenerationOptions options) + { + model.SourceFile = options?.ApiXmlFile; + + if (node is IXmlLineInfo info && info.HasLineInfo ()) { + model.LineNumber = info.LineNumber; + model.LinePosition = info.LinePosition; + } + } + + static bool ShouldBind (XElement elem) + { + // Don't bind things the user has said are "obfuscated" + if (elem.XGetAttribute ("obfuscated") == "true") + return false; + + var java_name = elem.XGetAttribute ("name"); + + // Ignore types that do not have a name (nested classes would end in a period like "Document.") + if (!java_name.HasValue () || java_name.EndsWith (".", StringComparison.Ordinal)) + return false; + + return true; + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs new file mode 100644 index 00000000000..735844ddd16 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ClassGen.cs @@ -0,0 +1,310 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.TypeNameMappings; +using Xamarin.Android.Binder; + +namespace MonoDroid.Generation +{ + public class ClassGen : GenBase + { + bool fill_explicit_implementation_started; + HashSet skipped_interface_methods; + + public List Ctors { get; private set; } = new List (); + + public ClassGen (GenBaseSupport support) : base (support) + { + InheritsObject = true; + + if (Namespace == "Java.Lang" && (Name == "Object" || Name == "Throwable")) + InheritsObject = false; + + DefaultValue = "IntPtr.Zero"; + NativeType = "IntPtr"; + } + + static void AddNestedInterfaceTypes (GenBase type, List nestedInterfaces) + { + foreach (var nt in type.NestedTypes) { + if (nt is InterfaceGen ni) + nestedInterfaces.Add (new InterfaceExtensionInfo { + DeclaringType = type.FullName.Substring (type.Namespace.Length + 1).Replace (".", "_"), + Type = ni + }); + else + AddNestedInterfaceTypes (nt, nestedInterfaces); + } + } + + public override ClassGen BaseGen => + (base_symbol is GenericSymbol ? (base_symbol as GenericSymbol).Gen : base_symbol) as ClassGen; + + public string BaseType { get; set; } + + public bool ContainsCtor (string jni_sig) => Ctors.Any (c => c.JniSignature == jni_sig); + + public bool ContainsNestedType (GenBase gen) + { + if (BaseGen != null && BaseGen.ContainsNestedType (gen)) + return true; + + return HasNestedType (gen.Name); + } + + public List ExplicitlyImplementedInterfaceMethods { get; } = new List (); // do not initialize here; see FixupMethodOverides() + + public override void FixupAccessModifiers (CodeGenerationOptions opt) + { + while (!IsAnnotation && !string.IsNullOrEmpty (BaseType)) { + if (opt.SymbolTable.Lookup (BaseType) is ClassGen baseClass && RawVisibility == "public" && baseClass.RawVisibility != "public") { + //Skip the BaseType and copy over any "missing" methods + foreach (var baseMethod in baseClass.Methods) { + var method = Methods.FirstOrDefault (m => m.Matches (baseMethod)); + if (method == null) + Methods.Add (baseMethod.Clone (this)); + } + BaseType = baseClass.BaseType; + } else { + break; + } + } + + base.FixupAccessModifiers (opt); + } + + public override void FixupExplicitImplementation () + { + if (fill_explicit_implementation_started) + return; // already done. + fill_explicit_implementation_started = true; + if (BaseGen != null && BaseGen.ExplicitlyImplementedInterfaceMethods == null) + BaseGen.FixupExplicitImplementation (); + + foreach (InterfaceGen iface in GetAllDerivedInterfaces ()) { + if (iface.IsGeneric) { + bool skip = false; + foreach (ISymbol isym in Interfaces) { + if (isym is GenericSymbol gs && gs.IsConcrete && gs.Gen == iface) + skip = true; + } + if (skip) + continue; // we don't handle it here; generic interface methods are generated in different manner. + } + if (BaseGen != null && BaseGen.GetAllDerivedInterfaces ().Contains (iface)) + continue; // no need to fill members for already-implemented-in-base-class iface. + foreach (var m in iface.Methods.Where (m => !ContainsMethod (m, false, false))) { + string sig = m.GetSignature (); + bool doExplicitly = false; + if (IsCovariantMethod (m)) + doExplicitly = true; + else if (m.IsGeneric) + doExplicitly = true; + if (doExplicitly) + ExplicitlyImplementedInterfaceMethods.Add (sig); + } + } + + // Keep in sync with Generate() that generates explicit iface method impl. + foreach (ISymbol isym in Interfaces) { + if (isym is GenericSymbol) { + GenericSymbol gs = isym as GenericSymbol; + if (gs.IsConcrete) { + foreach (Method m in gs.Gen.Methods) + if (m.IsGeneric) { + ExplicitlyImplementedInterfaceMethods.Add (m.GetSignature ()); + } + } + } + } + + foreach (var nt in NestedTypes) + nt.FixupExplicitImplementation (); + } + + public override string FromNative (CodeGenerationOptions opt, string varname, bool owned) => opt.CodeGenerationTarget switch { + CodeGenerationTarget.JavaInterop1 => + "global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<" + + opt.GetOutputName (FullName) + + $"> (ref {varname}, JniObjectReferenceOptions.{(owned ? "CopyAndDispose" : "Copy")})", + _ => + $"global::Java.Lang.Object.GetObject<{opt.GetOutputName (FullName)}> ({varname}, {(owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer")})" + }; + + public bool FromXml { get; set; } + + public override void Generate (CodeGenerationOptions opt, GenerationInfo gen_info) + { + using (var sw = gen_info.OpenStream (opt.GetFileName (FullName))) { + WriteAutoGeneratedHeader (sw); + sw.WriteLine ("using System;"); + sw.WriteLine ("using System.Collections.Generic;"); + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + sw.WriteLine ("using Android.Runtime;"); + } + sw.WriteLine ("using Java.Interop;"); + sw.WriteLine (); + var hasNamespace = !string.IsNullOrWhiteSpace (Namespace); + if (hasNamespace) { + sw.WriteLine ("namespace {0} {{", Namespace); + sw.WriteLine (); + } + + var generator = opt.CreateCodeGenerator (sw); + generator.WriteType (this, hasNamespace ? "\t" : string.Empty, gen_info); + + if (hasNamespace) { + sw.WriteLine ("}"); + } + } + } + + public static void GenerateEnumList (GenerationInfo gen_info) + { + using (var sw = new StreamWriter (File.Create (Path.Combine (gen_info.CSharpDir, "enumlist")))) { + foreach (string e in gen_info.Enums.OrderBy (p => p, StringComparer.OrdinalIgnoreCase)) + sw.WriteLine (e); + } + } + + static void WriteAutoGeneratedHeader (StreamWriter sw) + { + sw.WriteLine ("//------------------------------------------------------------------------------"); + sw.WriteLine ("// "); + sw.WriteLine ("// This code was generated by a tool."); + sw.WriteLine ("//"); + sw.WriteLine ("// Changes to this file may cause incorrect behavior and will be lost if"); + sw.WriteLine ("// the code is regenerated."); + sw.WriteLine ("// "); + sw.WriteLine ("//------------------------------------------------------------------------------"); + sw.WriteLine (); + sw.WriteLine ("#nullable restore"); // Roslyn turns off NRT for generated files by default, re-enable it + } + + protected override bool GetEnumMappedMemberInfo () + { + foreach (var m in Ctors) + return true; + + return base.GetEnumMappedMemberInfo (); + } + + internal IEnumerable GetNestedInterfaceTypes () + { + var nestedInterfaces = new List (); + AddNestedInterfaceTypes (this, nestedInterfaces); + return nestedInterfaces; + } + + public bool InheritsObject { get; set; } + + public bool IsAbstract { get; set; } + + public bool IsExplicitlyImplementedMethod (string sig) + { + for (var c = this; c != null; c = c.BaseGen) + if (c.ExplicitlyImplementedInterfaceMethods.Contains (sig)) + return true; + return false; + } + + public bool IsFinal { get; set; } + + // Kotlin @JvmInline value class support. + // When IsKotlinInlineClass is true, the generator emits a `readonly struct` + // wrapper around KotlinInlineClassUnderlyingJniType instead of the usual + // peer-class binding. + public bool IsKotlinInlineClass { get; set; } + + public string KotlinInlineClassUnderlyingJniType { get; set; } + + public bool NeedsNew { get; set; } + + public string PeerConstructorPartialMethod { get; set; } + + protected override bool OnValidate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + if (validated) + return IsValid; + + validated = true; + + if (!support.OnValidate (opt)) { + IsValid = false; + return false; + } + + // We're validating this in prior to BaseType. + if (TypeParameters != null && !TypeParameters.Validate (opt, type_params, context)) { + IsValid = false; + return false; + } + + if (char.IsNumber (Name [0])) { + // it is an anonymous class which does not need output. + IsValid = false; + return false; + } + + base_symbol = IsAnnotation ? opt.SymbolTable.Lookup ("java.lang.Object") : BaseType != null ? opt.SymbolTable.Lookup (BaseType) : null; + if (base_symbol == null && FullName != "Java.Lang.Object" && FullName != "System.Object") { + Report.LogCodedWarning (0, Report.WarningUnknownBaseType, this, FullName, BaseType); + IsValid = false; + return false; + } + + if ((base_symbol != null && !base_symbol.Validate (opt, TypeParameters, context)) || !base.OnValidate (opt, type_params, context)) { + Report.LogCodedWarning (0, Report.WarningInvalidBaseType, this, FullName, BaseType); + IsValid = false; + return false; + } + + var valid_ctors = new List (); + + foreach (var c in Ctors) + if (c.Validate (opt, TypeParameters, context)) + valid_ctors.Add (c); + + Ctors = valid_ctors; + + return true; + } + + public override void ResetValidation () + { + validated = false; + base.ResetValidation (); + } + + public HashSet SkippedInterfaceMethods => skipped_interface_methods ??= new HashSet (); + + public override string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings = null) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"({varname}?.PeerReference ?? default)"; + } + return $"JNIEnv.ToLocalJniHandle ({varname})"; + } + + public override void UpdateEnumsInInterfaceImplementation () + { + foreach (InterfaceGen iface in GetAllDerivedInterfaces ()) { + if (iface.HasEnumMappedMembers) { + foreach (Method imethod in iface.Methods) { + var method = Methods.FirstOrDefault (m => m.Name == imethod.Name && m.JniSignature == imethod.JniSignature); + if (method != null) { + if (imethod.IsReturnEnumified) + method.RetVal.SetGeneratedEnumType (imethod.RetVal.FullName); + for (int i = 0; i < imethod.Parameters.Count; i++) + if (imethod.Parameters [i].IsEnumified) + method.Parameters [i].SetGeneratedEnumType (imethod.Parameters [i].Type); + } + } + } + } + base.UpdateEnumsInInterfaceImplementation (); + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Ctor.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Ctor.cs new file mode 100644 index 00000000000..0848e9497b6 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Ctor.cs @@ -0,0 +1,33 @@ +using System; +using System.IO; +using System.Xml; + +namespace MonoDroid.Generation +{ + public class Ctor : MethodBase + { + public Ctor (GenBase declaringType) : base (declaringType) + { + } + + public string CustomAttributes { get; set; } + public bool IsNonStaticNestedType { get; set; } + public string JniSignature { get; private set; } + public bool MissingEnclosingClass { get; set; } + + public string ID => "id_ctor" + IDSignature; + + protected override bool OnValidate (CodeGenerationOptions opt, GenericParameterDefinitionList tps, CodeGeneratorContext context) + { + if (MissingEnclosingClass) + return false; + + if (!base.OnValidate (opt, tps, context)) + return false; + + JniSignature = "(" + Parameters.JniSignature + ")V"; + + return true; + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs new file mode 100644 index 00000000000..1a3f89f5b4a --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using Java.Interop.Tools.Generator; + +namespace MonoDroid.Generation +{ + public class Field : ApiVersionsSupport.IApiAvailability, ISourceLineInfo + { + public string AnnotatedVisibility { get; set; } + public string Annotation { get; set; } + public AndroidSdkVersion ApiAvailableSince { get; set; } + public AndroidSdkVersion ApiRemovedSince { get; set; } + public string DeprecatedComment { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } + public bool IsAcw { get; set; } + public bool IsDeprecated { get; set; } + public bool IsDeprecatedError { get; set; } + public bool IsEnumified { get; set; } + public bool IsFinal { get; set; } + public bool IsStatic { get; set; } + public ParameterList SetParameters { get; private set; } + public ISymbol Symbol { get; private set; } + public string JavaName { get; set; } + public string Name { get; set; } + public bool NotNull { get; set; } + public Parameter SetterParameter { get; set; } + public string TypeName { get; set; } + public string Value { get; set; } + public string Visibility { get; set; } + public string JniSignature { get; set; } + + public JavadocInfo JavadocInfo { get; set; } + + public int LineNumber { get; set; } = -1; + public int LinePosition { get; set; } = -1; + public string SourceFile { get; set; } + + internal string GetMethodPrefix => TypeNameUtilities.GetCallPrefix (Symbol); + + internal string ID => JavaName + "_jfieldId"; + + public bool IsConst => IsFinal && IsStatic; + + public bool NeedsProperty => !IsStatic || !IsFinal || string.IsNullOrEmpty (Value) || Symbol.IsArray || !primitive_types.Contains (Symbol.JavaName); + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + Symbol = opt.SymbolTable.Lookup (TypeName, type_params); + + if (Symbol == null || !Symbol.Validate (opt, type_params, context)) { + Report.LogCodedWarning (0, Report.WarningUnexpectedFieldType, this, TypeName, context.GetContextTypeMember ()); + return false; + } + + if (!string.IsNullOrEmpty (Value) && Symbol != null && Symbol.FullName == "char" && !Value.StartsWith ("(char)", StringComparison.Ordinal)) + Value = "(char)" + Value; + + SetParameters = new ParameterList { + SetterParameter, + }; + + if (!SetParameters.Validate (opt, type_params, context)) + throw new NotSupportedException ( + string.Format ("Unable to generate setter parameter list {0}", context.ContextString)); + + return true; + } + + static readonly HashSet primitive_types = new HashSet { + "boolean", + "char", + "byte", + "short", + "int", + "long", + "float", + "double", + // while technically not a primitive type, Strings have the feature that + // their value is stored within bytecode and their value is thus accessible + // within the api.xml description. + "java.lang.String", + }; + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs new file mode 100644 index 00000000000..4f0ca0b8e01 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs @@ -0,0 +1,1059 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation.Utilities; +using Xamarin.Android.Binder; + +namespace MonoDroid.Generation +{ + public abstract class GenBase : IGeneratable, ApiVersionsSupport.IApiAvailability, ISourceLineInfo + { + bool enum_updated; + bool property_filled; + bool property_filling; + protected internal ISymbol base_symbol; + protected bool iface_validation_failed; + protected GenBaseSupport support; + protected bool validated = false; + + readonly List implemented_interfaces = new List (); + readonly Dictionary jni_sig_hash = new Dictionary (); + readonly Dictionary prop_hash = new Dictionary (); + + protected GenBase (GenBaseSupport support) + { + this.support = support; + } + + public List Fields { get; private set; } = new List (); + public List Interfaces { get; } = new List (); + public List Methods { get; private set; } = new List (); + public List NestedTypes { get; private set; } = new List (); + public List Properties { get; } = new List (); + public string DefaultValue { get; set; } + public bool HasVirtualMethods { get; set; } + + public int LineNumber { get; set; } = -1; + public int LinePosition { get; set; } = -1; + public string SourceFile { get; set; } + + public string ReturnCast => string.Empty; + + public JavadocInfo JavadocInfo { get; set; } + + // This means Ctors/Methods/Properties/Fields has not been populated yet. + // If this type is retrieved from the SymbolTable, it will call PopulateAction + // to fill in members before returning it to the user. + internal bool IsShallow { get; set; } + internal Action PopulateAction { get; set; } + + public void AddField (Field f) + { + Fields.Add (f); + } + + public void AddImplementedInterface (string name) + { + implemented_interfaces.Add (name); + } + + public void AddMethod (Method m) + { + Methods.Add (m); + } + + public virtual void AddNestedType (GenBase gen) + { + foreach (var nest in NestedTypes) { + if (gen.JavaName.StartsWith (nest.JavaName + ".", StringComparison.Ordinal)) { + nest.AddNestedType (gen); + return; + } + } + + var removes = new List (); + + foreach (var nest in NestedTypes) { + if (nest.JavaName.StartsWith (gen.JavaName + ".", StringComparison.Ordinal)) { + gen.AddNestedType (nest); + removes.Add (nest); + } + } + + foreach (var rmv in removes) + NestedTypes.Remove (rmv); + + NestedTypes.Add (gen); + } + + void AdjustNestedTypeFullName (GenBase parent) + { + if (parent is ClassGen) + foreach (var nested in parent.NestedTypes) + nested.FullName = parent.FullName + "." + nested.Name; + } + + void AddPropertyAccessors () + { + // First pass extracts getters and creates property hash + List unmatched = new List (); + foreach (Method m in Methods) { + if (m.IsPropertyAccessor) { + string prop_name = m.PropertyName; + if (m.CanSet || prop_name == string.Empty || Name == prop_name || m.Name == "GetHashCode" || HasNestedType (prop_name) || IsInfrastructural (prop_name)) + unmatched.Add (m); + else if (BaseGen != null && !BaseGen.prop_hash.ContainsKey (prop_name) && BaseGen.Methods.Any (mm => mm.Name == m.Name && ReturnTypeMatches (m, mm) && ParameterList.Equals (mm.Parameters, m.Parameters))) + // this is to filter out those method that was *not* a property + // in the base type for some reason (e.g. name overlap). + // For example, android.graphics.drawable.BitmapDrawable#getConstantState() + // ContainsProperty() check is required here to not exclude such methods + // that are known to be property. AbstractSelectionKey.IsValid is an example. + unmatched.Add (m); + else { + if (prop_hash.ContainsKey (prop_name)) { + if (m.Name.StartsWith ("Get", StringComparison.Ordinal)) + unmatched.Add (m); + else { + unmatched.Add (prop_hash [prop_name].Getter); + prop_hash [prop_name].Getter = m; + } + } else { + var prop = new Property (prop_name) { + Getter = m + }; + prop_hash [prop_name] = prop; + } + } + } else + unmatched.Add (m); + } + Methods = unmatched; + + // Second pass adds setters + unmatched = new List (); + foreach (Method m in Methods) { + if (!m.CanSet) { + unmatched.Add (m); + continue; + } + + if (Ancestors ().All (a => !a.prop_hash.ContainsKey (m.PropertyName)) && Ancestors ().Any (a => a.Methods.Any (mm => mm.Name == m.Name && ReturnTypeMatches (m, mm) && ParameterList.Equals (mm.Parameters, m.Parameters)))) + unmatched.Add (m); // base setter exists, and it was not a property. + else if (prop_hash.ContainsKey (m.PropertyName)) { + Property baseProp = BaseGen?.Properties.FirstOrDefault (p => p.Name == m.PropertyName); + var prop = prop_hash [m.PropertyName]; + if (prop.Getter.RetVal.FullName == m.Parameters [0].Type && + prop.Getter.IsAbstract == m.IsAbstract && // SearchIterator abstract getIndex() and non-abstract setIndex() + prop.Getter.Visibility == m.Visibility && + (baseProp == null || baseProp.Setter != null) && + prop.Getter.SourceApiLevel <= m.SourceApiLevel) + prop.Setter = m; + else + unmatched.Add (m); + } else if (prop_hash.ContainsKey ("Is" + m.PropertyName)) { + var prop = prop_hash ["Is" + m.PropertyName]; + if (prop.Getter.RetVal.FullName == m.Parameters [0].Type && + prop.Getter.Visibility == m.Visibility && + CanMethodBeIsStyleSetter (m) && + prop.Getter.SourceApiLevel <= m.SourceApiLevel) { + prop.Name = m.PropertyName; + prop.Setter = m; + prop_hash [m.PropertyName] = prop; + prop_hash.Remove ("Is" + m.PropertyName); + } else + unmatched.Add (m); + } else + unmatched.Add (m); + if (m.GenerateDispatchingSetter && prop_hash.ContainsKey (m.PropertyName)) + prop_hash [m.PropertyName].GenerateDispatchingSetter = true; + } + Methods = unmatched; + } + + IEnumerable Ancestors () + { + for (var g = BaseGen; g != null; g = g.BaseGen) + yield return g; + } + + public string AnnotatedVisibility => support.AnnotatedVisibility; + + // not: not currently assembly qualified, but it uses needed + // Type.GetType() conventions such as '/' for nested types. + public string AssemblyQualifiedName => string.IsNullOrWhiteSpace (Namespace) + ? $"{FullName.Replace ('.', '/')}" + : $"{Namespace}." + $"{FullName.Substring (Namespace.Length + 1).Replace ('.', '/')}"; + + public AndroidSdkVersion ApiAvailableSince { get; set; } + + public AndroidSdkVersion ApiRemovedSince { get; set; } + + public virtual ClassGen BaseGen => null; + + public GenBase BaseSymbol => + (base_symbol is GenericSymbol ? (base_symbol as GenericSymbol).Gen : base_symbol) as GenBase; + + public string Call (CodeGenerationOptions opt, string var_name) => opt.GetSafeIdentifier (var_name); + + bool CanMethodBeIsStyleSetter (Method m) + { + // returns false if there is an interface which has such a property that + // the method "will" result in the same name but lacks the corresponding setter. + // In that case, the method should not be converted to the setter, because + // it breaks the class due to missing interface implementation member (getter). + // bug #5020 repro uncovered this issue. + return GetAllDerivedInterfaces ().All (iface => !iface.Properties.Any (p => p.Name == "Is" + m.PropertyName && p.Setter == null)); + } + + public bool ContainsMethod (string name_and_jnisig) => jni_sig_hash.ContainsKey (name_and_jnisig); + + public bool ContainsMethod (Method method, bool check_ifaces) => ContainsMethod (method, check_ifaces, true); + + public bool ContainsMethod (Method method, bool check_ifaces, bool check_base_ifaces) + { + // background: bug #10123. + // Visibility check was introduced - and required so far - to block "public overrides protected" methods + // (which is allowed in Java but not in C#). + // The problem is, it does not *always* result in error and generates callable code, and we depend on + // that fact in several classes that implements some interface that requires "public Object clone()". + // + // This visibility inconsistency results in 1) error for abstract methods and 2) warning for virtual methods. + // Hence, for abstract methods we dare to ignore visibility difference and treat it as override, + // *then* C# compiler will report this inconsistency as error that users need to fix manually, but + // with obvious message saying "it is because of visibility consistency", + // not "abstract member not implemented" (it is *implemented* in different visibility and brings confusion). + // For virtual methods, just check the visibility difference and treat as different method. + // Regardless of whether it is actually an override or not, we just invoke Java method. + if (jni_sig_hash.ContainsKey (method.JavaName + method.JniSignature)) { + var bm = jni_sig_hash [method.JavaName + method.JniSignature]; + if (bm.Visibility == method.Visibility || bm.IsAbstract) + return true; + } + if (check_ifaces) { + foreach (ISymbol isym in Interfaces) { + if ((isym is GenericSymbol ? (isym as GenericSymbol).Gen : isym) is InterfaceGen igen && igen.ContainsMethod (method, true)) + return true; + } + } + return BaseSymbol != null && BaseSymbol.ContainsMethod (method, check_base_ifaces, check_base_ifaces); + } + + public bool ContainsName (string name) + { + if (HasNestedType (name) || ContainsProperty (name, true)) + return true; + + return Methods.Any (m => m.Name == name); + } + + public bool ContainsProperty (string name, bool check_ifaces) => ContainsProperty (name, check_ifaces, true); + + public bool ContainsProperty (string name, bool check_ifaces, bool check_base_ifaces) => + GetPropertyByName (name, check_ifaces, check_base_ifaces) != null; + + public string DeprecatedComment => support.DeprecatedComment; + + public AndroidSdkVersion? DeprecatedSince => support.DeprecatedSince; + + IEnumerable Descendants (IList gens) + { + foreach (var directDescendants in gens.Where (x => x.BaseGen == this)) { + yield return directDescendants; + foreach (var indirectDescendants in directDescendants.Descendants (gens)) { + yield return indirectDescendants; + } + } + } + + public string ElementType { get; set; } + + public void FillProperties () + { + if (property_filled) + return; + if (property_filling) + throw new Exception (); // check bad recursion + property_filling = true; + property_filled = true; + + if (BaseGen != null) + BaseGen.FillProperties (); + foreach (var iface in GetAllDerivedInterfaces ()) + iface.FillProperties (); + + AddPropertyAccessors (); + + var names = prop_hash.Keys; + foreach (string name in names) + Properties.Add (prop_hash [name]); + Properties.Sort ((p1, p2) => string.CompareOrdinal (p1.Name, p2.Name)); + property_filling = false; + + foreach (var nt in NestedTypes) + nt.FillProperties (); + } + + public virtual void FixupAccessModifiers (CodeGenerationOptions opt) + { + foreach (var nt in NestedTypes) + nt.FixupAccessModifiers (opt); + } + + public virtual void FixupExplicitImplementation () + { + } + + public void FixupMethodOverrides (CodeGenerationOptions opt) + { + // Process regular methods (non-static, non-interface default methods) + foreach (var m in Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod)) { + for (var bt = GetBaseGen (opt); bt != null; bt = bt.GetBaseGen (opt)) { + var bm = bt.Methods.FirstOrDefault (mm => + mm.Name == m.Name && + mm.Visibility == m.Visibility && + mm.RetVal.FullName == m.RetVal.FullName && // if return type is different, it could be still "new", not "override". + ParameterList.Equals (mm.Parameters, m.Parameters)); + if (bm == null) { + continue; + } + + m.IsOverride = true; + if (opt.FixObsoleteOverrides) { + // If method overrides a deprecated method, it also needs to be marked as deprecated + if (bm.Deprecated.HasValue () && !m.Deprecated.HasValue ()) + m.Deprecated = bm.Deprecated; + + // Fix issue when base method was deprecated before the overriding method, set both both to base method value + if (bm.DeprecatedSince.GetValueOrDefault (default) < m.DeprecatedSince.GetValueOrDefault (default)) + m.DeprecatedSince = bm.DeprecatedSince; + } + + // If a "removed" method overrides a "not removed" method, the method was + // likely moved to a base class, so don't mark it as removed. + if (m.ApiRemovedSince > 0 && bm.ApiRemovedSince == 0) { + m.ApiRemovedSince = default; + } + break; + } + } + + // Process property getter/setter methods for ApiRemovedSince fixup + foreach (var prop in Properties) { + for (var bt = GetBaseGen (opt); bt != null; bt = bt.GetBaseGen (opt)) { + var baseProp = bt.Properties.FirstOrDefault (p => p.Name == prop.Name && p.Type == prop.Type); + if (baseProp == null) { + continue; + } + + bool shouldBreak = false; + if (prop.Getter != null && prop.Getter.ApiRemovedSince > 0 && baseProp.Getter != null && baseProp.Getter.ApiRemovedSince == 0) { + if (baseProp.Getter.Visibility == prop.Getter.Visibility && + ParameterList.Equals (baseProp.Getter.Parameters, prop.Getter.Parameters) && + baseProp.Getter.RetVal.FullName == prop.Getter.RetVal.FullName) { + // If a "removed" property getter overrides a "not removed" getter, the method was + // likely moved to a base class, so don't mark it as removed. + prop.Getter.ApiRemovedSince = default; + shouldBreak = true; + } + } + if (prop.Setter != null && prop.Setter.ApiRemovedSince > 0 && baseProp.Setter != null && baseProp.Setter.ApiRemovedSince == 0) { + if (baseProp.Setter.Visibility == prop.Setter.Visibility && + ParameterList.Equals (baseProp.Setter.Parameters, prop.Setter.Parameters)) { + // If a "removed" property setter overrides a "not removed" setter, the method was + // likely moved to a base class, so don't mark it as removed. + prop.Setter.ApiRemovedSince = default; + shouldBreak = true; + } + } + if (shouldBreak) { + break; + } + } + } + + // Process interface inheritance for both regular and default interface methods + if (this is InterfaceGen currentInterface) { + // For interfaces, check all base interfaces (interfaces that this interface implements/extends) + var baseInterfaces = currentInterface.GetAllDerivedInterfaces (); + + foreach (var m in Methods.Where (m => !m.IsStatic)) { + foreach (var baseIface in baseInterfaces) { + var bm = baseIface.Methods.FirstOrDefault (mm => + mm.Name == m.Name && + mm.Visibility == m.Visibility && + mm.RetVal.FullName == m.RetVal.FullName && + ParameterList.Equals (mm.Parameters, m.Parameters)); + if (bm == null) { + continue; + } + // If a "removed" interface method overrides a "not removed" method, the method was + // likely moved to a base interface, so don't mark it as removed. + if (m.ApiRemovedSince > 0 && bm.ApiRemovedSince == 0) { + m.ApiRemovedSince = default; + } + break; + } + } + + // Process interface property getter/setter methods for ApiRemovedSince fixup + foreach (var prop in Properties) { + foreach (var baseIface in baseInterfaces) { + var baseProp = baseIface.Properties.FirstOrDefault (p => p.Name == prop.Name && p.Type == prop.Type); + if (baseProp == null) + continue; + + bool shouldBreak = false; + if (prop.Getter != null && prop.Getter.ApiRemovedSince > 0 && baseProp.Getter != null && baseProp.Getter.ApiRemovedSince == 0) { + if (baseProp.Getter.Visibility == prop.Getter.Visibility && + ParameterList.Equals (baseProp.Getter.Parameters, prop.Getter.Parameters) && + baseProp.Getter.RetVal.FullName == prop.Getter.RetVal.FullName) { + prop.Getter.ApiRemovedSince = default; + shouldBreak = true; + } + } + if (prop.Setter != null && prop.Setter.ApiRemovedSince > 0 && baseProp.Setter != null && baseProp.Setter.ApiRemovedSince == 0) { + if (baseProp.Setter.Visibility == prop.Setter.Visibility && + ParameterList.Equals (baseProp.Setter.Parameters, prop.Setter.Parameters)) { + prop.Setter.ApiRemovedSince = default; + shouldBreak = true; + } + } + if (shouldBreak) { + break; + } + } + } + + // Process interface field inheritance for ApiRemovedSince fixup + foreach (var field in Fields) { + foreach (var baseIface in baseInterfaces) { + var baseField = baseIface.Fields.FirstOrDefault (f => f.Name == field.Name && f.TypeName == field.TypeName && f.Visibility == field.Visibility); + if (baseField == null) { + continue; + } + // If a "removed" interface field overrides a "not removed" field, the field was + // likely moved to a base interface, so don't mark it as removed. + if (field.ApiRemovedSince > 0 && baseField.ApiRemovedSince == 0) { + field.ApiRemovedSince = default; + } + break; + } + } + } + + // Interface default methods can be overriden. We want to process them differently. + var checkDimOverrideTargets = opt.SupportDefaultInterfaceMethods ? Methods : Methods.Where (m => m.IsInterfaceDefaultMethod); + + // We need to check all the implemented interfaces of all the base types. + var allIfaces = new List (); + + for (var gen = this; gen != null; gen = gen.BaseGen) + gen.GetAllDerivedInterfaces (allIfaces); + + foreach (var m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { + foreach (var bt in allIfaces.Distinct ()) { + // We mark a method as an override if (1) it is a DIM, or (2) if the base method is DIM + // (i.e. we don't mark as override if a class method "implements" normal iface method.) + var bm = bt.Methods.FirstOrDefault (mm => (m.IsInterfaceDefaultMethod || !mm.IsAbstract) && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); + + if (bm != null) { + m.OverriddenInterfaceMethod = bm; + break; + } + } + } + + foreach (var m in Methods) { + if (m.Name == Name || ContainsProperty (m.Name, true) || HasNestedType (m.Name)) + m.Name = "Invoke" + m.Name; + if ((m.Name == "ToString" && m.Parameters.Count == 0) || (BaseGen != null && BaseGen.ContainsMethod (m, true))) + m.IsOverride = true; + } + + foreach (var nt in NestedTypes) + nt.FixupMethodOverrides (opt); + } + + public abstract string FromNative (CodeGenerationOptions opt, string varname, bool owned); + + public string FullName { + get => support.FullName; + set => support.FullName = value; + } + + (object Package, object Name, string Id) javaFullNameIdCache; + + /// + /// Fully-qualifed Java name, usable as a C# identifier, by replacing + /// `.` and `$` with `_`. Example: java_lang_Object. + /// + public string JavaFullNameId { + get { + if (object.ReferenceEquals (javaFullNameIdCache.Package, support.PackageName) && + object.ReferenceEquals (javaFullNameIdCache.Name, support.JavaSimpleName)) + return javaFullNameIdCache.Id; + javaFullNameIdCache.Package = support.PackageName; + javaFullNameIdCache.Name = support.JavaSimpleName; + javaFullNameIdCache.Id = + string.Concat (support.PackageName, support.PackageName == null ? null : "_", support.JavaSimpleName) + .Replace ('.', '_') + .Replace ('$', '_'); + return javaFullNameIdCache.Id; + } + } + + public abstract void Generate (CodeGenerationOptions opt, GenerationInfo gen_info); + + protected void GenerateAnnotationAttribute (CodeGenerationOptions opt, GenerationInfo gen_info) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return; + } + if (ShouldGenerateAnnotationAttribute) { + var baseName = Namespace.Length > 0 ? FullName.Substring (Namespace.Length + 1) : FullName; + var attrClassNameBase = baseName.Substring (TypeNamePrefix.Length) + "Attribute"; + var localFullName = Namespace + (Namespace.Length > 0 ? "." : string.Empty) + attrClassNameBase; + + using (var sw = gen_info.OpenStream (opt.GetFileName (localFullName))) { + sw.WriteLine ("using System;"); + sw.WriteLine (); + sw.WriteLine ("namespace {0} {{", Namespace); + sw.WriteLine (); + sw.WriteLine ("\t[global::Android.Runtime.Annotation (\"{0}\")]", JavaName); + sw.WriteLine ("\t{0} partial class {1} : Attribute", Visibility, attrClassNameBase); + sw.WriteLine ("\t{"); + + // An Annotation attribute property is generated for each applicable annotation method, + // where *applicable* means java annotation compatible types. See IsTypeCommensurate(). + foreach (var method in Methods.Where (m => m.Parameters.Count == 0 && + IsTypeCommensurate (opt, opt.SymbolTable.Lookup (m.RetVal.JavaName)))) { + sw.WriteLine ("\t\t[global::Android.Runtime.Register (\"{0}\"{1})]", method.JavaName, method.AdditionalAttributeString ()); + sw.WriteLine ("\t\tpublic {0} {1} {{ get; set; }}", opt.GetTypeReferenceName (method.RetVal), method.Name); + sw.WriteLine (); + } + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + } + } + } + + public List GetAllDerivedInterfaces () + { + var result = new List (); + GetAllDerivedInterfaces (result); + return result; + } + + void GetAllDerivedInterfaces (List ifaces) + { + foreach (var isym in Interfaces) { + if (!((isym is GenericSymbol ? (isym as GenericSymbol).Gen : isym) is InterfaceGen iface)) + continue; + + var found = false; + + foreach (var known in ifaces) + if (known.FullName == iface.FullName) + found = true; + + if (found) + continue; + + ifaces.Add (iface); + iface.GetAllDerivedInterfaces (ifaces); + } + } + + protected internal IEnumerable GetAllImplementedInterfaces () + { + var set = new HashSet (); + + void visit (ISymbol isym) + { + if ((isym is GenericSymbol gsym ? gsym.Gen : isym) is InterfaceGen igen) + set.Add (igen); + + if (!(isym is GenBase b)) + return; + + foreach (var i in b.Interfaces) + visit (i); + } + + foreach (var i in Interfaces) + visit (i); + + return set; + } + + public IEnumerable GetAllMethods () => + Methods.Concat (Properties.Select (p => p.Getter)).Concat (Properties.Select (p => p.Setter)).Where (m => m != null); + + GenBase GetBaseGen (CodeGenerationOptions opt) + { + if (this is InterfaceGen) + return null; + + if (BaseGen != null) + return BaseGen; + + if (BaseSymbol == null) + return null; + + if (opt.SymbolTable.Lookup (BaseSymbol.FullName) is GenBase bg && bg != this) + return bg; + + return null; + } + + protected virtual bool GetEnumMappedMemberInfo () + { + foreach (var f in Fields) + if (f.IsEnumified) + return true; + foreach (var m in Methods) + if (m.IsReturnEnumified | m.Parameters.Any (p => p.IsEnumified)) + return true; + return false; + } + + public bool GetGenericMappings (InterfaceGen gen, Dictionary mappings) + { + foreach (var sym in Interfaces) { + if (sym is GenericSymbol gsym) { + if (gsym.Gen.FullName == gen.FullName) { + for (int i = 0; i < gsym.TypeParams.Length; i++) + mappings [gsym.Gen.TypeParameters [i].Name] = gsym.TypeParams [i].FullName; + return true; + } else if (gsym.Gen.GetGenericMappings (gen, mappings)) { + string [] keys = new string [mappings.Keys.Count]; + mappings.Keys.CopyTo (keys, 0); + foreach (string tp in keys) + mappings [tp] = gsym.TypeParams [Array.IndexOf ((from gtp in gsym.Gen.TypeParameters select gtp.Name).ToArray (), mappings [tp])].FullName; + return true; + } + } + } + + return false; + } + + public virtual string GetGenericType (Dictionary mappings) + { + return null; + } + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"{variable}.PeerReference"; + } + var handleType = IsThrowable () ? "Java.Lang.Throwable" : "Java.Lang.Object"; + + return $"((global::{handleType}) {variable}).Handle"; + } + + public Property GetPropertyByName (string name, bool check_ifaces) => + GetPropertyByName (name, check_ifaces, true); + + public Property GetPropertyByName (string name, bool check_ifaces, bool check_base_ifaces) + { + if (prop_hash.ContainsKey (name)) + return prop_hash [name]; + + if (check_ifaces) { + foreach (ISymbol isym in Interfaces) { + if (!((isym is GenericSymbol ? (isym as GenericSymbol).Gen : isym) is InterfaceGen igen)) + continue; + + var ret = igen.GetPropertyByName (name, true); + if (ret != null) + return ret; + } + } + + return BaseSymbol?.GetPropertyByName (name, check_base_ifaces, check_base_ifaces); + } + + public bool HasEnumMappedMembers => GetEnumMappedMemberInfo (); + + protected internal bool HasNestedType (string name) => NestedTypes.Any (g => g.Name == name); + + public IEnumerable Invalidate () + { + IsValid = false; + validated = true; + + foreach (var nt in NestedTypes) { + foreach (var sub in nt.Invalidate ()) + yield return sub; + yield return nt; + } + } + + public bool IsAcw => support.IsAcw; + + public bool IsAnnotation => + implemented_interfaces.Any (n => n == "Java.Lang.Annotation.Annotation" || n == "java.lang.annotation.Annotation"); + + public bool IsArray => false; + + // TODO: check that method.ReturnType is a superclass of m.ReturnType + public bool IsCovariantMethod (Method method) => + Methods.Any (m => m.Name == method.Name && ParameterList.Equals (m.Parameters, method.Parameters)); + + public bool IsDeprecated => support.IsDeprecated; + + public bool IsEnum => false; + + public bool IsGeneratable => support.IsGeneratable; + + public bool IsGeneric => support.IsGeneric; + + // some names are reserved for use by us, e.g. we don't want another + // Handle property, as that conflicts with Java.Lang.Object.Handle. + bool IsInfrastructural (string name) => ObjectRequiresNew.Contains (name); + + public bool IsObfuscated => support.IsObfuscated; + + bool IsThrowable () => + FullName == "Java.Lang.Throwable" || Ancestors ().Any (a => a.FullName == "Java.Lang.Throwable"); + + // This is not a perfect match with Java language specification http://docs.oracle.com/javase/specs/jls/se5.0/html/interfaces.html#9.7 + // as it does not cover java.lang.Enum. Though C# attributes cannot handle JLE. + // Class literal (FooBar.class) cannot be supported either. + // We might be able to support System.Type for JLC and custom generated .NET Enums for JLE in the future. + static bool IsTypeCommensurate (CodeGenerationOptions opt, ISymbol sym) + { + if (sym == null) + return false; + if (sym is StringSymbol) + return true; + if (sym is SimpleSymbol) { + switch (sym.JavaName) { + case "boolean": + case "char": + case "byte": + case "short": + case "int": + case "long": + case "float": + case "double": + return true; + } + } + if (sym is ArraySymbol arr) + return IsTypeCommensurate (opt, opt.SymbolTable.Lookup (arr.ElementType)); + if (sym is GenericSymbol) + return sym.JavaName == "java.lang.Class"; + + // outside Mono.Android.dll they are ManagedClassGen. + if (sym is ClassGen) + return sym.JavaName == "java.lang.Class" || sym.JavaName == "java.lang.String"; + + return false; + } + + public IEnumerable ImplementedInterfaces => implemented_interfaces; + + public bool IsValid { get; set; } = true; + + public string JavaName => string.IsNullOrWhiteSpace (PackageName) + ? JavaSimpleName + : $"{PackageName}.{JavaSimpleName}"; + + public string JavaSimpleName => support.JavaSimpleName; + + public string JniName => $"L{RawJniName};"; + + public string MetadataXPathReference { + get { + string type = null; + + if (this is ClassGen) + type = "class"; + if (this is InterfaceGen) + type = "interface"; + if (type == null) + throw new InvalidOperationException ("Uh...xpath? this is " + GetType ().FullName); + + return $"/api/package[@name='{PackageName}']/{type}[@name='{JavaSimpleName}']"; + } + } + + public bool MethodValidationFailed { get; set; } + + public string Name { + get => support.Name; + set => support.Name = value; + } + + public string Namespace => support.Namespace; + + public string NativeType { get; set; } + + public bool NeedsPrep => true; + + static readonly HashSet ObjectRequiresNew = new HashSet ( + typeof (object) + .GetMethods () + .Where (m => !m.Attributes.HasFlag (MethodAttributes.SpecialName) && + !m.Attributes.HasFlag (MethodAttributes.RTSpecialName)) + .Select (m => m.Name) + .Concat (new [] { "Handle" }), + StringComparer.OrdinalIgnoreCase); + + protected virtual bool OnValidate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + if (Name.Length > TypeNamePrefix.Length && + (Name [TypeNamePrefix.Length] == '.' || char.IsDigit (Name [TypeNamePrefix.Length]))) // see bug #5111 + return false; + + if (!support.OnValidate (opt)) + return false; + + List valid_nests = new List (); + foreach (GenBase gen in NestedTypes) { + if (gen.Validate (opt, TypeParameters, context)) + valid_nests.Add (gen); + } + NestedTypes = valid_nests; + + AdjustNestedTypeFullName (this); + + foreach (string iface_name in implemented_interfaces) { + ISymbol isym = opt.SymbolTable.Lookup (iface_name); + if (isym != null && isym.Validate (opt, TypeParameters, context)) + Interfaces.Add (isym); + else { + if (isym == null) + Report.LogCodedWarning (0, Report.WarningBaseInterfaceNotFound, this, FullName, iface_name); + else + Report.LogCodedWarning (0, Report.WarningBaseInterfaceInvalid, this, FullName, iface_name); + iface_validation_failed = true; + } + } + + List valid_fields = new List (); + foreach (Field f in Fields) { + if (!f.Validate (opt, TypeParameters, context)) + continue; + valid_fields.Add (f); + } + Fields = valid_fields; + + // If we can't validate a static or default interface method it's ok to ignore it and still bind the interface + var method_cnt = Methods.Where (m => !m.IsInterfaceDefaultMethod && !m.IsStatic).Count (); + + Methods = Methods.Where (m => ValidateMethod (opt, m, context)).ToList (); + MethodValidationFailed = method_cnt != Methods.Where (m => !m.IsInterfaceDefaultMethod && !m.IsStatic).Count (); + + foreach (Method m in Methods) { + if (m.IsVirtual) + HasVirtualMethods = true; + if (m.Name == "HashCode" && m.Parameters.Count == 0) { + m.IsOverride = true; + m.Name = "GetHashCode"; + } + jni_sig_hash [m.JavaName + m.JniSignature] = m; + if ((m.Name == "ToString" && m.Parameters.Count == 0) || (BaseSymbol != null && BaseSymbol.ContainsMethod (m, true))) + m.IsOverride = true; + } + return true; + } + + public string PackageName { + get => support.PackageName; + set => support.PackageName = value; + } + + public string [] PreCall (CodeGenerationOptions opt, string var_name) => new string [] { }; + + public string [] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + var rgm = this as IRequireGenericMarshal; + + string format = opt.CodeGenerationTarget switch { + CodeGenerationTarget.JavaInterop1 => + "{0} {1} = {5}global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<{4}> (ref {2}, {3});", + _ => + "{0} {1} = {5}global::Java.Lang.Object.GetObject<{4}> ({2}, {3});", + }; + string transfer = opt.CodeGenerationTarget switch { + CodeGenerationTarget.JavaInterop1 => "JniObjectReferenceOptions.CopyAndDispose", + _ => "JniHandleOwnership.TransferLocalRef", + }; + string doNotTransfer = opt.CodeGenerationTarget switch { + CodeGenerationTarget.JavaInterop1 => "JniObjectReferenceOptions.Copy", + _ => "JniHandleOwnership.DoNotTransfer", + }; + + return new string []{ + string.Format (format, + "var", + opt.GetSafeIdentifier (var_name), + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), + owned ? transfer : doNotTransfer, + opt.GetOutputName (rgm != null ? (rgm.GetGenericJavaObjectTypeOverride () ?? FullName) : FullName), + rgm != null ? "(" + opt.GetOutputName (FullName) + opt.NullableOperator + ")" : string.Empty) + }; + } + + public string [] PostCall (CodeGenerationOptions opt, string var_name) => new string [] { }; + + public string [] PostCallback (CodeGenerationOptions opt, string var_name) => new string [] { }; + + public string RawJniName => (string.IsNullOrWhiteSpace (PackageName) ? string.Empty : PackageName.Replace ('.', '/') + "/") + JavaSimpleName.Replace ('.', '$'); + + public string RawVisibility => support.Visibility; + + public bool RequiresNew (Property property) + { + switch (property.AdjustedName.ToLowerInvariant ()) { + case "handle": + case "gethashcode": + case "gettype": + case "tostring": + case "equals": + case "referenceequals": + return true; + } + + return IsThrowable () && ThrowableRequiresNew.Contains (property.AdjustedName); + } + + public bool RequiresNew (string memberName, Method method) + { + switch (memberName.ToLowerInvariant ()) { + case "handle": + // The same name as a property always requires new, no matter the parameters + return true; + case "gethashcode": + case "gettype": + case "tostring": + return method.Parameters.Count == 0; + case "equals": + if (method.Parameters.Count == 1 && method.Parameters.All (p => p.Type == "object")) + return true; + if (method.Parameters.Count == 2 && method.Parameters.All (p => p.Type == "object")) + return true; + + break; + case "referenceequals": + if (method.Parameters.Count == 2 && method.Parameters.All (p => p.Type == "object")) + return true; + + break; + } + + return IsThrowable () && ThrowableRequiresNew.Contains (memberName); + } + + public virtual void ResetValidation () + { + Interfaces.Clear (); + iface_validation_failed = false; + + foreach (var nt in NestedTypes) + nt.ResetValidation (); + } + + bool ReturnTypeMatches (Method m, Method mm) + { + if (mm.RetVal.FullName == m.RetVal.FullName) + return true; + if (BaseSymbol.IsGeneric && mm.RetVal.IsGeneric) + return true; // sloppy but pass + return false; + } + + public bool ShouldGenerateAnnotationAttribute => IsAnnotation; + + public HashSet SkippedInvokerMethods => support.SkippedInvokerMethods; + + public void StripNonBindables (CodeGenerationOptions opt) + { + // Strip out default interface methods if not desired + if (!opt.SupportDefaultInterfaceMethods) + Methods = Methods.Where (m => !m.IsInterfaceDefaultMethod).ToList (); + + NestedTypes = NestedTypes.Where (n => !n.IsObfuscated && n.Visibility != "private").ToList (); + + foreach (var n in NestedTypes) + n.StripNonBindables (opt); + } + + static readonly HashSet ThrowableRequiresNew = new HashSet ( + typeof (System.Exception) + .GetMethods () + .Where (m => !m.Attributes.HasFlag (MethodAttributes.SpecialName) && + !m.Attributes.HasFlag (MethodAttributes.RTSpecialName)) + .Select (m => m.Name) + .Concat (typeof (System.Exception).GetProperties ().Select (p => p.Name)) + .Concat (new [] { "Handle" }), + StringComparer.OrdinalIgnoreCase); + + public abstract string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings = null); + + public string TypeNamePrefix => support.TypeNamePrefix; + + public GenericParameterDefinitionList TypeParameters => support.TypeParameters; + + // Prior to DIM, interfaces could not contain nested types so we generated them + // as sibling types. When DIM is enabled we can now generate them properly nested. + // However this is an API break for existing bindings. Setting this property + // to true opts this interface into the sibling compatibility behavior. + public bool Unnest { get; set; } + + public virtual void UpdateEnums (CodeGenerationOptions opt, AncestorDescendantCache cache) + { + if (enum_updated || !IsGeneratable) + return; + + enum_updated = true; + + var baseGen = GetBaseGen (opt); + + if (baseGen != null) + baseGen.UpdateEnums (opt, cache); + + foreach (var m in Methods) { + m.AutoDetectEnumifiedOverrideParameters (cache); + m.AutoDetectEnumifiedOverrideReturn (cache); + } + + foreach (var p in Properties) + p.AutoDetectEnumifiedOverrideProperties (cache); + + UpdateEnumsInInterfaceImplementation (); + + foreach (var ngen in NestedTypes) + ngen.UpdateEnums (opt, cache); + } + + public virtual void UpdateEnumsInInterfaceImplementation () + { + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + context.ContextTypes.Push (this); + + try { + return IsValid = OnValidate (opt, type_params, context); + } finally { + context.ContextTypes.Pop (); + } + } + + bool ValidateMethod (CodeGenerationOptions opt, Method m, CodeGeneratorContext context) => + m.Validate (opt, TypeParameters, context); + + public string Visibility { + get => string.IsNullOrEmpty (support.Visibility) ? "public" : support.Visibility; + set => support.Visibility = value; + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs new file mode 100644 index 00000000000..027e5cf62ac --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + +using Java.Interop.Tools.Generator; + +namespace MonoDroid.Generation +{ + public class GenBaseSupport + { + HashSet skipped_invoker_methods; + + public string AnnotatedVisibility { get; set; } + public bool IsAcw { get; set; } + public bool IsDeprecated { get; set; } + public string DeprecatedComment { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } + public bool IsGeneratable { get; set; } + public bool IsGeneric { get; set; } + public bool IsObfuscated { get; set; } + public string FullName { get; set; } + public string Name { get; set; } + public string Namespace { get; set; } + public string JavaSimpleName { get; set; } + public string PackageName { get; set; } + public string TypeNamePrefix { get; set; } = string.Empty; + public string Visibility { get; set; } + public GenericParameterDefinitionList TypeParameters { get; set; } + + public HashSet SkippedInvokerMethods => skipped_invoker_methods ??= new HashSet (); + + public virtual bool OnValidate (CodeGenerationOptions opt) + { + // See com.google.inject.internal.util package for this case. + // Some Java compiler-generated internals are named as $foobar (dollar prefixed). + // Since our jar2xml replaces all '$' with '.', it results in ".." namespace. + return !FullName.Contains (".."); + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs new file mode 100644 index 00000000000..353afedcc55 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterDefinition.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using Java.Interop.Tools.Generator; +using Mono.Cecil; + +using Xamarin.Android.Tools; + +namespace MonoDroid.Generation +{ + // Represents a generic parameter definition in GenBase. + public class GenericParameterDefinition + { + public GenericParameterDefinition (string name, string [] constraints) + { + Name = name; + ConstraintExpressions = constraints; + } + + public string Name { get; set; } + public string [] ConstraintExpressions { get; private set; } + + // post-validation information. + public ISymbol [] Constraints { get; private set; } + + bool validated, is_valid; + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + if (ConstraintExpressions == null || ConstraintExpressions.Length == 0) + return true; + if (validated) + return is_valid; + var syms = new List (); + foreach (var c in ConstraintExpressions) { + var sym = opt.SymbolTable.Lookup (c, type_params); + if (sym == null) { + Report.LogCodedWarning (0, Report.WarningUnknownGenericConstraint, c, context.GetContextTypeMember ()); + validated = true; + return false; + } + syms.Add (sym); + } + Constraints = syms.ToArray (); + validated = is_valid = true; + return true; + } + + public GenericParameterDefinition Clone () + { + return new GenericParameterDefinition (Name, ConstraintExpressions); + } + } + + public class GenericParameterDefinitionList : List + { + public static GenericParameterDefinitionList Merge (GenericParameterDefinitionList l1, GenericParameterDefinitionList l2) + { + if (l1 == null) + return l2; + if (l2 == null) + return l1; + var ret = new GenericParameterDefinitionList (); + ret.AddRange (l1); + ret.AddRange (l2); + return ret; + } + + public static GenericParameterDefinitionList FromMetadata (IEnumerable types) + { + GenericParameterDefinitionList ret = null; + foreach (var p in types) { + ret = ret ?? new GenericParameterDefinitionList (); + ret.Add (new GenericParameterDefinition ( + p.FullNameCorrected (), + (from a in p.Constraints + select a.ConstraintType.FullNameCorrected ()).ToArray ())); + } + return ret; + } + + public static GenericParameterDefinitionList FromXml (XElement tps) + { + var ret = new GenericParameterDefinitionList (); + var tpl = tps.Elements ("typeParameter"); + foreach (var n in tpl) { + var csts = new List (); + foreach (var x in n.XPathSelectElements ("genericConstraints/genericConstraint")) + csts.Add (x.XGetAttribute ("type")); + ret.Add (new GenericParameterDefinition (n.XGetAttribute ("name"), csts.ToArray ())); + } + return ret; + } + + public string ToGeneratedAttributeString () + { + var typeArgList = this.Select (t => t.Name + (t.ConstraintExpressions.Any () ? " extends " + string.Join (" & ", t.ConstraintExpressions) : null)); + return "[global::Java.Interop.JavaTypeParameters (new string [] {\"" + + string.Join ("\", \"", typeArgList) + "\"})]"; + } + + public int IndexOf (string name) + { + int i = 0; + foreach (var e in this) { + if (e.Name == name) + return i; + else + i++; + } + return -1; + } + + public string GetSignature () + { + return Count == 0 ? null : '<' + String.Join (",", (from p in this select p.Name).ToArray ()) + '>'; + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + foreach (var pd in this) + if (!pd.Validate (opt, type_params, context)) + return false; + return true; + } + } +} + + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterList.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterList.cs new file mode 100644 index 00000000000..8d472ba810a --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenericParameterList.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MonoDroid.Generation { + + public class GenericParameterList { + + public static string[] Parse (string type_params) + { + type_params = type_params.Replace ("? extends ", String.Empty); + type_params = type_params.Replace ("? super ", String.Empty); + int depth = 0; + StringBuilder sb = new StringBuilder (); + List parms = new List (); + for (int i = 1; i < type_params.Length - 1; i++) { + char c = type_params [i]; + if (c == ',' && depth == 0) { + parms.Add (sb.ToString ().TrimStart ()); + sb.Remove (0, sb.Length); + continue; + } + switch (c) { + case '<': + depth++; + break; + case '>': + depth--; + break; + default: + break; + } + sb.Append (c); + } + if (sb.Length > 0) + parms.Add (sb.ToString ().TrimStart ()); + + return parms.ToArray (); + } + + bool is_concrete; + bool is_valid; + bool validated; + string managed; + string [] java_params; + ISymbol [] type_params; + + public GenericParameterList (string type_params) + { + java_params = Parse (type_params); + } + + public bool IsConcrete { + get { return is_concrete; } + } + + public ISymbol [] TypeParams { + get { return type_params; } + } + + public override string ToString () + { + return managed; + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList in_params, CodeGeneratorContext context) + { + if (validated) + return is_valid; + + validated = true; + is_concrete = true; + type_params = new ISymbol [java_params.Length]; + for (int i = 0; i < java_params.Length; i++) { + string tp = java_params [i].TrimStart (); + var gpd = in_params != null ? in_params.FirstOrDefault (t => t.Name == tp) : null; + if (in_params != null && gpd != null) { + type_params [i] = new GenericTypeParameter (gpd); + is_concrete = false; + continue; + } else if (tp == "?") { + if (in_params != null && in_params.Count == 1) { + type_params [i] = new GenericTypeParameter (in_params [0]); + is_concrete = false; + } else + type_params [i] = new SimpleSymbol ("null", "java.lang.Object", "object", "Ljava/lang/Object;"); + continue; + } + + ISymbol psym = opt.SymbolTable.Lookup (tp, in_params); + if (psym == null || !psym.Validate (opt, in_params, context)) + return false; + + + if (psym is GenericSymbol && !(psym as GenericSymbol).IsConcrete) + is_concrete = false; + type_params [i] = /*psym is IGeneric ? (psym as IGeneric).GetGenericType (null) :*/ psym; + } + managed = "<" + String.Join (", ", (from tp in type_params select tp.FullName).ToArray ()) + ">"; + is_valid = true; + return true; + } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/IGeneratable.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/IGeneratable.cs new file mode 100644 index 00000000000..da84394f83b --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/IGeneratable.cs @@ -0,0 +1,9 @@ +using System; + +namespace MonoDroid.Generation { + + public interface IGeneratable : ISymbol { + bool IsGeneratable { get; } + void Generate (CodeGenerationOptions opt, GenerationInfo gen_info); + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/IRequireGenericMarshal.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/IRequireGenericMarshal.cs new file mode 100644 index 00000000000..453dc0f311f --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/IRequireGenericMarshal.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace MonoDroid.Generation +{ + public interface IRequireGenericMarshal + { + bool MayHaveManagedGenericArguments { get; } + string GetGenericJavaObjectTypeOverride (); + string ToInteroperableJavaObject (string varname); + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceExtensionInfo.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceExtensionInfo.cs new file mode 100644 index 00000000000..5103d984dc0 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceExtensionInfo.cs @@ -0,0 +1,9 @@ +namespace MonoDroid.Generation +{ + class InterfaceExtensionInfo + { + public string DeclaringType; + public InterfaceGen Type; + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs new file mode 100644 index 00000000000..7f36d0cff01 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs @@ -0,0 +1,274 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Java.Interop.Tools.Generator; +using Xamarin.Android.Binder; + +namespace MonoDroid.Generation +{ + public class InterfaceGen : GenBase, IRequireGenericMarshal + { + public InterfaceGen (GenBaseSupport support) : base (support) + { + DefaultValue = "IntPtr.Zero"; + NativeType = "IntPtr"; + } + + public override void AddNestedType (GenBase gen) + { + base.AddNestedType (gen); + + var nest_name = gen.JavaName.Substring (JavaName.Length + 1); + + if (nest_name.IndexOf ('.') < 0) { + // We don't need to mangle the name if we support nested interface types + // ex: my.namespace.IParent.IChild + if (!gen.Unnest) { + gen.FullName = FullName + "." + gen.Name; + return; + } + + if (gen is InterfaceGen) { + // ex: my.namespace.IParentChild + gen.FullName = FullName + gen.Name.Substring (1); + gen.Name = Name + gen.Name.Substring (1); + } else { + gen.FullName = FullName.Substring (0, FullName.Length - Name.Length) + Name.Substring (1) + gen.Name; + gen.Name = Name.Substring (1) + gen.Name; + } + } + } + + public string ArgsType { get; set; } + + public override string FromNative (CodeGenerationOptions opt, string varname, bool owned) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return "global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<" + + opt.GetOutputName (FullName) + + $"> (ref {varname}, JniObjectReferenceOptions.{(owned ? "CopyAndDispose" : "Copy")})"; + } + return string.Format ("global::Java.Lang.Object.GetObject<{0}> ({1}, {2})", opt.GetOutputName (FullName), varname, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + /* + if (String.IsNullOrEmpty (Marshaler)) + return String.Format ("global::Java.Lang.Object.GetObject<{0}> ({1}, {2})", opt.GetOutputName (FullName), varname, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + else + return String.Format ("new {1} ({0})", varname, Marshaler); + */ + } + + public override void FixupAccessModifiers (CodeGenerationOptions opt) + { + if (!IsAnnotation) { + foreach (var implementedInterface in ImplementedInterfaces) { + if (string.IsNullOrEmpty (implementedInterface)) { + System.Diagnostics.Debug.Assert (false, "BUGBUG - We should never have an empty or null string added on the implemented interface list."); + continue; + } + + var baseType = opt.SymbolTable.Lookup (implementedInterface); + if (baseType is InterfaceGen interfaceGen && interfaceGen.RawVisibility != "public") { + // Copy over "private" methods + foreach (var method in interfaceGen.Methods.ToList ()) + if (!Methods.Any (m => m.Matches (method))) + Methods.Add (method.Clone (this)); + } else { + break; + } + } + } + + + base.FixupAccessModifiers (opt); + } + + public override void Generate (CodeGenerationOptions opt, GenerationInfo gen_info) + { + using (var sw = gen_info.OpenStream (opt.GetFileName (FullName))) { + sw.WriteLine ("using System;"); + sw.WriteLine ("using System.Collections.Generic;"); + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + sw.WriteLine ("using Android.Runtime;"); + } + sw.WriteLine ("using Java.Interop;"); + sw.WriteLine (); + var hasNamespace = !string.IsNullOrWhiteSpace (Namespace); + if (hasNamespace) { + sw.WriteLine ("namespace {0} {{", Namespace); + sw.WriteLine (); + } + + var generator = opt.CreateCodeGenerator (sw); + generator.WriteType (this, hasNamespace ? "\t" : string.Empty, gen_info); + + if (hasNamespace) { + sw.WriteLine ("}"); + } + } + + GenerateAnnotationAttribute (opt, gen_info); + } + + internal string GetArgsName (Method m) + { + + string nameBase; + int start; + int trim = 0; + + if (Methods.Count > 1) { + if (!string.IsNullOrEmpty (m.ArgsType)) + return m.ArgsType; + if (m.IsSimpleEventHandler) + return "EventArgs"; + nameBase = m.AdjustedName; + start = nameBase.StartsWith ("On", StringComparison.Ordinal) ? 2 : 0; + } else { + if (!string.IsNullOrEmpty (ArgsType)) + return ArgsType; + if (m.IsSimpleEventHandler) + return "EventArgs"; + nameBase = Name; + start = Name.StartsWith ("IOn", StringComparison.Ordinal) ? 3 : 1; + trim = 8; // "Listener" + } + return nameBase.Substring (start, nameBase.Length - start - trim) + "EventArgs"; + } + + internal string GetEventDelegateName (Method m) + { + int start = Name.StartsWith ("IOn", StringComparison.Ordinal) ? 3 : 1; + if (m.RetVal.IsVoid) { + if (m.IsSimpleEventHandler) + return "EventHandler"; + else { + return "EventHandler<" + GetArgsName (m) + ">"; + } + } else if (m.IsEventHandlerWithHandledProperty) { + return "EventHandler<" + GetArgsName (m) + ">"; + } else { + string methodSpec = Methods.Count > 1 ? m.AdjustedName : string.Empty; + return Name.Substring (start, Name.Length - start - 8) + methodSpec + "Handler"; + } + } + + // These are fields that we currently support generating on the interface with DIM + public IEnumerable GetGeneratableFields (CodeGenerationOptions options) + { + var fields = new List (); + + // Constant fields + if (options.SupportInterfaceConstants) + fields.AddRange (Fields.Where (f => !f.NeedsProperty && !(f.DeprecatedComment?.Contains ("constant will be removed") == true))); + + // Invoked fields exposed as properties + if (options.SupportDefaultInterfaceMethods) + fields.AddRange (Fields.Where (f => f.NeedsProperty && !(f.DeprecatedComment?.Contains ("constant will be removed") == true))); + + return fields; + } + + public bool HasDefaultMethods => GetAllMethods ().Any (m => m.IsInterfaceDefaultMethod); + + public bool HasFieldsAsProperties => Fields.Any (f => f.NeedsProperty); + + public bool HasStaticMethods => GetAllMethods ().Any (m => m.IsStatic); + + public bool IsConstSugar (CodeGenerationOptions options) + { + if (!options.RemoveConstSugar) + return false; + + if (Methods.Count > 0 || Properties.Count > 0) + return false; + + foreach (InterfaceGen impl in GetAllDerivedInterfaces ()) + if (!impl.IsConstSugar (options)) + return false; + + // Need to keep Java.IO.ISerializable as a "marker interface"; want to + // hide android.provider.ContactsContract.DataColumnsWithJoins + if (Fields.Count == 0 && Interfaces.Count == 0) + return false; + + return true; + } + + // If there is a property it cannot generate valid implementor, so reject this at least so far. + public bool IsListener => Name.EndsWith ("Listener", StringComparison.Ordinal) && Properties.Count == 0 && Interfaces.Count == 0; + + public bool HasManagedName { get; set; } + + public bool MayHaveManagedGenericArguments { get; set; } + + internal bool NeedsSender => + Methods.Any (m => (m.RetVal.IsVoid && !m.Parameters.HasSender) || (m.IsEventHandlerWithHandledProperty && !m.Parameters.HasSender)); + + // If true, we will no longer generate the "interface alternative" legacy classes + // used to hold interface constants/static methods before we had C#8 + public bool NoAlternatives { get; set; } + + protected override bool OnValidate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + if (validated) + return IsValid; + + validated = true; + + // Due to demand to validate in prior to validate ClassGen's BaseType, it is *not* done at + // GenBase. + if (TypeParameters != null && !TypeParameters.Validate (opt, type_params, context)) + return false; + + if (!base.OnValidate (opt, type_params, context) || iface_validation_failed || MethodValidationFailed) { + if (iface_validation_failed) + Report.LogCodedWarning (0, Report.WarningInvalidDueToInterfaces, this, FullName); + else if (MethodValidationFailed) + Report.LogCodedWarning (0, Report.WarningInvalidDueToMethods, this, FullName); + foreach (GenBase nest in NestedTypes) + nest.Invalidate (); + IsValid = false; + return false; + } + + return true; + } + + public override void ResetValidation () + { + validated = false; + base.ResetValidation (); + } + + public override string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings = null) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"({varname}?.PeerReference ?? default)"; + } + return string.Format ("JNIEnv.ToLocalJniHandle ({0})", varname); + /* + if (String.IsNullOrEmpty (Marshaler)) + return String.Format ("JNIEnv.ToLocalJniHandle ({0})", varname); + else + return GetObjectHandleProperty (varname); + */ + } + + #region IRequireGenericMarshal implementation. + // SymbolTable.Lookup() for IList/IDictioanry/etc. results in this InterfaceGen, + // so we also have to override this property here. + public string GetGenericJavaObjectTypeOverride () + { + int idx = FullName.IndexOf ('<'); + return TypeNameUtilities.GetGenericJavaObjectTypeOverride ( + idx < 0 ? FullName : FullName.Substring (0, idx), + idx < 0 ? null : FullName.Substring (idx + 1).TrimEnd ('>')); + } + + public string ToInteroperableJavaObject (string var_name) + { + return GetGenericJavaObjectTypeOverride () != null ? TypeNameUtilities.GetNativeName (var_name) : var_name; + } + #endregion + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/JavadocInfo.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/JavadocInfo.cs new file mode 100644 index 00000000000..c142a930cfe --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/JavadocInfo.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +using Irony.Parsing; + +using Java.Interop.Tools.JavaSource; + +namespace MonoDroid.Generation +{ + enum ApiLinkStyle { + None, + DeveloperAndroidComReference_2020Nov, + } + + public sealed class JavadocInfo { + + public string Javadoc { get; set; } + + public XElement[] ExtraRemarks { get; set; } + + public XElement[] Copyright { get; set; } + + public XmldocStyle XmldocStyle { get; set; } + public string DocRootReplacement { get; set; } + + string MemberDescription; + + public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool appendCopyrightExtra = true) + { + if (element == null) { + return null; + } + + string javadoc = element.Element ("javadoc")?.Value; + + var desc = GetMemberDescription (element); + string declaringJniType = desc.DeclaringJniType; + string declaringMemberName = desc.DeclaringMemberName; + var declaringMemberParamString = desc.DeclaringMemberParameterString; + + var extras = GetExtra (element, style, declaringJniType, declaringMemberName, declaringMemberParamString, appendCopyrightExtra); + XElement[] extra = extras.Extras; + XElement[] copyright = extras.Copyright; + string docRoot = extras.DocRoot; + + if (string.IsNullOrEmpty (javadoc) && extra == null) + return null; + + var info = new JavadocInfo () { + ExtraRemarks = extra, + Copyright = copyright, + DocRootReplacement = docRoot, + Javadoc = javadoc, + MemberDescription = declaringMemberName == null + ? declaringJniType + : $"{declaringJniType}.{declaringMemberName}{declaringMemberParamString}", + XmldocStyle = style, + }; + return info; + } + + static (string DeclaringJniType, string DeclaringMemberName, string DeclaringMemberParameterString) GetMemberDescription (XElement element) + { + bool isType = element.Name.LocalName == "class" || + element.Name.LocalName == "interface"; + + string declaringJniType = isType + ? (string) element.Attribute ("jni-signature") + : (string) element.Parent.Attribute ("jni-signature"); + if (declaringJniType.StartsWith ("L", StringComparison.Ordinal) && + declaringJniType.EndsWith (";", StringComparison.Ordinal)) { + declaringJniType = declaringJniType.Substring (1, declaringJniType.Length-2); + } + + string declaringMemberName = isType + ? null + : (string) element.Attribute ("name") ?? declaringJniType.Substring (declaringJniType.LastIndexOf ('/')+1); + + string declaringMemberJniSignature = isType + ? null + : (string) element.Attribute ("jni-signature"); + + + string declaringMemberParameterString = null; + if (!isType && (declaringMemberJniSignature?.StartsWith ("(", StringComparison.Ordinal) ?? false)) { + var parameterTypes = element.Elements ("parameter")?.Select (e => e.Attribute ("type")?.Value)?.ToList (); + if (parameterTypes?.Any () ?? false) { + declaringMemberParameterString = $"({string.Join (", ", parameterTypes)})"; + } else { + declaringMemberParameterString = "()"; + } + } + + return (declaringJniType, declaringMemberName, declaringMemberParameterString); + } + + static (XElement[] Extras, XElement[] Copyright, string DocRoot) GetExtra (XElement element, XmldocStyle style, string declaringJniType, string declaringMemberName, string declaringMemberParameterString, bool appendCopyrightExtra) + { + if (!style.HasFlag (XmldocStyle.IntelliSenseAndExtraRemarks)) + return (null, null, null); + + XElement javadocMetadata = null; + while (element != null) { + javadocMetadata = element.Element ("javadoc-metadata"); + if (javadocMetadata != null) { + break; + } + element = element.Parent; + } + + List extra = null; + IEnumerable copyright = null; + string docRoot = null; + if (javadocMetadata != null) { + var link = javadocMetadata.Element ("link"); + var urlPrefix = (string) link.Attribute ("prefix"); + var linkStyle = (string) link.Attribute ("style"); + docRoot = (string) link.Attribute ("docroot"); + var kind = ParseApiLinkStyle (linkStyle); + + XElement docLink = null; + if (!string.IsNullOrEmpty (urlPrefix)) { + docLink = CreateDocLinkUrl (kind, urlPrefix, declaringJniType, declaringMemberName, declaringMemberParameterString); + } + extra = new List (); + extra.Add (docLink); + copyright = javadocMetadata.Element ("copyright").Elements (); + if (appendCopyrightExtra) { + extra.AddRange (copyright); + } + } + return (extra?.ToArray (), copyright?.ToArray (), docRoot); + } + + static ApiLinkStyle ParseApiLinkStyle (string style) + { + switch (style) { + case "developer.android.com/reference@2020-Nov": + return ApiLinkStyle.DeveloperAndroidComReference_2020Nov; + default: + return ApiLinkStyle.None; + } + } + + + public void AddJavadocs (ICollection comments) + { + var nodes = ParseJavadoc (); + AddComments (comments, nodes); + } + + public IEnumerable ParseJavadoc () + { + if (string.IsNullOrWhiteSpace (Javadoc)) + return Enumerable.Empty (); + + Javadoc = Javadoc.Trim (); + + ParseTree tree = null; + IEnumerable nodes = null; + + try { + var parser = new SourceJavadocToXmldocParser (new XmldocSettings { + Style = XmldocStyle, + ExtraRemarks = ExtraRemarks, + DocRootValue = DocRootReplacement, + }); + nodes = parser.TryParse (Javadoc, fileName: null, out tree); + } + catch (Exception e) { + Console.Error.WriteLine ($"## Exception translating remarks for {MemberDescription}:\n{e.ToString ()}"); + } + + if (tree != null && tree.HasErrors ()) { + Console.Error.WriteLine ($"## Unable to translate remarks for {MemberDescription}:"); + Console.Error.WriteLine ("```"); + Console.Error.WriteLine (Javadoc); + Console.Error.WriteLine ("```"); + PrintMessages (tree, Console.Error); + Console.Error.WriteLine (); + } + + return nodes; + } + + public static void AddComments (ICollection comments, IEnumerable nodes) + { + if (nodes == null) + return; + + foreach (var node in nodes) { + AddNode (comments, node); + } + } + + static void AddNode (ICollection comments, XNode node) + { + if (node == null) + return; + var contents = node.ToString (); + + var lines = new StringReader (contents); + string line; + while ((line = lines.ReadLine ()) != null) { + comments.Add ($"/// {line}"); + } + } + + static void PrintMessages (ParseTree tree, TextWriter writer) + { + var lines = GetLines (tree.SourceText); + foreach (var m in tree.ParserMessages) { + writer.WriteLine ($"JavadocImport-{m.Level} {m.Location}: {m.Message}"); + writer.WriteLine (lines [m.Location.Line]); + writer.Write (new string (' ', m.Location.Column)); + writer.WriteLine ("^"); + } + } + + static List GetLines (string text) + { + var lines = new List(); + var reader = new StringReader (text); + string line; + while ((line = reader.ReadLine()) != null) { + lines.Add (line); + } + return lines; + } + + static Dictionary> UrlCreators = new Dictionary> { + [ApiLinkStyle.DeveloperAndroidComReference_2020Nov] = CreateAndroidDocLinkUri, + }; + + static XElement CreateDocLinkUrl (ApiLinkStyle style, string prefix, string declaringJniType, string declaringMemberName, string declaringMemberParameterString) + { + if (style == ApiLinkStyle.None || prefix == null || declaringJniType == null) + return null; + if (UrlCreators.TryGetValue (style, out var creator)) { + return creator (prefix, declaringJniType, declaringMemberName, declaringMemberParameterString); + } + return null; + } + + static XElement CreateAndroidDocLinkUri (string prefix, string declaringJniType, string declaringMemberName, string declaringMemberParameterString) + { + // URL is: + // * {prefix} + // * declaring type in JNI format + // * when `declaringJniMemberName` != null, `#{declaringJniMemberName}` + // * for methods & constructors, a `(`, the arguments in *Java* syntax -- separated by `, ` -- and `)` + // + // Example: "https://developer.android.com/reference/android/app/Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener)" + // Example: "https://developer.android.com/reference/android/animation/ObjectAnimator#ofFloat(T,%20android.util.Property%3CT,%20java.lang.Float%3E,%20float...)" + + declaringJniType = declaringJniType.Replace ("$", "."); + var java = new StringBuilder (declaringJniType) + .Replace ("/", "."); + + var url = new StringBuilder (prefix); + if (!prefix.EndsWith ("/", StringComparison.Ordinal)) { + url.Append ("/"); + } + url.Append (declaringJniType); + + if (declaringMemberName != null) { + java.Append (".").Append (declaringMemberName); + url.Append ("#").Append (declaringMemberName); + if (declaringMemberParameterString != null) { + java.Append (declaringMemberParameterString); + url.Append (declaringMemberParameterString); + } + } + var format = new XElement ("format", + new XAttribute ("type", "text/html"), + new XElement ("a", + new XAttribute ("href", new Uri (url.ToString ()).AbsoluteUri), + new XAttribute ("title", "Reference documentation"), + "Java documentation for ", + new XElement ("code", java.ToString ()), + ".")); + return new XElement ("para", format); + } + + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs new file mode 100644 index 00000000000..c22bec439d7 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs @@ -0,0 +1,269 @@ +using System; +using System.Linq; +using Java.Interop.Tools.JavaCallableWrappers; +using MonoDroid.Generation.Utilities; + +namespace MonoDroid.Generation +{ + public class Method : MethodBase + { + bool is_override; + + public Method (GenBase declaringType) : base (declaringType) + { + } + + public string ArgsType { get; set; } + public string CustomAttributes { get; set; } + public string EventName { get; set; } + public bool GenerateAsyncWrapper { get; set; } + public bool GenerateDispatchingSetter { get; set; } + public bool IsAbstract { get; set; } + public bool IsCompatVirtualMethod { get; set; } + public bool IsFinal { get; set; } + public bool IsInterfaceDefaultMethod { get; set; } + public Method OverriddenInterfaceMethod { get; set; } + public bool IsReturnEnumified { get; set; } + public bool IsStatic { get; set; } + public bool IsVirtual { get; set; } + public string JavaName { get; set; } + public string ManagedOverride { get; set; } + public string ManagedReturn { get; set; } + public string KotlinInlineClassReturnJniType { get; set; } + public string PropertyNameOverride { get; set; } + public string Return { get; set; } + public bool ReturnNotNull { get; set; } + public ReturnValue RetVal { get; set; } + public int SourceApiLevel { get; set; } + public string ExplicitInterface { get; set; } + + // it used to be private though... + internal string AdjustedName => IsReturnCharSequence ? Name + "Formatted" : Name; + + public bool Asyncify { + get { + if (IsOverride) + return false; + + return GenerateAsyncWrapper; + } + } + + public string AutoDetectEnumifiedOverrideReturn (AncestorDescendantCache cache) + { + if (RetVal.FullName != "int") + return null; + + var classes = cache.GetAncestorsAndDescendants (DeclaringType); + classes = classes.Concat (classes.SelectMany (x => x.GetAllImplementedInterfaces ())); + + foreach (var t in classes) { + foreach (var candidate in t.GetAllMethods ().Where (m => m.Name == Name && m.Parameters.Count == Parameters.Count)) { + if (JniSignature != candidate.JniSignature) + continue; + if (candidate.IsReturnEnumified) + RetVal.SetGeneratedEnumType (candidate.RetVal.FullName); + } + } + return null; + } + + public bool CanAdd { + get { + return Name.Length > 3 && Name.StartsWith ("Add", StringComparison.Ordinal) && Name.EndsWith ("Listener", StringComparison.Ordinal) && IsVoid && + (Parameters.Count == 1 || (Parameters.Count == 2 && Parameters [1].Type == "Android.OS.Handler")) && + !(Parameters [0].IsArray); + } + } + + public bool CanGet { + get { + return Parameters.Count == 0 && + !IsVoid && !RetVal.IsArray && + ((Name.Length > 4 && Name.StartsWith ("Get", StringComparison.Ordinal) && char.IsUpper (Name [3])) || + ((Name.Length > 4 && Name.StartsWith ("Has", StringComparison.Ordinal) && char.IsUpper (Name [3]) && RetVal.JavaName == "boolean") || + (Name.Length > 3 && Name.StartsWith ("Is", StringComparison.Ordinal) && char.IsUpper (Name [2]) && RetVal.JavaName == "boolean"))); + } + } + + public bool CanSet { + get { + return Name.Length > 3 && Name.StartsWith ("Set", StringComparison.Ordinal) && Parameters.Count == 1 && IsVoid && + !(Parameters [0].IsArray); + } + } + + internal string CalculateEventName (Func checkNameDuplicate) + { + string event_name = EventName; + if (event_name == null) { + var trimSize = Name.EndsWith ("Listener", StringComparison.Ordinal) ? 8 : 0; + event_name = Name.Substring (0, Name.Length - trimSize).Substring (3); + if (event_name.StartsWith ("On", StringComparison.Ordinal)) + event_name = event_name.Substring (2); + if (checkNameDuplicate (event_name)) + event_name += "Event"; + } + return event_name; + } + + public bool CanHaveStringOverload => IsReturnCharSequence || Parameters.HasCharSequence; + + public Method Clone (GenBase declaringType) + { + var clone = new Method (declaringType); + + // MethodBase + clone.Annotation = Annotation; + clone.ApiAvailableSince = ApiAvailableSince; + clone.AssemblyName = AssemblyName; + clone.Deprecated = Deprecated; + clone.DeprecatedSince = DeprecatedSince; + clone.IsAcw = IsAcw; + clone.Name = Name; + clone.Visibility = Visibility; + clone.LineNumber = LineNumber; + clone.LinePosition = LinePosition; + clone.SourceFile = SourceFile; + clone.JavadocInfo = JavadocInfo; + + if (GenericArguments != null) { + if (clone.GenericArguments is null) + clone.GenericArguments = new GenericParameterDefinitionList (); + + foreach (var ga in GenericArguments) + clone.GenericArguments.Add (ga.Clone ()); + } + + foreach (var p in Parameters) + clone.Parameters.Add (p.Clone ()); + + // Method + clone.ArgsType = ArgsType; + clone.CustomAttributes = CustomAttributes; + clone.EventName = EventName; + clone.GenerateAsyncWrapper = GenerateAsyncWrapper; + clone.GenerateDispatchingSetter = GenerateDispatchingSetter; + clone.IsAbstract = IsAbstract; + clone.IsFinal = IsFinal; + clone.IsInterfaceDefaultMethod = IsInterfaceDefaultMethod; + clone.OverriddenInterfaceMethod = OverriddenInterfaceMethod; + clone.IsReturnEnumified = IsReturnEnumified; + clone.IsStatic = IsStatic; + clone.IsVirtual = IsVirtual; + clone.JavaName = JavaName; + clone.ManagedOverride = ManagedOverride; + clone.ManagedReturn = ManagedReturn; + clone.KotlinInlineClassReturnJniType = KotlinInlineClassReturnJniType; + clone.PropertyNameOverride = PropertyNameOverride; + clone.Return = Return; + clone.ReturnNotNull = ReturnNotNull; + clone.RetVal = RetVal.Clone (clone); + clone.SourceApiLevel = SourceApiLevel; + clone.ExplicitInterface = ExplicitInterface; + + return clone; + } + + public string ConnectorName => $"Get{Name}{IDSignature}Handler"; + + public string EscapedCallbackName => IdentifierValidator.CreateValidIdentifier ($"cb_{JavaName}_{Name}{IDSignatureWithReturnType}", true); + + public string EscapedIdName => IdentifierValidator.CreateValidIdentifier ($"id_{JavaName}{IDSignature}", true); + + internal void FillReturnType () + { + RetVal = new ReturnValue (this, Return, ManagedReturn, IsReturnEnumified, ReturnNotNull); + } + + internal string GetAdapterName (CodeGenerationOptions opt, string adapter) + { + if (string.IsNullOrEmpty (adapter)) + return adapter; + if (AssemblyName == null) + return adapter + ", " + opt.AssemblyName; + return adapter + AssemblyName; + } + + // Connectors for DIM are defined on the interface, not the implementing type + public string GetConnectorNameFull (CodeGenerationOptions opt) => ConnectorName + (opt.SupportDefaultInterfaceMethods && IsInterfaceDefaultMethod ? $":{DeclaringType.AssemblyQualifiedName}, " + (AssemblyName ?? opt.AssemblyName) : string.Empty); + + internal string GetDelegateType (CodeGenerationOptions opt) => opt.GetJniMarshalDelegate (this); + + public string GetMetadataXPathReference (GenBase declaringType) => + $"{declaringType.MetadataXPathReference}/method[@name='{JavaName}'{Parameters.GetMethodXPathPredicate ()}]"; + + public string GetSignature () => $"n_{JavaName}:{JniSignature}:{ConnectorName}"; + + public string GetSkipInvokerSignature () => $"{DeclaringType.RawJniName}.{JavaName}{JniSignature}"; + + public bool IsEventHandlerWithHandledProperty => RetVal.JavaName == "boolean" && EventName != ""; + + public override bool IsGeneric => base.IsGeneric || RetVal.IsGeneric; + + public bool IsListenerConnector => (CanAdd || CanSet) && Parameters [0].IsListener; + + public bool IsOverride { + get => !IsStatic && is_override; + set => is_override = value; + } + + public bool IsPropertyAccessor => CanGet || CanSet; + + public bool IsReturnCharSequence => RetVal.FullName.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal); + + public bool IsSimpleEventHandler => RetVal.IsVoid && (Parameters.Count == 0 || (Parameters.HasSender && Parameters.Count == 1)); + + public bool IsVoid => RetVal.JavaName == "void"; + + public string JniSignature => "(" + Parameters.JniSignature + ")" + RetVal.JniName; + + public InterfaceGen ListenerType => Parameters [0].ListenerType; + + public override bool Matches (MethodBase other) + { + var ret = base.Matches (other); + + if (!ret) + return ret; + + if (!(other is Method otherMethod)) + return false; + + if (RetVal.RawJavaType != otherMethod.RetVal.RawJavaType) + return false; + + return true; + } + + public string PropertyName { + get { + if (!IsPropertyAccessor) + throw new InvalidOperationException ("Not a property: " + Name); + var pn = PropertyNameOverride; + if (pn != null) + return pn; + var nameBase = Name; + if (CanAdd || CanSet || Name.StartsWith ("Get", StringComparison.Ordinal)) + nameBase = Name.Substring (3); + if (IsAbstract && (CanGet && RetVal.IsGeneric || CanSet && Parameters [0].IsGeneric) && + DeclaringType is ClassGen) // Interface methods cannot be RawXxx (because they are not generic so far...) + return "Raw" + nameBase; + return nameBase; + } + } + + public string ReturnType => RetVal.FullName; + + protected override bool OnValidate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + if (GenericArguments != null) + GenericArguments.Validate (opt, type_params, context); + var tpl = GenericParameterDefinitionList.Merge (type_params, GenericArguments); + if (!RetVal.Validate (opt, tpl, context)) + return false; + + return base.OnValidate (opt, tpl, context); + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs new file mode 100644 index 00000000000..6a0ea2a9481 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs @@ -0,0 +1,155 @@ +using System; +using System.Linq; +using System.Text; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation.Utilities; + +namespace MonoDroid.Generation +{ + public abstract class MethodBase : ApiVersionsSupport.IApiAvailability, ISourceLineInfo + { + protected MethodBase (GenBase declaringType) + { + DeclaringType = declaringType; + } + + public string AnnotatedVisibility { get; set; } + public string Annotation { get; internal set; } + public AndroidSdkVersion ApiAvailableSince { get; set; } + public AndroidSdkVersion ApiRemovedSince { get; set; } + public string AssemblyName { get; set; } + public GenBase DeclaringType { get; } + public string Deprecated { get; set; } + public AndroidSdkVersion? DeprecatedSince { get; set; } + public GenericParameterDefinitionList GenericArguments { get; set; } + public bool IsAcw { get; set; } + public bool IsValid { get; private set; } + public string Name { get; set; } + public ParameterList Parameters { get; } = new ParameterList (); + public string Visibility { get; set; } + + public int LineNumber { get; set; } = -1; + public int LinePosition { get; set; } = -1; + public string SourceFile { get; set; } + + public JavadocInfo JavadocInfo { get; set; } + + public string [] AutoDetectEnumifiedOverrideParameters (AncestorDescendantCache cache) + { + if (Parameters.All (p => p.Type != "int")) + return null; + + var classes = cache.GetAncestorsAndDescendants (DeclaringType); + classes = classes.Concat (classes.SelectMany (x => x.GetAllImplementedInterfaces ())); + + foreach (var t in classes) { + foreach (var candidate in t.GetAllMethods ().Where (m => m.Name == Name + && m.Parameters.Count == Parameters.Count + && m.Parameters.Any (p => p.IsEnumified))) { + var ret = new string [Parameters.Count]; + bool mismatch = false; + for (int i = 0; i < Parameters.Count; i++) { + if (Parameters [i].Type == "int" && candidate.Parameters [i].IsEnumified) + ret [i] = candidate.Parameters [i].Type; + else if (Parameters [i].Type != candidate.Parameters [i].Type) { + mismatch = true; + break; + } + } + if (mismatch) + continue; + for (int i = 0; i < ret.Length; i++) + if (ret [i] != null) + Parameters [i].SetGeneratedEnumType (ret [i]); + return ret; + } + } + return null; + } + + public string GetSignature (CodeGenerationOptions opt) + { + var sb = new StringBuilder (); + + foreach (var p in Parameters) { + if (sb.Length > 0) + sb.Append (", "); + if (p.IsEnumified) + sb.Append ("[global::Android.Runtime.GeneratedEnum] "); + if (p.Annotation != null) + sb.Append (p.Annotation); + sb.Append (opt.GetTypeReferenceName (p)); + sb.Append (" "); + sb.Append (opt.GetSafeIdentifier (p.Name)); + } + return sb.ToString (); + } + + internal string IDSignature => Parameters.Count > 0 ? "_" + EscapeSignature (Parameters.JniSignature) : string.Empty; + + internal string IDSignatureWithReturnType => IDSignature + (this is Method method ? "_" + EscapeSignature (method.RetVal.JniName) : ""); + + internal string EscapeSignature (string value) => value.Replace ("/", "_").Replace ("`", "_").Replace (";", "_").Replace ("$", "_").Replace ("[", "array"); + + public virtual bool IsGeneric => Parameters.HasGeneric; + + public bool IsKotlinNameMangled { + get { + // Kotlin generates methods that cannot be referenced in Java, + // like `add-impl` and `add-V5j3Lk8`. We will need to fix those later. + if (this is Method method) { + if (method.JavaName.IndexOf ("-impl", StringComparison.Ordinal) >= 0) + return true; + + return method.JavaName.Length >= 8 && method.JavaName [method.JavaName.Length - 8] == '-'; + } + + return false; + } + } + + public virtual bool Matches (MethodBase other) + { + if (Name != other.Name) + return false; + + if (Parameters.Count != other.Parameters.Count) + return false; + + for (int i = 0; i < Parameters.Count; i++) { + if (Parameters [i].RawNativeType != other.Parameters [i].RawNativeType) + return false; + // dotnet/java-interop#1431 (Phase 2): two Kotlin @JvmInline + // value classes can share the same underlying JVM primitive + // (e.g. multiple `ULong`-backed inline classes on Compose + // APIs). Their `RawNativeType` is identical (`long`), but the + // projected wrapper structs are distinct C# overloads, so + // also compare the inline-class JNI type to keep them apart. + if (Parameters [i].KotlinInlineClassJniType != other.Parameters [i].KotlinInlineClassJniType) + return false; + } + + return true; + } + + protected virtual bool OnValidate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + var tpl = GenericParameterDefinitionList.Merge (type_params, GenericArguments); + if (!Parameters.Validate (opt, tpl, context)) + return false; + + return true; + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + context.ContextMethod = this; + + try { + return IsValid = OnValidate (opt, type_params, context); + } finally { + context.ContextMethod = null; + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/NamespaceMapping.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/NamespaceMapping.cs new file mode 100644 index 00000000000..bb27a608761 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/NamespaceMapping.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation +{ + public class NamespaceMapping + { + Dictionary mappings = new Dictionary (); + + public NamespaceMapping (IEnumerable gens) + { + foreach (GenBase gen in gens) + if (!mappings.ContainsKey (gen.PackageName)) + mappings [gen.PackageName] = gen.Namespace; + } + + bool IsGeneratable { get { return true; } } + + public void Generate (CodeGenerationOptions opt, GenerationInfo gen_info) + { + using (var sw = gen_info.OpenStream (opt.GetFileName ("__NamespaceMapping__"))) { + sw.WriteLine ("using System;"); + sw.WriteLine (); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + foreach (var p in mappings) { + sw.WriteLine ($"[assembly:global::Android.Runtime.NamespaceMapping (Java = \"{p.Key}\", Managed=\"{p.Value}\")]"); + } + sw.WriteLine (); + } + + // [UnmanagedFunctionPointer (CallingConvention.Winapi)] + // delegate bool _JniMarshal_PPL_Z (IntPtr jnienv, IntPtr klass, IntPtr a); + foreach (var jni in opt.GetJniMarshalDelegates ()) { + sw.WriteLine ("[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]"); + sw.WriteLine ($"delegate {FromJniType (jni[jni.Length - 1])} {jni} (IntPtr jnienv, IntPtr klass{GetDelegateParameters (jni)});"); + } + + } + } + + string GetDelegateParameters (string jni) + { + var parameters = new List (); + + jni = jni.Substring ("_JniMarshal_PP".Length); + + var index = 0; + + while (jni[index] != '_') { + parameters.Add ($"{FromJniType (jni [index])} p{index}"); + index++; + } + + if (parameters.Count == 0) + return string.Empty; + + return ", " + string.Join (", ", parameters); + } + + string FromJniType (char c) + { + switch (c) { + case 'B': return "sbyte"; + case 'b': return "byte"; + case 'C': return "char"; + case 'D': return "double"; + case 'F': return "float"; + case 'I': return "int"; + case 'i': return "uint"; + case 'J': return "long"; + case 'j': return "ulong"; + case 'S': return "short"; + case 's': return "ushort"; + case 'Z': return "bool"; + case 'V': return "void"; + default: + return "IntPtr"; ; + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs new file mode 100644 index 00000000000..9b62666cfc8 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Parameter.cs @@ -0,0 +1,356 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using Java.Interop.Tools.Generator; +using Mono.Cecil; + +using Xamarin.Android.Binder; +using Xamarin.Android.Tools; + +namespace MonoDroid.Generation { + + public class Parameter : ISourceLineInfo + { + bool is_sender; + string name; + string type, managed_type, rawtype; + ISymbol sym; + bool is_enumified; + + public int LineNumber { get; set; } = -1; + public int LinePosition { get; set; } = -1; + public string SourceFile { get; set; } + + internal Parameter (string name, string type, string managedType, bool isEnumified, string rawtype = null, bool notNull = false) + { + this.name = name; + this.type = type; + this.rawtype = rawtype ?? type; + this.managed_type = managedType; + this.is_enumified = isEnumified; + NotNull = notNull; + } + + // Kotlin @JvmInline value class JNI signature (e.g. "Lcom/example/MyColor;") + // for inline-class projection. When set, Validate replaces the managed type + // with the wrapper struct's full name so the C# parameter signature uses the + // struct, while JNI marshaling stays on the underlying primitive (the `type`). + public string KotlinInlineClassJniType { get; set; } + + public Parameter Clone () + { + return new Parameter (name, type, managed_type, is_enumified, rawtype, NotNull) { + KotlinInlineClassJniType = KotlinInlineClassJniType, + }; + } + + public string GetCall (CodeGenerationOptions opt) + { + var rgm = sym as IRequireGenericMarshal; + var c = rgm != null + ? opt.GetSafeIdentifier (rgm.ToInteroperableJavaObject (Name)) + : ToNative (opt); + if (sym.NativeType != "IntPtr") + return c; + if (!NeedsPrep) + return c; + var h = sym.GetObjectHandleProperty (opt, c); + if (sym.PreCall (opt, Name).Length == 0) { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return c; + } + return string.Format ("({0} == null) ? IntPtr.Zero : {1}", c, h); + } + return c; + } + + public string ToNative (CodeGenerationOptions opt) + { + return NeedsPrep ? sym.Call (opt, Name) : sym.ToNative (opt, opt.GetSafeIdentifier (Name), null); + } + + public string GenericType { + get { return sym.GetGenericType (null) ?? Type; } + } + + public string GetGenericType (Dictionary mappings) + { + return sym.GetGenericType (mappings) ?? Type; + } + + public bool IsArray { + get { return sym.IsArray; } + } + + public bool IsGeneric { + get { return !string.IsNullOrEmpty (sym.GetGenericType (null)); } + } + + public bool IsListener { + get { return sym is InterfaceGen && (sym as InterfaceGen).IsListener; } + } + + public bool IsSender { + get { return is_sender; } + set { is_sender = value; } + } + + public bool IsEnumified { + get { return is_enumified; } + } + + public string JavaType { + get { return sym.JavaName; } + } + + public string JniType { + get { return sym.JniName; } + } + + public InterfaceGen ListenerType { + get { return IsListener ? sym as InterfaceGen : null; } + } + + public string Name { + get { return name; } + set { name = value; } + } + + public bool NotNull { get; set; } + + public string PropertyName { + get { + if (Name == "e") + return "Event"; + string name = Name; + return (name [0] == '@') + ? char.ToUpper (name [1]) + name.Substring (2) + : char.ToUpper (name [0]) + name.Substring (1); + } + } + + public string UnsafeNativeName { + get { + if (Type == NativeType) + return Name; + return TypeNameUtilities.GetNativeName (Name); + } + } + + public string JavaName { + get { + if (Name.StartsWith ("@", StringComparison.Ordinal)) + return Name.Substring (1); + return Name; + } + } + + public string NativeType { + get { return sym.NativeType; } + } + + public string RawNativeType { + get { return rawtype; } + } + + public bool NeedsPrep { + get { return sym.NeedsPrep; } + } + + public string[] GetPostCall (CodeGenerationOptions opt) + { + return !NeedsPrep ? new string [0] : sym.PostCall (opt, Name); + } + + public string[] GetPostCallback (CodeGenerationOptions opt) + { + return !NeedsPrep ? new string [0] : sym.PostCallback (opt, Name); + } + + public string GetName (string prefix = null) + { + if (string.IsNullOrEmpty (prefix)) + return Name; + return prefix + JavaName; + } + + public string[] GetPreCall (CodeGenerationOptions opt) + { + return !NeedsPrep ? new string [0] : sym.PreCall (opt, Name); + } + + public bool Equals (Parameter other) + { + if (this.IsGeneric == other.IsGeneric) { + if (this.GenericType != other.GenericType) + return false; + if (sym is GenericSymbol && other.sym is GenericSymbol) + if (!Equals ((GenericSymbol) sym, (GenericSymbol) other.sym)) + return false; + } + return this.IsArray == other.IsArray && + FilterCSharpType (this.Type) == FilterCSharpType (other.Type); + } + + static bool Equals (GenericSymbol g1, GenericSymbol g2) + { + if (g1.IsConcrete != g2.IsConcrete) + return false; + if (g1.FullName != g2.FullName) + return false; + return true; + } + + static string FilterCSharpType (string s) + { + switch (s) { + case "bool": + return "System.Boolean"; + case "char": + return "System.Char"; + case "byte": + return "System.Byte"; + case "short": + return "System.Int16"; + case "int": + return "System.Int32"; + case "long": + return "System.Int64"; + case "float": + return "System.Single"; + case "double": + return "System.Double"; + case "string": + return "System.String"; + default: + return s; + } + } + + public string[] GetPreCallback (CodeGenerationOptions opt) + { + if (Type == NativeType) + return new string [0]; + else if (NeedsPrep) + return sym.PreCallback (opt, Name, false); + else + return new string[] { "var " + opt.GetSafeIdentifier (Name) + " = " + FromNative (opt, false) + ";" }; + } + + public string Type { + //get { return sym is GenBase && !String.IsNullOrEmpty ((sym as GenBase).Marshaler) ? (sym as GenBase).Marshaler : sym.FullName; } + get { return managed_type ?? sym.FullName; } + } + + public string InternalType => managed_type ?? sym?.FullName ?? type; + + public string Annotation { get; internal set; } + + public void SetGeneratedEnumType (string enumType) + { + sym = new GeneratedEnumSymbol (enumType); + managed_type = null; + type = sym.JavaName; + is_enumified = true; + } + + public string FromNative (CodeGenerationOptions opt, bool owned) + { + return sym.FromNative (opt, UnsafeNativeName, owned); + } + + public string GetGenericCall (CodeGenerationOptions opt, Dictionary mappings) + { + string targetType = sym.GetGenericType (mappings); + if (string.IsNullOrEmpty (targetType)) + return name; + if (targetType == "string") + return string.Format ("{0}?.ToString ()", name); + if (targetType.EndsWith ("[]", StringComparison.Ordinal)) { + return string.Format ("{0}.ToArray<{1}> ()", name, targetType.Replace ("[]","")); + } + var rgm = opt.SymbolTable.Lookup (targetType) as IRequireGenericMarshal; + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return "global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<" + + opt.GetOutputName (rgm != null ? (rgm.GetGenericJavaObjectTypeOverride () ?? targetType) : targetType) + + $">(({name}?.PeerReference ?? default).Handle)"; + } + return string.Format ("global::Java.Interop.JavaObjectExtensions.JavaCast<{0}>({1}){2}", + opt.GetOutputName (rgm != null ? (rgm.GetGenericJavaObjectTypeOverride () ?? targetType) : targetType), + name, + opt.NullForgivingOperator); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + sym = opt.SymbolTable.Lookup (type, type_params); + if (sym == null) { + Report.LogCodedWarning (0, Report.WarningUnknownParameterType, this, type, context.GetContextTypeMember ()); + return false; + } + if (!sym.Validate (opt, type_params, context)) { + Report.LogCodedWarning (0, Report.WarningInvalidParameterType, this, type, context.GetContextTypeMember ()); + return false; + } + ApplyKotlinInlineClassProjection (opt, type_params); + return true; + } + + // If KotlinInlineClassJniType is set, look up the wrapper ClassGen and + // override managed_type so the C# parameter type is the struct (e.g. + // "Com.Example.MyColor") while sym remains the underlying primitive + // for JNI marshaling. + void ApplyKotlinInlineClassProjection (CodeGenerationOptions opt, GenericParameterDefinitionList type_params) + { + if (string.IsNullOrEmpty (KotlinInlineClassJniType)) + return; + var javaName = TypeNameUtilities.JniSignatureToJavaTypeName (KotlinInlineClassJniType); + if (javaName == null) + return; + var wrapper = opt.SymbolTable.Lookup (javaName, type_params) as ClassGen; + if (wrapper == null || !wrapper.IsKotlinInlineClass) + return; + managed_type = wrapper.FullName; + NotNull = true; + } + + public bool ShouldGenerateKeepAlive () + { + if (Symbol.IsEnum) + return false; + + // dotnet/java-interop#1431 (Phase 2): a Kotlin @JvmInline value + // class is projected as a `readonly struct` wrapping a primitive. + // The projection rewrites Type to the wrapper struct's FullName, + // which wouldn't match any case below and would fall through to + // `true`, generating an unnecessary GC.KeepAlive call for what is + // ultimately a value-type holding a primitive. + if (!string.IsNullOrEmpty (KotlinInlineClassJniType)) + return false; + + return Type switch { + "bool" => false, + "sbyte" => false, + "char" => false, + "double" => false, + "float" => false, + "int" => false, + "long" => false, + "short" => false, + "uint" => false, + "ushort" => false, + "ulong" => false, + "byte" => false, + "ubyte" => false, // Not a C# type, but we will see it from Kotlin unsigned types support + "string" => false, + "java.lang.String" => false, + "Android.Graphics.Color" => false, + _ => true + }; + } + + public ISymbol Symbol => sym; + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ParameterList.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ParameterList.cs new file mode 100644 index 00000000000..779c1d6574f --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ParameterList.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; +using System.Xml; +using System.IO; + +using Xamarin.Android.Binder; + +namespace MonoDroid.Generation { + + public class ParameterList : IEnumerable { + + public static bool Equals (ParameterList l1, ParameterList l2) + { + if (l1.Count != l2.Count) + return false; + for (int i = 0; i < l1.Count; i++) + if (!l1 [i].Equals (l2 [i])) + return false; + return true; + } + + List items = new List (); + + public Parameter this [int idx] { + get { return items [idx]; } + } + + public IEnumerator GetEnumerator () + { + return items.GetEnumerator (); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + + public string GetCall (CodeGenerationOptions opt) + { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + if (sb.Length > 0) + sb.Append (", "); + sb.Append (opt.GetSafeIdentifier (p.Name) + opt.GetNullForgiveness (p)); + } + return sb.ToString (); + } + + public string CallDropSender { + get { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + if (p.IsSender) + continue; + else if (sb.Length > 0) + sb.Append (", "); + sb.Append (p.Name); + } + return sb.ToString (); + } + } + + public string JavaCall { + get { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + if (sb.Length > 0) + sb.Append (", "); + sb.Append (p.JavaName); + } + return sb.ToString (); + } + } + + public string GetCallArgs (CodeGenerationOptions opt, bool invoker) + { + if (items.Count != 0) + return ", __args"; + if (invoker) + return ""; + return ", null"; + } + + public StringCollection GetCallCleanup (CodeGenerationOptions opt) + { + StringCollection result = new StringCollection (); + foreach (Parameter p in items) + foreach (string s in p.GetPostCall (opt)) + result.Add (s); + return result; + } + + public StringCollection GetCallPrep (CodeGenerationOptions opt) + { + StringCollection result = new StringCollection (); + foreach (Parameter p in items) + foreach (string s in p.GetPreCall (opt)) + result.Add (s); + return result; + } + + public StringCollection GetCallbackCleanup (CodeGenerationOptions opt) + { + StringCollection result = new StringCollection (); + foreach (Parameter p in items) + foreach (string s in p.GetPostCallback (opt)) + result.Add (s); + return result; + } + + public StringCollection GetCallbackPrep (CodeGenerationOptions opt) + { + StringCollection result = new StringCollection (); + foreach (Parameter p in items) + foreach (string s in p.GetPreCallback (opt)) + result.Add (s); + return result; + } + + public string GetCallbackSignature (CodeGenerationOptions opt) + { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + sb.Append (", "); + sb.Append (p.NativeType); + sb.Append (" "); + sb.Append (opt.GetSafeIdentifier (p.UnsafeNativeName)); + } + return sb.ToString (); + } + + public int Count { + get { return items.Count; } + } + + public string DelegateTypeParams { + get { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + sb.Append (", "); + sb.Append (p.NativeType); + } + return sb.ToString (); + } + } + + public bool HasCharSequence { + get { + foreach (Parameter p in items) + if (p.JavaType.StartsWith ("java.lang.CharSequence", StringComparison.Ordinal)) + return true; + return false; + } + } + + public bool HasCleanup { + get { + foreach (Parameter p in items) + if (p.NeedsPrep) + return true; + return false; + } + } + + public bool HasGeneric { + get { + foreach (Parameter p in items) + if (p.IsGeneric) + return true; + return false; + } + } + + public bool HasSender { + get { + foreach (Parameter p in items) + if (p.IsSender) + return true; + return false; + } + } + + public string JavaSignature { + get { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + if (sb.Length > 0) + sb.Append (", "); + sb.Append (p.JavaType); + sb.Append (" "); + sb.Append (p.JavaName); + } + return sb.ToString (); + } + } + + public string JniSignature { + get { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) + sb.Append (p.JniType); + return sb.ToString (); + } + } + + public string GetJniNestedDerivedSignature (CodeGenerationOptions opt) + { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + if (p.Name == "__self") { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + sb.AppendFormat ("L\" + global::Java.Interop.JniEnvironment.Runtime.TypeManager.GetTypeSignature (GetType ().DeclaringType{0}).SimpleReference + \";", opt.NullForgivingOperator); + } else { + sb.AppendFormat ("L\" + global::Android.Runtime.JNIEnv.GetJniName (GetType ().DeclaringType{0}) + \";", opt.NullForgivingOperator); + } + continue; + } + sb.Append (p.JniType); + } + return sb.ToString (); + } + + public string SenderName { + get { + foreach (Parameter p in items) + if (p.IsSender) + return p.Name; + return String.Empty; + } + } + + public string GetSignatureDropSender (CodeGenerationOptions opt) + { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + if (p.IsSender) + continue; + else if (sb.Length > 0) + sb.Append (", "); + sb.Append (opt.GetTypeReferenceName (p)); + sb.Append (" "); + sb.Append (p.Name); + } + return sb.ToString (); + } + + public void Add (Parameter parm) + { + items.Add (parm); + } + + public void AddFirst (Parameter parm) + { + items.Insert (0, parm); + } + + public string GetGenericCall (CodeGenerationOptions opt, Dictionary mappings) + { + StringBuilder sb = new StringBuilder (); + foreach (Parameter p in items) { + if (sb.Length > 0) + sb.Append (", "); + sb.Append (p.GetGenericCall (opt, mappings)); + } + return sb.ToString (); + } + + public string GetMethodXPathPredicate () + { + if (items.Count == 0) + return " and count(parameter)=0"; + + var sb = new StringBuilder (); + sb.Append (" and count(parameter)=").Append (items.Count); + for (int i = 0; i < items.Count; ++i) { + sb.Append (" and parameter[").Append (i+1).Append ("]") + .Append ("[@type='").Append (items [i].RawNativeType.Replace ("<", "<").Replace (">",">")).Append ("']"); + } + return sb.ToString (); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + foreach (Parameter p in items) + if (!p.Validate (opt, type_params, context)) + return false; + return true; + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Property.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Property.cs new file mode 100644 index 00000000000..a9a51ff74a5 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Property.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using MonoDroid.Generation.Utilities; + +namespace MonoDroid.Generation +{ + public class Property + { + private Method setter; + + public Property (string name) + { + Name = name; + } + + public Method Getter {get; set;} + + public Method Setter { + get => setter; + set { + setter = value; + + if (Getter?.RetVal?.NotNull == true) + Setter.Parameters.First ().NotNull = true; + } + } + + public bool IsGeneric => Getter.IsGeneric; + + // This is a workaround for generaing compatibility for Android.Graphics.Drawables.ColorDrawable.SetColor (wrt bug #4288). + public bool GenerateDispatchingSetter { get; set; } + + internal string AdjustedName => + Getter.ReturnType.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) ? Name + "Formatted" : Name; + + public string Name { get; set; } + + public string Type => Setter != null ? Setter.Parameters [0].Type : Getter.ReturnType; + + public void AutoDetectEnumifiedOverrideProperties (AncestorDescendantCache cache) + { + if (Type != "int") + return; + + var classes = cache.GetAncestorsAndDescendants (Getter.DeclaringType); + classes = classes.Concat (classes.SelectMany (x => x.GetAllImplementedInterfaces ())); + + foreach (var t in classes) { + foreach (var candidate in t.Properties.Where (p => p.Name == Name)) { + if (Getter.JniSignature != candidate.Getter.JniSignature) + continue; + if (candidate.Getter.IsReturnEnumified) + Getter.RetVal.SetGeneratedEnumType (candidate.Getter.RetVal.FullName); + } + } + } + + public string ExplicitInterface => Getter?.ExplicitInterface ?? Setter?.ExplicitInterface; + + public bool IsWholePropertyDeprecated { + get { + // If the getter isn't deprecated then the property isn't + if (Getter?.Deprecated is null) + return false; + + // If the getter is deprecated and there is no setter then the property is deprecated + if (Setter is null) + return true; + + // If the setter isn't deprecated then the property isn't + if (Setter.Deprecated is null) + return false; + + // If the getter/setter deprecation messages differ, don't use whole property deprecation + if (Getter.Deprecated != Setter.Deprecated) + return false; + + // If the getter/setter deprecation versions differ, don't use whole property deprecation + if (Getter.DeprecatedSince != Setter.DeprecatedSince) + return false; + + // Getter/Setter deprecation is the same, use whole property deprecation + return true; + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs new file mode 100644 index 00000000000..ee7b9bb6ceb --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Java.Interop.Tools.Generator; +using MonoDroid.Utils; +using Xamarin.Android.Binder; + +namespace MonoDroid.Generation { + + public class ReturnValue { + + ISymbol sym; + string java_type; + string managed_type; + string raw_type; + bool is_enumified; + Method owner; + + public ReturnValue (Method owner, string java_type, string managed_type, bool isEnumified, bool notNull) + { + this.raw_type = this.java_type = java_type; + this.managed_type = managed_type; + this.is_enumified = isEnumified; + this.owner = owner; + NotNull = notNull; + } + + public string CallMethodPrefix => TypeNameUtilities.GetCallPrefix (sym); + + public ReturnValue Clone (Method owner) + { + return new ReturnValue (owner, java_type, managed_type, is_enumified, NotNull); + } + + public string DefaultValue { + get { return sym.DefaultValue; } + } + + public string FullName { + get { + if (!String.IsNullOrEmpty (managed_type)) + return managed_type; + return sym.FullName; + //return sym is GenBase && !String.IsNullOrEmpty ((sym as GenBase).Marshaler) ? (sym as GenBase).Marshaler : sym.FullName; + } + } + + public void SetGeneratedEnumType (string enumType) + { + sym = new GeneratedEnumSymbol (enumType); + is_enumified = true; + managed_type = null; + java_type = sym.JavaName; + } + + public string GetGenericType (Dictionary mappings) + { + return sym.GetGenericType (mappings) ?? FullName; + } + + public bool IsVoid { + get { return java_type == "void"; } + } + + public bool IsArray { + get { return sym.IsArray; } + } + + public bool IsEnumified { + get { return is_enumified; } + } + + public bool IsGeneric { + get { return sym is GenericSymbol ? !(sym as GenericSymbol).IsConcrete : !string.IsNullOrEmpty (sym.GetGenericType (null)); } + } + + public string JavaName { + get { return sym.JavaName; } + } + + public string JniName { + get { return sym.JniName; } + } + + public string NativeType { + get { return sym.NativeType; } + } + + public bool NotNull { get; set; } + + public string RawJavaType { + get { return raw_type; } + } + + public string ReturnCast => sym?.ReturnCast ?? string.Empty; + + public ISymbol Symbol => sym; + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned, bool isMarshal = false) + { + if (!string.IsNullOrEmpty (managed_type) && (sym is ClassGen || sym is InterfaceGen)) { + if (opt.CodeGenerationTarget == Xamarin.Android.Binder.CodeGenerationTarget.JavaInterop1) { + return "global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<" + + opt.GetOutputName (managed_type) + + $"> (ref __rm, JniObjectReferenceOptions.Copy)"; + } + return string.Format ("global::Java.Lang.Object.GetObject<{0}> ({1}, {2})", + opt.GetOutputName (managed_type), var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + return sym.FromNative (opt, var_name, owned, isMarshal); + } + + public string ToNative (CodeGenerationOptions opt, string var_name) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + if ((sym is GenericTypeParameter) || (sym is GenericSymbol)) { + return $"({var_name}?.PeerReference ?? default)"; + } + return sym.ToNative (opt, var_name); + } + return ((sym is GenericTypeParameter) || (sym is GenericSymbol)) ? String.Format ("JNIEnv.ToLocalJniHandle ({0})", var_name) : sym.ToNative (opt, var_name); + } + + public string GetGenericReturn (CodeGenerationOptions opt, string name, Dictionary mappings) + { + string targetType = sym.GetGenericType (mappings); + if (string.IsNullOrEmpty (targetType)) + return name; + if (targetType == "string") + return string.Format ("{0}?.ToString ()", name); + var rgm = opt.SymbolTable.Lookup (targetType) as IRequireGenericMarshal; + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return "global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<" + + (rgm != null ? (rgm.GetGenericJavaObjectTypeOverride () ?? sym.FullName) : sym.FullName) + + $">(({opt.GetSafeIdentifier (rgm != null ? rgm.ToInteroperableJavaObject (name) : name)}?.PeerReference ?? default).Handle)"; + } + return string.Format ("global::Java.Interop.JavaObjectExtensions.JavaCast<{0}>({1}){2}", + rgm != null ? (rgm.GetGenericJavaObjectTypeOverride () ?? sym.FullName) : sym.FullName, + opt.GetSafeIdentifier (rgm != null ? rgm.ToInteroperableJavaObject (name) : name), + opt.NullForgivingOperator); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + sym = (IsEnumified ? opt.SymbolTable.Lookup (managed_type, type_params) : null) ?? opt.SymbolTable.Lookup (java_type, type_params); + if (sym == null) { + Report.LogCodedWarning (0, Report.WarningUnknownReturnType, owner, java_type, context.GetContextTypeMember ()); + return false; + } + if (!sym.Validate (opt, type_params, context)) { + Report.LogCodedWarning (0, Report.WarningInvalidReturnType, owner, java_type, context.GetContextTypeMember ()); + return false; + } + ApplyKotlinInlineClassProjection (opt, type_params); + return true; + } + + // If the owning Method has KotlinInlineClassReturnJniType set, override + // managed_type with the wrapper struct's full name so the C# return type + // is the struct, while sym remains the underlying primitive for JNI. + void ApplyKotlinInlineClassProjection (CodeGenerationOptions opt, GenericParameterDefinitionList type_params) + { + var jni = owner?.KotlinInlineClassReturnJniType; + if (string.IsNullOrEmpty (jni)) + return; + var javaName = TypeNameUtilities.JniSignatureToJavaTypeName (jni); + if (javaName == null) + return; + var wrapper = opt.SymbolTable.Lookup (javaName, type_params) as ClassGen; + if (wrapper == null || !wrapper.IsKotlinInlineClass) + return; + managed_type = wrapper.FullName; + NotNull = true; + } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ArraySymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ArraySymbol.cs new file mode 100644 index 00000000000..800360f60f6 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ArraySymbol.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +using MonoDroid.Utils; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class ArraySymbol : ISymbol { + + static ISymbol byte_sym = new SimpleSymbol ("0", "byte", "byte", "B"); + + ISymbol sym; + bool is_params; + CodeGenerationTarget target; + + public ArraySymbol (ISymbol sym, CodeGenerationTarget target) + { + this.target = target; + if (sym.FullName == "sbyte") + this.sym = byte_sym; + else + this.sym = sym; + } + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string ElementType { + get { + return sym.FullName; + } + } + + public string FullName { + get { + if (!is_params && target == CodeGenerationTarget.JavaInterop1) { + return GetJavaInterop1MarshalType (); + } + return (is_params ? "params " : String.Empty) + ElementType + "[]"; + } + } + + public bool IsGeneric { + get { return !string.IsNullOrEmpty (sym.GetGenericType (null)); } + } + + public bool IsParams { + get { return is_params; } + set { is_params = value; } + } + + public string JavaName { + get { return is_params ? sym.JavaName + "..." : sym.JavaName + "[]"; } + } + + public string JniName { + get { return "[" + sym.JniName; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return true; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + return sym.GetObjectHandleProperty (opt, variable); + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + var transfer = "JniObjectReferenceOptions." + (owned ? "CopyAndDispose" : "Copy"); + return $"global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue" + + $"(ref {var_name}, {transfer})"; + } + return String.Format ("({0}[]{4}) JNIEnv.GetArray ({1}, {2}, typeof ({3}))", opt.GetOutputName (ElementType), var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer", opt.GetOutputName (sym.FullName), opt.NullableOperator); + } + + public string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"global::{GetJavaInterop1MarshalMethod ()} ({var_name})"; + } + return String.Format ("JNIEnv.NewArray ({0})", var_name); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return sym.Validate (opt, type_params, context); + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + string managed_name = opt.GetSafeIdentifier (var_name); + string native_name = opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return new string[]{ + $"throw new NotSupportedException (\"ArraySymbol.PostCallback\");", + }; + } + return new[]{ + $"if ({managed_name} != null)", + $"\tJNIEnv.CopyArray ({managed_name}, {native_name});", + }; + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + string managed_name = opt.GetSafeIdentifier (var_name); + string native_name = opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + if (IsParams) { + return new[]{ + $"if ({native_name} != null) {{", + $"\t{native_name}.CopyTo ({managed_name}!, 0);", + $"\t{native_name}.Dispose ();", + $"}}", + }; + } + return new[]{ + $"if ({native_name} != null) {{", + $"\t{native_name}.DisposeUnlessReferenced ();", + $"}}", + }; + } + return new[]{ + $"if ({managed_name} != null) {{", + $"\tJNIEnv.CopyArray ({native_name}, {managed_name});", + $"\tJNIEnv.DeleteLocalRef ({native_name});", + $"}}", + }; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return new string[] { String.Format ("var {1} = ({0}[]{4}) JNIEnv.GetArray ({2}, JniHandleOwnership.DoNotTransfer, typeof ({3}));", opt.GetOutputName (ElementType), opt.GetSafeIdentifier (var_name), opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), opt.GetOutputName (sym.FullName), opt.NullableOperator) }; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + string managed_name = opt.GetSafeIdentifier (var_name); + string native_name = opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return new[]{ + $"var {native_name} = global::{GetJavaInterop1MarshalMethod ()} ({managed_name});", + }; + } + return new string[] { String.Format ("IntPtr {0} = JNIEnv.NewArray ({1});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), opt.GetSafeIdentifier (var_name)) }; + } + + public bool NeedsPrep { get { return true; } } + + string GetJavaInterop1MarshalMethod() + { + var typeParam = ElementType switch { + "string" => "string", + _ => $"global::{ElementType}", + }; + return sym.JniName switch { + "B" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalSByteArray", + "C" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalCharArray", + "D" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalDoubleArray", + "F" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalSingleArray", + "I" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalInt32Array", + "J" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalInt64Array", + "S" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalInt16Array", + "V" => throw new InvalidOperationException ("`void` cannot be used as an array type."), + "Z" => "Java.Interop.JniEnvironment.Arrays.CreateMarshalBooleanArray", + _ => $"Java.Interop.JniEnvironment.Arrays.CreateMarshalObjectArray<{typeParam}>", + }; + } + + string GetJavaInterop1MarshalType () + { + return sym.JniName switch { + "B" => "Java.Interop.JavaSByteArray", + "C" => "Java.Interop.JavaCharArray", + "D" => "Java.Interop.JavaDoubleArray", + "F" => "Java.Interop.JavaSingleArray", + "I" => "Java.Interop.JavaInt32Array", + "J" => "Java.Interop.JavaInt64Array", + "S" => "Java.Interop.JavaInt16Array", + "V" => throw new InvalidOperationException ("`void` cannot be used as an array type."), + "Z" => "Java.Interop.JavaBooleanArray", + _ => $"Java.Interop.JavaObjectArray<{ElementType}>", + }; + } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CharSequenceSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CharSequenceSymbol.cs new file mode 100644 index 00000000000..d474cb4214e --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CharSequenceSymbol.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class CharSequenceSymbol : ISymbol { + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return "Java.Lang.ICharSequence"; } + } + + public bool IsGeneric { + get { return false; } + } + + public string JavaName { + get { return "java.lang.CharSequence"; } + } + + public string JniName { + get { return "Ljava/lang/CharSequence;"; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"{variable}.PeerReference"; + } + return $"((global::Java.Lang.Object) {variable}).Handle"; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return "global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(" + + $"ref {var_name}, JniObjectReferenceOptions.{(owned ? "CopyAndDispose" : "Copy")})"; + } + return String.Format ("global::Java.Lang.Object.GetObject ({0}, {1})", var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + + public string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"({var_name}?.PeerReference ?? default)"; + } + return String.Format ("CharSequence.ToLocalJniHandle ({0})", var_name); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return var_name; + } + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return new string [0]; + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return Array.Empty(); + } + return new string[]{ + string.Format ("JNIEnv.DeleteLocalRef ({0});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))), + }; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return new[]{ + $"var {var_name} = global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue(" + + $"ref {TypeNameUtilities.GetNativeName (var_name)}, JniObjectReferenceOptions.Copy);", + }; + } + return new string[] { String.Format ("var {0} = global::Java.Lang.Object.GetObject ({1}, JniHandleOwnership.DoNotTransfer);", var_name, TypeNameUtilities.GetNativeName (var_name)) }; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return Array.Empty (); + } + return new string[] { String.Format ("IntPtr {0} = CharSequence.ToLocalJniHandle ({1});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), opt.GetSafeIdentifier (var_name)) }; + } + + public bool NeedsPrep { get { return true; } } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CollectionSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CollectionSymbol.cs new file mode 100644 index 00000000000..227a2f4013c --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CollectionSymbol.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class CollectionSymbol : ISymbol, IRequireGenericMarshal { + + string java_name; + string managed_name; + string marshaler; + GenericParameterList parms; + + public CollectionSymbol (string java_name, string managed_name, string marshaler, string type_params) + { + this.java_name = java_name; + this.managed_name = managed_name; + this.marshaler = marshaler; + if (!String.IsNullOrEmpty (type_params)) + parms = new GenericParameterList (type_params); + } + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return parms == null || !parms.IsConcrete ? "System.Collections." + managed_name : "System.Collections.Generic." + managed_name + parms; } + } + + public string JavaName { + get { return java_name; } + } + + public string JniName { + get { return "L" + java_name.Replace (".", "/") + ";"; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public bool MayHaveManagedGenericArguments { + get { return true; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"{variable}.PeerReference"; + } + return $"((global::Java.Lang.Object) {variable}).Handle"; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string varname, bool owned) + { + return String.Format ("{0}.FromJniHandle ({1}, {2})", + GetManagedTypeName (opt), + opt.GetSafeIdentifier (varname), + owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + + string GetManagedTypeName (CodeGenerationOptions opt) + { + return opt.GetOutputName (marshaler + + (parms != null && parms.IsConcrete + ? parms.ToString () + : string.Empty)); + } + + public string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings = null) + { + return string.Format ("{0}.ToLocalJniHandle ({1})", + GetManagedTypeName (opt), + opt.GetSafeIdentifier (varname)); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return parms == null || parms.Validate (opt, type_params, context); + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return new string[]{ + string.Format ("var {0} = {1}.FromJniHandle ({2}, {3});", + opt.GetSafeIdentifier (var_name), + GetManagedTypeName (opt), + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), + owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"), + }; + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return new string[]{ + }; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + return new string[] { + string.Format ("IntPtr {0} = {1}.ToLocalJniHandle ({2});", + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), + GetManagedTypeName (opt), + opt.GetSafeIdentifier (var_name)), + }; + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + return new string[]{ + string.Format ("JNIEnv.DeleteLocalRef ({0});", + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))), + }; + } + + public bool NeedsPrep { get { return true; } } + + #region IRequireGenericMarshal implementation + public string GetGenericJavaObjectTypeOverride () + { + return TypeNameUtilities.GetGenericJavaObjectTypeOverride (managed_name, parms != null ? parms.ToString () : null); + } + public string ToInteroperableJavaObject (string var_name) + { + return TypeNameUtilities.GetNativeName (var_name); + } + #endregion + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ColorSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ColorSymbol.cs new file mode 100644 index 00000000000..1a4d1d2583a --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ColorSymbol.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +using MonoDroid.Utils; + +namespace MonoDroid.Generation { + + public class ColorSymbol : SimpleSymbol, ISymbol { + + public ColorSymbol () + : base ("default (global::Android.Graphics.Color)", + "int", + "Android.Graphics.Color", + "I", + "int", + "new global::Android.Graphics.Color ({0})", + "{0}.ToArgb ()") + { + } + +#if false + public string DefaultValue { + get {return + } + + public string FullName { + get {return "Android.Graphics.Color";} + } + + public bool IsGeneric { + get {return false;} + } + + public string JavaName { + get {return "int";} + } + + public string JniName { + get {return "I";} + } + + public string NativeType { + get {return "int";} + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + return string.Format ("new global::Android.Graphics.Color ({0})", var_name); + } + + public string ToNative (CodeGenerationOptions opt, string var_name) + { + return string.Format ("{0}.ToArgb ()", var_name); + } + + public bool Validate (GenericParameterDefinitionList type_params) + { + return true; + } +#endif + } +} + + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/EnumSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/EnumSymbol.cs new file mode 100644 index 00000000000..ad377c13a12 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/EnumSymbol.cs @@ -0,0 +1,104 @@ +using System; +using System.Xml; +using System.Collections.Generic; + + +namespace MonoDroid.Generation { + + public class EnumSymbol : ISymbol { + + string type; + + public EnumSymbol (string type) + { + this.type = type; + } + + public string DefaultValue { + get { return "0"; } + } + + public string FullName { + get { return type; } + } + + public string JavaName { + get { return "int"; } + } + + public string JniName { + get { return "I"; } + } + + public string NativeType { + get { return "int"; } + } + + public bool IsEnum { + get { return true; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + return null; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string varname, bool owned) + { + return String.Format ("({0}) {1}", opt.GetOutputName (type), varname); + } + + public string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings = null) + { + return "(int) " + varname; + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + throw new NotSupportedException (string.Format ("{0} does not support PreCallback", this.GetType ().Name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PostCallback", this.GetType ().Name)); + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PreCall", this.GetType ().Name)); + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support Call", this.GetType ().Name)); + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PostCall", this.GetType ().Name)); + } + + public bool NeedsPrep { get { return false; } } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs new file mode 100644 index 00000000000..abbb5cfe9d0 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; + + +namespace MonoDroid.Generation { + + public class FormatSymbol : ISymbol { + + string default_value; + string from_fmt; + string java_type; + string jni_type; + string native_type; + string to_fmt; + string type; + string return_cast; + + public FormatSymbol (string default_value, string java_type, string jni_type, string native_type, string type, string from_fmt, string to_fmt, string returnCast) + { + this.default_value = default_value; + this.java_type = java_type; + this.jni_type = jni_type; + this.native_type = native_type; + this.type = type; + this.from_fmt = from_fmt; + this.to_fmt = to_fmt; + this.return_cast = returnCast ?? string.Empty; + } + + public string DefaultValue { + get { return default_value; } + } + + public string FullName { + get { return type; } + } + + public string FullOutputName { + get { return FullName; } + } + + public string JavaName { + get { return java_type; } + } + + public string JniName { + get { return jni_type; } + } + + public string NativeType { + get { return native_type; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => return_cast; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + return null; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string varname, bool owned) + { + return String.Format (from_fmt, varname, owned ? "/* FormatSymbol */ JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + + public string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings = null) + { + return String.Format (to_fmt, varname); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + throw new NotSupportedException (string.Format ("{0} does not support PreCallback", this.GetType ().Name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PostCallback", this.GetType ().Name)); + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PreCall", this.GetType ().Name)); + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support Call", this.GetType ().Name)); + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PostCall", this.GetType ().Name)); + } + + public bool NeedsPrep { get { return false; } } + + public bool OnlyFormatOnMarshal { get; set; } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GeneratedEnumSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GeneratedEnumSymbol.cs new file mode 100644 index 00000000000..b2b687eabf8 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GeneratedEnumSymbol.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; + +namespace MonoDroid.Generation +{ + // This could be array and non-array, depending on metadata fixup. + public class GeneratedEnumSymbol : ISymbol + { + string enum_type; + bool is_array; + + public GeneratedEnumSymbol (string enumType) + { + if (enumType.EndsWith ("[]", StringComparison.Ordinal)) { + enum_type = enumType.Substring (0, enumType.Length - 2); + is_array = true; + } + else + this.enum_type = enumType; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + if (IsArray) + return String.Format ("({0}[]{3}) JNIEnv.GetArray ({1}, {2}, typeof ({0}))", opt.GetOutputName (enum_type), var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer", opt.NullableOperator); + else + return String.Format ("({0}) {1}", opt.GetOutputName (enum_type), var_name); + } + + public string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null) + { + if (IsArray) + return String.Format ("JNIEnv.NewArray ({0})", var_name); + else + return String.Format ("({0}) {1}", JavaName, var_name); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string DefaultValue { + get { return IsArray ? "null" : "0"; } + } + + public string FullName { + get { return enum_type + (IsArray ? "[]" : String.Empty); } + } + + public string JavaName { + get { return IsArray ? "int[]" : "int"; } + } + + public string JniName { + get { return IsArray ? "[I" : "I"; } + } + + public string NativeType { + get { return IsArray ? "int[]" : "int"; } + } + + public bool IsEnum { + get { return true; } + } + + public bool IsArray { + get { return is_array; } + } + + public string ElementType { + get { return enum_type; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + return null; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + throw new NotSupportedException (string.Format ("{0} does not support PreCallback", this.GetType ().Name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PostCallback", this.GetType ().Name)); + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PreCall", this.GetType ().Name)); + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support Call", this.GetType ().Name)); + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + throw new NotSupportedException (string.Format ("{0} does not support PostCall", this.GetType ().Name)); + } + + public bool NeedsPrep { get { return false; } } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericSymbol.cs new file mode 100644 index 00000000000..49849c91346 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericSymbol.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MonoDroid.Generation { + + public class GenericSymbol : ISymbol { + + bool is_concrete; + GenBase gen; + string [] java_params; + string tps; + ISymbol [] type_params; + + public GenericSymbol (GenBase gen, string type_params) + { + this.gen = gen; + java_params = GenericParameterList.Parse (type_params); + } + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return gen.FullName; } + } + + public GenBase Gen { + get { return gen; } + } + + public bool IsConcrete { + get { return is_concrete; } + } + + public string JavaName { + get { return gen.JavaName; } + } + + public string JniName { + get { return gen.JniName; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public ISymbol [] TypeParams { + get { return type_params; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + return gen.GetObjectHandleProperty (opt, variable); + } + + string MapTypeParams (Dictionary mappings) + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<"); + foreach (var tp in type_params) { + if (sb.Length > 1) + sb.Append (", "); + if (mappings.ContainsKey (tp.FullName)) + sb.Append (mappings[tp.FullName]); + else + sb.Append (tp.FullName); + } + sb.Append (">"); + return sb.ToString (); + } + + public string FromNative (CodeGenerationOptions opt, string varname, bool owned) + { + return gen.FromNative (opt, varname, owned); + } + + public string GetGenericType (Dictionary mappings) + { + var rgm = gen as IRequireGenericMarshal; + return gen.FullName + (rgm != null && !rgm.MayHaveManagedGenericArguments ? null : mappings == null ? tps : MapTypeParams (mappings)); + } + + public string ToNative (CodeGenerationOptions opt, string varname) + { + return gen.ToNative (opt, varname); + } + + public string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings) + { + return varname; + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList in_params, CodeGeneratorContext context) + { + if (!gen.Validate (opt, in_params, context)) + return false; + + is_concrete = true; + type_params = new ISymbol [java_params.Length]; + for (int i = 0; i < java_params.Length; i++) { + string tp = java_params [i]; + var gpd = in_params != null ? in_params.FirstOrDefault (t => t.Name == tp) : null; + if (gpd != null) { + type_params [i] = new GenericTypeParameter (gpd); + is_concrete = false; + continue; + } else if (tp == "?") { + if (in_params != null && in_params.Count == 1) { + type_params [i] = new GenericTypeParameter (in_params [0]); + is_concrete = false; + } else + type_params [i] = new SimpleSymbol ("null", "java.lang.Object", "object", "Ljava/lang/Object;"); + continue; + } + + ISymbol psym = opt.SymbolTable.Lookup (tp, in_params); + if (psym == null || !psym.Validate (opt, in_params, context)) + return false; + + if (psym is GenericSymbol && !(psym as GenericSymbol).IsConcrete) + is_concrete = false; + type_params [i] = /*psym is IGeneric ? (psym as IGeneric).GetGenericType (null) : psym.FullName*/ psym; + } + tps = type_params == null ? null : "<" + String.Join (", ", (from tp in type_params select tp.FullName).ToArray ()) + ">"; + return true; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return gen.PreCallback (opt, var_name, owned); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return gen.PostCallback (opt, var_name); + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + return gen.PreCall (opt, var_name); + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return gen.Call (opt, var_name); + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + return gen.PostCall (opt, var_name); + } + + public bool NeedsPrep { get { return true; } } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericTypeParameter.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericTypeParameter.cs new file mode 100644 index 00000000000..db11a3dd90c --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericTypeParameter.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class GenericTypeParameter : ISymbol { + + string type; + string java_type; + string jni_type; + GenericParameterDefinition parm; + + public GenericTypeParameter (GenericParameterDefinition parm) + { + if (parm == null) + throw new ArgumentNullException ("parm"); + this.parm = parm; +#if false // FIXME: we want to enable generic type constraints to get valid JNI output. So far we "remove" any method that involves generic parameter constraints. + type = parm.Constraints != null ? parm.Constraints [0].FullName : "Java.Lang.Object"; + java_type = parm != null && parm.Constraints != null && parm.Constraints [0] != null ? parm.Constraints [0].JavaName : "java.lang.Object"; +#else + type = "Java.Lang.Object"; + java_type = parm != null && parm.Constraints != null && parm.Constraints [0] != null ? parm.Constraints [0].JavaName : "java.lang.Object"; +#endif + // some unknown types could result in "null" constraints items. So far we treat this as JLO. + jni_type = parm.Constraints != null && parm.Constraints [0] != null ? parm.Constraints [0].JniName : "Ljava/lang/Object;"; + } + + public GenericParameterDefinition Definition { + get { return parm; } + } + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return type; } + } + + public string JavaName { + get { return java_type; } + } + + public string JniName { + get { return jni_type; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string varname, bool owned) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + var transfer = "JniObjectReferenceOptions." + (owned ? "CopyAndDispose" : "Copy"); + return $"global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<{opt.GetOutputName (FullName)}>" + + $"(ref {varname}, {transfer})"; + } + return String.Format ("({0}{4}) global::Java.Lang.Object.GetObject<{3}> ({1}, {2})", opt.GetOutputName (type), varname, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer", opt.GetOutputName (FullName), opt.NullableOperator); + } + + public string GetGenericType (Dictionary mappings) + { + var mapped = mappings != null && mappings.ContainsKey (parm.Name) ? mappings [parm.Name] : null; + return mapped ?? parm.Name; + } + + public string ToNative (CodeGenerationOptions opt, string varname, Dictionary mappings = null) + { + var mapped = mappings != null && mappings.ContainsKey (parm.Name) ? mappings [parm.Name] : null; + string targetType = opt.GetOutputName (mappings == null ? parm.Name : mapped); + if (targetType == "string") + return string.Format ("new global::Java.Lang.String ({0})", varname); + return varname; + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return new string[]{ + string.Format ("var {1} = global::Java.Lang.Object.GetObject<{0}> ({2}, {3});", + opt.GetOutputName (FullName), + var_name, + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), + owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"), + }; + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return new string[]{ + }; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + var native_name = opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + var name = opt.GetSafeIdentifier (var_name); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return new[]{ + $"var {native_name} = ({name}?.PeerReference ?? default);", + }; + } + return new string[] { + string.Format ("IntPtr {0} = JNIEnv.ToLocalJniHandle ({1});", + native_name, name), + }; + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return new string[]{ + }; + } + return new string[]{ + string.Format ("JNIEnv.DeleteLocalRef ({0});", + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))), + }; + } + + public bool NeedsPrep { get { return true; } } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs new file mode 100644 index 00000000000..15ff68daf13 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; + +namespace MonoDroid.Generation { + + public interface ISymbol { + + string DefaultValue { get; } + string FullName { get; } + string JavaName { get; } + string JniName { get; } + string NativeType { get; } + bool IsEnum { get; } + bool IsArray { get; } + string ElementType { get; } + string ReturnCast { get; } + + // Only apply ToNative/FromNative for marshal methods. This is used when + // we want to change the marshal type to be blittable, like bool -> byte. + // But it will not be used for normal invocations, like InvokeVirtualBooleanMethod, etc. + bool OnlyFormatOnMarshal { get => false; } + + string GetObjectHandleProperty (CodeGenerationOptions opt, string variable); + + string GetGenericType (Dictionary mappings); + + string FromNative (CodeGenerationOptions opt, string var_name, bool owned, bool isMarshal = true) + { + if (OnlyFormatOnMarshal && !isMarshal) + return var_name; + + return FromNative (opt, var_name, owned); + } + + string FromNative (CodeGenerationOptions opt, string var_name, bool owned); + string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null); + + bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context); + + string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned); + string[] PostCallback (CodeGenerationOptions opt, string var_name); + + string[] PreCall (CodeGenerationOptions opt, string var_name); + string Call (CodeGenerationOptions opt, string var_name); + string[] PostCall (CodeGenerationOptions opt, string var_name); + + bool NeedsPrep {get;} + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SimpleSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SimpleSymbol.cs new file mode 100644 index 00000000000..c8d3e9e2b67 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SimpleSymbol.cs @@ -0,0 +1,14 @@ +using System; + +namespace MonoDroid.Generation { + + public class SimpleSymbol : FormatSymbol { + + public SimpleSymbol (string default_value, string java_type, string type, string jni_type, string native_type = null, string from_fmt="{0}", string to_fmt="{0}", string returnCast = null) + : base (default_value, java_type, jni_type, native_type ?? type, type, from_fmt, to_fmt, returnCast) + { + } + + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StreamSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StreamSymbol.cs new file mode 100644 index 00000000000..0e7b5022fad --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StreamSymbol.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class StreamSymbol : ISymbol { + + string base_name; + string java_name; + string jni_name; + + public StreamSymbol (string name) : this (name, name) {} + + public StreamSymbol (string name, string base_name) + { + this.base_name = base_name; + java_name = "java.io." + name; + jni_name = "Ljava/io/" + name + ";"; + } + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return "System.IO.Stream"; } + } + + public bool IsGeneric { + get { return false; } + } + + public string JavaName { + get { return java_name; } + } + + public string JniName { + get { return jni_name; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"{variable}.PeerReference"; + } + return $"((global::Java.Lang.Object) {variable}).Handle"; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + return String.Format (opt.GetOutputName ("Android.Runtime.{0}Invoker") + ".FromJniHandle ({1}, {2})", base_name, var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + + public string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null) + { + return String.Format (opt.GetOutputName ("Android.Runtime.{0}Adapter") + ".ToLocalJniHandle ({1})", base_name, var_name); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + return new string[] { + string.Format ("IntPtr {0} = global::Android.Runtime.{1}Adapter.ToLocalJniHandle ({2});", + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), + base_name, + opt.GetSafeIdentifier (var_name)), + }; + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + return new string[]{ + string.Format ("JNIEnv.DeleteLocalRef ({0});", + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))), + }; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return new string[]{ + string.Format ("var {0} = global::Android.Runtime.{1}Invoker.FromJniHandle ({2}, {3});", + var_name, + base_name, + opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), + owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"), + }; + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return new string [0]; + } + + public bool NeedsPrep { get { return true; } } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StringSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StringSymbol.cs new file mode 100644 index 00000000000..093ea470ec4 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StringSymbol.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +using MonoDroid.Utils; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class StringSymbol : ISymbol { + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return "string"; } + } + + public bool IsGeneric { + get { return false; } + } + + public string JavaName { + get { return "java.lang.String"; } + } + + public string JniName { + get { return "Ljava/lang/String;"; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"{variable}.PeerReference"; + } + return $"((global::Java.Lang.Object) {variable}).Handle"; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return String.Format ( + "global::Java.Interop.JniEnvironment.Strings.ToString (ref {0}, JniObjectReferenceOptions.{1})", + var_name, + owned ? "CopyAndDispose" : "Copy"); + } + return String.Format ("JNIEnv.GetString ({0}, {1})", var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + + public string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return String.Format ("global::Java.Interop.JniEnvironment.Strings.NewString ({0})", var_name); + } + return String.Format ("JNIEnv.NewString ({0})", var_name); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return new string [0]; + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + string native_name = opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return new[]{ + $"global::Java.Interop.JniObjectReference.Dispose (ref {native_name});", + }; + } + return new string[]{ + string.Format ("JNIEnv.DeleteLocalRef ({0});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))), + }; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return new string[] { String.Format ("var {0} = JNIEnv.GetString ({1}, JniHandleOwnership.DoNotTransfer);", opt.GetSafeIdentifier (var_name), opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))) }; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + string managed_name = opt.GetSafeIdentifier (var_name); + string native_name = opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return new[]{ + $"var {native_name} = global::Java.Interop.JniEnvironment.Strings.NewString ({managed_name});", + }; + } + return new[]{ + $"IntPtr {native_name} = JNIEnv.NewString ((string{opt.NullableOperator}){managed_name});", + }; + } + + public bool NeedsPrep { get { return true; } } + } +} + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs new file mode 100644 index 00000000000..3d93535630a --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs @@ -0,0 +1,382 @@ +using System; +using System.Linq; +using System.Text; +using System.Collections.Generic; +using System.Collections.Concurrent; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class SymbolTable { + + // The symbols dictionary may contain shallow types (types that have not populated Ctors/Methods/Fields). + // If you make any changes to the SymbolTable class that accesses the symbols you need to keep + // that in mind. Also if you add any new public methods that expose symbols from the table you must + // EnsurePopulated them before letting them leave this class. + ConcurrentDictionary> symbols = new ConcurrentDictionary> (); + + ISymbol char_seq; + ISymbol fileinstream_sym; + ISymbol fileoutstream_sym; + ISymbol instream_sym; + ISymbol outstream_sym; + ISymbol xmlpullparser_sym; + ISymbol xmlresourceparser_sym; + ISymbol string_sym; + + CodeGenerationTarget target; + + static readonly string[] InvariantSymbols = new string[]{ + "Android.Graphics.Color", + "boolean", + "byte", + "char", + "double", + "float", + "int", + "long", + "short", + "ubyte", + "uint", + "ulong", + "ushort", + "void", + }; + + public IEnumerable AllRegisteredSymbols (CodeGenerationOptions options) + { + if (options.UseShallowReferencedTypes) + throw new InvalidOperationException ("Not safe to retrieve all registered symbols when using shallow types."); + + return symbols.Values.SelectMany (v => v); + } + + public SymbolTable (CodeGenerationTarget target) + { + this.target = target; + + AddType (new SimpleSymbol ("IntPtr.Zero", "void", "void", "V")); + AddType (new SimpleSymbol ("false", "boolean", "bool", "Z", "sbyte", from_fmt: "{0} != 0", to_fmt: "{0} ? (sbyte)1 : (sbyte)0") { OnlyFormatOnMarshal = true }); + AddType (new SimpleSymbol ("0", "byte", "sbyte", "B")); + AddType (new SimpleSymbol ("(char)0", "char", "char", "C", "ushort", from_fmt: "(char){0}", to_fmt: "(ushort){0}") { OnlyFormatOnMarshal = true }); + AddType (new SimpleSymbol ("0.0", "double", "double", "D")); + AddType (new SimpleSymbol ("0.0F", "float", "float", "F")); + AddType (new SimpleSymbol ("0", "int", "int", "I")); + AddType (new SimpleSymbol ("0L", "long", "long", "J")); + AddType (new SimpleSymbol ("0", "short", "short", "S")); + AddType (new SimpleSymbol ("0", "uint", "uint", "I", returnCast: "(uint)")); + AddType (new SimpleSymbol ("0", "ushort", "ushort", "S", returnCast: "(ushort)")); + AddType (new SimpleSymbol ("0", "ulong", "ulong", "J", returnCast: "(ulong)")); + AddType (new SimpleSymbol ("0", "ubyte", "byte", "B", returnCast: "(byte)")); + char_seq = new CharSequenceSymbol (); + string_sym = new StringSymbol (); + if (target == CodeGenerationTarget.JavaInterop1) { + return; + } + AddType ("Android.Graphics.Color", new ColorSymbol ()); + instream_sym = new StreamSymbol ("InputStream"); + outstream_sym = new StreamSymbol ("OutputStream"); + fileinstream_sym = new StreamSymbol ("FileInputStream", "InputStream"); + fileoutstream_sym = new StreamSymbol ("FileOutputStream", "OutputStream"); + xmlpullparser_sym = new XmlPullParserSymbol (); + xmlresourceparser_sym = new XmlResourceParserSymbol (); + } + + // Extract symbol information + // java_type: "foo.Bar[]>[]..." + // returns: "foo.Bar" + // type_params: "[]>" + // arrayRank: 2 + // has_ellipsis: true + public string GetSymbolInfo (string java_type, out string type_params, out int arrayRank, out bool has_ellipsis) + { + type_params = string.Empty; + arrayRank = 0; + has_ellipsis = false; + + if (string.IsNullOrEmpty (java_type)) + return java_type; + + var erased = new StringBuilder (java_type.Length); + int ltCount = 0; + for (int i = 0; i < java_type.Length; ++i) { + char c = java_type [i]; + switch (c) { + case '<': + ltCount++; + type_params += c; + break; + case '>': + ltCount--; + type_params += c; + break; + case '[': + if (ltCount == 0) + arrayRank++; + goto case ']'; + case ']': + if (ltCount > 0) + type_params += c; + break; + default: + if (ltCount == 0) + erased.Append (c); + else + type_params += c; + break; + } + } + + has_ellipsis = erased.Length > 3 && + erased [erased.Length-1] == '.' && + erased [erased.Length-2] == '.' && + erased [erased.Length-3] == '.'; + if (has_ellipsis) { + arrayRank++; + erased.Length -= 3; + } + + return erased.ToString (); + } + + public void AddType (ISymbol symbol) + { + string dummy; + int ar; + bool he; + string key = symbol.IsEnum ? symbol.FullName : GetSymbolInfo (symbol.JavaName, out dummy, out ar, out he); + + AddType (key, symbol); + } + + bool ShouldAddType (string key) + { + if (!symbols.ContainsKey (key)) + return true; + if (Array.BinarySearch (InvariantSymbols, key, StringComparer.OrdinalIgnoreCase) >= 0) + return false; + return true; + } + + public void AddType (string key, ISymbol symbol) + { + if (!ShouldAddType (key)) + return; + + symbols.AddOrUpdate (key, + (value) => { + // Key not found, add it to Dictionary + lock (cache_population_lock) + all_symbols_cache = null; + + return new List { symbol }; + }, + (value, list) => { + // Key already exists, add it to List + if (!list.Any (v => object.ReferenceEquals (v, symbol))) + list.Add (symbol); + + return list; + }); + } + + public ISymbol Lookup (string java_type, GenericParameterDefinitionList in_params) + { + string type_params; + int arrayRank; + bool has_ellipsis; + string key = GetSymbolInfo (java_type, out type_params, out arrayRank, out has_ellipsis); + + // FIXME: we should make sure to differentiate those ref types IF we use those modifiers in the future. + switch (key [key.Length - 1]) { + case '&': // managed ref type + case '*': // managed (well, unmanaged...) pointer type + key = key.Substring (0, key.Length - 1); + break; + } + key = TypeNameUtilities.FilterPrimitiveFullName (key) ?? key; + + if (target == CodeGenerationTarget.JavaInterop1) { + if (key == "java.lang.CharSequence") { + return CreateArray (char_seq, arrayRank, has_ellipsis); + } + if (key == "java.lang.String") { + return CreateArray (string_sym, arrayRank, has_ellipsis); + } + } + + switch (this.target != CodeGenerationTarget.JavaInterop1 ? key : null) { + case "android.content.res.XmlResourceParser": + return CreateArray (xmlresourceparser_sym, arrayRank, has_ellipsis); + case "org.xmlpull.v1.XmlPullParser": + return CreateArray (xmlpullparser_sym, arrayRank, has_ellipsis); + case "java.io.FileInputStream": + return CreateArray (fileinstream_sym, arrayRank, has_ellipsis); + case "java.io.FileOutputStream": + return CreateArray (fileoutstream_sym, arrayRank, has_ellipsis); + case "java.io.InputStream": + return CreateArray (instream_sym, arrayRank, has_ellipsis); + case "java.io.OutputStream": + return CreateArray (outstream_sym, arrayRank, has_ellipsis); + case "java.lang.CharSequence": + return CreateArray (char_seq, arrayRank, has_ellipsis); + case "java.lang.String": + return CreateArray (string_sym, arrayRank, has_ellipsis); + case "java.util.List": + case "java.util.ArrayList": + case "System.Collections.IList": + return CreateArray (new CollectionSymbol (key, "IList", "Android.Runtime.JavaList", type_params), arrayRank, has_ellipsis); + case "java.util.Map": + case "java.util.HashMap": + case "java.util.SortedMap": + case "System.Collections.IDictionary": + return CreateArray (new CollectionSymbol (key, "IDictionary", "Android.Runtime.JavaDictionary", type_params), arrayRank, has_ellipsis); + case "java.util.Set": + return CreateArray (new CollectionSymbol (key, "ICollection", "Android.Runtime.JavaSet", type_params), arrayRank, has_ellipsis); + case "java.util.Collection": + case "System.Collections.ICollection": + return CreateArray (new CollectionSymbol (key, "ICollection", "Android.Runtime.JavaCollection", type_params), arrayRank, has_ellipsis); + default: + break; + } + + ISymbol result; + var gpd = in_params != null ? in_params.FirstOrDefault (t => t.Name == key) : null; + if (gpd != null) { + result = new GenericTypeParameter (gpd); + } + else + result = Lookup (key + type_params); + + return CreateArray (result, arrayRank, has_ellipsis); + } + + ISymbol CreateArray (ISymbol symbol, int rank, bool has_ellipsis) + { + if (symbol == null) + return null; + + ArraySymbol r = null; + while (rank-- > 0) + symbol = r = new ArraySymbol (symbol, target); + if (r != null) + r.IsParams = has_ellipsis; + return symbol; + } + + ConcurrentDictionary all_symbols_cache; + static object cache_population_lock = new object (); + + public ISymbol Lookup (string java_type) + { + string type_params; + int ar; + bool he; + string key = GetSymbolInfo (java_type, out type_params, out ar, out he); + ISymbol sym; + List values; + if (symbols.TryGetValue (key, out values)) { + sym = values [values.Count-1]; + } else { + // Note we're potentially searching shallow types, but this is only looking at the type name + // Anything we find we will populate before returning to the user + + lock (cache_population_lock) { + if (all_symbols_cache == null) + all_symbols_cache = new ConcurrentDictionary (symbols.Values.SelectMany (v => v).GroupBy (s => s.FullName).ToDictionary (s => s.Key, s => s.FirstOrDefault ())); + + if (!all_symbols_cache.TryGetValue (key, out sym)) { + // We may be looking for a type like: + // - System.Collections.Generic.IList + // Our key is "System.Collections.Generic.IList", but it's stored in + // the symbol table with the arity so we need to look for + // "System.Collections.Generic.IList`1" to find a match + key = AddArity (key, type_params); + all_symbols_cache.TryGetValue (key, out sym); + } + } + } + ISymbol result; + if (sym != null) { + if (type_params.Length > 0) { + GenBase gen = sym as GenBase; + + EnsurePopulated (gen); + + if (gen != null && gen.IsGeneric) + result = new GenericSymbol (gen, type_params); + // In other case, it is still valid to derive from non-generic type. + // Generics are likely removed but we should not invalidate such derived classes. + else + result = gen; + } + // disable this condition; consider that "java.lang.Class[]" can be specified as a parameter type + //else if (sym is GenBase && (sym as GenBase).IsGeneric) + // return null; + else + result = sym; + } else + return null; + + if (result is GenBase gen_base) + EnsurePopulated (gen_base); + + return result; + } + + private string AddArity (string key, string typeParams) + { + if (string.IsNullOrWhiteSpace (typeParams) || !typeParams.StartsWith ("<", StringComparison.Ordinal) || !typeParams.EndsWith (">", StringComparison.Ordinal)) + return key; + + var nested_count = 0; + var arity = 1; + + // Remove the outer <> + typeParams = typeParams.Substring (1, typeParams.Length - 2); + + foreach (var c in typeParams) { + if (c == '>') + nested_count--; + + if (c == '<') + nested_count++; + + if (nested_count == 0 && c == ',') + arity++; + } + + return $"{key}`{arity}"; + } + + public void Dump () + { + foreach (var p in symbols) { + if (p.Key.StartsWith ("System", StringComparison.Ordinal)) + continue; + foreach (var s in p.Value) { + Console.Error.WriteLine ("[{0}]: {1} {2}", p.Key, s.GetType (), s.FullName); + } + } + } + + static readonly object populate_lock = new object (); + + void EnsurePopulated (GenBase gen) + { + if (gen == null || !gen.IsShallow) + return; + + foreach (var nested in gen.NestedTypes) + EnsurePopulated (nested); + + // We need to fully populate this shallow type + lock (populate_lock) { + gen.PopulateAction (); + gen.IsShallow = false; + gen.PopulateAction = null; + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlPullParserSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlPullParserSymbol.cs new file mode 100644 index 00000000000..a2b4e14663e --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlPullParserSymbol.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class XmlPullParserSymbol : ISymbol { + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return "System.Xml.XmlReader"; } + } + + public bool IsGeneric { + get { return false; } + } + + public string JavaName { + get { return "org.xmlpull.v1.XmlPullParser"; } + } + + public string JniName { + get { return "Lorg/xmlpull/v1/XmlPullParser;"; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"{variable}.PeerReference"; + } + return $"((global::Java.Lang.Object) {variable}).Handle"; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + return String.Format (opt.GetOutputName ("Android.Runtime.XmlPullParserReader") + ".FromJniHandle ({0}, {1})", var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + + public string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null) + { + return String.Format ("global::Android.Runtime.XmlReaderPullParser.ToLocalJniHandle ({0})", var_name); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return new string [0]; + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + return new string []{ + string.Format ("JNIEnv.DeleteLocalRef ({0});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))), + }; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return new string[] { String.Format ("var {0} = global::Android.Runtime.XmlPullParserReader.FromJniHandle ({1}, JniHandleOwnership.DoNotTransfer);", opt.GetSafeIdentifier (var_name), opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))) }; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + return new string[] { String.Format ("IntPtr {0} = global::Android.Runtime.XmlReaderPullParser.ToLocalJniHandle ({1});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), opt.GetSafeIdentifier (var_name)) }; + } + + public bool NeedsPrep { get { return true; } } + } +} + + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlResourceParserSymbol.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlResourceParserSymbol.cs new file mode 100644 index 00000000000..63569ae020c --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlResourceParserSymbol.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace MonoDroid.Generation { + + public class XmlResourceParserSymbol : ISymbol { + + public string DefaultValue { + get { return "IntPtr.Zero"; } + } + + public string FullName { + get { return "System.Xml.XmlReader"; } + } + + public bool IsGeneric { + get { return false; } + } + + public string JavaName { + get { return "android.content.res.XmlResourceParser"; } + } + + public string JniName { + get { return "Landroid/content/res/XmlResourceParser;"; } + } + + public string NativeType { + get { return "IntPtr"; } + } + + public bool IsEnum { + get { return false; } + } + + public bool IsArray { + get { return false; } + } + + public string ElementType { + get { return null; } + } + + public string ReturnCast => string.Empty; + + public string GetObjectHandleProperty (CodeGenerationOptions opt, string variable) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + return $"{variable}.PeerReference"; + } + return $"((global::Java.Lang.Object) {variable}).Handle"; + } + + public string GetGenericType (Dictionary mappings) + { + return null; + } + + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + { + return String.Format (opt.GetOutputName ("Android.Runtime.XmlResourceParserReader") + ".FromJniHandle ({0}, {1})", var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); + } + + public string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null) + { + return String.Format ("global::Android.Runtime.XmlReaderResourceParser.ToLocalJniHandle ({0})", var_name); + } + + public bool Validate (CodeGenerationOptions opt, GenericParameterDefinitionList type_params, CodeGeneratorContext context) + { + return true; + } + + public string Call (CodeGenerationOptions opt, string var_name) + { + return opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)); + } + + public string[] PostCallback (CodeGenerationOptions opt, string var_name) + { + return new string [0]; + } + + public string[] PostCall (CodeGenerationOptions opt, string var_name) + { + return new string []{ + string.Format ("JNIEnv.DeleteLocalRef ({0});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))), + }; + } + + public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool owned) + { + return new string[] { String.Format ("var {0} = global::Android.Runtime.XmlResourceParserReader.FromJniHandle ({1}, JniHandleOwnership.DoNotTransfer);", opt.GetSafeIdentifier (var_name), opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name))) }; + } + + public string[] PreCall (CodeGenerationOptions opt, string var_name) + { + return new string[] { String.Format ("IntPtr {0} = global::Android.Runtime.XmlReaderResourceParser.ToLocalJniHandle ({1});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), opt.GetSafeIdentifier (var_name)) }; + } + + public bool NeedsPrep { get { return true; } } + } +} + + diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiTransform.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiTransform.cs new file mode 100644 index 00000000000..ce9c738e314 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiTransform.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace MonoDroid.Generation +{ + public class ApiTransform + { + public bool PreserveType { get; set; } + public string Version { get; set; } + public string Package { get; set; } + public string Class { get; set; } + public string Member { get; set; } + public string Parameter { get; set; } + public string Enum { get; set; } + + public ApiTransform (bool preserveType, string[] args) + { + PreserveType = preserveType; + Version = args[0].Trim (); + Package = args[1].Trim (); + Class = args[2].Trim (); + Member = args[3].Trim (); + Parameter = args[4].Trim (); + Enum = args[5].Trim (); + } + + public void WriteTransform (StreamWriter sw) + { + string preserveAttr = PreserveType ? " preserveType=\"true\"" : null; + + string cls = Class.StartsWith ("[Interface]", StringComparison.Ordinal) ? Class.Substring ("[Interface]".Length) : Class; + + if (string.IsNullOrEmpty (Parameter)) { + // This is a field + sw.WriteLine (" {3}", Package, Class, Member, Enum, preserveAttr); + } else if (Parameter == "return") { + // This is the return type + sw.WriteLine (" {3}", Package, cls, Member, Enum, preserveAttr); + } else if (Member == "ctor" || Member == "constructor") { + // This is the return type + sw.WriteLine (" {3}", Package, cls, Parameter, Enum, preserveAttr); + } else { + // This is a parameter + sw.WriteLine (" {4}", Package, cls, Member, Parameter, Enum, preserveAttr); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiXmlAdjuster.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiXmlAdjuster.cs new file mode 100644 index 00000000000..dff3e8f5a05 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/ApiXmlAdjuster.cs @@ -0,0 +1,34 @@ +using System; +using MonoDroid.Generation; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public class Adjuster + { + public void Process (string inputXmlFile, CodeGenerationOptions opt, GenBase [] gens, string outputXmlFile, int reportVerbosity) + { + switch (reportVerbosity) { + case 0: + break; + case 1: + Log.Verbosity = Log.LoggingLevel.Error; + break; + case 2: + Log.Verbosity = Log.LoggingLevel.Warning; + break; + default: + Log.Verbosity = Log.LoggingLevel.Debug; + break; + } + var api = new JavaApi (); + api.LoadReferences (opt, gens); + api.Load (inputXmlFile); + api.StripNonBindables (); + api.Resolve (); + api.CreateGenericInheritanceMapping (); + api.MarkOverrides (); + api.FindDefects (); + api.Save (outputXmlFile); + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs new file mode 100644 index 00000000000..58920379913 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMap.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Xml; + +using Xamarin.Android; +using Java.Interop.Tools.Generator; + +namespace MonoDroid.Generation +{ + partial class EnumMappings + { + private string output_dir; + private string output_metadata; + private List> remove_nodes; + private AndroidSdkVersion version; + private bool fix_constants_instead_of_removing; + + public EnumMappings (string outputDir, string outputMetadata, string version, bool fixConstantsInsteadOfRemove) + { + output_dir = outputDir; + output_metadata = outputMetadata; + this.version = version == null ? default : AndroidSdkVersion.Parse (version); + fix_constants_instead_of_removing = fixConstantsInsteadOfRemove; + } + + internal Dictionary Process (string fieldMap, string flagsFile, string methodMap) + { + remove_nodes = new List> (); + var enums = (fieldMap ?? "").EndsWith (".csv", StringComparison.OrdinalIgnoreCase) + ? ParseFieldMappings (fieldMap, flagsFile, version, remove_nodes) + : ParseXmlFieldMappings (fieldMap, version, remove_nodes); + + var methods = (methodMap ?? "").EndsWith (".csv", StringComparison.OrdinalIgnoreCase) + ? ParseMethodMappings (methodMap, version) + : ParseXmlMethodMappings (methodMap, version); + + // Create output metadata file + Directory.CreateDirectory (output_dir); + using (StreamWriter sw = new StreamWriter (output_metadata, false)) { + sw.WriteLine (""); + WriteEnumerationRegistrations (sw, enums); + + foreach (var m in methods) + m.WriteTransform (sw); + + if (fix_constants_instead_of_removing) + FixOldConstants (sw); + else + RemoveOldConstants (sw); + + sw.WriteLine (""); + } + return enums; + } + + // + void RemoveOldConstants (StreamWriter sw) + { + foreach (var e in remove_nodes) { + string enu = e.Key; + string package, type, member; + ParseJniMember (enu, out package, out type, out member); + try { + sw.WriteLine (" ", + package, type, member, enu.StartsWith ("I:", StringComparison.Ordinal) ? "interface" : "class"); + } catch (Exception ex) { + Report.LogCodedErrorAndExit (Report.ErrorFailedToRemoveConstants, ex, enu); + throw; + } + } + } + + void FixOldConstants (StreamWriter sw) + { + foreach (var pair in remove_nodes) { + var enu = pair.Key; + + string package, type, member; + ParseJniMember (enu, out package, out type, out member); + + if (pair.Value != null) { + sw.WriteLine (" {4}", + package, type, member, enu.StartsWith ("I:", StringComparison.Ordinal) ? "interface" : "class", pair.Value); + sw.WriteLine (" This constant will be removed in the future version. Use {4} enum directly instead of this field.", + package, type, member, enu.StartsWith ("I:", StringComparison.Ordinal) ? "interface" : "class", pair.Value); + sw.WriteLine (" true", + package, type, member, enu.StartsWith ("I:", StringComparison.Ordinal) ? "interface" : "class", pair.Value); + continue; + } + try { + sw.WriteLine (" ", + package, type, member, enu.StartsWith ("I:", StringComparison.Ordinal) ? "interface" : "class"); + } catch (Exception ex) { + Report.LogCodedErrorAndExit (Report.ErrorFailedToRemoveConstants, ex, enu); + throw; + } + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs new file mode 100644 index 00000000000..425fffb01f1 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/EnumMappings.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.Generator.Enumification; +using Mono.Options; + +using Xamarin.Android.Tools; + +namespace MonoDroid.Generation { + + partial class EnumMappings { + + public class EnumDescription { + public List Members = new List (); + public bool BitField; + public bool FieldsRemoved; + } + + internal Dictionary ParseXmlFieldMappings (string csv, AndroidSdkVersion filter_version, IList> remove_nodes) + { + return ParseFieldMappings (FieldXmlToCsv (csv), null, filter_version, remove_nodes); + } + + internal Dictionary ParseFieldMappings (string csv, string flagsFile, AndroidSdkVersion filter_version, IList> remove_nodes) + { + if (csv == null) + return new Dictionary (); + using (var csr = new StreamReader (csv)) + return ParseFieldMappings (csr, flagsFile != null ? File.ReadAllLines (flagsFile) : null, filter_version, remove_nodes); + } + + // key: Enum name + // value: Dictionary: + // key: enum element name + // value: enum element value + internal Dictionary ParseFieldMappings (TextReader source, string [] enumFlags, AndroidSdkVersion filter_version, IList> remove_nodes) + { + var enums = new Dictionary (); + + if (source == null) + return enums; + + var constants = ConstantsParser.FromEnumMapCsv (source); + + // Discard ignored constants + constants = constants.Where (c => + c.Action.In (ConstantAction.Enumify, ConstantAction.Add, ConstantAction.Remove) && + (c.ApiLevel == 0 || c.ApiLevel <= filter_version)).ToList (); + + // Find the constant fields we need remove + foreach (var constant in constants.Where (c => c.Action.In (ConstantAction.Enumify, ConstantAction.Remove))) + remove_nodes.Add (new KeyValuePair (constant.JavaSignature, constant.FieldAction == FieldAction.Remove && constant.EnumFullType.HasValue () ? constant.EnumFullType : null)); + + // Find the enumerations that we need to create + foreach (var group in constants.Where (c => c.Action.In (ConstantAction.Enumify, ConstantAction.Add)).GroupBy (c => c.EnumFullType)) { + + var desc = new EnumDescription { + FieldsRemoved = group.Any (c => c.FieldAction != FieldAction.Remove), + BitField = group.Any (c => c.IsFlags) || enumFlags?.Contains (group.Key) == true + }; + + desc.Members.AddRange (group); + + enums.Add (group.Key, desc); + } + + return enums; + } + + internal void ParseJniMember (string jniMember, out string package, out string type, out string member) + { + try { + DoParseJniMember (jniMember, out package, out type, out member); + } catch (Exception ex) { + throw new Exception (string.Format ("failed to parse enum mapping: JNI member: {0}", jniMember, ex)); + } + } + + static void DoParseJniMember (string jniMember, out string package, out string type, out string member) + { + int endPackage = jniMember.LastIndexOf ('/'); + int endClass = jniMember.LastIndexOf ('.'); + + package = jniMember.Substring (0, endPackage).Replace ('/', '.'); + if (package.StartsWith ("I:", StringComparison.Ordinal)) + package = package.Substring (2); + + if (endClass >= 0) { + type = jniMember.Substring (endPackage + 1, endClass - endPackage - 1).Replace ('$', '.'); + member = jniMember.Substring (endClass + 1); + } else { + type = jniMember.Substring (endPackage + 1).Replace ('$', '.'); + member = ""; + } + } + + internal List WriteEnumerations (string output_dir, Dictionary enums, GenBase [] gens, CodeGenerationOptions opt) + { + bool useShortFileNames = opt.UseShortFileNames; + if (!Directory.Exists (output_dir)) + Directory.CreateDirectory (output_dir); + + var files = new ConcurrentBag (); + + Parallel.ForEach (enums, enu => { + var path = Path.Combine (output_dir, GetFileName (enu.Key, useShortFileNames) + ".cs"); + files.Add (path); + + using (var sw = File.CreateText (path)) { + var generator = new EnumGenerator (sw); + generator.WriteEnumeration (opt, enu, gens); + } + }); + + return files.ToList (); + } + + readonly Dictionary file_name_map = new Dictionary (); + + string GetFileName (string file, bool useShortFileNames) + { + if (!useShortFileNames) + return file; + string s; + + lock (file_name_map) { + if (file_name_map.TryGetValue (file, out s)) + return s; + s = file_name_map.Count.ToString (); + file_name_map [file] = s; + } + + return s; + } + + internal void WriteEnumerationRegistrations (StreamWriter sw, Dictionary enums) + { + foreach (var enu in enums) + sw.WriteLine (" ", enu.Key); + } + + StringReader MethodXmlToCsv (string file) + { + if (file == null) + return null; + + var sw = new StringWriter (); + var doc = XDocument.Load (file, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo); + foreach (XElement e in doc.XPathSelectElements ("/enum-method-mappings/mapping")) { + string version = e.XGetAttribute ("api-level"); + string package = null; + string java_class = null; + if (e.Attribute ("jni-class") != null) { + string c = e.XGetAttribute ("jni-class"); + int s = c.LastIndexOf ('/'); + package = c.Substring (0, s).Replace ('/', '.'); + java_class = c.Substring (s+1).Replace ('$', '.'); + } else if (e.Attribute ("jni-interface") != null) { + string c = e.XGetAttribute ("jni-interface"); + int s = c.LastIndexOf ('/'); + package = c.Substring (0, s).Replace ('/', '.'); + java_class = "[Interface]" + c.Substring (s+1).Replace ('$', '.'); + } else { + throw new InvalidOperationException (string.Format ("Missing mandatory attribute 'jni-class' or 'jni-interface' on a mapping element: {0}", e)); + } + + foreach (var m in e.XPathSelectElements ("method")) { + string method = GetMandatoryAttribute (m, "jni-name"); + string parameter = GetMandatoryAttribute (m, "parameter"); + string enum_type = GetMandatoryAttribute (m, "clr-enum-type"); + + sw.WriteLine ("{0}, {1}, {2}, {3}, {4}, {5}", String.IsNullOrEmpty (version) ? "0" : version, package, java_class, method, parameter, enum_type); + } + } + return new StringReader (sw.ToString ()); + } + + internal List ParseXmlMethodMappings (string file, AndroidSdkVersion filter_version) + { + return ParseMethodMappings (MethodXmlToCsv (file), filter_version); + } + + internal List ParseMethodMappings (string file, AndroidSdkVersion filter_version) + { + if (file == null) + return new List (); + using (StreamReader sr = new StreamReader (file)) + return ParseMethodMappings (sr, filter_version); + } + + internal List ParseMethodMappings (TextReader source, AndroidSdkVersion filter_version) + { + var list = new List (); + if (source == null) + return list; + + string s; + bool preserveTypeMode = false; + + while ((s = source.ReadLine ()) != null) { + if (s.Trim () == "---- PRESERVE TYPE MODE ----") + preserveTypeMode = true; + + if (s.Length == 0 || s.StartsWith ("//", StringComparison.Ordinal)) + continue; + var items = s.Split (','); + AndroidSdkVersion ver; + if (filter_version > 0 && + AndroidSdkVersion.TryParse (items [0], out ver) && + filter_version < ver) + continue; + try { + list.Add (new ApiTransform (preserveTypeMode, items)); + } catch (Exception ex) { + Report.LogCodedErrorAndExit (Report.ErrorFailedToProcessEnumMap, ex, s); + throw; + } + } + + return list; + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs new file mode 100644 index 00000000000..bf830145777 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/JavaTypeResolutionFixups.cs @@ -0,0 +1,93 @@ +using System; +using System.IO; +using System.Linq; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Generator; +using Java.Interop.Tools.JavaTypeSystem; +using Xamarin.Android.Binder; + +namespace generator +{ + public static class JavaTypeResolutionFixups + { + [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] + public static void Fixup (string xmlFile, string outputXmlFile, DirectoryAssemblyResolver resolver, string [] references) => throw new NotSupportedException (); + + // This fixup ensures all referenced Java types can be resolved, and + // removes types and members that rely on unresolvable Java types. + public static void Fixup (string xmlFile, string outputXmlFile, DirectoryAssemblyResolver resolver, string [] references, TypeDefinitionCache cache, CodeGeneratorOptions opt) + { + // Parse api.xml + var type_collection = JavaXmlApiImporter.Parse (xmlFile); + var options = new ApiImporterOptions (); + + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + options.SupportedTypeMapAttributes.Clear (); + options.SupportedTypeMapAttributes.Add ("Java.Interop.JniTypeSignatureAttribute"); + } + + // Add in reference types from assemblies + foreach (var reference in references.Distinct ()) { + Report.Verbose (0, "Resolving assembly for Java type resolution: '{0}'.", reference); + var assembly = resolver.Load (reference); + + ManagedApiImporter.Parse (assembly, type_collection, cache, options); + } + + // Run the type resolution pass + var results = type_collection.ResolveCollection (); + + OutputResults (results, xmlFile, outputXmlFile); + + // Output the adjusted xml + JavaXmlApiExporter.Save (type_collection, outputXmlFile); + } + + static void OutputResults (CollectionResolutionResults results, string xmlFile, string outputXmlFile) + { + if (results.Count == 0) + return; + + var source = new SourceLineInfo (xmlFile); + + var first_cycle = results.First (); + + // The first cycle is more interesting to the user, as it is mainly external Java types + // that could not be resolved, which often point to a missing reference jar or NuGet. + // Thus, we're going to output these as warnings. + var missing_types = first_cycle.Unresolvables.Select (u => u.MissingType).Distinct ().OrderBy (t => t); + + foreach (var type in missing_types) + Report.LogCodedWarning (0, Report.WarningJavaTypeNotResolved, source, type); + + // The remaining cycles are generally just user types that are being removed because + // other user types have been removed. Since the root cause is actually the missing external + // types above, these aren't as important. We'll write them to a diagnostic file + // for the user to inspect for details if they want. + var report_file = Path.Combine (Path.GetDirectoryName (outputXmlFile), "java-resolution-report.log"); + + using (var tw = File.CreateText (report_file)) { + for (var i = 0; i < results.Count; i++) + WriteCycle (tw, i + 1, results [i]); + } + + // Output diagnostic messages to verbose log + foreach (var result in results.SelectMany (r => r.Unresolvables)) + Report.Verbose (0, result.GetDisplayMessage ()); + + // Let users know about this report + Report.LogCodedWarning (0, Report.WarningTypesNotBoundDueToMissingJavaTypes, new SourceLineInfo (report_file)); + } + + static void WriteCycle (StreamWriter writer, int index, CollectionResolutionResult result) + { + writer.WriteLine ($"==== Cycle {index} ===="); + writer.WriteLine (); + + foreach (var item in result.Unresolvables) + writer.WriteLine (item.GetDisplayMessage ()); + + writer.WriteLine (); + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/JavadocFixups.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/JavadocFixups.cs new file mode 100644 index 00000000000..c9eca4a247c --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/JavadocFixups.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +using Java.Interop.Tools.JavaSource; + +using MonoDroid.Generation; +using MonoDroid.Utils; + +using Xamarin.Android.Binder; + +namespace Java.Interop.Tools.Generator.Transformation +{ + public static class JavadocFixups + { + public static void Fixup (List gens, CodeGeneratorOptions options) + { + if (options.JavadocXmlFiles == null || options.JavadocXmlFiles.Count == 0) + return; + + var typeJavadocs = new Dictionary (); + + foreach (var path in options.JavadocXmlFiles) { + XDocument doc = null; + try { + doc = XDocument.Load (path); + } + catch (Exception e) { + Report.LogCodedWarning (0, Report.WarningInvalidXmlFile, e, path, e.Message); + continue; + } + + var types = doc.Elements ("api") + .Elements ("package") + .Elements (); + foreach (var typeXml in types) { + var typeJniSig = (string) typeXml.Attribute ("jni-signature"); + if (string.IsNullOrEmpty (typeJniSig)) + continue; + if (!typeJavadocs.TryGetValue (typeJniSig, out _)) + typeJavadocs.Add (typeJniSig, typeXml); + } + } + + foreach (var type in gens) { + AddJavadoc (type, typeJavadocs, options.XmldocStyle); + foreach (var nested in type.NestedTypes) { + AddJavadoc (nested, typeJavadocs, options.XmldocStyle); + } + } + } + + static void AddJavadoc (GenBase type, Dictionary typeJavadocs, XmldocStyle style) + { + if (!typeJavadocs.TryGetValue (type.JniName, out XElement typeJavadoc)) + return; + if (typeJavadoc == null) + return; + + if (type.JavadocInfo == null) { + type.JavadocInfo = JavadocInfo.CreateInfo (typeJavadoc, style); + } + + foreach (var method in type.Methods) { + if (method.JavadocInfo != null) + continue; + var methodJavadoc = GetMemberJavadoc (typeJavadoc, "method", method.JavaName, method.JniSignature); + method.JavadocInfo = JavadocInfo.CreateInfo (methodJavadoc?.Parent, style); + } + + foreach (var property in type.Properties) { + if (property.Getter != null && property.Getter.JavadocInfo == null) { + var getterJavadoc = GetMemberJavadoc (typeJavadoc, "method", property.Getter.JavaName, property.Getter.JniSignature); + property.Getter.JavadocInfo = JavadocInfo.CreateInfo (getterJavadoc?.Parent, style, appendCopyrightExtra: false); + } + if (property.Setter != null && property.Setter.JavadocInfo == null) { + var setterJavadoc = GetMemberJavadoc (typeJavadoc, "method", property.Setter.JavaName, property.Setter.JniSignature); + property.Setter.JavadocInfo = JavadocInfo.CreateInfo (setterJavadoc?.Parent, style, appendCopyrightExtra: false); + } + } + + foreach (var field in type.Fields) { + if (field.JavadocInfo != null) + continue; + var fieldJavadoc = GetMemberJavadoc (typeJavadoc, "field", field.JavaName, field.JniSignature); + field.JavadocInfo = JavadocInfo.CreateInfo (fieldJavadoc?.Parent, style); + } + + if (type is ClassGen @class) { + foreach (var ctor in @class.Ctors) { + if (ctor.JavadocInfo != null) + continue; + var ctorJavadoc = GetMemberJavadoc (typeJavadoc, "constructor", null, ctor.JniSignature); + ctor.JavadocInfo = JavadocInfo.CreateInfo (ctorJavadoc?.Parent, style); + } + } + } + + static XElement GetMemberJavadoc (XElement typeJavadoc, string elementName, string name, string jniSignature) + { + return typeJavadoc + .Elements (elementName) + .Where (e => jniSignature == (string) e.Attribute ("jni-signature") && + (name == null ? true : name == (string) e.Attribute ("name"))) + .Elements ("javadoc") + .FirstOrDefault (); + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/KotlinFixups.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/KotlinFixups.cs new file mode 100644 index 00000000000..5d068acdaae --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/KotlinFixups.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using MonoDroid.Utils; + +namespace Java.Interop.Tools.Generator.Transformation +{ + public static class KotlinFixups + { + public static void Fixup (List gens) + { + foreach (var c in gens.OfType ()) + FixupClass (c); + foreach (var i in gens.OfType ()) + FixupInterface (i); + } + + private static void FixupClass (ClassGen c) + { + // Kotlin mangles the name of some methods to make them + // inaccessible from Java, like `add-impl` and `add-V5j3Lk8`. + // We need to generate C# compatible names as well as prevent overriding + // them as we cannot generate JCW for them. + + var mangled = c.Methods.Where (m => m.IsKotlinNameMangled).ToList (); + + foreach (var method in mangled) { + + // If the method is virtual, mark it as !virtual as it can't be overridden in Java + if (!method.IsFinal) + method.IsFinal = true; + + if (method.IsVirtual) + method.IsVirtual = false; + + FixMethodName (method); + } + + RemoveCollidingSiblings (c, mangled); + } + + private static void FixupInterface (InterfaceGen gen) + { + var mangled = gen.Methods.Where (m => m.IsKotlinNameMangled).ToList (); + + foreach (var method in mangled) + FixMethodName (method); + + RemoveCollidingSiblings (gen, mangled); + } + + // After the rename above, hash-mangled siblings can collide with each + // other AND with pre-existing non-mangled overloads. Both cases produce + // CS0111 in the generated code. Until step 2 of dotnet/java-interop#1431 + // projects inline-class params as strongly-typed wrappers, drop the + // mangled duplicate deterministically and warn so the user can override + // via Metadata.xml if desired. Non-mangled methods are always kept; only + // mangled methods are ever removed. + private static void RemoveCollidingSiblings (GenBase gen, List renamed) + { + if (renamed.Count == 0) + return; + + foreach (var method in renamed) { + // A mangled method is always the "lesser" choice compared to a + // real non-mangled Kotlin API, so drop it whenever ANY non-mangled + // overload matches — regardless of source order. + var nonMangledMatch = gen.Methods + .FirstOrDefault (m => m != method && !m.IsKotlinNameMangled + && m.Name == method.Name && m.Matches (method)); + if (nonMangledMatch == null) { + // Otherwise (only mangled siblings collide), keep the + // first-declared one and drop later mangled duplicates. + var earlierMangled = gen.Methods + .TakeWhile (m => m != method) + .FirstOrDefault (m => m.Name == method.Name && m.Matches (method)); + if (earlierMangled == null) + continue; + } + + Report.LogCodedWarning (0, Report.WarningKotlinNameMangledCollision, method, gen.FullName, method.Name, method.JavaName); + gen.Methods.Remove (method); + } + } + + private static void FixMethodName (Method method) + { + // Only run this if it's the default name (ie: not a user's "managedName") + if (method.Name == StringRocks.MemberToPascalCase (method.JavaName).Replace ('-', '_')) { + // We want to remove the hyphen and anything afterwards to fix mangled names, + // but a previous step converted it to an underscore. Remove the final + // underscore and anything after it. + var index = method.Name.IndexOf ("_impl", StringComparison.Ordinal); + + if (index >= 0) + method.Name = method.Name.Substring (0, index); + else + method.Name = method.Name.Substring (0, method.Name.Length - 8); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/SealedProtectedFixups.cs b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/SealedProtectedFixups.cs new file mode 100644 index 00000000000..d0454ecc761 --- /dev/null +++ b/external/Java.Interop/tools/generator/Java.Interop.Tools.Generator.Transformation/SealedProtectedFixups.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MonoDroid.Generation; + +namespace Java.Interop.Tools.Generator.Transformation +{ + public static class SealedProtectedFixups + { + public static void Fixup (List gens) + { + foreach (var c in gens.OfType ().Where (c => c.IsFinal)) { + foreach (var m in c.Methods.Where (m => m.Visibility == "protected" && !m.IsOverride)) + m.Visibility = "private"; + + foreach (var p in c.Properties.Where (p => p.Getter?.Visibility == "protected" && !p.Getter.IsOverride)) + p.Getter.Visibility = "private"; + + foreach (var p in c.Properties.Where (p => p.Setter?.Visibility == "protected" && !p.Setter.IsOverride)) + p.Setter.Visibility = "private"; + + foreach (var p in c.Fields.Where (f => f.Visibility == "protected")) + p.Visibility = "private"; + + foreach (var p in c.NestedTypes.Where (t => t.Visibility == "protected")) + p.Visibility = "private"; + } + } + } +} diff --git a/external/Java.Interop/tools/generator/ManagedTypeFinderGeneratorTypeSystem.cs b/external/Java.Interop/tools/generator/ManagedTypeFinderGeneratorTypeSystem.cs new file mode 100644 index 00000000000..5a1e5d8d05f --- /dev/null +++ b/external/Java.Interop/tools/generator/ManagedTypeFinderGeneratorTypeSystem.cs @@ -0,0 +1,158 @@ +#if GENERATOR +using System; +using System.Collections.Generic; +using System.Linq; +using MonoDroid.Generation; + +namespace Xamarin.AndroidTools.AnnotationSupport +{ + public class ManagedTypeFinderGeneratorTypeSystem : ManagedTypeFinderDefault + { + public ManagedTypeFinderGeneratorTypeSystem (GenBase [] types) + { + this.types = types; + } + + GenBase [] types; + + protected override void OnAnnotationsParsed (IEnumerable itemsToBeBound) + { + LoadManagedMappings (itemsToBeBound, types.Select (t => t.Wrap ()).ToArray ()); + } + + #region ManagedTypeFinder implementation + + public abstract class Wrapper + { + public T Value { get; set; } + } + + public class TType : Wrapper, IType { } + public class TDefinition : Wrapper, IDefinition { } + public class TProperty : Wrapper, IProperty { } + public class TMethodBase : Wrapper, IMethodBase { } + + public override string GetManagedName (ManagedTypeFinder.IType t) + { + return t.Value ().FullName; + } + + public override string GetJavaName (IDefinition f) + { + return f.Value ().JavaName; + } + + public override string GetJavaName (IType t) + { + return t.Value ().JavaName; + } + + public override IProperty GetAnnotatedField (IType t, string fieldName) + { + return GetField (t, fieldName).WrapAsProperty (); + } + + public override IDefinition GetDefinitionField (IType t, string fieldName) + { + return GetField (t, fieldName).WrapAsDefinition (); + } + + Field GetField (IType t, string fieldName) + { + return t.Value ().Fields.FirstOrDefault (f => f.JavaName == fieldName); + } + + public override TypeName [] GetParameterTypes (IMethodBase method) + { + return method.Value ().Parameters.Select (p => new TypeName () { Name = p.Type }).ToArray (); + } + + public override string GetPropertyName (IProperty m) + { + return m.Value ().Name; + } + + public override string GetDefinitionName (IDefinition m) + { + return m.Value ().Name; + } + + public override void SetName (ManagedMemberInfo destination, IType iType) + { + var type = iType.Value (); + destination.Type.Namespace = type.Namespace; + destination.Type.Name = type.Name.Replace ('/', '.'); + } + + public override IEnumerable GetFields (IType t) + { + return t.Value ().Fields.Select (f => f.WrapAsDefinition ()); + } + + public override string GetMethodName (IMethodBase m) + { + return m.Value ()?.Name; + } + + public override string GetFieldManagedTypeName (ManagedTypeFinder.IProperty property) + { + return property.Value ()?.TypeName; + } + + public override string GetMethodReturnManagedTypeName (IMethodBase method) + { + var m = method.Value (); + return m is Ctor ? null : ((Method) m)?.ManagedReturn; + } + + public override string GetParameterManagedTypeName (IMethodBase m, int index) + { + return m.Value ()?.Parameters [index]?.Type; + } + + public override IMethodBase GetMethod (IType iType, AnnotatedItem item) + { + var t = iType.Value (); + var list = t.GetMethods ().Where (m => item.MemberName == "#ctor" ? m is Ctor : m is Method); + var methods = list.Where (m => + (item.MemberName == "#ctor" && m is Ctor || m is Method && ((Method) m).JavaName == item.MemberName) && + m.Parameters.Count == item.Arguments.Length) + .ToArray (); + + var argTypeLists = methods.Select (m => new { Method = m, Jni = m is Ctor ? ((Ctor) m).JniSignature : ((Method) m).JniSignature}) + .Select (p => new { Method = p.Method, Arguments = p.Jni == null ? null : ParseJniMethodArgumentsSignature (p.Jni)}) + .ToArray (); + + // this .Replace() is needed so that T[] can match generic arguments + Func stripParamSuffix = s => s.Replace ("...", "").Replace ("[]", ""); + Func stripGenParams = s => s == null ? s : (s.Contains ('<') ? s.Substring (0, s.IndexOf ('<')) : s).Replace ("...", "[]"); + Func cmp = (v, w) => stripGenParams (v) == stripGenParams (w); + + for (int i = 0; i < argTypeLists.Length; i++) { + var argTypeListPair = argTypeLists [i]; + var argTypeList = argTypeListPair.Arguments; + if (argTypeList == null || item.Arguments.Length != argTypeList.Length) + continue; + + bool mismatch = false; + for (int a = 0; a < argTypeList.Length; a++) { + if (cmp (argTypeList [a], item.Arguments [a]) + || t.TypeParameters != null && t.TypeParameters.Any (ga => cmp (ga.Name, stripParamSuffix (item.Arguments [a]))) + || argTypeListPair.Method.GenericArguments != null && argTypeListPair.Method.GenericArguments.Any (ga => cmp (ga.Name, stripParamSuffix (item.Arguments [a])))) + continue; + mismatch = true; + break; + } + if (mismatch) + continue; + return methods [i].Wrap (); + } + Errors.Add ("warning: method overload not found: " + t.FullName + " member: " + item.FormatMember ()); + return null; + } + + #endregion + } +} + +#endif diff --git a/external/Java.Interop/tools/generator/Properties/AssemblyInfo.cs b/external/Java.Interop/tools/generator/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..0021446c82e --- /dev/null +++ b/external/Java.Interop/tools/generator/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("generator-Tests")] \ No newline at end of file diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/CustomAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/CustomAttr.cs new file mode 100644 index 00000000000..5ef54358f7f --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/CustomAttr.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class CustomAttr : AttributeWriter + { + public string Value { get; set; } + + public CustomAttr (string value) + { + Value = value; + } + + public override void WriteAttribute (CodeWriter writer) + { + writer.WriteLine (Value); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/DebuggerBrowsableAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/DebuggerBrowsableAttr.cs new file mode 100644 index 00000000000..ee984b1410f --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/DebuggerBrowsableAttr.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class DebuggerBrowsableAttr : AttributeWriter + { + public override void WriteAttribute (CodeWriter writer) + { + writer.WriteLine ("[global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/EditorBrowsableAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/EditorBrowsableAttr.cs new file mode 100644 index 00000000000..a965ac3a7ad --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/EditorBrowsableAttr.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class EditorBrowsableAttr : AttributeWriter + { + public override void WriteAttribute (CodeWriter writer) + { + writer.WriteLine ("[global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/FlagsAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/FlagsAttr.cs new file mode 100644 index 00000000000..a329ab052ec --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/FlagsAttr.cs @@ -0,0 +1,13 @@ +using System; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class FlagsAttr : AttributeWriter + { + public override void WriteAttribute (CodeWriter writer) + { + writer.WriteLine ("[System.Flags]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/GeneratedEnumAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/GeneratedEnumAttr.cs new file mode 100644 index 00000000000..15481851731 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/GeneratedEnumAttr.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class GeneratedEnumAttr : AttributeWriter + { + readonly bool is_return; + + public GeneratedEnumAttr (bool isReturn = false) => is_return = isReturn; + + public override void WriteAttribute (CodeWriter writer) + { + if (is_return) + writer.WriteLine ($"[return:global::Android.Runtime.GeneratedEnum]"); + else + writer.Write ($"[global::Android.Runtime.GeneratedEnum] "); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/IntDefinitionAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/IntDefinitionAttr.cs new file mode 100644 index 00000000000..380d2cbaa98 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/IntDefinitionAttr.cs @@ -0,0 +1,23 @@ +using System; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class IntDefinitionAttr : AttributeWriter + { + public string ManagedMember { get; set; } + public string JniField { get; set; } + + public IntDefinitionAttr (string managedMember, string jniField) + { + ManagedMember = managedMember; + JniField = jniField; + } + + public override void WriteAttribute (CodeWriter writer) + { + var member = ManagedMember is null ? "null" : "\"" + ManagedMember + "\""; + writer.WriteLine ($"[global::Android.Runtime.IntDefinition ({member}, JniField = \"{JniField}\")]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/ObsoleteAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/ObsoleteAttr.cs new file mode 100644 index 00000000000..b00ef50081b --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/ObsoleteAttr.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class ObsoleteAttr : AttributeWriter + { + public string Message { get; set; } + public bool IsError { get; set; } + + public ObsoleteAttr (string message = null, bool isError = false) + { + Message = message?.Replace ("\"", "\"\"").Trim (); + IsError = isError; + } + + public override void WriteAttribute (CodeWriter writer) + { + var content = string.Empty; + + if (Message != null || IsError) + content += $"@\"{Message}\""; + + if (IsError) + content += ", error: true"; + + if (content.HasValue ()) + writer.WriteLine ($"[global::System.Obsolete ({content})]"); + else + writer.WriteLine ("[global::System.Obsolete]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/ObsoletedOSPlatformAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/ObsoletedOSPlatformAttr.cs new file mode 100644 index 00000000000..f8e398f4dc3 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/ObsoletedOSPlatformAttr.cs @@ -0,0 +1,31 @@ +using System; +using Xamarin.SourceWriter; + +using Java.Interop.Tools.Generator; + +namespace generator.SourceWriters +{ + public class ObsoletedOSPlatformAttr : AttributeWriter + { + public string Message { get; set; } + public AndroidSdkVersion Version { get; } + + public ObsoletedOSPlatformAttr (string message, AndroidSdkVersion version) + { + Message = message; + Version = version; + } + + public override void WriteAttribute (CodeWriter writer) + { + var apiLevel = Version.MinorRelease == 0 + ? $"{Version.ApiLevel}.0" + : Version.ToString (); + + if (Message.HasValue ()) + writer.WriteLine ($"[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android{apiLevel}\", @\"{Message.Replace ("\"", "\"\"")}\")]"); + else + writer.WriteLine ($"[global::System.Runtime.Versioning.ObsoletedOSPlatform (\"android{apiLevel}\")]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/RegisterAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/RegisterAttr.cs new file mode 100644 index 00000000000..bad28fbc654 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/RegisterAttr.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class RegisterAttr : AttributeWriter + { + public string Name { get; set; } + public string Signature { get; set; } + public string Connector { get; set; } + public bool DoNotGenerateAcw { get; set; } + public string AdditionalProperties { get; set; } + public bool UseGlobal { get; set; } // TODO: Temporary for matching existing unit tests + public bool UseShortForm { get; set; } // TODO: Temporary for matching existing unit tests + public bool AcwLast { get; set; } // TODO: Temporary for matching existing unit tests + + public MemberTypes? MemberType { get; set; } + + public RegisterAttr (string name, string signature = null, string connector = null, bool noAcw = false, string additionalProperties = null) + { + Name = name; + Signature = signature; + Connector = connector; + DoNotGenerateAcw = noAcw; + AdditionalProperties = additionalProperties; + } + + public override void WriteAttribute (CodeWriter writer) + { + if (MemberType.HasValue) { + WriteJavaInterop1Attribute (writer); + return; + } + var sb = new StringBuilder (); + + if (UseGlobal) + sb.Append ((string) $"[global::Android.Runtime.Register (\"{Name}\""); + else + sb.Append ((string) $"[Register (\"{Name}\""); + + if ((Signature.HasValue () || Connector.HasValue ()) && !UseShortForm) + sb.Append ((string) $", \"{Signature}\", \"{Connector}\""); + + if (DoNotGenerateAcw && !AcwLast) + sb.Append (", DoNotGenerateAcw=true"); + + if (AdditionalProperties.HasValue ()) + sb.Append (AdditionalProperties); + + if (DoNotGenerateAcw && AcwLast) + sb.Append (", DoNotGenerateAcw=true"); + + sb.Append (")]"); + + writer.WriteLine (sb.ToString ()); + } + + private void WriteJavaInterop1Attribute (CodeWriter writer) + { + switch (MemberType) { + case MemberTypes.TypeInfo: + var invokerType = string.IsNullOrEmpty (Connector) + ? "" + : $", InvokerType=typeof ({Connector.Replace ('/', '.')})"; + writer.WriteLine ($"[global::Java.Interop.JniTypeSignature (\"{Name}\", GenerateJavaPeer={(DoNotGenerateAcw ? "false" : "true")}{invokerType})]"); + break; + case MemberTypes.Constructor: + writer.WriteLine ($"[global::Java.Interop.JniConstructorSignature (\"{Signature}\")]"); + break; + case MemberTypes.Method: + writer.WriteLine ($"[global::Java.Interop.JniMethodSignature (\"{Name}\", \"{Signature}\")]"); + break; + default: + throw new NotImplementedException ($"Don't know how to write attribute for `{MemberType}`"); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/RestrictToAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/RestrictToAttr.cs new file mode 100644 index 00000000000..b634c0f14f6 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/RestrictToAttr.cs @@ -0,0 +1,20 @@ +using System; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class RestrictToAttr : AttributeWriter + { + bool is_type; + + public RestrictToAttr (bool isType) + { + is_type = isType; + } + + public override void WriteAttribute (CodeWriter writer) + { + writer.WriteLine ($"[global::System.Obsolete (\"While this {(is_type ? "type" : "member")} is 'public', Google considers it internal API and reserves the right to modify or delete it in the future. Use at your own risk.\", DiagnosticId = \"XAOBS001\")]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/SupportedOSPlatformAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/SupportedOSPlatformAttr.cs new file mode 100644 index 00000000000..6e79b48c8eb --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/SupportedOSPlatformAttr.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +using Java.Interop.Tools.Generator; + +namespace generator.SourceWriters +{ + public class SupportedOSPlatformAttr : AttributeWriter + { + public AndroidSdkVersion Version { get; } + + public SupportedOSPlatformAttr (AndroidSdkVersion version) => Version = version; + + public override void WriteAttribute (CodeWriter writer) + { + var apiLevel = Version.MinorRelease == 0 + ? $"{Version.ApiLevel}.0" + : Version.ToString (); + writer.WriteLine ($"[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android{apiLevel}\")]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Attributes/UnsupportedOSPlatformAttr.cs b/external/Java.Interop/tools/generator/SourceWriters/Attributes/UnsupportedOSPlatformAttr.cs new file mode 100644 index 00000000000..b15a70cbdf3 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Attributes/UnsupportedOSPlatformAttr.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +using Java.Interop.Tools.Generator; + +namespace generator.SourceWriters +{ + public class UnsupportedOSPlatformAttr : AttributeWriter + { + public AndroidSdkVersion Version { get; } + + public UnsupportedOSPlatformAttr (AndroidSdkVersion version) => Version = version; + + public override void WriteAttribute (CodeWriter writer) + { + var apiLevel = Version.MinorRelease == 0 + ? $"{Version.ApiLevel}.0" + : Version.ToString (); + writer.WriteLine ($"[global::System.Runtime.Versioning.UnsupportedOSPlatformAttribute (\"android{apiLevel}\")]"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundAbstractProperty.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundAbstractProperty.cs new file mode 100644 index 00000000000..7e09855283a --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundAbstractProperty.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundAbstractProperty : PropertyWriter + { + readonly MethodCallback getter_callback; + readonly MethodCallback setter_callback; + + public BoundAbstractProperty (GenBase gen, Property property, CodeGenerationOptions opt) + { + Name = property.AdjustedName; + ExplicitInterfaceImplementation = property.ExplicitInterface; + PropertyType = new TypeReferenceWriter (opt.GetTypeReferenceName (property.Getter.RetVal)); + + SetVisibility (property.Getter.RetVal.IsGeneric ? "protected" : property.Getter.Visibility); + + IsAbstract = true; + HasGet = true; + + var baseProp = gen.BaseSymbol != null ? gen.BaseSymbol.GetPropertyByName (property.Name, true) : null; + + if (baseProp != null) { + IsOverride = true; + } else { + IsShadow = gen.RequiresNew (property); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) + getter_callback = new MethodCallback (gen, property.Getter, opt, property.AdjustedName, false); + + if (property.Setter != null && opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) + setter_callback = new MethodCallback (gen, property.Setter, opt, property.AdjustedName, false); + } + + if (gen.IsGeneratable) + GetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Getter.JavaName}'{property.Getter.Parameters.GetMethodXPathPredicate ()}]\""); + if (property.Getter.IsReturnEnumified) + GetterAttributes.Add (new GeneratedEnumAttr (true)); + + SourceWriterExtensions.AddSupportedOSPlatform (GetterAttributes, property.Getter, opt); + + GetterAttributes.Add (new RegisterAttr (property.Getter.JavaName, property.Getter.JniSignature, property.Getter.GetConnectorNameFull (opt), additionalProperties: property.Getter.AdditionalAttributeString ()) { + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.Method, + }); + + SourceWriterExtensions.AddMethodCustomAttributes (GetterAttributes, property.Getter); + + if (property.Setter != null) { + HasSet = true; + + if (gen.IsGeneratable) + SetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Setter.JavaName}'{property.Setter.Parameters.GetMethodXPathPredicate ()}]\""); + + SourceWriterExtensions.AddSupportedOSPlatform (SetterAttributes, property.Setter, opt); + + SourceWriterExtensions.AddMethodCustomAttributes (SetterAttributes, property.Setter); + SetterAttributes.Add (new RegisterAttr (property.Setter.JavaName, property.Setter.JniSignature, property.Setter.GetConnectorNameFull (opt), additionalProperties: property.Setter.AdditionalAttributeString ()) { + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.Method, + }); + } + } + + public override void Write (CodeWriter writer) + { + // Need to write our property callbacks first + getter_callback?.Write (writer); + setter_callback?.Write (writer); + + base.Write (writer); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundClass.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundClass.cs new file mode 100644 index 00000000000..2c5b6fcfaef --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundClass.cs @@ -0,0 +1,400 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.Android.Binder; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class BoundClass : ClassWriter + { + readonly CodeGenerationOptions opt; + readonly List sibling_types = new List (); + + public BoundClass (ClassGen klass, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo generationInfo) + { + context.ContextTypes.Push (klass); + context.ContextGeneratedMethods = new List (); + + var is_enum = klass.base_symbol != null && klass.base_symbol.FullName == "Java.Lang.Enum"; + + if (is_enum) + generationInfo.Enums.Add (klass.RawJniName.Replace ('/', '.') + ":" + klass.Namespace + ":" + klass.JavaSimpleName); + + this.opt = opt; + + Name = klass.Name; + + SetVisibility (klass.Visibility); + IsShadow = klass.NeedsNew; + IsAbstract = klass.IsAbstract; + IsSealed = klass.IsFinal; + IsPartial = true; + + UsePriorityOrder = true; + + AddImplementedInterfaces (klass); + + klass.JavadocInfo?.AddJavadocs (Comments); + Comments.Add ($"// Metadata.xml XPath class reference: path=\"{klass.MetadataXPathReference}\""); + + SourceWriterExtensions.AddObsolete (Attributes, klass.DeprecatedComment, opt, forceDeprecate: klass.IsDeprecated, deprecatedSince: klass.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, klass.AnnotatedVisibility, true, opt); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, klass, opt); + + Attributes.Add (new RegisterAttr (klass.RawJniName, + signature: null, + connector: IsAbstract ? Name + "Invoker" : null, + noAcw: true, + additionalProperties: klass.AdditionalAttributeString ()) { + UseGlobal = true, + UseShortForm = true, + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.TypeInfo, + }); + + if (klass.TypeParameters != null && klass.TypeParameters.Any ()) + Attributes.Add (new CustomAttr (klass.TypeParameters.ToGeneratedAttributeString ())); + + // Figure out our base class + string obj_type = null; + + if (klass.base_symbol != null) + obj_type = klass.base_symbol is GenericSymbol gs && + gs.IsConcrete ? gs.GetGenericType (null) : opt.GetOutputName (klass.base_symbol.FullName); + + if (klass.InheritsObject && obj_type != null) + Inherits = obj_type; + + // Handle fields + var seen = new HashSet (); + + SourceWriterExtensions.AddFields (this, klass, klass.Fields, seen, opt, context); + + var ic = new InterfaceConstsClass (klass, seen, opt, context); + + if (ic.ShouldGenerate) + NestedTypes.Add (ic); + + // Sibling classes + if (!klass.AssemblyQualifiedName.Contains ('/')) { + foreach (InterfaceExtensionInfo nestedIface in klass.GetNestedInterfaceTypes ()) + if (nestedIface.Type.Methods.Any (m => m.CanHaveStringOverload) || nestedIface.Type.Methods.Any (m => m.Asyncify)) + sibling_types.Add (new InterfaceExtensionsClass (nestedIface.Type, nestedIface.DeclaringType, opt)); + } + + if (klass.IsAbstract) + sibling_types.Add (new ClassInvokerClass (klass, opt)); + + AddNestedTypes (klass, opt, context, generationInfo); + AddBindingInfrastructure (klass, opt); + AddConstructors (klass, opt, context); + AddProperties (klass, opt); + AddMethods (klass, opt, context); + AddAbstractMembers (klass, opt, context); + AddExplicitGenericInterfaceMembers (klass, opt); + AddCharSequenceEnumerator (klass); + + context.ContextGeneratedMethods.Clear (); + context.ContextTypes.Pop (); + } + + void AddBindingInfrastructure (ClassGen klass, CodeGenerationOptions opt) + { + // @class.InheritsObject is true unless @class refers to java.lang.Object or java.lang.Throwable. (see ClassGen constructor) + // If @class's base class is defined in the same api.xml file, then it requires the new keyword to overshadow the internal + // members of its baseclass since the two classes will be defined in the same assembly. If the base class is not from the + // same api.xml file, the new keyword is not needed because the internal access modifier already prevents it from being seen. + var baseFromSameAssembly = klass?.BaseGen?.FromXml ?? false; + var requireNew = klass.InheritsObject && baseFromSameAssembly; + + Fields.Add (new PeerMembersField (opt, klass.RawJniName, klass.Name, false)); + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + Properties.Add (new ClassHandleGetter (requireNew)); + } + + if (klass.BaseGen != null && klass.InheritsObject) { + Properties.Add (new JniPeerMembersGetter ()); + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + Properties.Add (new ClassThresholdClassGetter ()); + Properties.Add (new ThresholdTypeGetter ()); + } + } + } + + void AddConstructors (ClassGen klass, CodeGenerationOptions opt, CodeGeneratorContext context) + { + // Add required constructor for all JLO inheriting classes + if (klass.FullName != "Java.Lang.Object" && klass.InheritsObject) { + if (!string.IsNullOrWhiteSpace (klass.PeerConstructorPartialMethod)) { + Methods.Add (new ConstructorPartialMethod (klass.PeerConstructorPartialMethod)); + } + Constructors.Add (new JavaLangObjectConstructor (klass, opt, klass.PeerConstructorPartialMethod)); + } + + foreach (var ctor in klass.Ctors) { + // Don't bind final or protected constructors + if (klass.IsFinal && ctor.Visibility == "protected") + continue; + + // Bind Java declared constructor + Constructors.Add (new BoundConstructor(klass, ctor, klass.InheritsObject, opt, context)); + + // If the constructor takes ICharSequence, create an overload constructor that takes a string + if (ctor.Parameters.HasCharSequence && !klass.ContainsCtor (ctor.JniSignature.Replace ("java/lang/CharSequence", "java/lang/String"))) + Constructors.Add (new StringOverloadConstructor(klass, ctor, klass.InheritsObject, opt, context)); + } + } + + void AddCharSequenceEnumerator (ClassGen klass) + { + if (klass.Interfaces.Any (p => p.FullName == "Java.Lang.ICharSequence")) { + Methods.Add (new CharSequenceEnumeratorMethod ()); + Methods.Add (new CharSequenceGenericEnumeratorMethod ()); + } + } + + void AddImplementedInterfaces (ClassGen klass) + { + foreach (var isym in klass.Interfaces) { + if ((!(isym is GenericSymbol gs) ? isym : gs.Gen) is InterfaceGen gen && (gen.IsConstSugar (opt) || gen.RawVisibility != "public")) + continue; + + Implements.Add (opt.GetOutputName (isym.FullName)); + } + } + + void AddExplicitGenericInterfaceMembers (ClassGen klass, CodeGenerationOptions opt) + { + foreach (var gs in klass.Interfaces.Where (sym => sym is GenericSymbol).Cast ().Where (sym => sym.IsConcrete)) { + + // FIXME: not sure if excluding default methods is a valid idea... + foreach (var m in gs.Gen.Methods) { + if (m.IsInterfaceDefaultMethod || m.IsStatic) + continue; + if (m.IsGeneric) + Methods.Add (new GenericExplicitInterfaceImplementationMethod (m, gs, opt)); + } + + foreach (var p in gs.Gen.Properties) { + if (p.Getter?.IsInterfaceDefaultMethod == true || p.Getter?.IsStatic == true) + continue; + + if (p.Setter?.IsInterfaceDefaultMethod == true || p.Setter?.IsStatic == true) + continue; + + if (p.IsGeneric) { + var mappings = new Dictionary (); + for (var i = 0; i < gs.TypeParams.Length; i++) + mappings [gs.Gen.TypeParameters [i].Name] = gs.TypeParams [i].FullName; + + //If the property type is Java.Lang.Object, we don't need to generate an explicit implementation + if (p.Getter?.RetVal.GetGenericType (mappings) == "Java.Lang.Object") + return; + if (p.Setter?.Parameters [0].GetGenericType (mappings) == "Java.Lang.Object") + return; + + Properties.Add (new GenericExplicitInterfaceImplementationProperty (p, gs, gs.Gen.AssemblyQualifiedName + "Invoker", mappings, opt)); + } + } + } + + } + + void AddAbstractMembers (ClassGen klass, CodeGenerationOptions opt, CodeGeneratorContext context) + { + if (!klass.IsAbstract) + return; + + foreach (var gen in klass.GetAllDerivedInterfaces ()) + AddInterfaceAbstractMembers(klass, gen, opt, context); + } + + // For each interface, generate either an abstract method or an explicit implementation method. + void AddInterfaceAbstractMembers (ClassGen klass, InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) + { + foreach (var method in iface.Methods.Where (m => !m.IsInterfaceDefaultMethod && !m.IsStatic)) { + var mapped = false; + var sig = method.GetSignature (); + + if (context.ContextGeneratedMethods.Any (_ => _.Name == method.Name && _.JniSignature == method.JniSignature)) + continue; + if (klass.SkippedInterfaceMethods.Contains (method.GetSkipInvokerSignature ())) + continue; + + for (var cls = klass; cls != null; cls = cls.BaseGen) + if (cls.ContainsMethod (method, false) || cls != klass && klass.ExplicitlyImplementedInterfaceMethods.Contains (sig)) { + mapped = true; + break; + } + + if (mapped) + continue; + + if (klass.ExplicitlyImplementedInterfaceMethods.Contains (sig)) + Methods.Add (new MethodExplicitInterfaceImplementation(iface, method, opt)); + else + AddAbstractMethodDeclaration (klass, method, iface); + + context.ContextGeneratedMethods.Add (method); + } + + foreach (var prop in iface.Properties.Where (p => !p.Getter.IsInterfaceDefaultMethod && !p.Getter.IsStatic)) { + if (klass.ContainsProperty (prop.Name, false)) + continue; + + AddAbstractPropertyDeclaration (klass, prop, opt); + } + } + + void AddMethods (ClassGen klass, CodeGenerationOptions opt, CodeGeneratorContext context) + { + var methodsToDeclare = klass.Methods.AsEnumerable (); + + // This does not exclude overrides (unlike virtual methods) because we're not sure + // if calling the base interface default method via JNI expectedly dispatches to + // the derived method. + var defaultMethods = klass.GetAllDerivedInterfaces () + .SelectMany (i => i.Methods) + .Where (m => m.IsInterfaceDefaultMethod) + .Where (m => !klass.ContainsMethod (m, false, false)); + + var overrides = defaultMethods.Where (m => m.OverriddenInterfaceMethod != null); + + var overridens = defaultMethods.Where (m => overrides.Where (_ => _.Name == m.Name && _.JniSignature == m.JniSignature) + .Any (mm => mm.DeclaringType.GetAllDerivedInterfaces ().Contains (m.DeclaringType))); + + methodsToDeclare = opt.SupportDefaultInterfaceMethods ? methodsToDeclare : methodsToDeclare.Concat (defaultMethods.Except (overridens)).Where (m => m.DeclaringType.IsGeneratable); + + foreach (var m in methodsToDeclare) { + var virt = m.IsVirtual; + m.IsVirtual = !klass.IsFinal && virt; + + if (m.IsAbstract && m.OverriddenInterfaceMethod == null && (opt.SupportDefaultInterfaceMethods || !m.IsInterfaceDefaultMethod)) + AddAbstractMethodDeclaration (klass, m, null); + else + AddMethod (klass, m, opt); + + context.ContextGeneratedMethods.Add (m); + m.IsVirtual = virt; + } + + var methods = klass.Methods.Concat (klass.Properties.Where (p => p.Setter != null).Select (p => p.Setter)); + + foreach (var type in methods.Where (m => m.IsListenerConnector && m.EventName != string.Empty).Select (m => m.ListenerType).Distinct ()) { + AddInlineComment ($"#region \"Event implementation for {type.FullName}\""); + SourceWriterExtensions.AddInterfaceListenerEventsAndProperties (this, type, klass, opt); + AddInlineComment ("#endregion"); + } + + } + + void AddAbstractMethodDeclaration (GenBase klass, Method method, InterfaceGen iface) + { + Methods.Add (new BoundMethodAbstractDeclaration (iface, method, opt, klass)); + + if (method.IsReturnCharSequence || method.Parameters.HasCharSequence) + Methods.Add (new BoundMethodStringOverload (method, opt)); + + if (method.Asyncify) + Methods.Add (new MethodAsyncWrapper (method, opt)); + } + + void AddMethod (GenBase klass, Method method, CodeGenerationOptions opt) + { + if (!method.IsValid) + return; + + Methods.Add (new BoundMethod(klass, method, opt, true)); + + var name_and_jnisig = method.JavaName + method.JniSignature.Replace ("java/lang/CharSequence", "java/lang/String"); + var gen_string_overload = !method.IsOverride && method.Parameters.HasCharSequence && !klass.ContainsMethod (name_and_jnisig); + + if (gen_string_overload || method.IsReturnCharSequence) + Methods.Add (new BoundMethodStringOverload (method, opt)); + + if (method.Asyncify) + Methods.Add (new MethodAsyncWrapper (method, opt)); + } + + void AddProperties (ClassGen klass, CodeGenerationOptions opt) + { + foreach (var prop in klass.Properties) { + var get_virt = prop.Getter.IsVirtual; + var set_virt = prop.Setter == null ? false : prop.Setter.IsVirtual; + + prop.Getter.IsVirtual = !klass.IsFinal && get_virt; + + if (prop.Setter != null) + prop.Setter.IsVirtual = !klass.IsFinal && set_virt; + + if (prop.Getter.IsAbstract) + AddAbstractPropertyDeclaration (klass, prop, opt); + else + AddProperty (klass, prop, opt); + + prop.Getter.IsVirtual = get_virt; + + if (prop.Setter != null) + prop.Setter.IsVirtual = set_virt; + } + } + + void AddProperty (ClassGen klass, Property property, CodeGenerationOptions opt) + { + var bound_property = new BoundProperty (klass, property, opt, true, false); + Properties.Add (bound_property); + + if (property.Type.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) && !bound_property.IsOverride) + Properties.Add (new BoundPropertyStringVariant (property, opt, bound_property)); + } + + void AddAbstractPropertyDeclaration (ClassGen klass, Property property, CodeGenerationOptions opt) + { + var baseProp = klass.BaseSymbol?.GetPropertyByName (property.Name, true); + + if (baseProp != null) { + if (baseProp.Type != property.Getter.Return) { + // This may not be required if we can change generic parameter support to return constrained type (not just J.L.Object). + AddInlineComment ($"// skipped generating property {property.Name} because its Java method declaration is variant that we cannot represent in C#"); + return; + } + } + + var bound_property = new BoundAbstractProperty (klass, property, opt); + Properties.Add (bound_property); + + if (property.Type.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal)) + Properties.Add (new BoundPropertyStringVariant (property, opt, bound_property)); + } + + void AddNestedTypes (ClassGen klass, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo genInfo) + { + foreach (var nest in klass.NestedTypes) { + if (klass.BaseGen?.ContainsNestedType (nest) == true && nest is ClassGen c) + c.NeedsNew = true; + + NestedTypes.Add (SourceWriterExtensions.BuildManagedTypeModel (nest, opt, context, genInfo)); + } + } + + public override void Write (CodeWriter writer) + { + base.Write (writer); + + WriteSiblingClasses (writer); + } + + public void WriteSiblingClasses (CodeWriter writer) + { + foreach (var sibling in sibling_types) { + writer.WriteLine (); + sibling.Write (writer); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundConstructor.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundConstructor.cs new file mode 100644 index 00000000000..7f333f17c17 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundConstructor.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.Android.Binder; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class BoundConstructor : ConstructorWriter + { + protected Ctor constructor; + protected CodeGenerationOptions opt; + protected CodeGeneratorContext context; + readonly string context_this; + + public BoundConstructor (ClassGen klass, Ctor constructor, bool useBase, CodeGenerationOptions opt, CodeGeneratorContext context) + { + this.constructor = constructor; + this.opt = opt; + this.context = context; + + Name = klass.Name; + + constructor.JavadocInfo?.AddJavadocs (Comments); + Comments.Add (string.Format ("// Metadata.xml XPath constructor reference: path=\"{0}/constructor[@name='{1}'{2}]\"", klass.MetadataXPathReference, klass.JavaSimpleName, constructor.Parameters.GetMethodXPathPredicate ())); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, constructor, opt); + + Attributes.Add (new RegisterAttr (".ctor", constructor.JniSignature, string.Empty, additionalProperties: constructor.AdditionalAttributeString ()) { + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.Constructor, + }); + + SourceWriterExtensions.AddObsolete (Attributes, constructor.Deprecated, opt, deprecatedSince: constructor.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, constructor.AnnotatedVisibility, false, opt); + + if (constructor.CustomAttributes != null) + Attributes.Add (new CustomAttr (constructor.CustomAttributes)); + + if (constructor.Annotation != null) + Attributes.Add (new CustomAttr (constructor.Annotation)); + + SetVisibility (constructor.Visibility); + IsUnsafe = true; + + BaseCall = opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1 + ? $"{(useBase ? "base" : "this")} (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)" + : $"{(useBase ? "base" : "this")} (IntPtr.Zero, JniHandleOwnership.DoNotTransfer)"; + context_this = context.ContextType.GetObjectHandleProperty (opt, "this"); + + this.AddMethodParameters (constructor.Parameters, opt); + } + + protected override void WriteBody (CodeWriter writer) + { + writer.WriteLine ("{0}string __id = \"{1}\";", + constructor.IsNonStaticNestedType ? "" : "const ", + constructor.IsNonStaticNestedType + ? "(" + constructor.Parameters.GetJniNestedDerivedSignature (opt) + ")V" + : constructor.JniSignature); + writer.WriteLine (); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + writer.WriteLine ($"if (PeerReference.IsValid)"); + writer.WriteLine ("\treturn;"); + } else { + writer.WriteLine ($"if ({context_this} != IntPtr.Zero)"); + writer.WriteLine ("\treturn;"); + } + writer.WriteLine (); + + foreach (var prep in constructor.Parameters.GetCallPrep (opt)) + writer.WriteLine (prep); + + writer.WriteLine ("try {"); + + writer.Indent (); + WriteParamterListCallArgs (writer, constructor.Parameters, false, opt); + writer.WriteLine ("var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (){0});", constructor.Parameters.GetCallArgs (opt, invoker: false)); + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + writer.WriteLine ("Construct (ref __r, JniObjectReferenceOptions.CopyAndDispose);"); + } else { + writer.WriteLine ("SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef);"); + } + writer.WriteLine ("_members.InstanceMethods.FinishCreateInstance (__id, this{0});", constructor.Parameters.GetCallArgs (opt, invoker: false)); + writer.Unindent (); + + writer.WriteLine ("} finally {"); + + writer.Indent (); + var call_cleanup = constructor.Parameters.GetCallCleanup (opt); + foreach (string cleanup in call_cleanup) + writer.WriteLine (cleanup); + + foreach (var p in constructor.Parameters.Where (para => para.ShouldGenerateKeepAlive ())) + writer.WriteLine ($"global::System.GC.KeepAlive ({opt.GetSafeIdentifier (p.Name)});"); + + writer.Unindent (); + + writer.WriteLine ("}"); + } + + void WriteParamterListCallArgs (CodeWriter writer, ParameterList parameters, bool invoker, CodeGenerationOptions opt) + { + if (parameters.Count == 0) + return; + + string JValue = "JValue"; + + switch (opt.CodeGenerationTarget) { + case CodeGenerationTarget.XAJavaInterop1: + case CodeGenerationTarget.JavaInterop1: + JValue = invoker ? JValue : "JniArgumentValue"; + break; + } + + writer.WriteLine ("{0}* __args = stackalloc {0} [{1}];", JValue, parameters.Count); + + for (var i = 0; i < parameters.Count; ++i) { + var p = parameters [i]; + writer.WriteLine ("__args [{0}] = new {1} ({2});", i, JValue, p.GetCall (opt)); + } + } + } + + public class StringOverloadConstructor : BoundConstructor + { + public StringOverloadConstructor (ClassGen klass, Ctor constructor, bool useBase, CodeGenerationOptions opt, CodeGeneratorContext context) : + base (klass, constructor, useBase, opt, context) + { + Comments.Clear (); + Parameters.Clear (); + + // TODO: This is likely incorrect but done for compat with old generator. + // A string overload for an obsolete ctor will not be marked obsolete. + var obsolete_attr = Attributes.OfType ().FirstOrDefault (); + + if (obsolete_attr != null) + Attributes.Remove (obsolete_attr); + + this.AddMethodParametersStringOverloads (constructor.Parameters, opt); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundField.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundField.cs new file mode 100644 index 00000000000..0b8e28a44f6 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundField.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundField : FieldWriter + { + // // Metadata.xml XPath field reference: path="/api/package[@name='android.os']/class[@name='Vibrator']/field[@name='VIBRATION_EFFECT_SUPPORT_UNKNOWN']" + // [Register ("VIBRATION_EFFECT_SUPPORT_UNKNOWN", ApiSince = 30)] + // [Obsolete ("This constant will be removed in the future version. Use Android.OS.VibrationEffectSupport enum directly instead of this field.", error: true)] + // public const Android.OS.VibrationEffectSupport VibrationEffectSupportUnknown = (Android.OS.VibrationEffectSupport) 0; + public BoundField (GenBase type, Field field, CodeGenerationOptions opt) + { + Name = field.Name; + Type = new TypeReferenceWriter (opt.GetOutputName (field.Symbol.FullName)); + + field.JavadocInfo?.AddJavadocs (Comments); + Comments.Add ($"// Metadata.xml XPath field reference: path=\"{type.MetadataXPathReference}/field[@name='{field.JavaName}']\""); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + Attributes.Add (new RegisterAttr (field.JavaName, additionalProperties: field.AdditionalAttributeString ())); + } + + if (field.IsEnumified) + Attributes.Add (new GeneratedEnumAttr ()); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, field, opt); + SourceWriterExtensions.AddObsolete (Attributes, field.DeprecatedComment, opt, field.IsDeprecated, isError: field.IsDeprecatedError, deprecatedSince: field.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, field.AnnotatedVisibility, false, opt); + + if (field.Annotation.HasValue ()) + Attributes.Add (new CustomAttr (field.Annotation)); + + SetVisibility (field.Visibility); + IsConst = true; + + // the Value complication is due to constant enum from negative integer value (C# compiler requires explicit parenthesis). + Value = $"({opt.GetOutputName (field.Symbol.FullName)}) {(field.Value.Contains ('-') && field.Symbol.FullName.Contains ('.') ? '(' + field.Value + ')' : field.Value)}"; + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundFieldAsProperty.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundFieldAsProperty.cs new file mode 100644 index 00000000000..4bd7b0f7af4 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundFieldAsProperty.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + // This is a field that is not a constant, and thus we need to generate it as a + // property so it can access the Java field. + public class BoundFieldAsProperty : PropertyWriter + { + readonly Field field; + readonly CodeGenerationOptions opt; + + public BoundFieldAsProperty (GenBase type, Field field, CodeGenerationOptions opt) + { + this.field = field; + this.opt = opt; + + Name = field.Name; + + string fieldType; + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + fieldType = opt.GetTypeReferenceName (field); + } else { + fieldType = field.Symbol.IsArray + ? "IList<" + field.Symbol.ElementType + ">" + opt.NullableOperator + : opt.GetTypeReferenceName (field); + } + + PropertyType = new TypeReferenceWriter (fieldType); + + field.JavadocInfo?.AddJavadocs (Comments); + Comments.Add ($"// Metadata.xml XPath field reference: path=\"{type.MetadataXPathReference}/field[@name='{field.JavaName}']\""); + + if (field.IsEnumified) + Attributes.Add (new GeneratedEnumAttr ()); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, field, opt); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + Attributes.Add (new RegisterAttr (field.JavaName, additionalProperties: field.AdditionalAttributeString ())); + } + + SourceWriterExtensions.AddObsolete (Attributes, field.DeprecatedComment, opt, field.IsDeprecated, isError: field.IsDeprecatedError, deprecatedSince: field.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, field.AnnotatedVisibility, false, opt); + + SetVisibility (field.Visibility); + UseExplicitPrivateKeyword = true; + + IsStatic = field.IsStatic; + + HasGet = true; + + if (!field.IsConst) + HasSet = true; + } + + public override void Write (CodeWriter writer) + { + // This is just a temporary hack to write the [GeneratedEnum] attribute before the // Metadata.xml + // comment so that we are 100% equal to pre-refactor. + var generated_attr = Attributes.OfType ().FirstOrDefault (); + + generated_attr?.WriteAttribute (writer); + writer.WriteLine (); + + base.Write (writer); + } + + public override void WriteAttributes (CodeWriter writer) + { + // Part of above hack ^^ + foreach (var att in Attributes.Where (p => !(p is GeneratedEnumAttr))) + att.WriteAttribute (writer); + } + + protected override void WriteGetterBody (CodeWriter writer) + { + writer.WriteLine ($"const string __id = \"{field.JavaName}.{field.Symbol.JniName}\";"); + writer.WriteLine (); + + var invokeType = SourceWriterExtensions.GetInvokeType (field.GetMethodPrefix); + var indirect = field.IsStatic ? "StaticFields" : "InstanceFields"; + var invoke = "Get{0}Value"; + + invoke = string.Format (invoke, invokeType); + + writer.WriteLine ($"var __v = {field.Symbol.ReturnCast}_members.{indirect}.{invoke} (__id{(field.IsStatic ? "" : ", this")});"); + + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + if (field.Symbol.NativeType == field.Symbol.FullName || field.Symbol.OnlyFormatOnMarshal) { + writer.WriteLine ("return __v;"); + return; + } + writer.Write ("return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<"); + PropertyType.WriteTypeReference (writer); + writer.Write (">(ref __v, JniObjectReferenceOptions.Copy)"); + writer.WriteLine (";"); + return; + } + + if (field.Symbol.IsArray) { + writer.WriteLine ($"return global::Android.Runtime.JavaArray<{opt.GetOutputName (field.Symbol.ElementType)}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef);"); + } else if (field.Symbol.NativeType != field.Symbol.FullName && !field.Symbol.OnlyFormatOnMarshal) { + writer.WriteLine ($"return {field.Symbol.ReturnCast}{(field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true, false) + opt.GetNullForgiveness (field))};"); + } else { + writer.WriteLine ("return __v;"); + } + } + + protected override void WriteSetterBody (CodeWriter writer) + { + writer.WriteLine ($"const string __id = \"{field.JavaName}.{field.Symbol.JniName}\";"); + writer.WriteLine (); + + var invokeType = SourceWriterExtensions.GetInvokeType (field.GetMethodPrefix); + var indirect = field.IsStatic ? "StaticFields" : "InstanceFields"; + + string native_arg = opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName ("value")); + string arg; + bool have_prep = false; + + if (field.Symbol.IsArray) { + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + arg = "value"; + } else { + arg = native_arg; + writer.WriteLine ($"IntPtr {native_arg} = global::Android.Runtime.JavaArray<{opt.GetOutputName (field.Symbol.ElementType)}>.ToLocalJniHandle (value);"); + } + } else { + foreach (var prep in field.SetParameters.GetCallPrep (opt)) { + have_prep = true; + writer.WriteLine (prep); + } + + var param = field.SetParameters [0]; + arg = param.Symbol.OnlyFormatOnMarshal + ? opt.GetSafeIdentifier (param.Name) + : param.ToNative (opt); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 && + field.SetParameters.HasCleanup && + !have_prep) { + arg = native_arg; + writer.WriteLine ($"IntPtr {native_arg} = global::Android.Runtime.JNIEnv.ToLocalJniHandle (value);"); + } + } + + writer.WriteLine ("try {"); + + writer.Write ($"\t_members.{indirect}.SetValue (__id{(field.IsStatic ? "" : ", this")}, "); + + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + if (invokeType != "Object" || have_prep) { + if (field.SetParameters [0].Symbol.OnlyFormatOnMarshal) + writer.Write (opt.GetSafeIdentifier (field.SetParameters [0].Name)); + else + writer.Write (arg); + } else { + writer.Write ($"{arg}?.PeerReference ?? default"); + } + writer.WriteLine (");"); + } else { + writer.WriteLine ($"{(invokeType != "Object" ? arg : "new JniObjectReference (" + arg + ")")});"); + } + + writer.WriteLine ("} finally {"); + writer.Indent (); + + if (field.Symbol.IsArray) { + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + writer.WriteLine ($"global::Android.Runtime.JNIEnv.DeleteLocalRef ({arg});"); + } + } else { + foreach (var cleanup in field.SetParameters.GetCallCleanup (opt)) + writer.WriteLine (cleanup); + if (field.SetParameters.HasCleanup && !have_prep) { + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + writer.WriteLine ($"global::Android.Runtime.JNIEnv.DeleteLocalRef ({arg});"); + } + } + } + + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1 && + field.Symbol.JniName != null && + field.Symbol.JniName.Length > 1 && + (field.Symbol.JniName[0] == 'L' || field.Symbol.JniName[0] == '[')) { + writer.WriteLine ($"GC.KeepAlive (value);"); + } + + writer.Unindent (); + writer.WriteLine ("}"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundInterface.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundInterface.cs new file mode 100644 index 00000000000..258a6e91040 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundInterface.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundInterface : InterfaceWriter + { + readonly List pre_sibling_types = new List (); + readonly List post_sibling_types = new List (); + readonly bool dont_generate; + + public BoundInterface (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo genInfo) + { + context.ContextTypes.Push (iface); + + Name = iface.Name; + + AddNestedSiblingTypes (iface, opt, context, genInfo); + AddAlternativesClass (iface, opt, context); + + // If this interface is just fields and we can't generate any of them + // then we don't need to write the interface. We still keep this type + // because it may have nested types or need an InterfaceMemberAlternativeClass. + if (iface.IsConstSugar (opt) && iface.GetGeneratableFields (opt).Count () == 0) { + dont_generate = true; + return; + } + + IsPartial = true; + + UsePriorityOrder = true; + + SetVisibility (iface.Visibility); + + iface.JavadocInfo?.AddJavadocs (Comments); + Comments.Add ($"// Metadata.xml XPath interface reference: path=\"{iface.MetadataXPathReference}\""); + + SourceWriterExtensions.AddObsolete (Attributes, iface.DeprecatedComment, opt, iface.IsDeprecated, deprecatedSince: iface.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, iface.AnnotatedVisibility, true, opt); + + if (!iface.IsConstSugar (opt)) { + var signature = string.IsNullOrWhiteSpace (iface.Namespace) + ? iface.FullName.Replace ('.', '/') + : iface.Namespace + "." + iface.FullName.Substring (iface.Namespace.Length + 1).Replace ('.', '/'); + + var noAcw = false; + var memberType = (MemberTypes?) null; + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + noAcw = true; + memberType = MemberTypes.TypeInfo; + } + + Attributes.Add (new RegisterAttr (iface.RawJniName, string.Empty, signature + "Invoker", noAcw, additionalProperties: iface.AdditionalAttributeString ()) { + MemberType = memberType, + }); + } + + if (iface.TypeParameters != null && iface.TypeParameters.Any ()) + Attributes.Add (new CustomAttr (iface.TypeParameters.ToGeneratedAttributeString ())); + + AddInheritedInterfaces (iface, opt); + + AddClassHandle (iface, opt); + AddFields (iface, opt, context); + AddProperties (iface, opt); + AddMethods (iface, opt); + AddNestedTypes (iface, opt, context, genInfo); + + // If this interface is just constant fields we don't need to add all the invoker bits + if (iface.IsConstSugar (opt)) + return; + + if (!iface.AssemblyQualifiedName.Contains ('/')) { + if (iface.Methods.Any (m => m.CanHaveStringOverload) || iface.Methods.Any (m => m.Asyncify)) + post_sibling_types.Add (new InterfaceExtensionsClass (iface, null, opt)); + } + + post_sibling_types.Add (new InterfaceInvokerClass (iface, opt, context)); + + AddInterfaceEventHandler (iface, opt, context); + + context.ContextTypes.Pop (); + } + + + void AddNestedSiblingTypes (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo genInfo) + { + // Generate sibling types for nested types we don't want to nest + foreach (var nest in iface.NestedTypes.Where (t => t.Unnest)) + pre_sibling_types.Add (SourceWriterExtensions.BuildManagedTypeModel (nest, opt, context, genInfo)); + } + + + void AddAlternativesClass (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) + { + if (iface.NoAlternatives) + return; + + var staticMethods = iface.Methods.Where (m => m.IsStatic); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 && + (iface.Fields.Any () || staticMethods.Any ())) { + pre_sibling_types.Add (new InterfaceMemberAlternativeClass (iface, opt, context)); + } + } + + void AddInterfaceEventHandler (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) + { + if (!iface.IsListener) + return; + + foreach (var method in iface.Methods.Where (m => m.EventName != string.Empty)) { + if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty) { + if (!method.IsSimpleEventHandler || method.IsEventHandlerWithHandledProperty) { + var event_args_class = post_sibling_types.OfType ().SingleOrDefault (c => c.Name == iface.GetArgsName (method)); + + // Check if there's an existing EventArgs class to add to + if (event_args_class is null) { + event_args_class = new InterfaceEventArgsClass (iface, method); + post_sibling_types.Add (event_args_class); + } + + event_args_class.AddMembersFromMethod (iface, method, opt); + } + } else { + var del = new DelegateWriter { + Name = iface.GetEventDelegateName (method), + Type = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)), + IsPublic = true + }; + + SourceWriterExtensions.AddMethodParameters (del, method.Parameters, opt); + + post_sibling_types.Add (del); + } + } + + post_sibling_types.Add (new InterfaceEventHandlerImplClass (iface, opt, context)); + } + + void AddInheritedInterfaces (InterfaceGen iface, CodeGenerationOptions opt) + { + foreach (var isym in iface.Interfaces) { + var igen = (isym is GenericSymbol ? (isym as GenericSymbol).Gen : isym) as InterfaceGen; + + // igen *should not* be null here because we *should* only be inheriting interfaces, but + // in the case of constants on that interface we create a C# *class* that is registered for the + // Java *interface*. Thus when we do type resolution, we are actually pointed to the + // Foo abstract class instead of the IFoo interface. + if (igen is null || igen.IsConstSugar (opt) || igen.RawVisibility != "public") + continue; + + Implements.Add (opt.GetOutputName (isym.FullName)); + } + + if (Implements.Count == 0 && !iface.IsConstSugar (opt)) { + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + Implements.Add ("IJavaObject"); + } + Implements.Add ("IJavaPeerable"); + } + } + + void AddClassHandle (InterfaceGen iface, CodeGenerationOptions opt) + { + if (opt.SupportDefaultInterfaceMethods && (iface.HasDefaultMethods || iface.HasStaticMethods || iface.HasFieldsAsProperties)) + Fields.Add (new PeerMembersField (opt, iface.RawJniName, iface.Name, true)); + } + + void AddFields (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) + { + // Interface fields are only supported with DIM + if (!opt.SupportInterfaceConstants && !opt.SupportDefaultInterfaceMethods) + return; + + var seen = new HashSet (); + var fields = iface.GetGeneratableFields (opt).ToList (); + + SourceWriterExtensions.AddFields (this, iface, fields, seen, opt, context); + } + + void AddProperties (InterfaceGen iface, CodeGenerationOptions opt) + { + foreach (var prop in iface.Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod)) + Properties.Add (new BoundInterfacePropertyDeclaration (iface, prop, iface.AssemblyQualifiedName + "Invoker", opt)); + + if (!opt.SupportDefaultInterfaceMethods) + return; + + var dim_properties = iface.Properties.Where (p => p.Getter.IsInterfaceDefaultMethod || p.Getter.IsStatic); + + foreach (var prop in dim_properties) { + if (prop.Getter.IsAbstract) { + var baseProp = iface.BaseSymbol != null ? iface.BaseSymbol.GetPropertyByName (prop.Name, true) : null; + if (baseProp != null) { + if (baseProp.Type != prop.Getter.Return) { + // This may not be required if we can change generic parameter support to return constrained type (not just J.L.Object). + //writer.WriteLine ("{0}// skipped generating property {1} because its Java method declaration is variant that we cannot represent in C#", indent, property.Name); + return; + } + } + + var bound_property = new BoundAbstractProperty (iface, prop, opt); + Properties.Add (bound_property); + + if (prop.Type.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) && !bound_property.IsOverride) + Properties.Add (new BoundPropertyStringVariant (prop, opt, bound_property)); + } else { + var bound_property = new BoundProperty (iface, prop, opt, true, false); + Properties.Add (bound_property); + + if (prop.Type.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) && !bound_property.IsOverride) + Properties.Add (new BoundPropertyStringVariant (prop, opt, bound_property)); + } + } + } + + void AddMethods (InterfaceGen iface, CodeGenerationOptions opt) + { + foreach (var m in iface.Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod)) { + if (m.Name == iface.Name || iface.ContainsProperty (m.Name, true)) + m.Name = "Invoke" + m.Name; + + Methods.Add (new BoundInterfaceMethodDeclaration (m, iface.AssemblyQualifiedName + "Invoker", opt)); + } + + if (!opt.SupportDefaultInterfaceMethods) + return; + + foreach (var method in iface.Methods.Where (m => m.IsInterfaceDefaultMethod || m.IsStatic)) { + if (!method.IsValid) + continue; + + Methods.Add (new BoundMethod (iface, method, opt, true)); + + var name_and_jnisig = method.JavaName + method.JniSignature.Replace ("java/lang/CharSequence", "java/lang/String"); + var gen_string_overload = !method.IsOverride && method.Parameters.HasCharSequence && !iface.ContainsMethod (name_and_jnisig); + + if (gen_string_overload || method.IsReturnCharSequence) + Methods.Add (new BoundMethodStringOverload (method, opt)); + + if (method.Asyncify) + Methods.Add (new MethodAsyncWrapper (method, opt)); + } + } + + void AddNestedTypes (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo genInfo) + { + // Generate nested types for supported nested types. This is a new addition in C#8. + // Prior to this, types nested in an interface had to be generated as sibling types. + // The "Unnest" property is used to support backwards compatibility with pre-C#8 bindings. + foreach (var nest in iface.NestedTypes.Where (t => !t.Unnest)) + NestedTypes.Add (SourceWriterExtensions.BuildManagedTypeModel (nest, opt, context, genInfo)); + } + + public override void Write (CodeWriter writer) + { + WritePreSiblingClasses (writer); + + if (!dont_generate) + base.Write (writer); + + WritePostSiblingClasses (writer); + } + + public void WritePreSiblingClasses (CodeWriter writer) + { + foreach (var sibling in pre_sibling_types) { + sibling.Write (writer); + writer.WriteLine (); + } + } + + public void WritePostSiblingClasses (CodeWriter writer) + { + foreach (var sibling in post_sibling_types) { + writer.WriteLine (); + sibling.Write (writer); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundInterfaceMethodDeclaration.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundInterfaceMethodDeclaration.cs new file mode 100644 index 00000000000..01f8493de42 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundInterfaceMethodDeclaration.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundInterfaceMethodDeclaration : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + + public BoundInterfaceMethodDeclaration (Method method, string adapter, CodeGenerationOptions opt) + { + this.method = method; + this.opt = opt; + + Name = method.AdjustedName; + ExplicitInterfaceImplementation = method.ExplicitInterface; + + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + IsDeclaration = true; + + // Allow user to force adding the 'abstract' keyword for "reabstraction" + if (method.ManagedOverride?.ToLowerInvariant () == "reabstract") + IsAbstract = true; + + if (method.DeclaringType.IsGeneratable) + Comments.Add ($"// Metadata.xml XPath method reference: path=\"{method.GetMetadataXPathReference (method.DeclaringType)}\""); + + SourceWriterExtensions.AddObsolete (Attributes, method.Deprecated, opt, deprecatedSince: method.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, method.AnnotatedVisibility, false, opt); + + if (method.IsReturnEnumified) + Attributes.Add (new GeneratedEnumAttr (true)); + if (method.IsInterfaceDefaultMethod) + Attributes.Add (new CustomAttr ("[global::Java.Interop.JavaInterfaceDefaultMethod]")); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + Attributes.Add (new RegisterAttr (method.JavaName, method.JniSignature, method.ConnectorName + ":" + method.GetAdapterName (opt, adapter), additionalProperties: method.AdditionalAttributeString ()) { + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.Method, + }); + + method.JavadocInfo?.AddJavadocs (Comments); + + SourceWriterExtensions.AddMethodCustomAttributes (Attributes, method); + this.AddMethodParameters (method.Parameters, opt); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundInterfacePropertyDeclaration.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundInterfacePropertyDeclaration.cs new file mode 100644 index 00000000000..1031b197a5b --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundInterfacePropertyDeclaration.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundInterfacePropertyDeclaration : PropertyWriter + { + public BoundInterfacePropertyDeclaration (GenBase gen, Property property, string adapter, CodeGenerationOptions opt) + { + Name = property.AdjustedName; + ExplicitInterfaceImplementation = property.ExplicitInterface; + + PropertyType = new TypeReferenceWriter (opt.GetTypeReferenceName (property)); + IsAutoProperty = true; + + // Allow user to force adding the 'abstract' keyword for "reabstraction" + if ((property.Getter ?? property.Setter).ManagedOverride?.ToLowerInvariant () == "reabstract") + IsAbstract = true; + + if (property.Getter != null) { + HasGet = true; + + if (gen.IsGeneratable) + GetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Getter.JavaName}'{property.Getter.Parameters.GetMethodXPathPredicate ()}]\""); + if (property.Getter.GenericArguments?.Any () == true) + GetterAttributes.Add (new CustomAttr (property.Getter.GenericArguments.ToGeneratedAttributeString ())); + + SourceWriterExtensions.AddSupportedOSPlatform (GetterAttributes, property.Getter, opt); + + GetterAttributes.Add (new RegisterAttr (property.Getter.JavaName, property.Getter.JniSignature, property.Getter.ConnectorName + ":" + property.Getter.GetAdapterName (opt, adapter), additionalProperties: property.Getter.AdditionalAttributeString ()) { + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.Method, + }); + } + + if (property.Setter != null) { + HasSet = true; + + if (gen.IsGeneratable) + SetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Setter.JavaName}'{property.Setter.Parameters.GetMethodXPathPredicate ()}]\""); + if (property.Setter.GenericArguments?.Any () == true) + SetterAttributes.Add (new CustomAttr (property.Setter.GenericArguments.ToGeneratedAttributeString ())); + + SourceWriterExtensions.AddSupportedOSPlatform (SetterAttributes, property.Setter, opt); + + SetterAttributes.Add (new RegisterAttr (property.Setter.JavaName, property.Setter.JniSignature, property.Setter.ConnectorName + ":" + property.Setter.GetAdapterName (opt, adapter), additionalProperties: property.Setter.AdditionalAttributeString ()) { + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.Method, + }); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundMethod.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundMethod.cs new file mode 100644 index 00000000000..747191bce4e --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundMethod.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundMethod : MethodWriter + { + readonly MethodCallback callback; + + public Method JavaMethod { get; } + + public BoundMethod (GenBase type, Method method, CodeGenerationOptions opt, bool generateCallbacks) + { + JavaMethod = method; + + if (generateCallbacks && method.IsVirtual && opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) + callback = new MethodCallback (type, method, opt, null, method.IsReturnCharSequence); + + Name = method.AdjustedName; + + IsStatic = method.IsStatic; + IsSealed = method.IsOverride && method.IsFinal; + IsUnsafe = true; + + SetVisibility (type is InterfaceGen && !IsStatic ? string.Empty : method.Visibility); + + // TODO: Clean up this logic + var is_explicit = opt.SupportDefaultInterfaceMethods && type is InterfaceGen && method.OverriddenInterfaceMethod != null; + var virt_ov = is_explicit ? string.Empty : method.IsOverride ? (opt.SupportDefaultInterfaceMethods && method.OverriddenInterfaceMethod != null ? " virtual" : " override") : method.IsVirtual ? " virtual" : string.Empty; + + IsVirtual = virt_ov.Trim () == "virtual"; + IsOverride = virt_ov.Trim () == "override"; + + // When using DIM, don't generate "virtual sealed" methods, remove both modifiers instead + if (opt.SupportDefaultInterfaceMethods && method.OverriddenInterfaceMethod != null && IsVirtual && IsSealed) { + IsVirtual = false; + IsSealed = false; + } + + if (is_explicit) + ExplicitInterfaceImplementation = GetDeclaringTypeOfExplicitInterfaceMethod (method.OverriddenInterfaceMethod); + + // Allow user to override our explicit interface logic + if (method.ExplicitInterface.HasValue ()) + ExplicitInterfaceImplementation = method.ExplicitInterface; + + if ((IsVirtual || !IsOverride) && type.RequiresNew (method.AdjustedName, method)) + IsShadow = true; + + // Allow user to override our virtual/override logic + if (method.ManagedOverride?.ToLowerInvariant () == "virtual") { + IsVirtual = true; + IsOverride = false; + } else if (method.ManagedOverride?.ToLowerInvariant () == "override") { + IsVirtual = false; + IsOverride = true; + } else if (method.ManagedOverride?.ToLowerInvariant () == "none") { + IsVirtual = false; + IsOverride = false; + } + + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + + method.JavadocInfo?.AddJavadocs (Comments); + + if (method.DeclaringType.IsGeneratable) + Comments.Add ($"// Metadata.xml XPath method reference: path=\"{method.GetMetadataXPathReference (method.DeclaringType)}\""); + + SourceWriterExtensions.AddObsolete (Attributes, method.Deprecated, opt, deprecatedSince: method.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, method.AnnotatedVisibility, false, opt); + + if (method.IsReturnEnumified) + Attributes.Add (new GeneratedEnumAttr (true)); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + Attributes.Add (new RegisterAttr (method.JavaName, method.JniSignature, method.IsVirtual ? method.GetConnectorNameFull (opt) : string.Empty, additionalProperties: method.AdditionalAttributeString ()) { + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.Method, + }); + + SourceWriterExtensions.AddMethodCustomAttributes (Attributes, method); + this.AddMethodParameters (method.Parameters, opt); + + SourceWriterExtensions.AddMethodBody (Body, method, opt); + } + + static string GetDeclaringTypeOfExplicitInterfaceMethod (Method method) + { + return method.OverriddenInterfaceMethod != null ? + GetDeclaringTypeOfExplicitInterfaceMethod (method.OverriddenInterfaceMethod) : + method.DeclaringType.FullName; + } + + public override void Write (CodeWriter writer) + { + callback?.Write (writer); + + base.Write (writer); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundMethodAbstractDeclaration.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundMethodAbstractDeclaration.cs new file mode 100644 index 00000000000..95db2399165 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundMethodAbstractDeclaration.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundMethodAbstractDeclaration : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + readonly MethodCallback method_callback; + + public BoundMethodAbstractDeclaration (GenBase gen, Method method, CodeGenerationOptions opt, GenBase impl) + { + this.method = method; + this.opt = opt; + + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + this.AddMethodParameters (method.Parameters, opt); + + if (method.RetVal.IsGeneric && gen != null) { + Name = method.Name; + ExplicitInterfaceImplementation = opt.GetOutputName (gen.FullName); + + SourceWriterExtensions.AddMethodCustomAttributes (Attributes, method); + + Body.Add ("throw new NotImplementedException ();"); + + return; + } + + Name = method.AdjustedName; + ExplicitInterfaceImplementation = method.ExplicitInterface; + + IsAbstract = true; + IsShadow = impl.RequiresNew (method.Name, method); + SetVisibility (method.Visibility); + + NewFirst = true; + + if (method.ManagedOverride?.ToLowerInvariant () == "override") + IsOverride = true; + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + method_callback = new MethodCallback (impl, method, opt, null, method.IsReturnCharSequence); + } + + method.JavadocInfo?.AddJavadocs (Comments); + + if (method.DeclaringType.IsGeneratable) + Comments.Add ($"// Metadata.xml XPath method reference: path=\"{method.GetMetadataXPathReference (method.DeclaringType)}\""); + + SourceWriterExtensions.AddObsolete (Attributes, method.Deprecated, opt, deprecatedSince: method.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, method.AnnotatedVisibility, false, opt); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + Attributes.Add (new RegisterAttr (method.JavaName, method.JniSignature, method.ConnectorName, additionalProperties: method.AdditionalAttributeString ())); + } + + SourceWriterExtensions.AddMethodCustomAttributes (Attributes, method); + } + + public override void Write (CodeWriter writer) + { + // Need to write our property callback first + method_callback?.Write (writer); + + base.Write (writer); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs new file mode 100644 index 00000000000..527dfdd2e8f --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class BoundMethodExtensionStringOverload : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + readonly string self_type; + + public BoundMethodExtensionStringOverload (Method method, CodeGenerationOptions opt, string selfType) + { + this.method = method; + this.opt = opt; + self_type = selfType; + + Name = method.Name; + IsStatic = true; + + SetVisibility (method.Visibility); + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal).Replace ("Java.Lang.ICharSequence", "string").Replace ("global::string", "string")); + + SourceWriterExtensions.AddObsolete (Attributes, method.Deprecated, opt, deprecatedSince: method.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, method.AnnotatedVisibility, false, opt); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + Parameters.Add (new MethodParameterWriter ("self", new TypeReferenceWriter (selfType)) { IsExtension = true }); + this.AddMethodParametersStringOverloads (method.Parameters, opt); + } + + protected override void WriteBody (CodeWriter writer) + { + SourceWriterExtensions.WriteMethodStringOverloadBody (writer, method, opt, true); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundMethodStringOverload.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundMethodStringOverload.cs new file mode 100644 index 00000000000..a6d73d7fbfe --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundMethodStringOverload.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class BoundMethodStringOverload : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + + public BoundMethodStringOverload (Method method, CodeGenerationOptions opt) + { + this.method = method; + this.opt = opt; + + Name = method.Name; + IsStatic = method.IsStatic; + + SetVisibility (method.Visibility); + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal).Replace ("Java.Lang.ICharSequence", "string").Replace ("global::string", "string")); + + SourceWriterExtensions.AddObsolete (Attributes, method.Deprecated, opt, deprecatedSince: method.DeprecatedSince); + SourceWriterExtensions.AddRestrictToWarning (Attributes, method.AnnotatedVisibility, false, opt); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + method.JavadocInfo?.AddJavadocs (Comments); + + this.AddMethodParametersStringOverloads (method.Parameters, opt); + } + + protected override void WriteBody (CodeWriter writer) + { + SourceWriterExtensions.WriteMethodStringOverloadBody (writer, method, opt, false); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundProperty.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundProperty.cs new file mode 100644 index 00000000000..41b48d88e14 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundProperty.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class BoundProperty : PropertyWriter + { + readonly MethodCallback getter_callback; + readonly MethodCallback setter_callback; + + public BoundProperty (GenBase gen, Property property, CodeGenerationOptions opt, bool withCallbacks = true, bool forceOverride = false) + { + Name = property.AdjustedName; + ExplicitInterfaceImplementation = property.ExplicitInterface; + PropertyType = new TypeReferenceWriter (opt.GetTypeReferenceName (property.Getter.RetVal)); + + SetVisibility (gen is InterfaceGen ? string.Empty : property.Getter.IsAbstract && property.Getter.RetVal.IsGeneric ? "protected" : (property.Setter ?? property.Getter).Visibility); + + IsUnsafe = true; + HasGet = true; + + var is_virtual = property.Getter.IsVirtual && (property.Setter == null || property.Setter.IsVirtual); + + if (is_virtual && withCallbacks) { + IsVirtual = true; + IsShadow = gen.RequiresNew (property); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) + getter_callback = new MethodCallback (gen, property.Getter, opt, property.AdjustedName, false); + + if (property.Setter != null && opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) + setter_callback = new MethodCallback (gen, property.Setter, opt, property.AdjustedName, false); + } + + if (forceOverride || ShouldForceOverride (property)) { + IsVirtual = false; + IsOverride = true; + } + + if ((property.Getter ?? property.Setter).IsStatic) { + IsStatic = true; + IsVirtual = false; + IsOverride = false; + } else if (gen.BaseSymbol != null) { + // It should be using AdjustedName instead of Name, but ICharSequence ("Formatted") properties are not caught by this... + var base_prop = gen.BaseSymbol.GetPropertyByName (property.Name, true); + + // If the matching base getter we found is a DIM, we do not override it, it should stay virtual + if (base_prop != null && !base_prop.Getter.IsInterfaceDefaultMethod) { + IsVirtual = false; + IsOverride = true; + } + } + + // Allow user to override our virtual/override logic + if (!forceOverride && (property.Getter ?? property.Setter).ManagedOverride?.ToLowerInvariant () == "virtual") { + IsVirtual = true; + IsOverride = false; + } else if (!forceOverride && (property.Getter ?? property.Setter).ManagedOverride?.ToLowerInvariant () == "override") { + IsVirtual = false; + IsOverride = true; + } else if (!forceOverride && (property.Getter ?? property.Setter).ManagedOverride?.ToLowerInvariant () == "none") { + IsVirtual = false; + IsOverride = false; + } + + // Add [Obsolete] or [ObsoletedOSPlatform] + if (property.IsWholePropertyDeprecated) { + // This case applies [Obsolete] to the entire property + SourceWriterExtensions.AddObsolete (Attributes, property.Getter.Deprecated.Trim (), opt, deprecatedSince: property.Getter.DeprecatedSince); + } else { + // This case applies [Obsolete] to just the getter + if (property.Getter?.Deprecated != null) + SourceWriterExtensions.AddObsolete (GetterAttributes, property.Getter.Deprecated.Trim (), opt, deprecatedSince: property.Getter?.DeprecatedSince); + + // This case applies [Obsolete] to just the setter + if (property.Setter?.Deprecated != null) + SourceWriterExtensions.AddObsolete (SetterAttributes, property.Setter.Deprecated.Trim (), opt, deprecatedSince: property.Setter?.DeprecatedSince); + } + + SourceWriterExtensions.AddRestrictToWarning (GetterAttributes, property.Getter.AnnotatedVisibility, false, opt); + SourceWriterExtensions.AddRestrictToWarning (SetterAttributes, property.Setter?.AnnotatedVisibility, false, opt); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt); + + SourceWriterExtensions.AddMethodCustomAttributes (GetterAttributes, property.Getter); + + if (gen.IsGeneratable) + GetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Getter.JavaName}'{property.Getter.Parameters.GetMethodXPathPredicate ()}]\""); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + GetterAttributes.Add (new RegisterAttr (property.Getter.JavaName, property.Getter.JniSignature, property.Getter.IsVirtual ? property.Getter.GetConnectorNameFull (opt) : string.Empty, additionalProperties: property.Getter.AdditionalAttributeString ())); + } + + SourceWriterExtensions.AddMethodBody (GetBody, property.Getter, opt); + + if (property.Setter != null) { + HasSet = true; + + if (gen.IsGeneratable) + SetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Setter.JavaName}'{property.Setter.Parameters.GetMethodXPathPredicate ()}]\""); + + SourceWriterExtensions.AddSupportedOSPlatform (SetterAttributes, property.Setter, opt); + + SourceWriterExtensions.AddMethodCustomAttributes (SetterAttributes, property.Setter); + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + SetterAttributes.Add (new RegisterAttr (property.Setter.JavaName, property.Setter.JniSignature, property.Setter.IsVirtual ? property.Setter.GetConnectorNameFull (opt) : string.Empty, additionalProperties: property.Setter.AdditionalAttributeString ())); + } + + var pname = property.Setter.Parameters [0].Name; + property.Setter.Parameters [0].Name = "value"; + SourceWriterExtensions.AddMethodBody (SetBody, property.Setter, opt); + property.Setter.Parameters [0].Name = pname; + + } else if (property.GenerateDispatchingSetter) { + HasSet = true; + SetterComments.Add ("// This is a dispatching setter"); + SetBody.Add ($"Set{property.Name} (value);"); + } + + AddJavadocs (property); + } + + public override void Write (CodeWriter writer) + { + // Need to write our property callbacks first + getter_callback?.Write (writer); + setter_callback?.Write (writer); + + base.Write (writer); + } + + bool ShouldForceOverride (Property property) + { + // + // This is a special workaround for AdapterView inheritance. + // (How it is special? They have hand-written bindings AND brings generic + // version of AdapterView in the inheritance, also added by metadata!) + // + // They are on top of fragile hand-bound code, and when we are making changes + // in generator, they bite. Since we are not going to bring API breakage + // right now, we need special workarounds to get things working. + // + // So far, what we need here is to have AbsSpinner.Adapter compile. + // + // > platforms/*/src/generated/Android.Widget.AbsSpinner.cs(156,56): error CS0533: + // > `Android.Widget.AbsSpinner.Adapter' hides inherited abstract member + // > `Android.Widget.AdapterView.Adapter + // + // It is because the AdapterView.Adapter is hand-bound and cannot be + // detected by generator! + // + // So, we explicitly treat it as a special-case. + // + // Then, Spinner, ListView and GridView instantiate them, so they are also special cases. + // + if (property.Name == "Adapter" && + (property.Getter.DeclaringType.BaseGen.FullName == "Android.Widget.AdapterView" || + property.Getter.DeclaringType.BaseGen.BaseGen != null && property.Getter.DeclaringType.BaseGen.BaseGen.FullName == "Android.Widget.AdapterView")) + return true; + // ... and the above breaks generator tests... + if (property.Name == "Adapter" && + (property.Getter.DeclaringType.BaseGen.FullName == "Xamarin.Test.AdapterView" || + property.Getter.DeclaringType.BaseGen.BaseGen != null && property.Getter.DeclaringType.BaseGen.BaseGen.FullName == "Xamarin.Test.AdapterView")) + return true; + + return false; + } + + void AddJavadocs (Property property) + { + if (property.Getter?.JavadocInfo == null && property.Setter?.JavadocInfo == null) + return; + + var memberDocs = new XElement ("member"); + XElement[] copyrightExtra = null; + + if (property.Getter?.JavadocInfo != null) { + memberDocs.Add (property.Getter.JavadocInfo.ParseJavadoc ()); + copyrightExtra = property.Getter.JavadocInfo.Copyright; + } + + if (property.Setter?.JavadocInfo != null) { + var setterDocs = new XElement ("member", property.Setter.JavadocInfo.ParseJavadoc ()); + if (copyrightExtra == null) { + copyrightExtra = property.Setter.JavadocInfo.Copyright; + } + + MergeSummary (memberDocs, setterDocs); + MergeRemarks (memberDocs, setterDocs); + MergeReturns (memberDocs, setterDocs); + + memberDocs.Add (setterDocs.Nodes ()); + } + + if (copyrightExtra != null) { + var remarks = memberDocs.Element ("remarks"); + remarks?.Add (copyrightExtra); + } + + JavadocInfo.AddComments (Comments, memberDocs.Elements ()); + } + + static void MergeSummary (XElement mergeInto, XElement mergeFrom) + { + var toContent = mergeInto.Element ("summary"); + var fromContent = mergeFrom.Element ("summary"); + + if (toContent == null && fromContent != null) { + fromContent.Remove (); + mergeInto.Add (fromContent); + } + else if (toContent != null && fromContent != null) { + fromContent.Remove (); + toContent.Add (" -or- "); + toContent.Add (fromContent.Nodes ()); + } + } + + static void MergeRemarks (XElement mergeInto, XElement mergeFrom) + { + var toContent = mergeInto.Element ("remarks"); + var fromContent = mergeFrom.Element ("remarks"); + + if (toContent == null && fromContent != null) { + fromContent.Remove (); + mergeInto.Add (fromContent); + } + else if (toContent != null && fromContent != null) { + fromContent.Remove (); + toContent.AddFirst (new XElement ("para", "Property getter documentation:")); + toContent.Add (new XElement ("para", "Property setter documentation:")); + toContent.Add (fromContent.Nodes ()); + } + } + + static void MergeReturns (XElement mergeInto, XElement mergeFrom) + { + var toContent = mergeInto.Element ("returns"); + var fromContent = mergeFrom.Element ("returns"); + + if (toContent != null && fromContent != null) { + if (toContent.Value == fromContent.Value) { + fromContent.Remove (); + } else { + toContent.Add (" "); + toContent.Add (fromContent.Nodes ()); + } + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/BoundPropertyStringVariant.cs b/external/Java.Interop/tools/generator/SourceWriters/BoundPropertyStringVariant.cs new file mode 100644 index 00000000000..7a20ae516e6 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/BoundPropertyStringVariant.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; +using Xamarin.Android.Binder; + +namespace generator.SourceWriters +{ + // When a property has a type of 'Java.Lang.ICharSequence' we usually generate + // an overload with type 'string' as a convenience for the user. + public class BoundPropertyStringVariant : PropertyWriter + { + public BoundPropertyStringVariant (Property property, CodeGenerationOptions opt, BoundAbstractProperty original) + : this (property, opt, original.IsVirtual) + { } + + public BoundPropertyStringVariant (Property property, CodeGenerationOptions opt, BoundProperty original) + : this(property, opt, original.IsVirtual) + { } + + private BoundPropertyStringVariant (Property property, CodeGenerationOptions opt, bool isOriginalVirtual) + { + var is_array = property.Getter.RetVal.IsArray; + + Name = property.Name; + + PropertyType = new TypeReferenceWriter ("string" + (is_array ? "[]" : string.Empty)) { + Nullable = opt.SupportNullableReferenceTypes + }; + + SetVisibility ((property.Setter ?? property.Getter).Visibility); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt); + + string arrayConvertMethod = opt.GetStringArrayToCharSequenceArrayMethodName (); + + HasGet = true; + + if (is_array) + GetBody.Add ($"return {arrayConvertMethod} ({property.AdjustedName});"); + else + GetBody.Add ($"return {property.AdjustedName} == null ? null : {property.AdjustedName}.ToString ();"); + + if (property.Setter is null) + return; + + HasSet = true; + + if (is_array) { + SetBody.Add ($"global::Java.Lang.ICharSequence[] jlsa = {arrayConvertMethod} (value);"); + SetBody.Add ($"{property.AdjustedName} = jlsa;"); + SetBody.Add ($"foreach (var jls in jlsa) if (jls != null) jls.Dispose ();"); + } else { + if (isOriginalVirtual) { + SetBody.Add ($"var jls = value == null ? null : new global::Java.Lang.String (value);"); + SetBody.Add ($"{property.AdjustedName} = jls;"); + SetBody.Add ($"if (jls != null) jls.Dispose ();"); + } else { + // Emit a "fast" path if the property is non-virtual + IsUnsafe = true; + var method = property.Setter; + var parameter = method.Parameters [0]; + + SetBody.Add ($"const string __id = \"{method.JavaName}.{method.JniSignature}\";"); + SetBody.Add ($"global::Java.Interop.JniObjectReference {parameter.ToNative (opt)} = global::Java.Interop.JniEnvironment.Strings.NewString (value);"); + + SetBody.Add ("try {"); + + SourceWriterExtensions.AddMethodBodyTryBlock (SetBody, method, opt); + + SetBody.Add ("} finally {"); + SetBody.Add ($"\tglobal::Java.Interop.JniObjectReference.Dispose (ref {parameter.ToNative (opt)});"); + SetBody.Add ("}"); + } + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/CharSequenceEnumeratorMethod.cs b/external/Java.Interop/tools/generator/SourceWriters/CharSequenceEnumeratorMethod.cs new file mode 100644 index 00000000000..79c4b1f6d2f --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/CharSequenceEnumeratorMethod.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class CharSequenceEnumeratorMethod : MethodWriter + { + // System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + // { + // return GetEnumerator (); + // } + public CharSequenceEnumeratorMethod () + { + Name = "global::System.Collections.IEnumerable.GetEnumerator"; + ReturnType = new TypeReferenceWriter ("global::System.Collections.IEnumerator"); + + Body.Add ("return GetEnumerator ();"); + } + } + + public class CharSequenceGenericEnumeratorMethod : MethodWriter + { + // public System.Collections.Generic.IEnumerator GetEnumerator () + // { + // for (int i = 0; i < Length(); i++) + // yield return CharAt (i); + // } + public CharSequenceGenericEnumeratorMethod () + { + Name = "GetEnumerator"; + ReturnType = new TypeReferenceWriter ("global::System.Collections.Generic.IEnumerator"); + + IsPublic = true; + + Body.Add ("for (int i = 0; i < Length (); i++)"); + Body.Add ("\tyield return CharAt (i);"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/ClassInvokerClass.cs b/external/Java.Interop/tools/generator/SourceWriters/ClassInvokerClass.cs new file mode 100644 index 00000000000..41e983ea7bc --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/ClassInvokerClass.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Schema; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class ClassInvokerClass : ClassWriter + { + public ClassInvokerClass (ClassGen klass, CodeGenerationOptions opt) + { + Name = $"{klass.Name}Invoker"; + + IsInternal = true; + IsPartial = true; + UsePriorityOrder = true; + + Inherits = klass.Name; + + foreach (var igen in klass.GetAllDerivedInterfaces ().Where (i => i.IsGeneric)) + Implements.Add (opt.GetOutputName (igen.FullName)); + + Attributes.Add (new RegisterAttr (klass.RawJniName, noAcw: true, additionalProperties: klass.AdditionalAttributeString ()) { + UseGlobal = true, + MemberType = opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 ? null : (MemberTypes?) MemberTypes.TypeInfo, + }); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, klass, opt); + + ConstructorWriter ctor = opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1 + ? new ConstructorWriter { + Name = Name, + IsPublic = true, + BaseCall = "base (ref reference, options)", + Parameters = { + new MethodParameterWriter ("reference", new TypeReferenceWriter ("ref JniObjectReference")), + new MethodParameterWriter ("options", new TypeReferenceWriter ("JniObjectReferenceOptions")), + }, + } + : new ConstructorWriter { + Name = Name, + IsPublic = true, + BaseCall = "base (handle, transfer)", + Parameters = { + new MethodParameterWriter ("handle", TypeReferenceWriter.IntPtr), + new MethodParameterWriter ("transfer", new TypeReferenceWriter ("JniHandleOwnership")), + }, + } + ; + + Constructors.Add (ctor); + + // ClassInvokerHandle + Fields.Add (new PeerMembersField (opt, klass.RawJniName, $"{klass.Name}Invoker", false)); + Properties.Add (new JniPeerMembersGetter ()); + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + Properties.Add (new ThresholdTypeGetter ()); + } + + AddMemberInvokers (klass, opt, new HashSet (), klass.SkippedInvokerMethods); + } + + void AddMemberInvokers (ClassGen klass, CodeGenerationOptions opt, HashSet members, HashSet skipInvokers) + { + AddPropertyInvokers (klass, klass.Properties, members, opt); + AddMethodInvokers (klass, klass.Methods, members, skipInvokers, null, opt); + + foreach (var iface in klass.GetAllDerivedInterfaces ()) { + AddPropertyInvokers (klass, iface.Properties.Where (p => !klass.ContainsProperty (p.Name, false, false)), members, opt); + AddMethodInvokers (klass, iface.Methods.Where (m => (opt.SupportDefaultInterfaceMethods || !m.IsInterfaceDefaultMethod) && !klass.ContainsMethod (m, false, false) && !klass.IsCovariantMethod (m) && !klass.ExplicitlyImplementedInterfaceMethods.Contains (m.GetSignature ())), members, skipInvokers, iface, opt); + } + + if (klass.BaseGen != null && klass.BaseGen.FullName != "Java.Lang.Object") + AddMemberInvokers (klass.BaseGen, opt, members, skipInvokers); + } + + void AddPropertyInvokers (ClassGen klass, IEnumerable properties, HashSet members, CodeGenerationOptions opt) + { + foreach (var prop in properties) { + if (members.Contains (prop.Name)) + continue; + + members.Add (prop.Name); + + if ((prop.Getter != null && !prop.Getter.IsAbstract) || (prop.Setter != null && !prop.Setter.IsAbstract)) + continue; + + var bound_property = new BoundProperty (klass, prop, opt, false, true); + Properties.Add (bound_property); + + if (prop.Type.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) && !bound_property.IsOverride) + Properties.Add (new BoundPropertyStringVariant (prop, opt, bound_property)); + } + } + + void AddMethodInvokers (ClassGen klass, IEnumerable methods, HashSet members, HashSet skipInvokers, InterfaceGen gen, CodeGenerationOptions opt) + { + foreach (var m in methods) { + if (skipInvokers.Contains (m.GetSkipInvokerSignature ())) + continue; + + var sig = m.GetSignature (); + + if (members.Contains (sig)) + continue; + + members.Add (sig); + + if (!m.IsAbstract) + continue; + + if (klass.IsExplicitlyImplementedMethod (sig)) { + Methods.Add (new ExplicitInterfaceInvokerMethod (gen, m, opt)); + } else { + m.IsOverride = true; + Methods.Add (new BoundMethod (klass, m, opt, false)); + + if (m.Asyncify) + Methods.Add (new MethodAsyncWrapper (m, opt)); + + m.IsOverride = false; + } + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/ClassInvokers.cs b/external/Java.Interop/tools/generator/SourceWriters/ClassInvokers.cs new file mode 100644 index 00000000000..ad03036f31d --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/ClassInvokers.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class ClassHandleGetter : PropertyWriter + { + // internal static new IntPtr class_ref { + // get { return _members.JniPeerType.PeerReference.Handle; } + // } + public ClassHandleGetter (bool requireNew) + { + Name = "class_ref"; + PropertyType = TypeReferenceWriter.IntPtr; + + IsInternal = true; + IsStatic = true; + IsShadow = requireNew; + + HasGet = true; + GetBody.Add ("return _members.JniPeerType.PeerReference.Handle;"); + } + } + + public class InterfaceHandleGetter : PropertyWriter + { + // static IntPtr java_class_ref { + // get { return _members.JniPeerType.PeerReference.Handle; } + // } + public InterfaceHandleGetter (string members) + { + Name = "java_class_ref"; + PropertyType = TypeReferenceWriter.IntPtr; + + IsStatic = true; + + HasGet = true; + GetBody.Add ($"return {members}.JniPeerType.PeerReference.Handle;"); + } + } + + public class JniPeerMembersGetter : PropertyWriter + { + // [DebuggerBrowsable (DebuggerBrowsableState.Never)] + // [EditorBrowsable (EditorBrowsableState.Never)] + // public override global::Java.Interop.JniPeerMembers JniPeerMembers { + // get { return _members; } + // } + public JniPeerMembersGetter (string name = "_members") + { + Name = "JniPeerMembers"; + PropertyType = new TypeReferenceWriter ("global::Java.Interop.JniPeerMembers"); + + IsPublic = true; + IsOverride = true; + + Attributes.Add (new DebuggerBrowsableAttr ()); + Attributes.Add (new EditorBrowsableAttr ()); + + HasGet = true; + GetBody.Add ($"return {name};"); + } + } + + public class ClassThresholdClassGetter : PropertyWriter + { + // [DebuggerBrowsable (DebuggerBrowsableState.Never)] + // [EditorBrowsable (EditorBrowsableState.Never)] + // protected override IntPtr ThresholdClass { + // get { return _members.JniPeerType.PeerReference.Handle; } + // } + public ClassThresholdClassGetter () + { + Name = "ThresholdClass"; + PropertyType = TypeReferenceWriter.IntPtr; + + IsProtected = true; + IsOverride = true; + + Attributes.Add (new DebuggerBrowsableAttr ()); + Attributes.Add (new EditorBrowsableAttr ()); + + HasGet = true; + GetBody.Add ("return _members.JniPeerType.PeerReference.Handle;"); + } + } + + public class InterfaceThresholdClassGetter : PropertyWriter + { + // [DebuggerBrowsable (DebuggerBrowsableState.Never)] + // [EditorBrowsable (EditorBrowsableState.Never)] + // protected override IntPtr ThresholdClass { + // get { return class_ref; } + // } + public InterfaceThresholdClassGetter (string getExpression) + { + Name = "ThresholdClass"; + PropertyType = TypeReferenceWriter.IntPtr; + + IsProtected = true; + IsOverride = true; + + Attributes.Add (new DebuggerBrowsableAttr ()); + Attributes.Add (new EditorBrowsableAttr ()); + + HasGet = true; + GetBody.Add ($"return {getExpression};"); + } + } + + public class ThresholdTypeGetter : PropertyWriter + { + // [DebuggerBrowsable (DebuggerBrowsableState.Never)] + // [EditorBrowsable (EditorBrowsableState.Never)] + // protected override global::System.Type ThresholdType { + // get { return _members.ManagedPeerType; } + // } + public ThresholdTypeGetter (string members = "_members") + { + Name = "ThresholdType"; + PropertyType = new TypeReferenceWriter ("global::System.Type"); + + IsProtected = true; + IsOverride = true; + + Attributes.Add (new DebuggerBrowsableAttr ()); + Attributes.Add (new EditorBrowsableAttr ()); + + HasGet = true; + GetBody.Add ($"return {members}.ManagedPeerType;"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/ConstructorPartialMethod.cs b/external/Java.Interop/tools/generator/SourceWriters/ConstructorPartialMethod.cs new file mode 100644 index 00000000000..af0c4c4b878 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/ConstructorPartialMethod.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.Android.Binder; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class ConstructorPartialMethod : MethodWriter + { + public ConstructorPartialMethod (string partialMethodName) + { + Name = partialMethodName; + IsPartial = true; + IsDeclaration = true; + ReturnType = new TypeReferenceWriter ("void"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/CreateImplementorMethod.cs b/external/Java.Interop/tools/generator/SourceWriters/CreateImplementorMethod.cs new file mode 100644 index 00000000000..4d87793f794 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/CreateImplementorMethod.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class CreateImplementorMethod : MethodWriter + { + public CreateImplementorMethod (InterfaceGen iface, CodeGenerationOptions opt) + { + Name = $"__Create{iface.Name}Implementor"; + + ReturnType = new TypeReferenceWriter ($"{opt.GetOutputName (iface.FullName)}Implementor"); + + Body.Add ($"return new {opt.GetOutputName (iface.FullName)}Implementor ({(iface.NeedsSender ? "this" : "")});"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/ExplicitInterfaceInvokerMethod.cs b/external/Java.Interop/tools/generator/SourceWriters/ExplicitInterfaceInvokerMethod.cs new file mode 100644 index 00000000000..d6db5d484e4 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/ExplicitInterfaceInvokerMethod.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class ExplicitInterfaceInvokerMethod : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + + public ExplicitInterfaceInvokerMethod (GenBase iface, Method method, CodeGenerationOptions opt) + { + this.method = method; + this.opt = opt; + + Name = method.Name; + + IsUnsafe = true; + + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + ExplicitInterfaceImplementation = opt.GetOutputName (iface.FullName); + + this.AddMethodParameters (method.Parameters, opt); + SourceWriterExtensions.AddMethodBody (Body, method, opt); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs b/external/Java.Interop/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs new file mode 100644 index 00000000000..626eb1cb00d --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs @@ -0,0 +1,492 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using Xamarin.SourceWriter; +using Xamarin.Android.Binder; + +namespace generator.SourceWriters +{ + public static class SourceWriterExtensions + { + const int MINIMUM_API_LEVEL = 21; + + public static void AddField (TypeWriter tw, GenBase type, Field field, CodeGenerationOptions opt) + { + if (field.NeedsProperty) + tw.Properties.Add (new BoundFieldAsProperty (type, field, opt)); + else + tw.Fields.Add (new BoundField (type, field, opt)); + } + + public static bool AddFields (TypeWriter tw, GenBase gen, List fields, HashSet seen, CodeGenerationOptions opt, CodeGeneratorContext context) + { + var needsProperty = false; + + foreach (var f in fields) { + if (gen.ContainsName (f.Name)) { + Report.LogCodedWarning (0, GetFieldCollisionMessage (gen, f), f, gen.FullName, f.Name, gen.JavaName); + continue; + } + + if (seen != null && seen.Contains (f.Name)) { + Report.LogCodedWarning (0, Report.WarningDuplicateField, f, gen.FullName, f.Name, gen.JavaName); + continue; + } + + if (f.Validate (opt, gen.TypeParameters, context)) { + if (seen != null) + seen.Add (f.Name); + + needsProperty = needsProperty || f.NeedsProperty; + AddField (tw, gen, f, opt); + } + } + + return needsProperty; + } + + public static Report.LocalizedMessage GetFieldCollisionMessage (GenBase gen, Field f) + { + if (gen.HasNestedType (f.Name)) + return Report.WarningFieldNameCollision_NestedType; + if (gen.ContainsProperty (f.Name, false)) + return Report.WarningFieldNameCollision_Property; + + return Report.WarningFieldNameCollision_Method; + } + + public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, InterfaceGen iface, ClassGen target, CodeGenerationOptions opt) + { + var methods = target.Methods.Concat (target.Properties.Where (p => p.Setter != null).Select (p => p.Setter)); + var props = new HashSet (); + var refs = new HashSet (); + var eventMethods = methods.Where (m => m.IsListenerConnector && m.EventName != string.Empty && m.ListenerType == iface).OrderBy (m => m.Parameters.Count).GroupBy (m => m.Name).Select (g => g.First ()).Distinct (); + + foreach (var method in eventMethods) { + var name = method.CalculateEventName (target.ContainsName); + + if (string.IsNullOrEmpty (name)) { + Report.LogCodedWarning (0, Report.WarningEmptyEventName, method, iface.FullName, method.Name); + continue; + } + + if (opt.GetSafeIdentifier (name) != name) { + Report.LogCodedWarning (0, Report.WarningInvalidEventName, method, iface.FullName, method.Name); + continue; + } + + var prop = target.Properties.FirstOrDefault (p => p.Setter == method); + + if (prop != null) { + var setter = "__Set" + prop.Name; + props.Add (prop.Name); + refs.Add (setter); + + AddInterfaceListenerEventsAndProperties (tw, iface, target, name, setter, + string.Format ("__v => {0} = __v", prop.Name), + string.Format ("__v => {0} = null", prop.Name), opt, prop.Getter); + } else { + refs.Add (method.Name); + string rm = null; + string remove; + + if (method.Name.StartsWith ("Set", StringComparison.Ordinal)) + remove = string.Format ("__v => {0} (null)", method.Name); + else if (method.Name.StartsWith ("Add", StringComparison.Ordinal) && + (rm = "Remove" + method.Name.Substring ("Add".Length)) != null && + methods.Where (m => m.Name == rm).Any ()) + remove = string.Format ("__v => {0} (__v)", rm); + else + remove = string.Format ("__v => {{throw new NotSupportedException (\"Cannot unregister from {0}.{1}\");}}", + iface.FullName, method.Name); + + AddInterfaceListenerEventsAndProperties (tw, iface, target, name, method.Name, + method.Name, + remove, opt, method); + } + } + + foreach (var r in refs) + tw.Fields.Add (new WeakImplementorField (r, opt)); + + tw.Methods.Add (new CreateImplementorMethod (iface, opt)); + } + + // Parameter 'setListenerMethod' refers to the method used to set the listener, like 'addOnRoutingChangedListener'/'setOnRoutingChangedListener'. + // This is used to determine what API level the listener setter is available on. + public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, InterfaceGen iface, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt, Method setListenerMethod) + { + if (!iface.IsValid) + return; + + foreach (var method in iface.Methods) { + var nameSpec = iface.Methods.Count > 1 ? method.EventName ?? method.AdjustedName : string.Empty; + var nameUnique = string.IsNullOrEmpty (nameSpec) ? name : nameSpec; + + if (nameUnique.StartsWith ("On", StringComparison.Ordinal)) + nameUnique = nameUnique.Substring (2); + + if (target.ContainsName (nameUnique)) + nameUnique += "Event"; + + AddInterfaceListenerEventOrProperty (tw, iface, method, target, nameUnique, connector_fmt, add, remove, opt, setListenerMethod); + } + } + + public static void AddInterfaceListenerEventOrProperty (TypeWriter tw, InterfaceGen iface, Method method, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt, Method setListenerMethod) + { + if (method.EventName == string.Empty) + return; + + var nameSpec = iface.Methods.Count > 1 ? method.AdjustedName : string.Empty; + var idx = iface.FullName.LastIndexOf (".", StringComparison.Ordinal); + var start = iface.Name.StartsWith ("IOn", StringComparison.Ordinal) ? 3 : 1; + var full_delegate_name = iface.FullName.Substring (0, idx + 1) + iface.Name.Substring (start, iface.Name.Length - start - 8) + nameSpec; + + if (method.IsSimpleEventHandler) + full_delegate_name = "EventHandler"; + else if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty) + full_delegate_name = "EventHandler<" + iface.FullName.Substring (0, idx + 1) + iface.GetArgsName (method) + ">"; + else + full_delegate_name += "Handler"; + + if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty) { + if (opt.GetSafeIdentifier (name) != name) { + Report.LogCodedWarning (0, Report.WarningInvalidEventName2, method, iface.FullName, name); + return; + } else { + var mt = target.Methods.Where (method => string.Compare (method.Name, connector_fmt, StringComparison.OrdinalIgnoreCase) == 0 && method.IsListenerConnector).FirstOrDefault (); + var hasHandlerArgument = mt != null && mt.IsListenerConnector && mt.Parameters.Count == 2 && mt.Parameters [1].Type == "Android.OS.Handler"; + + tw.Events.Add (new InterfaceListenerEvent (iface, setListenerMethod, name, nameSpec, full_delegate_name, connector_fmt, add, remove, hasHandlerArgument, opt)); + } + } else { + if (opt.GetSafeIdentifier (name) != name) { + Report.LogCodedWarning (0, Report.WarningInvalidEventPropertyName, method, iface.FullName, name); + return; + } + + tw.Properties.Add (new InterfaceListenerPropertyImplementor (iface, name, opt)); + tw.Properties.Add (new InterfaceListenerProperty (iface, name, nameSpec, method.AdjustedName, full_delegate_name, opt)); + } + } + + public static void AddMethodCustomAttributes (List attributes, Method method) + { + if (method.GenericArguments != null && method.GenericArguments.Any ()) + attributes.Add (new CustomAttr (method.GenericArguments.ToGeneratedAttributeString ())); + if (method.CustomAttributes != null) + attributes.Add (new CustomAttr (method.CustomAttributes)); + if (method.Annotation != null) + attributes.Add (new CustomAttr (method.Annotation)); + } + + public static void AddMethodParameters (this ITakeParameters method, ParameterList parameters, CodeGenerationOptions opt) + { + foreach (var p in parameters) { + var para = new MethodParameterWriter (opt.GetSafeIdentifier (p.Name), new TypeReferenceWriter (opt.GetTypeReferenceName (p))); + + if (p.IsEnumified) + para.Attributes.Add (new GeneratedEnumAttr ()); + if (p.Annotation != null) + para.Attributes.Add (new CustomAttr (p.Annotation)); + + method.Parameters.Add (para); + } + } + + // This replaces any `Java.Lang.ICharSequence` parameters with `string`. + public static void AddMethodParametersStringOverloads (this MethodWriter method, ParameterList parameters, CodeGenerationOptions opt) + { + foreach (var p in parameters) { + var para = new MethodParameterWriter (opt.GetSafeIdentifier (p.Name), new TypeReferenceWriter (opt.GetTypeReferenceName (p).Replace ("Java.Lang.ICharSequence", "string").Replace ("global::string", "string"))); + + if (p.IsEnumified) + para.Attributes.Add (new GeneratedEnumAttr ()); + if (p.Annotation != null) + para.Attributes.Add (new CustomAttr (p.Annotation)); + + method.Parameters.Add (para); + } + } + + public static string GetInvokeType (string type) + { + switch (type) { + case "Bool": return "Boolean"; + case "Byte": return "SByte"; + case "Int": return "Int32"; + case "Short": return "Int16"; + case "Long": return "Int64"; + case "Float": return "Single"; + case "UInt": return "Int32"; + case "UShort": return "Int16"; + case "ULong": return "Int64"; + case "UByte": return "SByte"; + default: return type; + } + } + + public static void AddMethodBody (List body, Method method, CodeGenerationOptions opt, string members = "_members") + { + body.Add ($"const string __id = \"{method.JavaName}.{method.JniSignature}\";"); + + foreach (string prep in method.Parameters.GetCallPrep (opt)) + body.Add (prep); + + body.Add ("try {"); + + AddMethodBodyTryBlock (body, method, opt, members); + + if (method.IsCompatVirtualMethod) { + body.Add ("}"); + body.Add ("catch (Java.Lang.NoSuchMethodError) {"); + body.Add (" throw new Java.Lang.AbstractMethodError (__id);"); + } + + body.Add ("} finally {"); + + foreach (string cleanup in method.Parameters.GetCallCleanup (opt)) + body.Add ("\t" + cleanup); + + foreach (var p in method.Parameters.Where (para => para.ShouldGenerateKeepAlive ())) + body.Add ($"\tglobal::System.GC.KeepAlive ({opt.GetSafeIdentifier (p.Name)});"); + + body.Add ("}"); + } + + public static void AddMethodBodyTryBlock (List body, Method method, CodeGenerationOptions opt, string members = "_members") + { + AddParameterListCallArgs (body, method.Parameters, opt, false); + + var invokeType = JavaInteropCodeGenerator.GetInvokeType (method.RetVal.CallMethodPrefix); + + var return_var = method.IsVoid ? string.Empty : "var __rm = "; + var method_type = method.IsStatic ? "StaticMethods" : "InstanceMethods"; + var virt_type = method switch + { + { IsStatic: true } => string.Empty, + { IsFinal: true } => "Nonvirtual", + { IsVirtual: true, IsAbstract: false } => "Virtual", + { IsInterfaceDefaultMethod: true } => "Virtual", + _ => "Abstract" + }; + var call_args = method.Parameters.GetCallArgs (opt, invoker: false); + var this_param = method.IsStatic ? $"__id{call_args}" : $"__id, this{call_args}"; + + // Example: var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); + body.Add ($"\t{return_var}{members}.{method_type}.Invoke{virt_type}{invokeType}Method ({this_param});"); + + if (!method.IsVoid) { + var r = "__rm"; + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 && invokeType == "Object") { + r += ".Handle"; + } + body.Add ($"\treturn {method.RetVal.ReturnCast}{method.RetVal.FromNative (opt, r, true, false) + opt.GetNullForgiveness (method.RetVal)};"); + } + } + + public static void AddParameterListCallArgs (List body, ParameterList parameters, CodeGenerationOptions opt, bool invoker) + { + if (parameters.Count == 0) + return; + + invoker = invoker && opt.EmitLegacyInterfaceInvokers; + + var JValue = invoker ? "JValue" : "JniArgumentValue"; + + body.Add ($"\t{JValue}* __args = stackalloc {JValue} [{parameters.Count}];"); + + for (var i = 0; i < parameters.Count; ++i) { + var p = parameters [i]; + body.Add ($"\t__args [{i}] = new {JValue} ({p.GetCall (opt)});"); + } + } + + public static void AddSupportedOSPlatform (List attributes, ApiVersionsSupport.IApiAvailability member, CodeGenerationOptions opt) + { + AddSupportedOSPlatform (attributes, member.ApiAvailableSince, opt); + AddUnsupportedOSPlatform (attributes, member.ApiRemovedSince, opt); + } + + public static void AddSupportedOSPlatform (List attributes, AndroidSdkVersion since, CodeGenerationOptions opt) + { + // There's no sense in writing say 'android15' because we do not support older APIs, + // so those APIs will be available in all of our versions. + if (since > MINIMUM_API_LEVEL && opt.CodeGenerationTarget == Xamarin.Android.Binder.CodeGenerationTarget.XAJavaInterop1) + attributes.Add (new SupportedOSPlatformAttr (since)); + } + + public static void AddUnsupportedOSPlatform (List attributes, AndroidSdkVersion since, CodeGenerationOptions opt) + { + // Here it makes sense to still write 'android15' because it will be missing in later versions like `android35`. + if (since > 0 && opt.CodeGenerationTarget == CodeGenerationTarget.XAJavaInterop1) + attributes.Add (new UnsupportedOSPlatformAttr (since)); + } + + public static void AddObsolete (List attributes, string message, CodeGenerationOptions opt, bool forceDeprecate = false, bool isError = false, AndroidSdkVersion? deprecatedSince = null) + { + // Bail if we're not obsolete + if ((!forceDeprecate && !message.HasValue ()) || message == "not deprecated") + return; + + // Check if we should use [ObsoletedOSPlatform] instead of [Obsolete] + if (AddObsoletedOSPlatformAttribute (attributes, message, deprecatedSince, opt)) + return; + + attributes.Add (new ObsoleteAttr (message, isError)); + } + + // Returns true if attribute was applied + static bool AddObsoletedOSPlatformAttribute (List attributes, string message, AndroidSdkVersion? deprecatedSince, CodeGenerationOptions opt) + { + if (!opt.UseObsoletedOSPlatformAttributes) + return false; + + // If it was obsoleted in a version earlier than we support (like 15), use a regular [Obsolete] instead + if (!deprecatedSince.HasValue || deprecatedSince.Value <= MINIMUM_API_LEVEL) + return false; + + // This is the default Android message, but it isn't useful so remove it + if (message == "deprecated") + message = string.Empty; + + attributes.Add (new ObsoletedOSPlatformAttr (message, deprecatedSince.Value)); + + return true; + } + + public static void AddRestrictToWarning (List attributes, string scope, bool isType, CodeGenerationOptions opt) + { + if (!opt.UseRestrictToAttributes) + return; + + // Empty scope means there is no @RestrictTo annotation + if (!scope.HasValue ()) + return; + + // We can't add 2 [Obsolete] attributes, we'll let a "real" obsolete message take precedence + if (attributes.OfType ().Any ()) + return; + + // We consider all scopes to be "internal" API we need to warn about + attributes.Add (new RestrictToAttr (isType)); + } + + public static void WriteMethodInvokerBodyLegacy (CodeWriter writer, Method method, CodeGenerationOptions opt, string contextThis) + { + writer.WriteLine ($"if ({method.EscapedIdName} == IntPtr.Zero)"); + writer.WriteLine ($"\t{method.EscapedIdName} = JNIEnv.GetMethodID (class_ref, \"{method.JavaName}\", \"{method.JniSignature}\");"); + + foreach (var prep in method.Parameters.GetCallPrep (opt)) + writer.WriteLine (prep); + + WriteParameterListCallArgs (writer, method.Parameters, opt, invoker: true); + + var env_method = $"Call{method.RetVal.CallMethodPrefix}Method"; + var call = $"{method.RetVal.ReturnCast}JNIEnv.{env_method} ({contextThis}, {method.EscapedIdName}{method.Parameters.GetCallArgs (opt, invoker: true)})"; + + if (method.IsVoid) + writer.WriteLine (call + ";"); + else + writer.WriteLine ($"{(method.Parameters.HasCleanup ? "var __ret = " : "return ")}{method.RetVal.FromNative (opt, call, true) + opt.GetNullForgiveness (method.RetVal)};"); + + foreach (var cleanup in method.Parameters.GetCallCleanup (opt)) + writer.WriteLine (cleanup); + + if (!method.IsVoid && method.Parameters.HasCleanup) + writer.WriteLine ("return __ret;"); + } + + public static void WriteParameterListCallArgs (CodeWriter writer, ParameterList parameters, CodeGenerationOptions opt, bool invoker) + { + if (parameters.Count == 0) + return; + + invoker = invoker && opt.EmitLegacyInterfaceInvokers; + + var JValue = invoker ? "JValue" : "JniArgumentValue"; + + writer.WriteLine ($"{JValue}* __args = stackalloc {JValue} [{parameters.Count}];"); + + for (var i = 0; i < parameters.Count; ++i) { + var p = parameters [i]; + writer.WriteLine ($"__args [{i}] = new {JValue} ({p.GetCall (opt)});"); + } + } + + public static void WriteMethodStringOverloadBody (CodeWriter writer, Method method, CodeGenerationOptions opt, bool haveSelf) + { + var call = new StringBuilder (); + + foreach (var p in method.Parameters) { + var pname = p.Name; + if (p.Type == "Java.Lang.ICharSequence") { + pname = p.GetName ("jls_"); + writer.WriteLine ($"var {pname} = {p.Name} == null ? null : new global::Java.Lang.String ({p.Name});"); + } else if (p.Type == "Java.Lang.ICharSequence[]" || p.Type == "params Java.Lang.ICharSequence[]") { + pname = p.GetName ("jlca_"); + writer.WriteLine ($"var {pname} = {opt.GetStringArrayToCharSequenceArrayMethodName ()} ({p.Name});"); + } + + if (call.Length > 0) + call.Append (", "); + + call.Append (pname + (p.Type == "Java.Lang.ICharSequence" ? opt.GetNullForgiveness (p) : string.Empty)); + } + + writer.WriteLine ($"{(method.RetVal.IsVoid ? string.Empty : opt.GetTypeReferenceName (method.RetVal) + " __result = ")}{(haveSelf ? "self." : "")}{method.AdjustedName} ({call.ToString ()});"); + + switch (method.RetVal.FullName) { + case "void": + break; + case "Java.Lang.ICharSequence[]": + writer.WriteLine ("var __rsval = CharSequence.ArrayToStringArray (__result);"); + break; + case "Java.Lang.ICharSequence": + writer.WriteLine ("var __rsval = __result?.ToString ();"); + break; + default: + writer.WriteLine ("var __rsval = __result;"); + break; + } + + foreach (var p in method.Parameters) { + if (p.Type == "Java.Lang.ICharSequence") + writer.WriteLine ($"{p.GetName ("jls_")}?.Dispose ();"); + else if (p.Type == "Java.Lang.ICharSequence[]") + writer.WriteLine ($"if ({p.GetName ("jlca_")} != null) foreach (var s in {p.GetName ("jlca_")}) s?.Dispose ();"); + } + + if (!method.RetVal.IsVoid) + writer.WriteLine ($"return __rsval{opt.GetNullForgiveness (method.RetVal)};"); + } + + public static TypeWriter BuildManagedTypeModel (GenBase gen, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo genInfo) + { + if (gen is ClassGen klass) + return new BoundClass (klass, opt, context, genInfo); + else if (gen is InterfaceGen iface) + return new BoundInterface (iface, opt, context, genInfo); + + throw new InvalidOperationException ("Unknown GenBase type"); + } + + public static void WarnIfTypeNameMatchesNamespace (TypeWriter type, GenBase gen) + { + // We only care about the last part of a namespace + // eg: android.graphics.drawable -> drawable + var ns = gen.Namespace?.LastSubset ('.'); + + if (!ns.HasValue ()) + return; + + if (string.Equals (ns, type.Name, StringComparison.OrdinalIgnoreCase)) + Report.LogCodedWarning (0, Report.WarningTypeNameMatchesEnclosingNamespace, $"{gen.Namespace}.{type.Name}"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/GenericExplicitInterfaceImplementationMethod.cs b/external/Java.Interop/tools/generator/SourceWriters/GenericExplicitInterfaceImplementationMethod.cs new file mode 100644 index 00000000000..869fb50205d --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/GenericExplicitInterfaceImplementationMethod.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + // This is supposed to generate instantiated generic method output, but I don't think it is done yet. + public class GenericExplicitInterfaceImplementationMethod : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + readonly GenericSymbol gen; + + public GenericExplicitInterfaceImplementationMethod (Method method, GenericSymbol gen, CodeGenerationOptions opt) + { + this.method = method; + this.opt = opt; + this.gen = gen; + + Name = method.Name; + + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + ExplicitInterfaceImplementation = opt.GetOutputName (gen.Gen.FullName); + + Comments.Add ($"// This method is explicitly implemented as a member of an instantiated {gen.FullName}"); + + SourceWriterExtensions.AddMethodCustomAttributes (Attributes, method); + this.AddMethodParameters (method.Parameters, opt); + } + + protected override void WriteBody (CodeWriter writer) + { + var mappings = new Dictionary (); + + for (var i = 0; i < gen.TypeParams.Length; i++) + mappings [gen.Gen.TypeParameters [i].Name] = gen.TypeParams [i].FullName; + + var call = method.Name + " (" + method.Parameters.GetGenericCall (opt, mappings) + ")"; + writer.WriteLine ($"{(method.IsVoid ? string.Empty : "return ")}{method.RetVal.GetGenericReturn (opt, call, mappings)};"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/GenericExplicitInterfaceImplementationProperty.cs b/external/Java.Interop/tools/generator/SourceWriters/GenericExplicitInterfaceImplementationProperty.cs new file mode 100644 index 00000000000..ee9880aaa0a --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/GenericExplicitInterfaceImplementationProperty.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class GenericExplicitInterfaceImplementationProperty : PropertyWriter + { + public GenericExplicitInterfaceImplementationProperty (Property property, GenericSymbol gen, string adapter, Dictionary mappings, CodeGenerationOptions opt) + { + Name = property.AdjustedName; + + PropertyType = new TypeReferenceWriter (opt.GetTypeReferenceName (property)); + ExplicitInterfaceImplementation = opt.GetOutputName (gen.Gen.FullName); + + Comments.Add ($"// This method is explicitly implemented as a member of an instantiated {gen.FullName}"); + + if (property.Getter != null) { + HasGet = true; + + if (gen.Gen.IsGeneratable) + GetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.Gen.MetadataXPathReference}/method[@name='{property.Getter.JavaName}'{property.Getter.Parameters.GetMethodXPathPredicate ()}]\""); + if (property.Getter.GenericArguments != null && property.Getter.GenericArguments.Any ()) + GetterAttributes.Add (new CustomAttr (property.Getter.GenericArguments.ToGeneratedAttributeString ())); + + SourceWriterExtensions.AddSupportedOSPlatform (GetterAttributes, property.Getter, opt); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + GetterAttributes.Add (new RegisterAttr (property.Getter.JavaName, property.Getter.JniSignature, property.Getter.ConnectorName + ":" + property.Getter.GetAdapterName (opt, adapter), additionalProperties: property.Getter.AdditionalAttributeString ())); + } + + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1 && + mappings.Values.Any (v => v == "string")) { + // Hackity Hack; `Java.Lang.Object` doesn't (currently) provide an + // implicit conversion from `string`, meaning that given + // `tests/generator-Tests/Integration-Tests/Interfaces.cs` output: + // + // /* 1 */ partial class GenericStringPropertyImplementation : IGenericPropertyInterface { + // /* 2 */ public string Object { get; set;} + // /* 3 */ Java.Lang.Object IGenericPropertyInterface.Object { + // /* 4 */ get { return Object; } + // /* 5 */ set { Object = value?.ToString (); } + // /* 6 */ } + // /* 7 */ } + // + // then when building for JavaInterop1 line 4 will result in: + // + // error CS0029: Cannot implicitly convert type 'string' to 'Java.Lang.Object' + // + // Explicitly construct a `Java.Lang.String` to avoid this. + GetBody.Add ($"return new Java.Lang.String ({property.Name});"); + } + else { + GetBody.Add ($"return {property.Name};"); + } + } + + if (property.Setter != null) { + HasSet = true; + + if (gen.Gen.IsGeneratable) + SetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.Gen.MetadataXPathReference}/method[@name='{property.Setter.JavaName}'{property.Setter.Parameters.GetMethodXPathPredicate ()}]\""); + if (property.Setter.GenericArguments != null && property.Setter.GenericArguments.Any ()) + SetterAttributes.Add (new CustomAttr (property.Setter.GenericArguments.ToGeneratedAttributeString ())); + + SourceWriterExtensions.AddSupportedOSPlatform (SetterAttributes, property.Setter, opt); + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + SetterAttributes.Add (new RegisterAttr (property.Setter.JavaName, property.Setter.JniSignature, property.Setter.ConnectorName + ":" + property.Setter.GetAdapterName (opt, adapter), additionalProperties: property.Setter.AdditionalAttributeString ())); + } + + // Temporarily rename the parameter to "value" + var pname = property.Setter.Parameters [0].Name; + property.Setter.Parameters [0].Name = "value"; + SetBody.Add ($"{property.Name} = {property.Setter.Parameters.GetGenericCall (opt, mappings)};"); + property.Setter.Parameters [0].Name = pname; + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceConstsClass.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceConstsClass.cs new file mode 100644 index 00000000000..1689f4e11a4 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceConstsClass.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceConstsClass : ClassWriter + { + public InterfaceConstsClass (ClassGen klass, HashSet seen, CodeGenerationOptions opt, CodeGeneratorContext context) + { + Name = "InterfaceConsts"; + + IsPublic = true; + IsStatic = true; + + UsePriorityOrder = true; + + foreach (var iface in klass.GetAllImplementedInterfaces () + .Except (klass.BaseGen?.GetAllImplementedInterfaces () ?? new InterfaceGen [0]) + .Where (i => i.Fields.Count > 0)) { + + AddInlineComment ($"// The following are fields from: {iface.JavaName}"); + + SourceWriterExtensions.AddFields (this, iface, iface.Fields, seen, opt, context); + } + } + + public bool ShouldGenerate => Fields.Any () || Properties.Any (); + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceEventArgsClass.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceEventArgsClass.cs new file mode 100644 index 00000000000..5e0b9dee939 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceEventArgsClass.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceEventArgsClass : ClassWriter + { + public InterfaceEventArgsClass (InterfaceGen iface, Method method) + { + Name = iface.GetArgsName (method); + Inherits = "global::System.EventArgs"; + + IsPublic = true; + IsPartial = true; + + UsePriorityOrder = true; + + Comments.Add ($"// event args for {iface.JavaName}.{method.JavaName}"); + + if (method.IsEventHandlerWithHandledProperty) + Properties.Add (new HandledProperty ()); + } + + public void AddMembersFromMethod (InterfaceGen iface, Method method, CodeGenerationOptions opt) + { + AddConstructor (iface, method, opt); + AddProperties (method, opt); + } + + void AddConstructor (InterfaceGen iface, Method method, CodeGenerationOptions opt) + { + var ctor = new ConstructorWriter { + Name = iface.GetArgsName (method), + IsPublic = true + }; + + if (method.IsEventHandlerWithHandledProperty) { + ctor.Parameters.Add (new MethodParameterWriter ("handled", TypeReferenceWriter.Bool)); + ctor.Body.Add ("this.handled = handled;"); + } + + foreach (var p in method.Parameters) { + if (p.IsSender) + continue; + + ctor.Parameters.Add (new MethodParameterWriter (p.Name, new TypeReferenceWriter (opt.GetTypeReferenceName (p)))); + ctor.Body.Add ($"this.{opt.GetSafeIdentifier (p.Name)} = {opt.GetSafeIdentifier (p.Name)};"); + } + + Constructors.Add (ctor); + } + + void AddProperties (Method method, CodeGenerationOptions opt) + { + foreach (var p in method.Parameters) { + if (p.IsSender) + continue; + + // We've already added this property from a different overload + if (Properties.Any (prop => prop.Name == p.PropertyName)) + continue; + + Fields.Add (new FieldWriter { + Name = opt.GetSafeIdentifier (p.Name), + Type = new TypeReferenceWriter (opt.GetTypeReferenceName (p)) + }); + + var prop = new PropertyWriter { + Name = p.PropertyName, + PropertyType = new TypeReferenceWriter (opt.GetTypeReferenceName (p)), + IsPublic = true, + HasGet = true + }; + + prop.GetBody.Add ($"return {opt.GetSafeIdentifier (p.Name)};"); + + Properties.Add (prop); + } + } + } + + public class HandledProperty : PropertyWriter + { + public HandledProperty () + { + Name = "Handled"; + PropertyType = TypeReferenceWriter.Bool; + + IsPublic = true; + + HasGet = true; + GetBody.Add ("return handled;"); + + HasSet = true; + SetBody.Add ("handled = value;"); + } + + public override void Write (CodeWriter writer) + { + writer.WriteLine ("bool handled;"); + writer.WriteLine (); + + base.Write (writer); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceEventHandlerImplClass.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceEventHandlerImplClass.cs new file mode 100644 index 00000000000..6fee9ef06a5 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceEventHandlerImplClass.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceEventHandlerImplClass : ClassWriter + { + public InterfaceEventHandlerImplClass (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) + { + var jni_class = "mono/" + iface.RawJniName.Replace ('$', '_') + "Implementor"; + + Name = iface.Name + "Implementor"; + Inherits = "global::Java.Lang.Object"; + Implements.Add (iface.Name); + + IsInternal = true; + IsSealed = true; + IsPartial = true; + + if (iface.NeedsSender) { + var type = TypeReferenceWriter.Object; + type.Nullable = opt.SupportNullableReferenceTypes; + Fields.Add (new FieldWriter { Name = "sender", Type = type }); + } + Attributes.Add (new RegisterAttr (jni_class, additionalProperties: iface.AdditionalAttributeString ()) { UseGlobal = true }); + + AddConstructor (iface); + AddMethods (iface, opt); + } + + void AddConstructor (InterfaceGen iface) + { + var ctor = new ConstructorWriter { + Name = iface.Name + "Implementor", + IsPublic = true + }; + + if (iface.NeedsSender) + ctor.Parameters.Add (new MethodParameterWriter ("sender", TypeReferenceWriter.Object)); + + ctor.IsUnsafe = true; + ctor.BaseCall = "base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer)"; + + ctor.Body.Add ("const string __id = \"()V\";"); + ctor.Body.Add ("if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero)"); + ctor.Body.Add ("\treturn;"); + ctor.Body.Add ("var h = JniPeerMembers.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null);"); + ctor.Body.Add ("SetHandle (h.Handle, JniHandleOwnership.TransferLocalRef);"); + ctor.Body.Add ("JniPeerMembers.InstanceMethods.FinishCreateInstance (__id, this, null);"); + + if (iface.NeedsSender) + ctor.Body.Add ("this.sender = sender;"); + + Constructors.Add (ctor); + } + + void AddMethods (InterfaceGen iface, CodeGenerationOptions opt) + { + var handlers = new List (); + + foreach (var m in iface.Methods) + Methods.Add (new InterfaceEventHandlerImplMethod (iface, m, handlers, opt)); + + var is_empty_method = new MethodWriter { + Name = "__IsEmpty", + IsInternal = true, + IsStatic = true, + ReturnType = TypeReferenceWriter.Bool + }; + + is_empty_method.Parameters.Add (new MethodParameterWriter ("value", new TypeReferenceWriter (iface.Name + "Implementor"))); + + if (!iface.Methods.Any (m => m.EventName != string.Empty) || handlers.Count == 0) + is_empty_method.Body.Add ("return true;"); + else + is_empty_method.Body.Add ($"return {string.Join (" && ", handlers.Select (e => string.Format ("value.{0}Handler == null", e)))};"); + + Methods.Add (is_empty_method); + } + } + + public class InterfaceEventHandlerImplMethod : MethodWriter + { + readonly InterfaceGen iface; + readonly Method method; + readonly CodeGenerationOptions opt; + readonly bool needs_sender; + readonly string method_spec; + readonly string args_name; + + public InterfaceEventHandlerImplMethod (InterfaceGen iface, Method method, List handlers, CodeGenerationOptions opt) + { + this.iface = iface; + this.method = method; + this.opt = opt; + needs_sender = iface.NeedsSender; + + method_spec = iface.Methods.Count > 1 ? method.AdjustedName : string.Empty; + args_name = iface.GetArgsName (method); + + handlers.Add (method_spec); + + Name = method.Name; + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + + IsPublic = true; + + this.AddMethodParameters (method.Parameters, opt); + } + + protected override void WriteBody (CodeWriter writer) + { + // generate nothing + if (method.EventName == string.Empty) + return; + + if (method.IsVoid) { + writer.WriteLine ($"var __h = {method_spec}Handler;"); + writer.WriteLine ($"if (__h != null)"); + writer.WriteLine ($"\t__h ({(needs_sender ? "sender" : method.Parameters.SenderName)}, new {args_name} ({method.Parameters.CallDropSender}));"); + return; + } + + if (method.IsEventHandlerWithHandledProperty) { + writer.WriteLine ($"var __h = {method_spec}Handler;"); + writer.WriteLine ($"if (__h == null)"); + writer.WriteLine ($"\treturn {method.RetVal.DefaultValue};"); + + var call = method.Parameters.CallDropSender; + writer.WriteLine ($"var __e = new {args_name} (true{(call.Length != 0 ? ", " : "")}{call});"); + writer.WriteLine ($"__h ({(needs_sender ? "sender" : method.Parameters.SenderName)}, __e);"); + writer.WriteLine ($"return __e.Handled;"); + return; + } + + writer.WriteLine ($"var __h = {method_spec}Handler;"); + writer.WriteLine ($"return __h != null ? __h ({method.Parameters.GetCall (opt)}) : default ({opt.GetTypeReferenceName (method.RetVal)});"); + } + + public override void Write (CodeWriter writer) + { + if (method.EventName != string.Empty) { + writer.WriteLine ("#pragma warning disable 0649"); + writer.WriteLine ($"public {iface.GetEventDelegateName (method)}{opt.NullableOperator} {method_spec}Handler;"); + writer.WriteLine ("#pragma warning restore 0649"); + writer.WriteLine (); + } + + base.Write (writer); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceExtensionsClass.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceExtensionsClass.cs new file mode 100644 index 00000000000..378c7323ad4 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceExtensionsClass.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceExtensionsClass : ClassWriter + { + public InterfaceExtensionsClass (InterfaceGen iface, string declaringTypeName, CodeGenerationOptions opt) + { + Name = $"{declaringTypeName}{iface.Name}Extensions"; + + IsPublic = true; + IsStatic = true; + IsPartial = true; + + SourceWriterExtensions.AddObsolete (Attributes, iface.DeprecatedComment, opt, iface.IsDeprecated, deprecatedSince: iface.DeprecatedSince); + + foreach (var method in iface.Methods.Where (m => !m.IsStatic)) { + if (method.CanHaveStringOverload) { + // TODO: Don't allow obsolete here to match old generator. + // Probably should allow this in the future. + var deprecated = method.Deprecated; + method.Deprecated = null; + Methods.Add (new BoundMethodExtensionStringOverload (method, opt, iface.FullName)); + method.Deprecated = deprecated; + } + + if (method.Asyncify) + Methods.Add (new MethodExtensionAsyncWrapper (method, opt, iface.FullName)); + } + } + + public bool ShouldGenerate => Methods.Any (); + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerClass.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerClass.cs new file mode 100644 index 00000000000..1ae292f1f2b --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerClass.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Schema; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class InterfaceInvokerClass : ClassWriter + { + public InterfaceInvokerClass (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) + { + Name = $"{iface.Name}Invoker"; + + IsInternal = true; + IsPartial = true; + UsePriorityOrder = true; + + Inherits = "global::Java.Lang.Object"; + Implements.Add (iface.Name); + + bool ji = opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1; + + Attributes.Add (new RegisterAttr (iface.RawJniName, noAcw: true, additionalProperties: iface.AdditionalAttributeString ()) { + UseGlobal = true, + MemberType = (!ji) ? null : (MemberTypes?) MemberTypes.TypeInfo, + }); + + SourceWriterExtensions.AddObsolete (Attributes, iface.DeprecatedComment, opt, iface.IsDeprecated, deprecatedSince: iface.DeprecatedSince); + + if (opt.EmitLegacyInterfaceInvokers) { + Fields.Add (new PeerMembersField (opt, iface.RawJniName, $"{iface.Name}Invoker", false)); + } + + string members = opt.EmitLegacyInterfaceInvokers ? "_members" : $"_members_{iface.JavaFullNameId}"; + + if (!ji) { + Properties.Add (new InterfaceHandleGetter (members)); + } + + Properties.Add (new JniPeerMembersGetter (members)); + + if (!ji) { + string thresholdClassGet = opt.EmitLegacyInterfaceInvokers + ? "class_ref" + : $"{members}.JniPeerType.PeerReference.Handle"; + Properties.Add (new InterfaceThresholdClassGetter (thresholdClassGet)); + Properties.Add (new ThresholdTypeGetter (members)); + } + + if (opt.EmitLegacyInterfaceInvokers) { + Fields.Add (new FieldWriter { Name = "class_ref", Type = TypeReferenceWriter.IntPtr, IsShadow = opt.BuildingCoreAssembly }); + + Methods.Add (new GetObjectMethod (iface, opt)); + Methods.Add (new ValidateMethod (iface)); + Methods.Add (new DisposeMethod ()); + } else { + foreach (var i in GetCompleteImplementedInterfaces (new (), iface).OrderBy (x => x.JavaFullNameId)) { + var mi = new PeerMembersField (opt, i.RawJniName, $"{iface.Name}Invoker", isInterface:false, name: $"_members_{i.JavaFullNameId}"); + Fields.Add (mi); + } + } + + Constructors.Add (new InterfaceInvokerConstructor (opt, iface, context)); + + AddMemberInvokers (iface, new HashSet (), iface.SkippedInvokerMethods, opt, context); + } + + static HashSet GetCompleteImplementedInterfaces (HashSet ifaces, InterfaceGen toplevel) + { + ifaces.Add (toplevel); + foreach (var i in toplevel.GetAllImplementedInterfaces ()) { + GetCompleteImplementedInterfaces (ifaces, i); + } + return ifaces; + } + + void AddMemberInvokers (InterfaceGen iface, HashSet members, HashSet skipInvokers, CodeGenerationOptions opt, CodeGeneratorContext context) + { + AddPropertyInvokers (iface, iface.Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod), members, opt, context); + AddMethodInvokers (iface, iface.Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod), members, skipInvokers, opt, context); + AddCharSequenceEnumerators (iface); + + foreach (var i in iface.GetAllDerivedInterfaces ()) { + AddPropertyInvokers (iface, i.Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod), members, opt, context); + AddMethodInvokers (iface, i.Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod && !iface.IsCovariantMethod (m) && !(i.FullName.StartsWith ("Java.Lang.ICharSequence", StringComparison.Ordinal) && m.Name.EndsWith ("Formatted", StringComparison.Ordinal))), members, skipInvokers, opt, context); + AddCharSequenceEnumerators (i); + } + } + + void AddCharSequenceEnumerators (InterfaceGen iface) + { + if (iface.FullName == "Java.Lang.ICharSequence") { + Methods.Add (new CharSequenceEnumeratorMethod ()); + Methods.Add (new CharSequenceGenericEnumeratorMethod ()); + } + } + + void AddPropertyInvokers (InterfaceGen iface, IEnumerable properties, HashSet members, CodeGenerationOptions opt, CodeGeneratorContext context) + { + foreach (var prop in properties) { + if (members.Contains (prop.Name)) + continue; + + members.Add (prop.Name); + + Properties.Add (new InterfaceInvokerProperty (iface, prop, opt, context)); + } + } + + void AddMethodInvokers (InterfaceGen iface, IEnumerable methods, HashSet members, HashSet skipInvokers, CodeGenerationOptions opt, CodeGeneratorContext context) + { + foreach (var m in methods) { + if (skipInvokers.Contains (m.GetSkipInvokerSignature ())) + continue; + + var sig = m.GetSignature (); + + if (members.Contains (sig)) + continue; + + members.Add (sig); + + Methods.Add (new InterfaceInvokerMethod (iface, m, opt, context)); + } + } + } + + public class GetObjectMethod : MethodWriter + { + // public static IInterface? GetObject (IntPtr handle, JniHandleOwnership transfer) + // { + // return global::Java.Lang.Object.GetObject (handle, transfer); + // } + public GetObjectMethod (InterfaceGen iface, CodeGenerationOptions opt) + { + Name = "GetObject"; + + ReturnType = new TypeReferenceWriter (iface.Name) { Nullable = opt.SupportNullableReferenceTypes }; + + IsPublic = true; + IsStatic = true; + + Parameters.Add (new MethodParameterWriter ("handle", TypeReferenceWriter.IntPtr)); + Parameters.Add (new MethodParameterWriter ("transfer", new TypeReferenceWriter ("JniHandleOwnership"))); + + Body.Add ($"return global::Java.Lang.Object.GetObject<{iface.Name}> (handle, transfer);"); + } + } + + public class ValidateMethod : MethodWriter + { + // static IntPtr Validate (IntPtr handle) + // { + // if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + // throw new InvalidCastException (string.Format (\"Unable to convert instance of type '{{0}}' to type '{{1}}'.\", JNIEnv.GetClassNameFromInstance (handle), \"{iface.JavaName}\")); + // + // return handle; + // } + public ValidateMethod (InterfaceGen iface) + { + Name = "Validate"; + + ReturnType = TypeReferenceWriter.IntPtr; + + IsStatic = true; + + Parameters.Add (new MethodParameterWriter ("handle", TypeReferenceWriter.IntPtr)); + + Body.Add ("if (!JNIEnv.IsInstanceOf (handle, java_class_ref))"); + Body.Add ($"\tthrow new InvalidCastException ($\"Unable to convert instance of type '{{JNIEnv.GetClassNameFromInstance (handle)}}' to type '{iface.JavaName}'.\");"); + Body.Add ("return handle;"); + } + } + + public class DisposeMethod : MethodWriter + { + // protected override void Dispose (bool disposing) + // { + // if (this.class_ref != IntPtr.Zero) + // JNIEnv.DeleteGlobalRef (this.class_ref); + // this.class_ref = IntPtr.Zero; + // base.Dispose (disposing); + // } + public DisposeMethod () + { + Name = "Dispose"; + + IsProtected = true; + IsOverride = true; + + Parameters.Add (new MethodParameterWriter ("disposing", TypeReferenceWriter.Bool)); + ReturnType = TypeReferenceWriter.Void; + + Body.Add ("if (this.class_ref != IntPtr.Zero)"); + Body.Add ("\tJNIEnv.DeleteGlobalRef (this.class_ref);"); + Body.Add ("this.class_ref = IntPtr.Zero;"); + Body.Add ("base.Dispose (disposing);"); + } + } + + public class InterfaceInvokerConstructor : ConstructorWriter + { + // public IfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + // { + // IntPtr local_ref = JNIEnv.GetObjectClass (this) + // this.class_ref = JNIEnv.NewGlobalRef (local_ref); + // JNIEnv.DeleteLocalRef (local_ref); + // } + public InterfaceInvokerConstructor (CodeGenerationOptions opt, InterfaceGen iface, CodeGeneratorContext context) + { + Name = iface.Name + "Invoker"; + + IsPublic = true; + + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + Parameters.Add (new MethodParameterWriter ("reference", new TypeReferenceWriter ("ref JniObjectReference"))); + Parameters.Add (new MethodParameterWriter ("options", new TypeReferenceWriter ("JniObjectReferenceOptions"))); + BaseCall = "base (ref reference, options)"; + + } else { + Parameters.Add (new MethodParameterWriter ("handle", TypeReferenceWriter.IntPtr)); + Parameters.Add (new MethodParameterWriter ("transfer", new TypeReferenceWriter ("JniHandleOwnership"))); + BaseCall = opt.EmitLegacyInterfaceInvokers + ? "base (Validate (handle), transfer)" + : "base (handle, transfer)"; + } + + + if (opt.EmitLegacyInterfaceInvokers) { + Body.Add ($"IntPtr local_ref = JNIEnv.GetObjectClass ({context.ContextType.GetObjectHandleProperty (opt, "this")});"); + Body.Add ("this.class_ref = JNIEnv.NewGlobalRef (local_ref);"); + Body.Add ("JNIEnv.DeleteLocalRef (local_ref);"); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerMethod.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerMethod.cs new file mode 100644 index 00000000000..2345961d636 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerMethod.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class InterfaceInvokerMethod : MethodWriter + { + readonly MethodCallback method_callback; + readonly Method method; + readonly CodeGenerationOptions opt; + readonly string context_this; + + public InterfaceInvokerMethod (InterfaceGen iface, Method method, CodeGenerationOptions opt, CodeGeneratorContext context) + { + this.method = method; + this.opt = opt; + + Name = method.AdjustedName; + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + + IsPublic = true; + IsUnsafe = true; + IsStatic = method.IsStatic; + + if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { + method_callback = new MethodCallback (iface, method, opt, null, method.IsReturnCharSequence); + } + context_this = context.ContextType.GetObjectHandleProperty (opt, "this"); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + this.AddMethodParameters (method.Parameters, opt); + + if (!opt.EmitLegacyInterfaceInvokers) { + SourceWriterExtensions.AddMethodBody (Body, method, opt, $"_members_{method.DeclaringType.JavaFullNameId}"); + } + } + + public override void Write (CodeWriter writer) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.XAJavaInterop1) { + method_callback?.Write (writer); + } + + if (!opt.EmitLegacyInterfaceInvokers) { + base.Write (writer); + return; + } + + writer.WriteLine ($"IntPtr {method.EscapedIdName};"); + + base.Write (writer); + } + + protected override void WriteBody (CodeWriter writer) + { + if (opt.EmitLegacyInterfaceInvokers) { + SourceWriterExtensions.WriteMethodInvokerBodyLegacy (writer, method, opt, context_this); + return; + } + base.WriteBody (writer); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerProperty.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerProperty.cs new file mode 100644 index 00000000000..8742bdecbd2 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceInvokerProperty.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget; + +namespace generator.SourceWriters +{ + public class InterfaceInvokerProperty : PropertyWriter + { + readonly MethodCallback getter_callback; + readonly MethodCallback setter_callback; + readonly Property property; + readonly CodeGenerationOptions opt; + readonly string context_this; + + public InterfaceInvokerProperty (InterfaceGen iface, Property property, CodeGenerationOptions opt, CodeGeneratorContext context) + { + this.property = property; + this.opt = opt; + + Name = property.AdjustedName; + PropertyType = new TypeReferenceWriter (opt.GetTypeReferenceName (property)); + + IsPublic = true; + IsUnsafe = true; + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt); + + HasGet = property.Getter != null; + + if (property.Getter != null) { + HasGet = true; + getter_callback = new MethodCallback (iface, property.Getter, opt, property.AdjustedName, false); + } + + if (property.Setter != null) { + HasSet = true; + setter_callback = new MethodCallback (iface, property.Setter, opt, property.AdjustedName, false); + } + + context_this = context.ContextType.GetObjectHandleProperty (opt, "this"); + + if (!opt.EmitLegacyInterfaceInvokers) { + if (HasGet) { + SourceWriterExtensions.AddMethodBody (GetBody, property.Getter, opt, $"_members_{property.Getter.DeclaringType.JavaFullNameId}"); + } + if (HasSet) { + var pname = property.Setter.Parameters [0].Name; + property.Setter.Parameters [0].Name = "value"; + SourceWriterExtensions.AddMethodBody (SetBody, property.Setter, opt, $"_members_{property.Setter.DeclaringType.JavaFullNameId}"); + property.Setter.Parameters [0].Name = pname; + } + } + } + + public override void Write (CodeWriter writer) + { + if (opt.CodeGenerationTarget == CodeGenerationTarget.XAJavaInterop1) { + getter_callback?.Write (writer); + setter_callback?.Write (writer); + } + + if (opt.EmitLegacyInterfaceInvokers) { + if (property.Getter != null) + writer.WriteLine ($"IntPtr {property.Getter.EscapedIdName};"); + + if (property.Setter != null) + writer.WriteLine ($"IntPtr {property.Setter.EscapedIdName};"); + } + + base.Write (writer); + } + + protected override void WriteGetterBody (CodeWriter writer) + { + if (!opt.EmitLegacyInterfaceInvokers) { + base.WriteGetterBody (writer); + return; + } + SourceWriterExtensions.WriteMethodInvokerBodyLegacy (writer, property.Getter, opt, context_this); + } + + protected override void WriteSetterBody (CodeWriter writer) + { + if (!opt.EmitLegacyInterfaceInvokers) { + base.WriteSetterBody (writer); + return; + } + var pname = property.Setter.Parameters [0].Name; + property.Setter.Parameters [0].Name = "value"; + + SourceWriterExtensions.WriteMethodInvokerBodyLegacy (writer, property.Setter, opt, context_this); + + property.Setter.Parameters [0].Name = pname; + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerEvent.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerEvent.cs new file mode 100644 index 00000000000..fb7a2cc4bf5 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerEvent.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceListenerEvent : EventWriter + { + readonly InterfaceListenerEventHandlerHelper helper_method; + + public InterfaceListenerEvent (InterfaceGen iface, Method method, string name, string nameSpec, string fullDelegateName, string wrefSuffix, string add, string remove, bool hasHandlerArgument, CodeGenerationOptions opt) + { + Name = name; + EventType = new TypeReferenceWriter (opt.GetOutputName (fullDelegateName)); + + IsPublic = true; + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + HasAdd = true; + + AddBody.Add ($"global::Java.Interop.EventHelper.AddEventHandler<{opt.GetOutputName (iface.FullName)}, {opt.GetOutputName (iface.FullName)}Implementor>("); + AddBody.Add ($"ref weak_implementor_{wrefSuffix},"); + AddBody.Add ($"__Create{iface.Name}Implementor,"); + AddBody.Add ($"{add + (hasHandlerArgument ? "_Event_With_Handler_Helper" : null)},"); + AddBody.Add ($"__h => __h.{nameSpec}Handler += value);"); + + HasRemove = true; + + RemoveBody.Add ($"global::Java.Interop.EventHelper.RemoveEventHandler<{opt.GetOutputName (iface.FullName)}, {opt.GetOutputName (iface.FullName)}Implementor>("); + RemoveBody.Add ($"ref weak_implementor_{wrefSuffix},"); + RemoveBody.Add ($"{opt.GetOutputName (iface.FullName)}Implementor.__IsEmpty,"); + RemoveBody.Add ($"{remove},"); + RemoveBody.Add ($"__h => __h.{nameSpec}Handler -= value);"); + + if (hasHandlerArgument) + helper_method = new InterfaceListenerEventHandlerHelper (iface, method, add, opt); + } + + public override void Write (CodeWriter writer) + { + base.Write (writer); + + helper_method?.Write (writer); + } + } + + public class InterfaceListenerEventHandlerHelper : MethodWriter + { + public InterfaceListenerEventHandlerHelper (InterfaceGen iface, Method method, string add, CodeGenerationOptions opt) + { + Name = add + "_Event_With_Handler_Helper"; + Parameters.Add (new MethodParameterWriter ("value", new TypeReferenceWriter (opt.GetOutputName (iface.FullName)))); + ReturnType = TypeReferenceWriter.Void; + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + Body.Add ($"{add} (value, null);"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerProperty.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerProperty.cs new file mode 100644 index 00000000000..98532860210 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerProperty.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceListenerProperty : PropertyWriter + { + public InterfaceListenerProperty (InterfaceGen iface, string name, string nameSpec, string methodName, string fullDelegateName, CodeGenerationOptions opt) + { + Name = name; + PropertyType = new TypeReferenceWriter (opt.GetOutputName (fullDelegateName)) { Nullable = opt.SupportNullableReferenceTypes }; + + IsPublic = true; + + HasGet = true; + + var handlerPrefix = iface.Methods.Count > 1 ? methodName : string.Empty; + + GetBody.Add ($"{opt.GetOutputName (iface.FullName)}Implementor{opt.NullableOperator} impl = Impl{name};"); + GetBody.Add ($"return impl == null ? null : impl.{handlerPrefix}Handler;"); + + HasSet = true; + + SetBody.Add ($"{opt.GetOutputName (iface.FullName)}Implementor{opt.NullableOperator} impl = Impl{name};"); + SetBody.Add ($"if (impl == null) {{"); + SetBody.Add ($"\timpl = new {opt.GetOutputName (iface.FullName)}Implementor ({(iface.NeedsSender ? "this" : string.Empty)});"); + SetBody.Add ($"\tImpl{name} = impl;"); + SetBody.Add ($"}} else"); + SetBody.Add ($"impl.{nameSpec}Handler = value;"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerPropertyImplementor.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerPropertyImplementor.cs new file mode 100644 index 00000000000..b74e87f77b1 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceListenerPropertyImplementor.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceListenerPropertyImplementor : PropertyWriter + { + readonly string name; + readonly CodeGenerationOptions opt; + + public InterfaceListenerPropertyImplementor (InterfaceGen iface, string name, CodeGenerationOptions opt) + { + this.name = name; + this.opt = opt; + + Name = "Impl" + name; + PropertyType = new TypeReferenceWriter (opt.GetOutputName (iface.FullName) + "Implementor") { Nullable = opt.SupportNullableReferenceTypes }; + + HasGet = true; + + GetBody.Add ($"if (weak_implementor_{name} == null || !weak_implementor_{name}.IsAlive)"); + GetBody.Add ($"\treturn null;"); + GetBody.Add ($"return weak_implementor_{name}.Target as {opt.GetOutputName (iface.FullName)}Implementor;"); + + HasSet = true; + + SetBody.Add ($"weak_implementor_{name} = new WeakReference (value, true);"); + } + + public override void Write (CodeWriter writer) + { + // Write our backing field first + writer.WriteLine ($"WeakReference{opt.NullableOperator} weak_implementor_{name};"); + writer.WriteLine (); + + base.Write (writer); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/InterfaceMemberAlternativeClass.cs b/external/Java.Interop/tools/generator/SourceWriters/InterfaceMemberAlternativeClass.cs new file mode 100644 index 00000000000..c247fceb732 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/InterfaceMemberAlternativeClass.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Java.Interop.Tools.Generator; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class InterfaceMemberAlternativeClass : ClassWriter + { + readonly List sibling_classes = new List (); + + // Historically .NET has not allowed interface implemented fields or constants, so we + // initially worked around that by moving them to an abstract class, generally + // IMyInterface -> MyInterfaceConsts + // This was later expanded to accomodate static interface methods, creating a more appropriately named class + // IMyInterface -> MyInterface + // In this case the XXXConsts class is [Obsolete]'d and simply inherits from the newer class + // in order to maintain backward compatibility. + // If we're creating a binding that supports DIM, we remove the XXXConsts class as they've been + // [Obsolete:iserror] for a long time, and we add [Obsolete] to the interface "class". + public InterfaceMemberAlternativeClass (InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) + { + var should_obsolete = opt.SupportInterfaceConstants && opt.SupportDefaultInterfaceMethods; + + Name = iface.HasManagedName + ? iface.Name.Substring (1) + "Consts" + : iface.Name.Substring (1); + + Inherits = "Java.Lang.Object"; + + IsPublic = true; + IsAbstract = true; + + UsePriorityOrder = true; + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, iface, opt); + + // Place this class in a dummy package that won't conflict the actual interface + Attributes.Add (new RegisterAttr ("mono/internal/" + iface.RawJniName, noAcw: true, additionalProperties: iface.AdditionalAttributeString ()) { AcwLast = true }); + + if (should_obsolete) + SourceWriterExtensions.AddObsolete (Attributes, $"Use the '{iface.FullName}' type. This class will be removed in a future release.", opt); + + Constructors.Add (new ConstructorWriter { Name = Name, IsInternal = true }); + + var needs_class_ref = AddFields (iface, should_obsolete, opt, context); + AddMethods (iface, should_obsolete, opt); + + if (needs_class_ref || iface.Methods.Where (m => m.IsStatic).Any ()) + Fields.Add (new PeerMembersField (opt, iface.RawJniName, Name, false)); + + if (!iface.HasManagedName && !opt.SupportInterfaceConstants) + sibling_classes.Add (new InterfaceConstsForwardClass (iface, opt)); + } + + void AddMethods (InterfaceGen iface, bool shouldObsolete, CodeGenerationOptions opt) + { + foreach (var method in iface.Methods.Where (m => m.IsStatic)) { + var original = method.Deprecated; + + if (shouldObsolete && string.IsNullOrWhiteSpace (method.Deprecated)) + method.Deprecated = $"Use '{iface.FullName}.{method.AdjustedName}'. This class will be removed in a future release."; + + Methods.Add (new BoundMethod (iface, method, opt, true)); + + var name_and_jnisig = method.JavaName + method.JniSignature.Replace ("java/lang/CharSequence", "java/lang/String"); + var gen_string_overload = !method.IsOverride && method.Parameters.HasCharSequence && !iface.ContainsMethod (name_and_jnisig); + + if (gen_string_overload || method.IsReturnCharSequence) + Methods.Add (new BoundMethodStringOverload (method, opt)); + + if (method.Asyncify) + Methods.Add (new MethodAsyncWrapper (method, opt)); + + method.Deprecated = original; + } + } + + bool AddFields (InterfaceGen iface, bool shouldObsolete, CodeGenerationOptions opt, CodeGeneratorContext context) + { + var seen = new HashSet (); + + var original_fields = DeprecateFields (iface, shouldObsolete); + var needs_class_ref = AddInterfaceFields (iface, iface.Fields, seen, opt, context); + RestoreDeprecatedFields (original_fields); + + foreach (var i in iface.GetAllImplementedInterfaces ().OfType ()) { + AddInlineComment ($"// The following are fields from: {i.JavaName}"); + + original_fields = DeprecateFields (i, shouldObsolete); + needs_class_ref = AddInterfaceFields (i, i.Fields, seen, opt, context) || needs_class_ref; + RestoreDeprecatedFields (original_fields); + } + + return needs_class_ref; + } + + bool AddInterfaceFields (InterfaceGen iface, List fields, HashSet seen, CodeGenerationOptions opt, CodeGeneratorContext context) + { + var needs_property = false; + + foreach (var f in fields) { + if (iface.ContainsName (f.Name)) { + Report.LogCodedWarning (0, SourceWriterExtensions.GetFieldCollisionMessage (iface, f), f, iface.FullName, f.Name, iface.JavaName); + continue; + } + + if (seen.Contains (f.Name)) { + Report.LogCodedWarning (0, Report.WarningDuplicateField, f, iface.FullName, f.Name, iface.JavaName); + continue; + } + + if (f.Validate (opt, iface.TypeParameters, context)) { + seen.Add (f.Name); + needs_property = needs_property || f.NeedsProperty; + + if (f.NeedsProperty) + Properties.Add (new BoundFieldAsProperty (iface, f, opt)); + else + Fields.Add (new BoundField (iface, f, opt)); + } + } + + return needs_property; + } + + List<(Field field, bool deprecated, string comment)> DeprecateFields (InterfaceGen iface, bool shouldObsolete) + { + var original_fields = iface.Fields.Select (f => (f, f.IsDeprecated, f.DeprecatedComment)).ToList (); + + if (!shouldObsolete) + return original_fields; + + foreach (var f in iface.Fields) { + // Only use this derprecation if it's not already deprecated for another reason + if (!f.IsDeprecated) { + f.IsDeprecated = true; + f.DeprecatedComment = $"Use '{iface.FullName}.{f.Name}'. This class will be removed in a future release."; ; + } + } + + return original_fields; + } + + void RestoreDeprecatedFields (List<(Field field, bool deprecated, string comment)> fields) + { + foreach (var (field, deprecated, comment) in fields) { + field.IsDeprecated = deprecated; + field.DeprecatedComment = comment; + } + } + + public override void Write (CodeWriter writer) + { + base.Write (writer); + + WriteSiblingClasses (writer); + } + + public void WriteSiblingClasses (CodeWriter writer) + { + foreach (var sibling in sibling_classes) { + writer.WriteLine (); + sibling.Write (writer); + } + } + } + + public class InterfaceConstsForwardClass : ClassWriter + { + public InterfaceConstsForwardClass (InterfaceGen iface, CodeGenerationOptions opt) + { + Name = iface.Name.Substring (1) + "Consts"; + Inherits = iface.Name.Substring (1); + + IsPublic = true; + IsAbstract = true; + + // Place this class in a dummy package that won't conflict the actual interface + Attributes.Add (new RegisterAttr ("mono/internal/" + iface.RawJniName, noAcw: true, additionalProperties: iface.AdditionalAttributeString ())); + + SourceWriterExtensions.AddObsolete (Attributes, $"Use the '{iface.Name.Substring (1)}' type. This type will be removed in a future release.", opt, isError: true); + + Constructors.Add (new ConstructorWriter { + Name = Name, + IsPrivate = true + }); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/JavaLangObjectConstructor.cs b/external/Java.Interop/tools/generator/SourceWriters/JavaLangObjectConstructor.cs new file mode 100644 index 00000000000..7c6381e1434 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/JavaLangObjectConstructor.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.Android.Binder; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class JavaLangObjectConstructor : ConstructorWriter + { + public JavaLangObjectConstructor (ClassGen klass, CodeGenerationOptions opt, string callPartialMethod) + { + Name = klass.Name; + + if (klass.IsFinal) + IsInternal = true; + else + IsProtected = true; + + if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { + Parameters.Add (new MethodParameterWriter ("reference", new TypeReferenceWriter ("ref JniObjectReference"))); + Parameters.Add (new MethodParameterWriter ("options", new TypeReferenceWriter ("JniObjectReferenceOptions"))); + + BaseCall = "base (ref reference, options)"; + } else { + Parameters.Add (new MethodParameterWriter ("javaReference", TypeReferenceWriter.IntPtr)); + Parameters.Add (new MethodParameterWriter ("transfer", new TypeReferenceWriter ("JniHandleOwnership"))); + + BaseCall = "base (javaReference, transfer)"; + } + if (!string.IsNullOrWhiteSpace (callPartialMethod)) { + Body.Add ($"{callPartialMethod} ();"); + } + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/KotlinInlineClassStruct.cs b/external/Java.Interop/tools/generator/SourceWriters/KotlinInlineClassStruct.cs new file mode 100644 index 00000000000..612608c9e2a --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/KotlinInlineClassStruct.cs @@ -0,0 +1,84 @@ +using System; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + // Emits a `readonly struct` wrapper for a Kotlin @JvmInline value class. + // The struct holds the underlying primitive (e.g. long, float) that the + // JVM passes across JNI, and provides implicit conversions so the wrapper + // can be used directly in projected method signatures while existing JNI + // thunks marshal the primitive value unchanged. + public class KotlinInlineClassStruct : TypeWriter + { + readonly string underlying_csharp_type; + readonly string nullable; + + public KotlinInlineClassStruct (ClassGen klass, CodeGenerationOptions opt) + { + underlying_csharp_type = JniPrimitiveToCSharpType (klass.KotlinInlineClassUnderlyingJniType); + nullable = opt.NullableOperator; + + Name = klass.Name; + SetVisibility (klass.Visibility); + + klass.JavadocInfo?.AddJavadocs (Comments); + Comments.Add ($"// Metadata.xml XPath class reference: path=\"{klass.MetadataXPathReference}\""); + Comments.Add ("// Kotlin @JvmInline value class wrapper."); + } + + public override void WriteSignature (CodeWriter writer) + { + if (IsPublic) + writer.Write ("public "); + if (IsProtected) + writer.Write ("protected "); + if (IsInternal) + writer.Write ("internal "); + if (IsPrivate) + writer.Write ("private "); + + writer.Write ("readonly partial struct "); + writer.Write (Name + " "); + writer.WriteLine (": global::System.IEquatable<" + Name + "> {"); + writer.Indent (); + } + + public override void WriteMembers (CodeWriter writer) + { + var t = underlying_csharp_type; + var n = Name; + var q = nullable; + + writer.WriteLine ($"public readonly {t} Value;"); + writer.WriteLine (); + writer.WriteLine ($"public {n} ({t} value) {{ Value = value; }}"); + writer.WriteLine (); + writer.WriteLine ($"public static implicit operator {t} ({n} value) => value.Value;"); + writer.WriteLine ($"public static implicit operator {n} ({t} value) => new {n} (value);"); + writer.WriteLine (); + writer.WriteLine ($"public static bool operator == ({n} left, {n} right) => left.Equals (right);"); + writer.WriteLine ($"public static bool operator != ({n} left, {n} right) => !left.Equals (right);"); + writer.WriteLine (); + writer.WriteLine ($"public bool Equals ({n} other) => Value.Equals (other.Value);"); + writer.WriteLine ($"public override bool Equals (object{q} obj) => obj is {n} other && Equals (other);"); + writer.WriteLine ("public override int GetHashCode () => Value.GetHashCode ();"); + writer.WriteLine ($"public override string{q} ToString () => Value.ToString ();"); + } + + static string JniPrimitiveToCSharpType (string jni) + { + return jni switch { + "Z" => "bool", + "B" => "sbyte", + "C" => "char", + "D" => "double", + "F" => "float", + "I" => "int", + "J" => "long", + "S" => "short", + _ => throw new ArgumentOutOfRangeException (nameof (jni), jni, "Unsupported JNI primitive descriptor"), + }; + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/MethodAsyncWrapper.cs b/external/Java.Interop/tools/generator/SourceWriters/MethodAsyncWrapper.cs new file mode 100644 index 00000000000..838fc368dc6 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/MethodAsyncWrapper.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class MethodAsyncWrapper : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + + public MethodAsyncWrapper (Method method, CodeGenerationOptions opt) + { + this.method = method; + this.opt = opt; + + Name = method.AdjustedName + "Async"; + IsStatic = method.IsStatic; + + SetVisibility (method.Visibility); + + ReturnType = new TypeReferenceWriter ("global::System.Threading.Tasks.Task"); + + if (!method.IsVoid) + ReturnType.Name += "<" + opt.GetTypeReferenceName (method.RetVal) + ">"; + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + Body.Add ($"return global::System.Threading.Tasks.Task.Run (() => {method.AdjustedName} ({method.Parameters.GetCall (opt)}));"); + + this.AddMethodParameters (method.Parameters, opt); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/MethodCallback.cs b/external/Java.Interop/tools/generator/SourceWriters/MethodCallback.cs new file mode 100644 index 00000000000..84375400266 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/MethodCallback.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.Android.Binder; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class MethodCallback : MethodWriter + { + readonly GenBase type; + readonly Method method; + readonly string property_name; + readonly bool is_formatted; + readonly CodeGenerationOptions opt; + + readonly FieldWriter delegate_field; + readonly MethodWriter delegate_getter; + + // static sbyte n_ByteValueExact (IntPtr jnienv, IntPtr native__this) + // { + // var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + // return __this.ByteValueExact (); + // } + public MethodCallback (GenBase type, Method method, CodeGenerationOptions options, string propertyName, bool isFormatted) + { + this.type = type; + this.method = method; + + property_name = propertyName; + is_formatted = isFormatted; + opt = options; + + delegate_field = new MethodCallbackDelegateField (method, options); + delegate_getter = new GetDelegateHandlerMethod (method, options); + + Name = "n_" + method.Name + method.IDSignature; + ReturnType = new TypeReferenceWriter (method.RetVal.NativeType); + + IsStatic = true; + IsPrivate = method.IsInterfaceDefaultMethod; + + SourceWriterExtensions.AddObsolete (Attributes, null, opt, forceDeprecate: !string.IsNullOrWhiteSpace (method.Deprecated), deprecatedSince: method.DeprecatedSince); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + Parameters.Add (new MethodParameterWriter ("jnienv", TypeReferenceWriter.IntPtr)); + Parameters.Add (new MethodParameterWriter ("native__this", TypeReferenceWriter.IntPtr)); + + foreach (var p in method.Parameters) + Parameters.Add (new MethodParameterWriter (options.GetSafeIdentifier (p.UnsafeNativeName), new TypeReferenceWriter (p.NativeType))); + } + + protected override void WriteBody (CodeWriter writer) + { + var paramArgs = string.Join ("", method.Parameters.Select (p => $", {opt.GetSafeIdentifier (p.UnsafeNativeName)}")); + var call = $"global::Java.Interop.JniMarshal.{(method.IsVoid ? "SafeInvokeAction" : "SafeInvokeFunc")} (jnienv, native__this{paramArgs}, &__{Name})"; + + writer.WriteLine ("unsafe {"); + writer.Indent (); + writer.WriteLine (method.IsVoid ? call + ";" : "return " + call + ";"); + writer.Unindent (); + writer.WriteLine ("}"); + } + + void WriteMarshalBody (CodeWriter writer) + { + var attributes = new List (); + SourceWriterExtensions.AddObsolete (attributes, null, opt, forceDeprecate: !string.IsNullOrWhiteSpace (method.Deprecated), deprecatedSince: method.DeprecatedSince); + SourceWriterExtensions.AddSupportedOSPlatform (attributes, method, opt); + foreach (var attribute in attributes) + attribute.WriteAttribute (writer); + + writer.WriteLine ($"private static {method.RetVal.NativeType} __{Name} (IntPtr jnienv, IntPtr native__this{method.Parameters.GetCallbackSignature (opt)})"); + writer.WriteLine ("{"); + + writer.Indent (); + writer.WriteLine ($"var __this = global::Java.Lang.Object.GetObject<{opt.GetOutputName (type.FullName)}> (jnienv, native__this, JniHandleOwnership.DoNotTransfer){opt.NullForgivingOperator};"); + + foreach (var s in method.Parameters.GetCallbackPrep (opt)) + writer.WriteLine (s); + + if (string.IsNullOrEmpty (property_name)) { + var call = "__this." + method.Name + (is_formatted ? "Formatted" : string.Empty) + " (" + method.Parameters.GetCall (opt) + ")"; + if (method.IsVoid) + writer.WriteLine (call + ";"); + else + writer.WriteLine ("{0} {1};", method.Parameters.HasCleanup ? method.RetVal.NativeType + " __ret =" : "return", method.RetVal.ToNative (opt, call)); + } else { + if (method.IsVoid) + writer.WriteLine ("__this.{0} = {1};", property_name, method.Parameters.GetCall (opt)); + else + writer.WriteLine ("{0} {1};", method.Parameters.HasCleanup ? method.RetVal.NativeType + " __ret =" : "return", method.RetVal.ToNative (opt, "__this." + property_name)); + } + + foreach (var cleanup in method.Parameters.GetCallbackCleanup (opt)) + writer.WriteLine (cleanup); + + if (!method.IsVoid && method.Parameters.HasCleanup) + writer.WriteLine ("return __ret;"); + + writer.Unindent (); + writer.WriteLine ("}"); + } + + public override void Write (CodeWriter writer) + { + delegate_field.Write (writer); + + writer.WriteLineNoIndent ("#pragma warning disable 0169"); + + delegate_getter.Write (writer); + writer.WriteLine (); + + base.Write (writer); + WriteMarshalBody (writer); + + writer.WriteLineNoIndent ("#pragma warning restore 0169"); + writer.WriteLine (); + } + } + + public class MethodCallbackDelegateField : FieldWriter + { + // static Delegate cb_byteValueExact; + public MethodCallbackDelegateField (Method method, CodeGenerationOptions options) + { + Name = method.EscapedCallbackName; + Type = TypeReferenceWriter.Delegate; + + IsStatic = true; + IsPrivate = method.IsInterfaceDefaultMethod; + + if (!string.IsNullOrEmpty (options.NullableOperator)) + Type.Nullable = true; + } + } + + public class GetDelegateHandlerMethod : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + + // static Delegate GetByteValueExactHandler () + // { + // if (cb_byteValueExact == null) + // cb_byteValueExact = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_B) n_ByteValueExact); + // return cb_byteValueExact; + // } + public GetDelegateHandlerMethod (Method method, CodeGenerationOptions opt) + { + this.method = method; + this.opt = opt; + + Name = method.ConnectorName; + ReturnType = TypeReferenceWriter.Delegate; + + IsStatic = true; + IsPrivate = method.IsInterfaceDefaultMethod; + + SourceWriterExtensions.AddObsolete (Attributes, null, opt, forceDeprecate: !string.IsNullOrWhiteSpace (method.Deprecated), deprecatedSince: method.DeprecatedSince); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + } + + protected override void WriteBody (CodeWriter writer) + { + var callback_name = method.EscapedCallbackName; + writer.WriteLine ($"return {callback_name} ??= new {method.GetDelegateType (opt)} (n_{method.Name + method.IDSignature});"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/MethodExplicitInterfaceImplementation.cs b/external/Java.Interop/tools/generator/SourceWriters/MethodExplicitInterfaceImplementation.cs new file mode 100644 index 00000000000..7b8fe53b055 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/MethodExplicitInterfaceImplementation.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class MethodExplicitInterfaceImplementation : MethodWriter + { + readonly Method method; + readonly CodeGenerationOptions opt; + + public MethodExplicitInterfaceImplementation (GenBase iface, Method method, CodeGenerationOptions opt) + { + this.method = method; + this.opt = opt; + + Name = method.Name; + + ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal)); + ExplicitInterfaceImplementation = opt.GetOutputName (iface.FullName); + + SourceWriterExtensions.AddMethodCustomAttributes (Attributes, method); + + this.AddMethodParameters (method.Parameters, opt); + } + + protected override void WriteBody (CodeWriter writer) + { + writer.WriteLine ($"return {Name} ({method.Parameters.GetCall (opt)})"); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs b/external/Java.Interop/tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs new file mode 100644 index 00000000000..f7d0cd5518f --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class MethodExtensionAsyncWrapper : MethodWriter + { + public MethodExtensionAsyncWrapper (Method method, CodeGenerationOptions opt, string selfType) + { + Name = method.AdjustedName + "Async"; + IsStatic = true; + + SetVisibility (method.Visibility); + + ReturnType = new TypeReferenceWriter ("global::System.Threading.Tasks.Task"); + + if (!method.IsVoid) + ReturnType.Name += "<" + opt.GetTypeReferenceName (method.RetVal) + ">"; + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + + Body.Add ($"return global::System.Threading.Tasks.Task.Run (() => self.{method.AdjustedName} ({method.Parameters.GetCall (opt)}));"); + + Parameters.Add (new MethodParameterWriter ("self", new TypeReferenceWriter (selfType)) { IsExtension = true }); + + this.AddMethodParameters (method.Parameters, opt); + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/PeerMembersField.cs b/external/Java.Interop/tools/generator/SourceWriters/PeerMembersField.cs new file mode 100644 index 00000000000..9b6e877b805 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/PeerMembersField.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class PeerMembersField : FieldWriter + { + // static readonly JniPeerMembers _members = new XAPeerMembers ("android/provider/ContactsContract$AggregationExceptions", typeof (AggregationExceptions)); + public PeerMembersField (CodeGenerationOptions opt, string rawJniType, string declaringType, bool isInterface, string name = "_members") + { + Name = name; + Type = new TypeReferenceWriter ("JniPeerMembers"); + + IsPrivate = isInterface; + IsStatic = true; + IsReadonly = true; + + var peer = opt.CodeGenerationTarget == Xamarin.Android.Binder.CodeGenerationTarget.XAJavaInterop1 ? "XAPeerMembers" : "JniPeerMembers"; + + Value = $"new {peer} (\"{rawJniType}\", typeof ({declaringType}){(isInterface ? ", isInterface: true" : string.Empty)})"; + } + } +} diff --git a/external/Java.Interop/tools/generator/SourceWriters/WeakImplementorField.cs b/external/Java.Interop/tools/generator/SourceWriters/WeakImplementorField.cs new file mode 100644 index 00000000000..e46e00c1045 --- /dev/null +++ b/external/Java.Interop/tools/generator/SourceWriters/WeakImplementorField.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Generation; +using Xamarin.SourceWriter; + +namespace generator.SourceWriters +{ + public class WeakImplementorField : FieldWriter + { + public WeakImplementorField (string name, CodeGenerationOptions opt) + { + Name = "weak_implementor_" + name; + Type = new TypeReferenceWriter (opt.GetOutputName ("WeakReference")) { Nullable = opt.SupportNullableReferenceTypes }; + } + } +} diff --git a/external/Java.Interop/tools/generator/TestOutput.txt b/external/Java.Interop/tools/generator/TestOutput.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external/Java.Interop/tools/generator/Utilities/AncestorDescendantCache.cs b/external/Java.Interop/tools/generator/Utilities/AncestorDescendantCache.cs new file mode 100644 index 00000000000..756f4bc46ea --- /dev/null +++ b/external/Java.Interop/tools/generator/Utilities/AncestorDescendantCache.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MonoDroid.Generation.Utilities +{ + // Finding all descendants of a type is expensive, so we cache the results here + public class AncestorDescendantCache + { + readonly List gens; + readonly Dictionary> cache = new Dictionary> (); + + public AncestorDescendantCache (List gens) + { + this.gens = gens; + } + + public IEnumerable GetAncestorsAndDescendants (GenBase gen) + { + if (cache.TryGetValue (gen, out var value)) + return value; + + var new_value = GetAncestors (gen).Concat (GetDescendants (gen)).ToList (); + + cache [gen] = new_value; + + return new_value; + } + + IEnumerable GetAncestors (GenBase gen) + { + for (var g = gen.BaseGen; g != null; g = g.BaseGen) + yield return g; + } + + IEnumerable GetDescendants (GenBase gen) + { + foreach (var directDescendants in gens.Where (x => x.BaseGen == gen)) { + yield return directDescendants; + + foreach (var indirectDescendants in GetDescendants (directDescendants)) + yield return indirectDescendants; + } + } + } +} diff --git a/external/Java.Interop/tools/generator/Utilities/CsvParser.cs b/external/Java.Interop/tools/generator/Utilities/CsvParser.cs new file mode 100644 index 00000000000..15e7b2648e3 --- /dev/null +++ b/external/Java.Interop/tools/generator/Utilities/CsvParser.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MonoDroid.Generation +{ + public class CsvParser + { + readonly string [] fields; + + public CsvParser (string line) + { + fields = line.Split (','); + } + + public string GetField (int index) + { + if (index >= fields.Length) + return string.Empty; + + return fields [index].Trim (); + } + } +} diff --git a/external/Java.Interop/tools/generator/Utilities/ParsedType.cs b/external/Java.Interop/tools/generator/Utilities/ParsedType.cs new file mode 100644 index 00000000000..a7c1026eaa2 --- /dev/null +++ b/external/Java.Interop/tools/generator/Utilities/ParsedType.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MonoDroid.Generation +{ + // Parses a type string into its type and optionally its generic type arguments + // ex: Dictionary> + // -> Type: Dictionary<{0}> + // - GenericArguments: + // - Type: string + // - Type: List<{0}> + // - GenericArguments: + // - Type: string + // A placeholder "{0}" is added because the type may extend past the generics: + // ex: "List.Enumerator[]" becomes "List<{0}>.Enumerator[]" + public class ParsedType + { + public string Type { get; set; } + public List GenericArguments { get; } = new List (); + public bool HasGenerics => GenericArguments.Count > 0; + + ParsedType () { } + + public static ParsedType Parse (string type) + { + var less_than = type.IndexOf ('<'); + + // No generics + if (less_than < 0) + return new ParsedType { Type = type }; + + var greater_than = type.LastIndexOf ('>'); + var type_args = type.Substring (less_than + 1, greater_than - less_than - 1); + var type_string = type.Substring (0, less_than) + "<{0}>" + (greater_than + 1 < type.Length ? type.Substring (greater_than + 1) : string.Empty); + + var parsed_args = ParseTypeList (type_args); + + var t = new ParsedType { Type = type_string }; + + foreach (var p in parsed_args) + t.GenericArguments.Add (Parse (p)); + + return t; + } + + public override string ToString () + { + return ToString (false); + } + + public string ToString (bool useGlobal = false) + { + var type = (useGlobal && Type.IndexOf ('.') >= 0 ? "global::" : string.Empty) + Type; + + if (!HasGenerics) + return type; + + return type.Replace ("{0}", string.Join (", ", GenericArguments.Select (p => p.ToString (useGlobal)))); + } + + static List ParseTypeList (string type) + { + var list = new List (); + + // Only one type + if (type.IndexOf (',') < 0) { + list.Add (type); + return list; + } + + // Remove any whitespace + type = type.Replace (" ", ""); + + var start = 0; + var counter = -1; + var depth = 0; + + while (++counter < type.Length) { + if (type [counter] == '<') { + depth++; + continue; + } + + if (type [counter] == '>') { + depth--; + continue; + } + + // This is a list separator, add the previous type + if (depth == 0 && type [counter] == ',') { + list.Add (type.Substring (start, counter - start)); + start = counter + 1; + continue; + } + } + + // Add the final type + list.Add (type.Substring (start, counter - start)); + + return list; + } + } +} diff --git a/external/Java.Interop/tools/generator/Utilities/ProcessRocks.cs b/external/Java.Interop/tools/generator/Utilities/ProcessRocks.cs new file mode 100644 index 00000000000..04f0d45e61d --- /dev/null +++ b/external/Java.Interop/tools/generator/Utilities/ProcessRocks.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.IO; + +namespace MonoDroid.Utils { + + public static class ProcessRocks { + + public static IEnumerable ReadStandardOutput (IEnumerable commandLine, bool printCommandLine) + { + var psi = new ProcessStartInfo () { + FileName = commandLine.First (), + Arguments = "\"" + string.Join ("\" \"", commandLine.Skip (1).ToArray ()) + "\"", + }; + return ReadStandardOutput (psi, printCommandLine); + } + + public static IEnumerable ReadStandardOutput (ProcessStartInfo psi, bool printCommandLine) + { + psi.RedirectStandardError = true; + psi.RedirectStandardOutput = true; + psi.UseShellExecute = false; + + if (printCommandLine) + Console.WriteLine ("Running command: {0} {1}", psi.FileName, psi.Arguments); + + var timer = Stopwatch.StartNew (); + using (Process p = Process.Start (psi)) { + var stderr = new StringBuilder (); + Func readStderrLine = p.StandardError.ReadLine; + AsyncCallback appendStderr = null; + IAsyncResult r; + appendStderr = ar => { + try { + string l = readStderrLine.EndInvoke (ar); + if (l == null) { + r = null; + return; + } + stderr.Append (l).Append (Environment.NewLine); + r = readStderrLine.BeginInvoke (appendStderr, null); + } + catch (ObjectDisposedException) { + r = null; + // ignore; 'p' was disposed while we were blocking on stderr. + } + }; + r = readStderrLine.BeginInvoke (appendStderr, null); + + string line; + while ((line = p.StandardOutput.ReadLine ()) != null) { + yield return line; + } + + IAsyncResult _r; + while ((_r = r) != null && !_r.IsCompleted) + _r.AsyncWaitHandle.WaitOne (); + + p.WaitForExit (); + if (p.ExitCode != 0) { + _r = r; + if (_r != null && !_r.IsCompleted) + _r.AsyncWaitHandle.WaitOne (); + string e = stderr.ToString (); + + throw new CommandFailedException (psi.FileName, psi.Arguments, e, p.ExitCode); + } + } + timer.Stop (); + if (printCommandLine) + Console.WriteLine ("\tProcess executed in: {0}", timer.Elapsed); + } + } + + static class MessageUtils { + + internal static string MapGeneratedToProjectFile (string filename) + { + // At this point, all we have is something like this: + // ...\MonoDroidApplication22\obj\Debug\res\layout\main.axml + // We are going to best guess it back to the original file: + // ...\MonoDroidApplication22\Resources\Layout\Main.axml + + try { + // Find the root, by stripping off \obj and beyond + string root = filename.Substring (0, filename.IndexOf (string.Format ("{0}obj{0}", Path.DirectorySeparatorChar), StringComparison.Ordinal)); + + var files = FindFileInDirectory (root, Path.GetFileName (filename)); + + // This pretty much only works if there is only 1 matching file + // name, which should be the commong case + if (files.Count == 1) + return files[0]; + + // We couldn't successfully map, return only the file name, + // and let the user figure it out. + return Path.GetFileName (filename); + } catch (Exception) { + return Path.GetFileName (filename); + } + } + + private static List FindFileInDirectory (string directory, string filename) + { + var results = new List (); + + // Recurse + foreach (var dir in Directory.GetDirectories (directory)) { + // Don't go into obj or bin directories + if (Path.GetFileName (dir).ToLowerInvariant () == "obj" || Path.GetFileName (dir).ToLowerInvariant () == "bin") + continue; + + results.AddRange (FindFileInDirectory (dir, filename)); + } + + // Check this directory for the file + foreach (var file in Directory.GetFiles (directory)) { + if (Path.GetFileName (file).ToLowerInvariant () == filename.ToLowerInvariant ()) + results.Add (file); + } + + return results; + } + } + + class CommandFailedException : InvalidOperationException + { + public string FileName { get; private set; } + public string Arguments { get; private set; } + public string ErrorLog { get; private set; } + public int ExitCode { get; private set; } + public new string Message { get; private set; } + + public CommandFailedException () : base () + { + } + + public CommandFailedException (string message) : base (message) + { + } + + public CommandFailedException (string filename, string arguments, string errorLog, int exitCode) + { + FileName = filename; + Arguments = arguments; + ErrorLog = errorLog; + ExitCode = exitCode; + + + Message = "Command failed. Command: " + FileName + " " + Arguments + "\n" + + "\t" + (string.IsNullOrEmpty (ErrorLog) ? "\n" : ErrorLog); + } + + public string VSFormattedErrorLog { + get { return FormatForVS (ErrorLog); } + } + + private string FormatForVS (string text) + { + Regex regex = new Regex (@"(?.+):(?\d+): error: Error: (?.+)"); + + if (!regex.IsMatch (text)) + return text; + + var match = regex.Match (text); + + string filename = match.Groups["FileName"].Value; + string line = match.Groups["LineNumber"].Value; + string error = match.Groups["Error"].Value; + + int line_no; + + if (!int.TryParse (line, out line_no)) + return text; + + // Fix off by one error + line_no++; + + return string.Format ("{0}({1}): error 1: {2}", MessageUtils.MapGeneratedToProjectFile (filename), line_no, error); + } + } +} + diff --git a/external/Java.Interop/tools/generator/Utilities/TypeNameUtilities.cs b/external/Java.Interop/tools/generator/Utilities/TypeNameUtilities.cs new file mode 100644 index 00000000000..a7db40fd299 --- /dev/null +++ b/external/Java.Interop/tools/generator/Utilities/TypeNameUtilities.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoDroid.Utils; + +namespace MonoDroid.Generation +{ + public static class TypeNameUtilities + { + // Convert a JNI type signature like "Lcom/example/MyColor;" into the Java + // type name "com.example.MyColor". Returns null for non-reference signatures + // (primitives or arrays) since those are not used by the Kotlin inline-class + // projection path. + public static string JniSignatureToJavaTypeName (string jniSignature) + { + if (string.IsNullOrEmpty (jniSignature)) + return null; + if (jniSignature.Length < 3 || jniSignature [0] != 'L' || jniSignature [jniSignature.Length - 1] != ';') + return null; + return jniSignature.Substring (1, jniSignature.Length - 2) + .Replace ('/', '.') + .Replace ('$', '.'); + } + + // These must be sorted for BinarySearch to work + // Missing "this" because it's handled elsewhere as "this_" + internal static string [] reserved_keywords = new [] { + "abstract", "as", "base", "bool", "break", "byte", "callback", "case", "catch", "char", "checked", "class", "const", + "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", + "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", + "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", + "protected", "public", "readonly", "ref", "remove", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", + "struct", "switch", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", + "using", "virtual", "void", "volatile", "where", "while", + }; + + public static string FilterPrimitiveFullName (string s) + { + switch (s) { + case "System.Boolean": + return "boolean"; + case "System.Char": + return "char"; + case "System.Byte": + return "byte"; + case "System.SByte": + return "byte"; + case "System.Int16": + return "short"; + case "System.Int32": + return "int"; + case "System.Int64": + return "long"; + case "System.Single": + return "float"; + case "System.Double": + return "double"; + case "System.Void": + return "void"; + case "System.String": + return "java.lang.String"; + } + return null; + } + + public static string GetGenericJavaObjectTypeOverride (string managed_name, string parms) + { + switch (managed_name) { + case "System.Collections.ICollection": + return "JavaCollection"; + case "System.Collections.IDictionary": + return "JavaDictionary"; + case "System.Collections.IList": + return "JavaList"; + case "System.Collections.Generic.ICollection": + return "JavaCollection" + parms; + case "System.Collections.Generic.IList": + return "JavaList" + parms; + case "System.Collections.Generic.IDictionary": + return "JavaDictionary" + parms; + } + return null; + } + + public static string GetNativeName (string name) + { + if (name.StartsWith ("@", StringComparison.Ordinal)) + return "native__" + name.Substring (1); + return "native_" + name; + } + + public static string MangleName (string name) + { + if (name == "event") + return "e"; + + if (Array.BinarySearch (reserved_keywords, name, StringComparer.Ordinal) >= 0) + return "@" + name; + + return name; + } + + public static string StudlyCase (string name) + { + StringBuilder builder = new StringBuilder (); + bool raise = true; + foreach (char c in name) { + if (c == '_' || c == '-') + raise = true; + else if (raise) { + builder.Append (Char.ToUpper (c)); + raise = false; + } else + builder.Append (c); + } + return builder.ToString (); + } + + public static string GetCallPrefix (ISymbol symbol) + { + if (symbol is SimpleSymbol || symbol.IsEnum) { + var ret = StringRocks.MemberToPascalCase (symbol.JavaName); + + // We do not have unsigned versions of GetIntValue, etc. + // We use the signed versions and cast the result + if (ret == "Uint") + return "Int"; + if (ret == "Ushort") + return "Short"; + if (ret == "Ulong") + return "Long"; + if (ret == "Ubyte") + return "Byte"; + + return ret; + + } else + return "Object"; + } + } +} diff --git a/external/Java.Interop/tools/generator/generator.csproj b/external/Java.Interop/tools/generator/generator.csproj new file mode 100644 index 00000000000..f58833442c5 --- /dev/null +++ b/external/Java.Interop/tools/generator/generator.csproj @@ -0,0 +1,62 @@ + + + + $(DotNetTargetFramework) + Exe + $(DefineConstants);GENERATOR;HAVE_CECIL;JCW_ONLY_TYPE_NAMES + + + + + + $(UtilityOutputFullPath) + + + + + + + + + utils\StringRocks.cs + + + utils\EnumMappings.Xml.cs + + + utils\XmlExtensions.cs + + + + + + + + + + + + $(PkgHtmlAgilityPack)\lib\netstandard2.0\HtmlAgilityPack.dll + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/generator/generator.slnf b/external/Java.Interop/tools/generator/generator.slnf new file mode 100644 index 00000000000..cef077108f4 --- /dev/null +++ b/external/Java.Interop/tools/generator/generator.slnf @@ -0,0 +1,24 @@ +{ + "solution": { + "path": "..\\..\\Java.Interop.sln", + "projects": [ + "external\\xamarin-android-tools\\src\\Xamarin.Android.Tools.AndroidSdk\\Xamarin.Android.Tools.AndroidSdk.csproj", + "src\\Java.Interop.Localization\\Java.Interop.Localization.csproj", + "src\\Java.Interop.Tools.Cecil\\Java.Interop.Tools.Cecil.csproj", + "src\\Java.Interop.Tools.Diagnostics\\Java.Interop.Tools.Diagnostics.csproj", + "src\\Java.Interop.Tools.Generator\\Java.Interop.Tools.Generator.csproj", + "src\\Java.Interop.Tools.JavaCallableWrappers\\Java.Interop.Tools.JavaCallableWrappers.csproj", + "src\\Java.Interop.Tools.JavaSource\\Java.Interop.Tools.JavaSource.csproj", + "src\\Java.Interop.Tools.JavaTypeSystem\\Java.Interop.Tools.JavaTypeSystem.csproj", + "src\\Xamarin.Android.Tools.AnnotationSupport\\Xamarin.Android.Tools.AnnotationSupport.csproj", + "src\\Xamarin.Android.Tools.ApiXmlAdjuster\\Xamarin.Android.Tools.ApiXmlAdjuster.csproj", + "src\\Xamarin.Android.Tools.Bytecode\\Xamarin.Android.Tools.Bytecode.csproj", + "src\\Xamarin.SourceWriter\\Xamarin.SourceWriter.csproj", + "tests\\Xamarin.Android.Tools.Bytecode-Tests\\Xamarin.Android.Tools.Bytecode-Tests.csproj", + "tests\\Xamarin.SourceWriter-Tests\\Xamarin.SourceWriter-Tests.csproj", + "tests\\generator-Tests\\generator-Tests.csproj", + "tools\\class-parse\\class-parse.csproj", + "tools\\generator\\generator.csproj" + ] + } +} \ No newline at end of file diff --git a/external/Java.Interop/tools/generator/library-project-template.txt b/external/Java.Interop/tools/generator/library-project-template.txt new file mode 100644 index 00000000000..208a5b0ff5d --- /dev/null +++ b/external/Java.Interop/tools/generator/library-project-template.txt @@ -0,0 +1,47 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {4C50E542-C1F5-4F2E-8EB7-C78B2F705387} + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + $$$$$$$$ ROOT NAMESPACE HERE $$$$$$$$ + Resources + Assets + $$$$$$$$ ASSEMBLY NAME HERE $$$$$$$$ + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + None + false + + + none + false + bin\Release + prompt + 4 + false + SdkOnly + false + + + + + + + + + +$$$$$$$$ FILENAMES HERE $$$$$$$$ + + diff --git a/external/Java.Interop/tools/java-source-utils/.classpath b/external/Java.Interop/tools/java-source-utils/.classpath new file mode 100644 index 00000000000..cbded1104bc --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/java-source-utils/.gitignore b/external/Java.Interop/tools/java-source-utils/.gitignore new file mode 100644 index 00000000000..5e4e31eb49c --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/.gitignore @@ -0,0 +1,10 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# ??? +.settings + +# Ignore Gradle build output directory +build + + diff --git a/external/Java.Interop/tools/java-source-utils/.project b/external/Java.Interop/tools/java-source-utils/.project new file mode 100644 index 00000000000..dd0d1f07ac3 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/.project @@ -0,0 +1,34 @@ + + + java-source-utils + Project java-source-utils created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + + + 1736435235222 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/external/Java.Interop/tools/java-source-utils/CGManifest.json b/external/Java.Interop/tools/java-source-utils/CGManifest.json new file mode 100644 index 00000000000..b05c7e02d7a --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/CGManifest.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json.schemastore.org/component-detection-manifest.json", + "version": 1, + "registrations": [ + { + "component": { + "type": "maven", + "maven": { + "groupId": "com.github.javaparser", + "artifactId": "javaparser-core", + "version": "3.16.1" + } + }, + "developmentDependency":false + }, + { + "component": { + "type": "maven", + "maven": { + "groupId": "com.github.javaparser", + "artifactId": "javaparser-symbol-solver-core", + "version": "3.16.1" + } + }, + "developmentDependency":false + } + ] +} diff --git a/external/Java.Interop/tools/java-source-utils/README.md b/external/Java.Interop/tools/java-source-utils/README.md new file mode 100644 index 00000000000..9a845f8081d --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/README.md @@ -0,0 +1,8 @@ +# java-source-utils + +`java-source-utils` is a Java program which uses [JavaParser][0] to process +Java source code in order to extract method parameter names and Javadoc +documentation, as the typical alternative is to instead process Javadoc *HTML* +to obtain this information, and Javadoc HTML is less "stable" than Java source. + +[0]: https://github.com/javaparser/javaparser diff --git a/external/Java.Interop/tools/java-source-utils/build.gradle b/external/Java.Interop/tools/java-source-utils/build.gradle new file mode 100644 index 00000000000..d232f08e65a --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/build.gradle @@ -0,0 +1,63 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * User Manual available at https://docs.gradle.org/6.3/userguide/tutorial_java_projects.html + */ + +plugins { + // Apply the java plugin to add support for Java + id 'java' + + // Apply the application plugin to add support for building a CLI application. + id 'application' +} + +java { + ext.javaSourceVer = project.hasProperty('javaSourceVer') ? JavaVersion.toVersion(project.getProperty('javaSourceVer')) : JavaVersion.VERSION_1_8 + ext.javaTargetVer = project.hasProperty('javaTargetVer') ? JavaVersion.toVersion(project.getProperty('javaTargetVer')) : JavaVersion.VERSION_1_8 + + sourceCompatibility = ext.javaSourceVer + targetCompatibility = ext.javaTargetVer +} + +repositories { + // Use maven central for resolving dependencies. + // You can declare any Maven/Ivy/file repository here. + mavenCentral() +} + +dependencies { + // This dependency is used by the application. + implementation 'com.github.javaparser:javaparser-core:3.18.0' + implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.18.0' + + // Use JUnit test framework + testImplementation 'junit:junit:4.12' +} + +application { + // Define the main class for the application. + mainClassName = 'com.microsoft.android.App' +} + +jar { + duplicatesStrategy = 'exclude' + manifest { + attributes 'Main-Class': 'com.microsoft.android.App' + } + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } { + exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' + } + archiveFileName.set('java-source-utils.jar') +} + +test { + reports { + junitXml { + } + } +} diff --git a/external/Java.Interop/tools/java-source-utils/java-source-utils.csproj b/external/Java.Interop/tools/java-source-utils/java-source-utils.csproj new file mode 100644 index 00000000000..03383d089eb --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/java-source-utils.csproj @@ -0,0 +1,27 @@ + + + + $(DotNetTargetFramework) + + + + + + $(UtilityOutputFullPath) + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tools/java-source-utils/java-source-utils.targets b/external/Java.Interop/tools/java-source-utils/java-source-utils.targets new file mode 100644 index 00000000000..ed1c790d478 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/java-source-utils.targets @@ -0,0 +1,99 @@ + + + + + + + + + <_XATBJavaSourceFile Include="JavaType.java" /> + <_XATBJavaSource Include="@(_XATBJavaSourceFile->'$(MSBuildThisFileDirectory)../../tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/%(Identity)')" /> + <_XATBJavaDest Include="@(_XATBJavaSourceFile->'$(MSBuildThisFileDirectory)src/test/resources/com/xamarin/%(Identity)')" /> + + + + + <_Dirs Include="@(_XATBJavaDest->'%(RelativeDir)')" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_JavaSource Include="src/test/resources/com/microsoft/android/Outer.java" /> + <_JavaSource Include="src/test/resources/com/xamarin/JavaType.java" /> + + + + + + + + + diff --git a/external/Java.Interop/tools/java-source-utils/settings.gradle b/external/Java.Interop/tools/java-source-utils/settings.gradle new file mode 100644 index 00000000000..8a5eebc5986 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/settings.gradle @@ -0,0 +1,10 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html + */ + +rootProject.name = 'java-source-utils' diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/App.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/App.java new file mode 100644 index 00000000000..9b15ef73081 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/App.java @@ -0,0 +1,75 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.microsoft.android; + +import java.io.IOException; + +import com.github.javaparser.*; +import com.github.javaparser.ParserConfiguration; + +import com.microsoft.android.ast.*; +import com.microsoft.android.util.Parameter; + +public class App { + public static final String APP_NAME = "java-source-utils"; + + public static void main (final String[] args) throws Throwable { + JavaSourceUtilsOptions options; + try { + options = JavaSourceUtilsOptions.parse(args); + if (options == null) { + System.out.println(APP_NAME + " " + JavaSourceUtilsOptions.HELP_STRING); + return; + } + } catch (Throwable t) { + System.err.println(APP_NAME + ": error: " + t.getMessage()); + if (JavaSourceUtilsOptions.verboseOutput) { + t.printStackTrace(System.err); + } + System.err.println("Usage: " + APP_NAME + " " + JavaSourceUtilsOptions.HELP_STRING); + System.exit(1); + return; + } + + try { + final JavaParser parser = createParser(options); + final JniPackagesInfoFactory packagesFactory = new JniPackagesInfoFactory(parser); + final JniPackagesInfo packages = packagesFactory.parse(options.inputFiles); + + if ((options.outputParamsTxt = Parameter.normalize(options.outputParamsTxt, "")).length() > 0) { + generateParamsTxt(options.outputParamsTxt, packages); + } + generateXml(options, packages); + options.close(); + } + catch (Throwable t) { + options.close(); + System.err.println(APP_NAME + ": internal error: " + t.getMessage()); + if (JavaSourceUtilsOptions.verboseOutput) { + t.printStackTrace(System.err); + } + System.exit(2); + return; + } + } + + static JavaParser createParser(JavaSourceUtilsOptions options) throws IOException { + final ParserConfiguration config = options.createConfiguration(); + final JavaParser parser = new JavaParser(config); + return parser; + } + + static void generateParamsTxt(String filename, JniPackagesInfo packages) throws Throwable { + try (final ParameterNameGenerator paramsTxtGen = new ParameterNameGenerator(filename)) { + paramsTxtGen.writePackages(packages); + } + } + + static void generateXml(JavaSourceUtilsOptions options, JniPackagesInfo packages) throws Throwable { + try (final JavadocXmlGenerator javadocXmlGen = new JavadocXmlGenerator(options.outputJavadocXml)) { + javadocXmlGen.writeCopyrightInfo(options.docCopyrightFile, options.docUrlPrefix, options.docUrlStyle, options.docRootUrl); + javadocXmlGen.writePackages(packages); + } + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JavaSourceUtilsOptions.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JavaSourceUtilsOptions.java new file mode 100644 index 00000000000..4cc08b08bab --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JavaSourceUtilsOptions.java @@ -0,0 +1,357 @@ +package com.microsoft.android; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import com.github.javaparser.*; +import com.github.javaparser.JavaParser; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.*; +import com.github.javaparser.ast.type.*; +import com.github.javaparser.ast.body.*; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.TypeDeclaration; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.nodeTypes.*; +import com.github.javaparser.ast.nodeTypes.NodeWithJavadoc; +import com.github.javaparser.ast.nodeTypes.NodeWithParameters; +import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName; +import com.github.javaparser.resolution.SymbolResolver; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.*; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.*; + + +public class JavaSourceUtilsOptions implements AutoCloseable { + public static final String HELP_STRING = + "[-v] [<-a|--aar> AAR]* [<-j|--jar> JAR]* [<-s|--source> DIRS]*\n" + + "\t[--bootclasspath CLASSPATH]\n" + + "\t[<-P|--output-params> OUT.params.txt] [<-D|--output-javadoc> OUT.xml]\n" + + "\t[--doc-copyright FILE] [--doc-url-prefix URL] [--doc-url-style STYLE]\n" + + "\t[@RESPONSE-FILE]* FILES\n" + + "\n" + + "Options:\n" + + " @RESPONSE-FILE Additional options to parse, one option per line.\n" + + " FILES .java files to parse.\n" + + " -v Verbose output; show diagnostic information.\n" + + " -h, -?, --help Show this message and exit.\n" + + "\n" + + "Java type resolution options:\n" + + " --bootclasspath CLASSPATH\n" + + " '" + File.pathSeparator + "'-separated list of .jar files to use\n" + + " for type resolution.\n" + + " -a, --aar FILE .aar file to use for type resolution.\n" + + " -j, --jar FILE .jar file to use for type resolution.\n" + + " -s, --source DIR Directory containing .java files for type\n" + + " resolution purposes. DOES NOT parse all files.\n" + + "\n" + + "Documentation copyright file options:\n" + + " Results in an additional '/api/javadoc-metadata' element when using\n" + + " --output-javadoc.\n" + + " --doc-copyright FILE Copyright information for Javadoc. Should be in\n" + + " mdoc(5) XML, to be held within .\n" + + " Stored in //javadoc-metadata/copyright.\n" + + " --doc-url-prefix URL Base URL for links to documentation.\n" + + " Stored in //javadoc-metadata/link/@prefix.\n" + + " --doc-url-style STYLE STYLE of URLs to generate for member links.\n" + + " Stored in //javadoc-metadata/link/@style.\n" + + " Supported styles include:\n" + + " - developer.android.com/reference@2020-Nov\n" + + " --doc-root-url URL Base URL to use in place of @{docRoot} elements.\n" + + " Stored in //javadoc-metadata/link/@docroot.\n" + + "\n" + + "Output file options:\n" + + " -P, --output-params FILE Write method parameter names to FILE.\n" + + " -D, --output-javadoc FILE Write Javadoc within XML container to FILE.\n" + + ""; + + public static boolean verboseOutput; + + public final List aarFiles = new ArrayList(); + public final List jarFiles = new ArrayList(); + + public final Collection inputFiles = new ArrayList(); + + public boolean haveBootClassPath; + public String outputParamsTxt; + public String outputJavadocXml; + + public File docCopyrightFile; + public String docUrlPrefix; + public String docUrlStyle; + public String docRootUrl; + + private final Collection sourceDirectoryFiles = new ArrayList(); + private File extractedTempDir; + + + public void close() { + if (extractedTempDir != null) { + try { + Files.walk(extractedTempDir.toPath()) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + extractedTempDir.delete(); + } + catch (Throwable t) { + System.err.println(App.APP_NAME + ": error deleting temp directory `" + extractedTempDir.getAbsolutePath() + "`: " + t.getMessage()); + if (verboseOutput) { + t.printStackTrace(System.err); + } + } + } + extractedTempDir = null; + } + + public ParserConfiguration createConfiguration() throws IOException { + final ParserConfiguration config = new ParserConfiguration() + // Associate Javadoc comments with AST members + .setAttributeComments(true) + + // If there are blank lines between Javadoc blocks & declarations, + // *ignore* those blank lines and associate the Javadoc w/ the decls + .setDoNotAssignCommentsPrecedingEmptyLines(false) + + // Associate Javadoc comments w/ the declaration, *not* with + // any annotations on the declaration + .setIgnoreAnnotationsWhenAttributingComments(true) + ; + final TypeSolver typeSolver = createTypeSolver(config); + config.setSymbolResolver(new JavaSymbolSolver(typeSolver)); + return config; + } + + private final TypeSolver createTypeSolver(ParserConfiguration config) throws IOException { + final CombinedTypeSolver typeSolver = new CombinedTypeSolver(); + for (File file : aarFiles) { + typeSolver.add(new AarTypeSolver(file)); + } + for (File file : jarFiles) { + typeSolver.add(new JarTypeSolver(file)); + } + if (!haveBootClassPath) { + typeSolver.add(new ReflectionTypeSolver()); + } + for (File srcDir : sourceDirectoryFiles) { + typeSolver.add(new JavaParserTypeSolver(srcDir, config)); + } + return typeSolver; + } + + private final JavaSourceUtilsOptions parse(Iterator args) throws IOException { + if (args == null || !args.hasNext()) + return this; + + while (args.hasNext()) { + String arg = args.next(); + switch (arg) { + case "-bootclasspath": { + final String bootClassPath = getNextOptionValue(args, arg); + final ArrayList files = new ArrayList(); + for (final String cp : bootClassPath.split(File.pathSeparator)) { + final File file = new File(cp); // CodeQL [SM00697] java-source-utils.jar is a command-line app, and is useless if it doesn't support command-line args. + if (!file.exists()) { + System.err.println(App.APP_NAME + ": warning: invalid file path for option `-bootclasspath`: " + cp); + continue; + } + files.add(file); + } + for (int j = files.size(); j > 0; --j) { + jarFiles.add(0, files.get(j-1)); + } + haveBootClassPath = true; + break; + } + case "-a": + case "--aar": { + final File file = getNextOptionFile(args, arg); + if (file == null) { + break; + } + aarFiles.add(file); + break; + } + case "--doc-copyright": { + final File file = getNextOptionFile(args, arg); + if (file == null) { + break; + } + docCopyrightFile = file; + break; + } + case "--doc-url-prefix": { + final String prefix = getNextOptionValue(args, arg); + docUrlPrefix = prefix; + break; + } + case "--doc-url-style": { + final String style = getNextOptionValue(args, arg); + docUrlStyle = style; + break; + } + case "--doc-root-url": { + final String docRoot = getNextOptionValue(args, arg); + docRootUrl = docRoot; + break; + } + case "-j": + case "--jar": { + final File file = getNextOptionFile(args, arg); + if (file == null) { + break; + } + jarFiles.add(file); + break; + } + case "-s": + case "--source": { + final File dir = getNextOptionFile(args, arg); + if (dir == null) { + break; + } + sourceDirectoryFiles.add(dir); + break; + } + case "-D": + case "--output-javadoc": { + outputJavadocXml = getNextOptionValue(args, arg); + break; + } + case "-P": + case "--output-params": { + outputParamsTxt = getNextOptionValue(args, arg); + break; + } + case "-v": { + verboseOutput = true; + break; + } + case "-h": + case "-?": + case "--help": { + return null; + } + default: { + if (arg.startsWith("@")) { + // response file? + final String responseFileName = arg.substring(1); + final File responseFile = new File(responseFileName); // CodeQL [SM00697] java-source-utils.jar is a command-line app, and is useless if it doesn't support command-line args. + if (responseFile.exists()) { + final Iterator lines = + Files.readAllLines(responseFile.toPath()) + .stream() + .filter(line -> line.length() > 0 && !line.startsWith("#")) + .iterator(); + + final JavaSourceUtilsOptions r = parse(lines); + if (r == null) + return null; + break; + } + } + final File file = new File(arg); // CodeQL [SM00697] java-source-utils.jar is a command-line app, and is useless if it doesn't support command-line args. + if (!file.exists()) { + System.err.println(App.APP_NAME + ": warning: invalid file path for option `FILES`: " + arg); + break; + } + + if (file.isDirectory()) { + sourceDirectoryFiles.add(file); + Files.walk(file.toPath()) + .filter(f -> Files.isRegularFile(f) && f.getFileName().toString().endsWith(".java")) + .map(Path::toFile) + .forEach(f -> inputFiles.add(f)); + break; + } + if (file.getName().endsWith(".java")) { + inputFiles.add(file); + break; + } + if (!file.getName().endsWith(".jar") && !file.getName().endsWith(".zip")) { + System.err.println(App.APP_NAME + ": warning: ignoring input file `" + file.getAbsolutePath() +"`."); + break; + } + if (extractedTempDir == null) { + extractedTempDir = Files.createTempDirectory("ji-jst").toFile(); + } + File toDir = new File(extractedTempDir, file.getName()); + sourceDirectoryFiles.add(toDir); + extractTo(file, toDir, inputFiles); + break; + } + } + } + return this; + } + + public static JavaSourceUtilsOptions parse(final String[] args) throws IOException { + final JavaSourceUtilsOptions options = new JavaSourceUtilsOptions(); + final Iterator a = Arrays.stream(args).iterator(); + + return options.parse(a); + } + + private static void extractTo(final File zipFilePath, final File toDir, final Collection inputFiles) throws IOException { + try (final ZipFile zipFile = new ZipFile(zipFilePath)) { + Enumeration e = zipFile.entries(); + while (e.hasMoreElements()) { + final ZipEntry entry = e.nextElement(); + if (entry.isDirectory()) + continue; + if (!entry.getName().endsWith(".java")) + continue; + final File target = new File(toDir, entry.getName()); + if (!target.toPath().normalize().startsWith(toDir.toPath())) { + System.err.println(App.APP_NAME + ": warning: skipping bad zip entry: " + zipFilePath + "!" + entry.getName()); + continue; + } + if (verboseOutput) { + System.out.println ("# creating file: " + target.getAbsolutePath()); + } + target.getParentFile().mkdirs(); + final InputStream zipContents = zipFile.getInputStream(entry); + Files.copy(zipContents, target.toPath()); + zipContents.close(); + inputFiles.add(target); + } + } + } + + static String getNextOptionValue(final Iterator args, final String option) { + if (!args.hasNext()) + throw new IllegalArgumentException( + "Expected required value for option `" + option + "`."); + return args.next(); + } + + static File getNextOptionFile(final Iterator args, final String option) { + if (!args.hasNext()) + throw new IllegalArgumentException( + "Expected required value for option `" + option + "`."); + final String fileName = args.next(); + final File file = new File(fileName); // CodeQL [SM00697] java-source-utils.jar is a command-line app, and is useless if it doesn't support command-line args. + if (!file.exists()) { + System.err.println(App.APP_NAME + ": warning: invalid file path for option `" + option + "`: " + fileName); + return null; + } + return file; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JavadocXmlGenerator.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JavadocXmlGenerator.java new file mode 100644 index 00000000000..5e380452ee8 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JavadocXmlGenerator.java @@ -0,0 +1,237 @@ +package com.microsoft.android; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.microsoft.android.ast.*; +import com.microsoft.android.util.Parameter; + +public final class JavadocXmlGenerator implements AutoCloseable { + + final PrintStream output; + + Document document; + Element api; + + public JavadocXmlGenerator(final String output) throws FileNotFoundException, ParserConfigurationException, UnsupportedEncodingException { + if (output == null) + this.output = System.out; + else { + final File file = new File(output); // CodeQL [SM00697] java-source-utils.jar is a command-line app, and is useless if it doesn't support command-line args. + final File parent = file.getParentFile(); + if (parent != null) { + parent.mkdirs(); + } + this.output = new PrintStream(file, "UTF-8"); + } + + startApi(); + } + + public JavadocXmlGenerator(final PrintStream output) throws ParserConfigurationException { + Parameter.requireNotNull("output", output); + + this.output = output; + + startApi(); + } + + private void startApi() throws ParserConfigurationException { + document = DocumentBuilderFactory.newInstance () + .newDocumentBuilder() + .newDocument(); + api = document.createElement("api"); + api.setAttribute("api-source", "java-source-utils"); + document.appendChild(api); + } + + public void close() throws TransformerException { + InputStream is = getClass().getClassLoader().getResourceAsStream("transform-style.xsl"); + InputStreamReader isr = new InputStreamReader(is); + Transformer transformer = TransformerFactory.newInstance() + .newTransformer(new StreamSource (isr)); + transformer.transform(new DOMSource(document), new StreamResult(output)); + + if (output != System.out) { + output.flush(); + output.close(); + } + } + + public final void writeCopyrightInfo(final File copyright, final String urlPrefix, final String urlStyle, final String docRootUrl) throws IOException, ParserConfigurationException { + final Element info = document.createElement("javadoc-metadata"); + if (copyright != null) { + final Element blurb = document.createElement("copyright"); + final NodeList contents = readXmlFile(copyright); + if (contents == null) { + final byte[] data = Files.readAllBytes(copyright.toPath()); // CodeQL [SM00697] java-source-utils.jar is a command-line app, and is useless if it doesn't support command-line args. + blurb.appendChild(document.createCDATASection(new String(data, StandardCharsets.UTF_8))); + } else { + final int len = contents.getLength(); + for (int i = 0; i < len; ++i) + blurb.appendChild(document.importNode(contents.item(i),true)); + } + info.appendChild(blurb); + } + + final Element link = document.createElement("link"); + if (urlPrefix != null) { + link.setAttribute("prefix", urlPrefix); + } + if (urlStyle != null) { + link.setAttribute("style", urlStyle); + } + if (docRootUrl != null) { + link.setAttribute("docroot", docRootUrl); + } + + info.appendChild(link); + + if (info.hasChildNodes()) { + api.appendChild(info); + } + } + + final NodeList readXmlFile(final File file) throws ParserConfigurationException { + final DocumentBuilder builder = DocumentBuilderFactory.newInstance () + .newDocumentBuilder(); + try { + final Document contents = builder.parse(file); + return contents.getChildNodes(); + } + catch (Throwable t) { + return null; + } + } + + public final void writePackages(final JniPackagesInfo packages) throws ParserConfigurationException, TransformerException { + Parameter.requireNotNull("packages", packages); + + for (JniPackageInfo packageInfo : packages.getSortedPackages()) { + writePackage(document, api, packageInfo); + } + } + + private static final void writePackage(final Document document, final Element api, final JniPackageInfo packageInfo) { + final Element packageXml = document.createElement("package"); + packageXml.setAttribute("name", packageInfo.getPackageName()); + packageXml.setAttribute("jni-name", packageInfo.getPackageName().replace(".", "/")); + api.appendChild(packageXml); + + for (JniTypeInfo typeInfo : packageInfo.getSortedTypes()) { + writeType(document, packageXml, typeInfo); + } + } + + private static final void writeType(final Document document, final Element packageXml, final JniTypeInfo typeInfo) { + final Element typeXml = document.createElement(typeInfo.getTypeKind()); + typeXml.setAttribute("name", typeInfo.getRawName()); + typeXml.setAttribute("jni-signature", getTypeJniName(typeInfo)); + packageXml.appendChild(typeXml); + + writeJavadoc(document, typeXml, typeInfo.getJavadocComment()); + + for (JniMemberInfo memberInfo : typeInfo.getSortedMembers()) { + writeMember(document, typeXml, memberInfo); + } + } + + private static String getTypeJniName(JniTypeInfo typeInfo) { + final String packageName = typeInfo.getDeclaringPackage().getPackageName(); + final StringBuilder name = new StringBuilder(); + + name.append("L"); + if (packageName.length() > 0) { + name.append(packageName.replace(".", "/")); + name.append("/"); + } + name.append(typeInfo.getRawName().replace(".", "$")); + name.append(";"); + + return name.toString(); + } + + private static final void writeJavadoc(final Document document, final Element parent, String javadoc) { + javadoc = Parameter.normalize(javadoc, ""); + + if (javadoc.length() == 0) { + return; + } + + final Element javadocXml = document.createElement("javadoc"); + parent.appendChild(javadocXml); + + javadocXml.appendChild(document.createCDATASection(javadoc)); + } + + private static void writeMember(final Document document, final Element typeXml, final JniMemberInfo memberInfo) { + JniMethodBaseInfo paramsInfo = null; + int paramsCount = 0; + if (memberInfo.isConstructor() || memberInfo.isMethod()) { + paramsInfo = (JniMethodBaseInfo) memberInfo; + paramsCount = paramsInfo.getParameters().size(); + } + final String javadoc = Parameter.normalize(memberInfo.getJavadocComment(), ""); + if (paramsCount == 0 && javadoc.length() == 0) { + return; + } + + final Element memberXml = document.createElement(getMemberXmlElement(memberInfo)); + if (!memberInfo.isConstructor()) { + memberXml.setAttribute("name", memberInfo.getName()); + } + memberXml.setAttribute("jni-signature", memberInfo.getJniSignature()); + typeXml.appendChild(memberXml); + + if (memberInfo.isMethod()) { + final JniMethodInfo methodInfo = (JniMethodInfo) memberInfo; + memberXml.setAttribute("return", methodInfo.getJavaReturnType()); + memberXml.setAttribute("jni-return", methodInfo.getJniReturnType()); + } + + if (paramsInfo != null) { + for (JniParameterInfo paramInfo : paramsInfo.getParameters()) { + final Element parameter = document.createElement("parameter"); + parameter.setAttribute("name", paramInfo.name); + parameter.setAttribute("type", paramInfo.javaType); + parameter.setAttribute("jni-type", paramInfo.jniType); + + memberXml.appendChild(parameter); + } + } + + writeJavadoc(document, memberXml, memberInfo.getJavadocComment()); + } + + private static String getMemberXmlElement(JniMemberInfo member) { + if (member.isConstructor()) + return "constructor"; + if (member.isMethod()) + return "method"; + if (member.isField()) + return "field"; + throw new Error("Don't know XML element for: " + member.toString()); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JniPackagesInfoFactory.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JniPackagesInfoFactory.java new file mode 100644 index 00000000000..93c9b3fb64a --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/JniPackagesInfoFactory.java @@ -0,0 +1,495 @@ +package com.microsoft.android; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import com.github.javaparser.*; +import com.github.javaparser.JavaParser; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.*; +import com.github.javaparser.ast.comments.*; +import com.github.javaparser.ast.type.*; +import com.github.javaparser.ast.body.*; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.body.TypeDeclaration; +import com.github.javaparser.ast.comments.JavadocComment; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.nodeTypes.*; +import com.github.javaparser.ast.nodeTypes.NodeWithJavadoc; +import com.github.javaparser.ast.nodeTypes.NodeWithParameters; +import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName; +import com.github.javaparser.resolution.SymbolResolver; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.*; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.*; + +import com.github.javaparser.ParseResult; +import com.github.javaparser.ast.CompilationUnit; + +import com.microsoft.android.ast.*; + +import static com.microsoft.android.util.Parameter.*; + +public final class JniPackagesInfoFactory { + + final JavaParser parser; + + public JniPackagesInfoFactory(final JavaParser parser) { + requireNotNull("parser", parser); + + this.parser = parser; + } + + public JniPackagesInfo parse(final Collection files) throws Throwable { + requireNotNull("files", files); + + final JniPackagesInfo packages = new JniPackagesInfo(); + + for (final File file : files) { + final ParseResult result = parser.parse(file); + final Optional unit = result.getResult(); + if (!unit.isPresent()) { + logParseErrors(file, result.getProblems()); + continue; + } + parse(packages, unit.get()); + } + + return packages; + } + + private static void logParseErrors(final File file, final List problems) { + System.err.println(App.APP_NAME + ": could not parse file `" + file.getName() + "`:"); + for (final Problem p : problems) { + System.err.print("\t"); + Optional location = p.getLocation(); + if (location.isPresent()) { + System.err.print(location.get()); + System.err.print(": "); + } + System.err.println(p.getVerboseMessage()); + if (JavaSourceUtilsOptions.verboseOutput && p.getCause().isPresent()) { + p.getCause().get().printStackTrace(System.err); + } + } + } + + /** parse method */ + private void parse(final JniPackagesInfo packages, final CompilationUnit unit) throws Throwable { + final String packageName = unit.getPackageDeclaration().isPresent() + ? unit.getPackageDeclaration().get().getNameAsString() + : ""; + final JniPackageInfo packageInfo = packages.getPackage(packageName); + + fixJavadocComments(unit, unit.getTypes()); + + for (final TypeDeclaration type : unit.getTypes()) { + if (JavaSourceUtilsOptions.verboseOutput && type.getFullyQualifiedName().isPresent()) { + System.out.println("Processing: " + type.getFullyQualifiedName().get()); + } + if (type.isAnnotationDeclaration()) { + final AnnotationDeclaration annoDecl = type.asAnnotationDeclaration(); + final JniTypeInfo annoInfo = createAnnotationInfo(packageInfo, annoDecl, null); + parseType(packageInfo, annoInfo, annoDecl); + continue; + } + if (type.isClassOrInterfaceDeclaration()) { + final ClassOrInterfaceDeclaration typeDecl = type.asClassOrInterfaceDeclaration(); + final JniTypeInfo typeInfo = createTypeInfo(packageInfo, typeDecl, null); + parseType(packageInfo, typeInfo, typeDecl); + continue; + } + if (type.isEnumDeclaration()) { + final EnumDeclaration enumDecl = type.asEnumDeclaration(); + final JniTypeInfo nestedEnum = createEnumInfo(packageInfo, enumDecl, null); + parseType(packageInfo, nestedEnum, enumDecl); + continue; + } + System.out.println("# TODO: unknown type decl " + type.getClass().getName()); + System.out.println(type.toString()); + } + } + + static JniTypeInfo createAnnotationInfo(final JniPackageInfo packageInfo, final AnnotationDeclaration annotationDecl, JniTypeInfo declInfo) { + final String declName = declInfo == null ? "" : declInfo.getRawName() + "."; + final JniTypeInfo annotationInfo = new JniInterfaceInfo(packageInfo, declName + annotationDecl.getNameAsString()); + packageInfo.add(annotationInfo); + fillJavadoc(annotationInfo, annotationDecl); + if (declInfo != null) { + for (String typeParameter : declInfo.getTypeParameters()) { + annotationInfo.addTypeParameter(typeParameter, declInfo.getTypeParameterJniType(typeParameter)); + } + } + return annotationInfo; + } + + static JniTypeInfo createEnumInfo(final JniPackageInfo packageInfo, final EnumDeclaration enumDecl, JniTypeInfo declInfo) { + final String declName = declInfo == null ? "" : declInfo.getRawName() + "."; + final JniTypeInfo enumInfo = new JniClassInfo(packageInfo, declName + enumDecl.getNameAsString()); + packageInfo.add(enumInfo); + fillJavadoc(enumInfo, enumDecl); + if (declInfo != null) { + for (String typeParameter : declInfo.getTypeParameters()) { + enumInfo.addTypeParameter(typeParameter, declInfo.getTypeParameterJniType(typeParameter)); + } + } + return enumInfo; + } + + static JniTypeInfo createTypeInfo(final JniPackageInfo packageInfo, final ClassOrInterfaceDeclaration typeDecl, JniTypeInfo declInfo) { + final String declName = declInfo == null ? "" : declInfo.getRawName() + "."; + final JniTypeInfo typeInfo = typeDecl.isInterface() + ? new JniInterfaceInfo(packageInfo, declName + typeDecl.getNameAsString()) + : new JniClassInfo(packageInfo, declName + typeDecl.getNameAsString()); + packageInfo.add(typeInfo); + fillJavadoc(typeInfo, typeDecl); + if (declInfo != null) { + for (String typeParameter : declInfo.getTypeParameters()) { + typeInfo.addTypeParameter(typeParameter, declInfo.getTypeParameterJniType(typeParameter)); + } + } + for (TypeParameter typeParameter : typeDecl.getTypeParameters()) { + typeInfo.addTypeParameter( + typeParameter.getNameAsString(), + getJniType(typeInfo, null, getTypeParameterBound(typeParameter), false)); + } + return typeInfo; + } + + static ClassOrInterfaceType getTypeParameterBound(TypeParameter typeParameter) { + for (ClassOrInterfaceType boundType : typeParameter.getTypeBound()) { + return boundType; + } + return null; + } + + private final void parseType(final JniPackageInfo packageInfo, final JniTypeInfo typeInfo, TypeDeclaration typeDecl) { + fixJavadocComments(typeDecl, getUndocumentedBodyMembers(typeDecl.getMembers())); + for (final BodyDeclaration body : typeDecl.getMembers()) { + if (body.isAnnotationDeclaration()) { + final AnnotationDeclaration annoDecl = body.asAnnotationDeclaration(); + final JniTypeInfo annoInfo = createAnnotationInfo(packageInfo, annoDecl, typeInfo); + parseType(packageInfo, annoInfo, annoDecl); + continue; + } + if (body.isClassOrInterfaceDeclaration()) { + final ClassOrInterfaceDeclaration nestedDecl = body.asClassOrInterfaceDeclaration(); + final JniTypeInfo nestedType = createTypeInfo(packageInfo, nestedDecl, typeInfo); + parseType(packageInfo, nestedType, nestedDecl); + continue; + } + if (body.isEnumDeclaration()) { + final EnumDeclaration enumDecl = body.asEnumDeclaration(); + final JniTypeInfo nestedEnum = createEnumInfo(packageInfo, enumDecl, typeInfo); + parseType(packageInfo, nestedEnum, enumDecl); + continue; + } + if (body.isAnnotationMemberDeclaration()) { + parseAnnotationMemberDecl(typeInfo, body.asAnnotationMemberDeclaration()); + continue; + } + if (body.isConstructorDeclaration()) { + parseConstructorDecl(typeInfo, body.asConstructorDeclaration()); + continue; + } + if (body.isFieldDeclaration()) { + parseFieldDecl(typeInfo, body.asFieldDeclaration()); + continue; + } + if (body.isMethodDeclaration()) { + parseMethodDecl(typeInfo, body.asMethodDeclaration()); + continue; + } + if (body.isInitializerDeclaration()) { + // e.g. `static { CREATOR = null; } + continue; + } + System.out.println("# TODO: unknown body member " + body.getClass().getName()); + System.out.println(body.toString()); + } + } + + private final void fixJavadocComments(final Node decl, final Iterable> bodyMembers) { + final List> members = getUndocumentedBodyMembers(bodyMembers); + final List orphanedComments = getOrphanComments(decl); + + if (members.size() == 0) + return; + + final BodyDeclaration firstMember = members.get(0); + JavadocComment comment = orphanedComments.stream() + .filter(c -> c.getBegin().get().isBefore(firstMember.getBegin().get())) + .reduce((a, b) -> b) + .orElse(null); + if (comment != null) { + ((NodeWithJavadoc) firstMember).setJavadocComment(comment); + } + + for (int i = 1; i < members.size(); ++i) { + BodyDeclaration prevMember = members.get(i-1); + BodyDeclaration member = members.get(i); + + Optional commentOpt = orphanedComments.stream() + .filter(c -> c.getBegin().get().isAfter(prevMember.getEnd().get()) && + c.getEnd().get().isBefore(member.getBegin().get())) + .findFirst(); + if (!commentOpt.isPresent()) + continue; + ((NodeWithJavadoc)member).setJavadocComment(commentOpt.get()); + } + } + + private final List> getUndocumentedBodyMembers(Iterable> bodyMembers) { + final List> members = new ArrayList> (); + for (BodyDeclaration member : bodyMembers) { + if (!(member instanceof NodeWithJavadoc)) { + continue; + } + final NodeWithJavadoc memberJavadoc = (NodeWithJavadoc) member; + if (memberJavadoc.getJavadocComment().isPresent()) + continue; + final Optional memberBeginOpt = member.getBegin(); + if (!memberBeginOpt.isPresent()) + continue; + members.add(member); + } + members.sort((a, b) -> a.getBegin().get().compareTo(b.getBegin().get())); + return members; + } + + private final List getOrphanComments(Node decl) { + final List orphanedComments = new ArrayList(decl.getOrphanComments().size()); + for (Comment c : decl.getOrphanComments()) { + if (!c.isJavadocComment()) + continue; + final Optional commentBeginOpt = c.getBegin(); + if (!commentBeginOpt.isPresent()) + continue; + orphanedComments.add(c.asJavadocComment()); + } + orphanedComments.sort((a, b) -> a.getBegin().get().compareTo(b.getBegin().get())); + return orphanedComments; + } + + private final void parseAnnotationMemberDecl(final JniTypeInfo typeInfo, final AnnotationMemberDeclaration memberDecl) { + final JniMethodInfo methodInfo = new JniMethodInfo(typeInfo, memberDecl.getNameAsString()); + typeInfo.add(methodInfo); + + methodInfo.setReturnType( + getJavaType(typeInfo, methodInfo, memberDecl.getType(), false), + getJniType(typeInfo, methodInfo, memberDecl.getType(), false)); + + fillJavadoc(methodInfo, memberDecl); + } + + private final void parseFieldDecl(final JniTypeInfo typeInfo, final FieldDeclaration fieldDecl) { + for (VariableDeclarator f : fieldDecl.getVariables()) { + final JniFieldInfo fieldInfo = new JniFieldInfo(typeInfo, f.getNameAsString()); + fieldInfo.setJniType(getJniType(typeInfo, null, f.getType(), false)); + + typeInfo.add(fieldInfo); + + fillJavadoc(fieldInfo, fieldDecl); + } + } + + private final void parseConstructorDecl(final JniTypeInfo typeInfo, final ConstructorDeclaration ctorDecl) { + final JniConstructorInfo ctorInfo = new JniConstructorInfo(typeInfo); + typeInfo.add(ctorInfo); + + fillMethodBase(ctorInfo, ctorDecl); + fillJavadoc(ctorInfo, ctorDecl); + } + + private final void parseMethodDecl(final JniTypeInfo typeInfo, final MethodDeclaration methodDecl) { + final JniMethodInfo methodInfo = new JniMethodInfo(typeInfo, methodDecl.getNameAsString()); + typeInfo.add(methodInfo); + + for (TypeParameter typeParameter : methodDecl.getTypeParameters()) { + methodInfo.addTypeParameter( + typeParameter.getNameAsString(), + getJniType(typeInfo, methodInfo, getTypeParameterBound(typeParameter), false)); + } + methodInfo.setReturnType( + getJavaType(typeInfo, methodInfo, methodDecl.getType(), false), + getJniType(typeInfo, methodInfo, methodDecl.getType(), false)); + + fillMethodBase(methodInfo, methodDecl); + fillJavadoc(methodInfo, methodDecl); + } + + private static final void fillJavadoc(final HasJavadocComment member, NodeWithJavadoc nodeWithJavadoc) { + JavadocComment javadoc = null; + if (nodeWithJavadoc.getJavadocComment().isPresent()) { + javadoc = nodeWithJavadoc.getJavadocComment().get(); + } + + if (javadoc != null) { + member.setJavadocComment(javadoc.parse().toText()); + } + } + + private final void fillMethodBase(final JniMethodBaseInfo methodBaseInfo, final CallableDeclaration callableDecl) { + JniMethodInfo methodInfo = null; + if (methodBaseInfo instanceof JniMethodInfo) { + methodInfo = (JniMethodInfo) methodBaseInfo; + } + NodeWithParameters params = callableDecl; + for (final Parameter p : params.getParameters()) { + String name = p.getNameAsString(); + String javaType = getJavaType(methodBaseInfo.getDeclaringType(), methodInfo, p.getType(), p.isVarArgs()); + String jniType = getJniType(methodBaseInfo.getDeclaringType(), methodInfo, p.getType(), p.isVarArgs()); + methodBaseInfo.addParameter(new JniParameterInfo(name, javaType, jniType)); + } + } + + static String getJavaType(JniTypeInfo typeInfo, JniMethodInfo methodInfo, Type type, boolean isVarArgs) { + String typeName = type.asString(); + if (methodInfo != null && methodInfo.getTypeParameters().contains(typeName)) + return typeName + (isVarArgs ? "..." : ""); + if (typeInfo.getTypeParameters().contains(typeName)) + return typeName + (isVarArgs ? "..." : ""); + try { + final ResolvedType rt = type.resolve(); + return rt.describe() + (isVarArgs ? "..." : ""); + } catch (final Throwable thr) { + return getUnresolvedJavaType(type) + (isVarArgs ? "..." : ""); + } + } + + static String getJniType(JniTypeInfo typeInfo, JniMethodInfo methodInfo, Type type, boolean isVarArgs) { + if (type == null) { + return "Ljava/lang/Object;"; + } + + if (type.isArrayType()) { + return (isVarArgs ? "[" : "") + getJniType(typeInfo, methodInfo, type.asArrayType()); + } + if (type.isPrimitiveType()) { + return (isVarArgs ? "[" : "") + getPrimitiveJniType(type.asString()); + } + + if (methodInfo != null && methodInfo.getTypeParameters().contains(type.asString())) { + return (isVarArgs ? "[" : "") + methodInfo.getTypeParameterJniType(type.asString()); + } + if (typeInfo.getTypeParameters().contains(type.asString())) { + return (isVarArgs ? "[" : "") + typeInfo.getTypeParameterJniType(type.asString()); + } + + try { + return getJniType(type.resolve()); + } + catch (final Exception thr) { + } + + return (isVarArgs ? "[" : "") + getUnresolvedJniType(type); + } + + static String getJniType(JniTypeInfo typeInfo, JniMethodInfo methodInfo, ArrayType type) { + final int level = type.getArrayLevel(); + final StringBuilder depth = new StringBuilder(); + for (int i = 0; i < level; ++i) + depth.append("["); + return depth.toString() + getJniType(typeInfo, methodInfo, type.getElementType(), false); + } + + static String getPrimitiveJniType(String javaType) { + switch (javaType) { + case "boolean": return "Z"; + case "byte": return "B"; + case "char": return "C"; + case "double": return "D"; + case "float": return "F"; + case "int": return "I"; + case "long": return "J"; + case "short": return "S"; + case "void": return "V"; + } + throw new Error("Don't know JNI type for primitive type `" + javaType + "`!"); + } + + static String getJniType(ResolvedType type) { + if (type.isPrimitive()) { + return getPrimitiveJniType(type.asPrimitive().describe()); + } + if (type.isReferenceType()) { + return getJniType(type.asReferenceType()); + } + if (type.isVoid()) { + return "V"; + } + return "-" + type.getClass().getName() + "-"; + } + + static String getJniType(ResolvedReferenceType type) { + final Optional typeDeclOpt = type.getTypeDeclaration(); + if (!typeDeclOpt.isPresent()) + throw new Error("Can't get `ResolvedReferenceTypeDeclaration` for type `" + type.toString() + "`!"); + + final ResolvedReferenceTypeDeclaration typeDecl = typeDeclOpt.get(); + if (!type.hasName()) + throw new Error("Type `" + type.toString() + "` has no name!"); + + StringBuilder name = new StringBuilder(); + name.append("L"); + name.append(typeDecl.getPackageName()); + int len = name.length(); + for (int i = 0; i < len; ++i) { + if (name.charAt (i) == '.') { + name.setCharAt(i, '/'); + } + } + if (len > 1) { + name.append("/"); + } + name.append(typeDecl.getName().replace(".", "$")); + name.append(";"); + return name.toString(); + } + + static String getUnresolvedJavaType(Type type) { + final StringBuilder jniType = new StringBuilder(); + + jniType.append(".*"); + + if (type.isClassOrInterfaceType()) { + // Special-case class-or-interface declarations so that we skip type parameters. + type.ifClassOrInterfaceType(c -> { + c.getScope().ifPresent(s -> jniType.append(s.asString()).append(".")); + jniType.append(c.getName().asString()); + }); + } else { + jniType.append(type.asString()); + } + + return jniType.toString(); + } + + static String getUnresolvedJniType(Type type) { + final StringBuilder jniType = new StringBuilder(); + + jniType.append("L.*"); + + if (type.isClassOrInterfaceType()) { + // Special-case class-or-interface declarations so that we skip type parameters. + type.ifClassOrInterfaceType(c -> { + c.getScope().ifPresent(s -> jniType.append(s.asString()).append(".")); + jniType.append(c.getName().asString()); + }); + } else { + jniType.append(type.asString()); + } + + jniType.append(";"); + + return jniType.toString(); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ParameterNameGenerator.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ParameterNameGenerator.java new file mode 100644 index 00000000000..7dbc56f82a1 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ParameterNameGenerator.java @@ -0,0 +1,103 @@ +package com.microsoft.android; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import com.microsoft.android.ast.*; +import com.microsoft.android.util.Parameter; + +public class ParameterNameGenerator implements AutoCloseable { + + final PrintStream output; + + public ParameterNameGenerator(final String output) throws FileNotFoundException, UnsupportedEncodingException { + if (output == null) + this.output = System.out; + else { + final File file = new File(output); + final File parent = file.getParentFile(); + if (parent != null) { + parent.mkdirs(); + } + this.output = new PrintStream(file, "UTF-8"); + } + } + + public ParameterNameGenerator(final PrintStream output) { + Parameter.requireNotNull("output", output); + + this.output = output; + } + + public void close() { + if (output != System.out) { + output.flush(); + output.close(); + } + } + + public final void writePackages(final JniPackagesInfo packages) { + Parameter.requireNotNull("packages", packages); + + boolean first = true; + for (JniPackageInfo packageInfo : packages.getSortedPackages()) { + if (!first) + output.println(); + first = false; + writePackage(packageInfo); + } + } + + private final void writePackage(final JniPackageInfo packageInfo) { + if (packageInfo.getPackageName().length() > 0) { + output.println("package " + packageInfo.getPackageName()); + } + output.println(";---------------------------------------"); + + for (JniTypeInfo type : packageInfo.getSortedTypes()) { + writeType(type); + } + } + + private final void writeType(JniTypeInfo type) { + output.println(" " + type.getTypeKind() + " " + type.getName()); + final List sortedMethods = type.getSortedMembers() + .stream() + .filter(member -> member.isMethod() || member.isConstructor()) + .map(member -> (JniMethodBaseInfo) member) + .filter(method -> method.getParameters().size() > 0) + .collect(Collectors.toList()); + + for (JniMethodBaseInfo method : sortedMethods) { + output.print(" "); + if (method.isMethod()) { + JniMethodInfo m = (JniMethodInfo) method; + Collection typeParameters = m.getTypeParameters(); + if (typeParameters.size() > 0) { + output.print("<"); + output.print(String.join(", ", typeParameters)); + output.print("> "); + } + } + output.print(method.getName()); + output.print("("); + boolean first = true; + for (JniParameterInfo parameter : method.getParameters()) { + if (!first) { + output.print(", "); + } + first = false; + output.print(parameter.javaType); + output.print(" "); + output.print(parameter.name); + } + output.print(")"); + output.println(); + } + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/HasJavadocComment.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/HasJavadocComment.java new file mode 100644 index 00000000000..6253eaf281b --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/HasJavadocComment.java @@ -0,0 +1,6 @@ +package com.microsoft.android.ast; + +public interface HasJavadocComment { + String getJavadocComment(); + void setJavadocComment(String javaDocComment); +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniClassInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniClassInfo.java new file mode 100644 index 00000000000..6eec50deb6e --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniClassInfo.java @@ -0,0 +1,12 @@ +package com.microsoft.android.ast; + +public class JniClassInfo extends JniTypeInfo { + public JniClassInfo(JniPackageInfo declaringPackage, String name) { + super(declaringPackage, name); + } + + @Override + public String getTypeKind() { + return "class"; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniConstructorInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniConstructorInfo.java new file mode 100644 index 00000000000..adb0994365b --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniConstructorInfo.java @@ -0,0 +1,17 @@ +package com.microsoft.android.ast; + +public final class JniConstructorInfo extends JniMethodBaseInfo { + public JniConstructorInfo(JniTypeInfo declaringType) { + super(declaringType, "#ctor"); + } + + @Override + public boolean isConstructor() { + return true; + } + + @Override + public String getJniSignature() { + return super.getJniSignature() + "V"; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniFieldInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniFieldInfo.java new file mode 100644 index 00000000000..cfb87966e51 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniFieldInfo.java @@ -0,0 +1,26 @@ +package com.microsoft.android.ast; + +import com.microsoft.android.util.Parameter; + +public final class JniFieldInfo extends JniMemberInfo { + + private String jniType; + + public JniFieldInfo(JniTypeInfo declaringType, String name) { + super(declaringType, name); + } + + @Override + public String getJniSignature() { + return jniType; + } + + @Override + public boolean isField() { + return true; + } + + public void setJniType(String jniType) { + this.jniType = Parameter.requireNotEmpty("jniType", jniType); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniInterfaceInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniInterfaceInfo.java new file mode 100644 index 00000000000..55d891765c8 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniInterfaceInfo.java @@ -0,0 +1,12 @@ +package com.microsoft.android.ast; + +public class JniInterfaceInfo extends JniTypeInfo { + public JniInterfaceInfo(JniPackageInfo declaringPackage, String name) { + super(declaringPackage, name); + } + + @Override + public String getTypeKind() { + return "interface"; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMemberInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMemberInfo.java new file mode 100644 index 00000000000..7ee6005fb67 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMemberInfo.java @@ -0,0 +1,49 @@ +package com.microsoft.android.ast; + +import com.microsoft.android.util.Parameter; + +public abstract class JniMemberInfo implements HasJavadocComment { + private final String name; + private final JniTypeInfo declaringType; + + String javadocComment = ""; + + JniMemberInfo(final JniTypeInfo declaringType, String name) { + Parameter.requireNotNull("declaringType", declaringType); + + name = Parameter.requireNotEmpty("name", name); + + this.declaringType = declaringType; + this.name = name; + } + + public final JniTypeInfo getDeclaringType() { + return declaringType; + } + + public abstract String getJniSignature(); + + public final String getName() { + return name; + } + + public boolean isField() { + return false; + } + + public boolean isMethod() { + return false; + } + + public boolean isConstructor() { + return false; + } + + public final String getJavadocComment() { + return javadocComment; + } + + public final void setJavadocComment(String javaDocComment) { + this.javadocComment = Parameter.normalize(javaDocComment, ""); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMethodBaseInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMethodBaseInfo.java new file mode 100644 index 00000000000..4824c03c570 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMethodBaseInfo.java @@ -0,0 +1,36 @@ +package com.microsoft.android.ast; + +import java.util.ArrayList; +import java.util.Collection; + +import com.microsoft.android.util.Parameter; + +public abstract class JniMethodBaseInfo extends JniMemberInfo { + + private final Collection parameters = new ArrayList (); + + JniMethodBaseInfo(final JniTypeInfo declaringType, final String name) { + super(declaringType, name); + } + + public final void addParameter(final JniParameterInfo parameter) { + Parameter.requireNotNull("parameter", parameter); + + parameters.add(parameter); + } + + public Collection getParameters() { + return parameters; + } + + @Override + public String getJniSignature() { + final StringBuilder sig = new StringBuilder(); + sig.append("("); + for (JniParameterInfo p : parameters) { + sig.append(p.jniType); + } + sig.append(")"); + return sig.toString(); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMethodInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMethodInfo.java new file mode 100644 index 00000000000..b1007430737 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniMethodInfo.java @@ -0,0 +1,64 @@ +package com.microsoft.android.ast; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + + +import com.microsoft.android.util.Parameter; + +public final class JniMethodInfo extends JniMethodBaseInfo { + + private String javaReturnType; + private String jniReturnType; + + private final Collection typeParameters = new ArrayList(); + private final Map jniTypes = new HashMap(); + + public JniMethodInfo(JniTypeInfo declaringType, String name) { + super(declaringType, name); + } + + @Override + public boolean isMethod() { + return true; + } + + public final void setReturnType(String javaType, String jniType) { + this.javaReturnType = Parameter.normalize(javaType, "void"); + this.jniReturnType = Parameter.normalize(jniType, "V"); + } + + public final void addTypeParameter(String typeParameter, String jniType) { + typeParameter = Parameter.requireNotEmpty("typeParameter", typeParameter); + jniType = Parameter.requireNotEmpty("jniType", jniType); + + if (typeParameters.contains(typeParameter)) + throw new IllegalArgumentException("Already added Type Parameter `" +typeParameter + "`"); + typeParameters.add(typeParameter); + jniTypes.put(typeParameter, jniType); + } + + public final Collection getTypeParameters() { + return typeParameters; + } + + public final String getTypeParameterJniType(String typeParameter) { + typeParameter = Parameter.requireNotEmpty("typeParameter", typeParameter); + return jniTypes.get(typeParameter); + } + + @Override + public String getJniSignature() { + return super.getJniSignature() + jniReturnType; + } + + public final String getJavaReturnType() { + return javaReturnType; + } + + public final String getJniReturnType() { + return jniReturnType; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniPackageInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniPackageInfo.java new file mode 100644 index 00000000000..563426bf42d --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniPackageInfo.java @@ -0,0 +1,47 @@ +package com.microsoft.android.ast; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.microsoft.android.util.Parameter; + +public final class JniPackageInfo { + private final String packageName; + + private final Map types = new HashMap(); + + public JniPackageInfo(String packageName) { + packageName = Parameter.normalize(packageName, ""); + + this.packageName = packageName; + } + + public final String getPackageName() { + return this.packageName; + } + + public final JniTypeInfo getType(String typeName) { + return types.getOrDefault(typeName, null); + } + + public final void add(JniTypeInfo type) { + if (types.containsKey(type.getName())) + throw new IllegalArgumentException("type"); + types.put(type.getName(), type); + } + + public final Collection getTypes() { + return types.values(); + } + + public final Collection getSortedTypes() { + final List sortedTypes = types.values() + .stream() + .sorted((t1, t2) -> t1.getRawName().compareTo(t2.getRawName())) + .collect(Collectors.toList()); + return sortedTypes; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniPackagesInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniPackagesInfo.java new file mode 100644 index 00000000000..f7e84dcb02d --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniPackagesInfo.java @@ -0,0 +1,37 @@ +package com.microsoft.android.ast; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.microsoft.android.util.Parameter; + +public final class JniPackagesInfo { + + private final Map packages = new HashMap(); + + public JniPackageInfo getPackage(String packageName) { + packageName = Parameter.normalize(packageName, ""); + + if (!packages.containsKey(packageName)) { + JniPackageInfo newPackage = new JniPackageInfo(packageName); + packages.put(packageName, newPackage); + return newPackage; + } + return packages.get(packageName); + } + + public final Collection getPackages() { + return packages.values(); + } + + public final Collection getSortedPackages() { + final List sortedPackages = packages.values() + .stream() + .sorted((p1, p2) -> p1.getPackageName().compareTo(p2.getPackageName())) + .collect(Collectors.toList()); + return sortedPackages; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniParameterInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniParameterInfo.java new file mode 100644 index 00000000000..dc6c177c433 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniParameterInfo.java @@ -0,0 +1,21 @@ +package com.microsoft.android.ast; + +public final class JniParameterInfo { + public final String name, jniType, javaType; + + public JniParameterInfo(String name, String javaType, String jniType) { + if (name == null || + (name = name.trim()).length() == 0) + throw new IllegalArgumentException("name"); + if (javaType == null || + (javaType = javaType.trim()).length() == 0) + throw new IllegalArgumentException("javaType"); + if (jniType == null || + (jniType = jniType.trim()).length() == 0) + throw new IllegalArgumentException("jniType"); + + this.name = name; + this.javaType = javaType; + this.jniType = jniType; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniTypeInfo.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniTypeInfo.java new file mode 100644 index 00000000000..cca84a95328 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/ast/JniTypeInfo.java @@ -0,0 +1,93 @@ +package com.microsoft.android.ast; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.microsoft.android.util.Parameter; + +public abstract class JniTypeInfo implements HasJavadocComment { + private final String name; + private final JniPackageInfo declaringPackage; + + private final Collection members = new ArrayList(); + private final Collection typeParameters = new ArrayList(); + private final Map jniTypes = new HashMap(); + + String javaDocComment = ""; + + JniTypeInfo(final JniPackageInfo declaringPackage, String name) { + Parameter.requireNotNull("declaringPackage", declaringPackage); + + name = Parameter.requireNotEmpty("name", name); + + this.declaringPackage = declaringPackage; + this.name = name; + } + + public abstract String getTypeKind(); + + public final JniPackageInfo getDeclaringPackage() { + return declaringPackage; + } + + public final String getName() { + if (typeParameters.isEmpty()) + return name; + return name + "<" + String.join(",", typeParameters) + ">"; + } + + public final String getRawName() { + return name; + } + + public final void addTypeParameter(String typeParameter, String jniType) { + typeParameter = Parameter.requireNotEmpty("typeParameter", typeParameter); + jniType = Parameter.requireNotEmpty("jniType", jniType); + + if (typeParameters.contains(typeParameter)) { + jniTypes.replace(typeParameter, jniType); + return; + } + typeParameters.add(typeParameter); + jniTypes.put(typeParameter, jniType); + } + + public final Collection getTypeParameters() { + return typeParameters; + } + + public final String getTypeParameterJniType(String typeParameter) { + typeParameter = Parameter.requireNotEmpty("typeParameter", typeParameter); + return jniTypes.get(typeParameter); + } + + public final void add(JniMemberInfo member) { + Parameter.requireNotNull("member", member); + + members.add(member); + } + + public final Collection getMembers() { + return members; + } + + public final String getJavadocComment() { + return javaDocComment; + } + + public final void setJavadocComment(String javaDocComment) { + this.javaDocComment = Parameter.normalize(javaDocComment, ""); + } + + public final Collection getSortedMembers() { + final List sortedMembers = members + .stream() + .sorted((m1, m2) -> (m1.getName() + "." + m1.getJniSignature()).compareTo((m2.getName() + "." + m2.getJniSignature()))) + .collect(Collectors.toList()); + return sortedMembers; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/util/Parameter.java b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/util/Parameter.java new file mode 100644 index 00000000000..6b0ec1b39d6 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/java/com/microsoft/android/util/Parameter.java @@ -0,0 +1,27 @@ +package com.microsoft.android.util; + +public final class Parameter { + private Parameter() { + } + + public static String requireNotEmpty(String parameterName, String value) { + if (value == null || + (value = value.trim()).length() == 0) + throw new IllegalArgumentException(parameterName); + return value; + } + + public static T requireNotNull(String parameterName, T value) { + if (value == null) + throw new IllegalArgumentException(parameterName); + return value; + } + + + public static String normalize(String value, String defaultValue) { + if (value == null || + (value = value.trim()).length() == 0) + value = defaultValue; + return value; + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/main/resources/transform-style.xsl b/external/Java.Interop/tools/java-source-utils/src/main/resources/transform-style.xsl new file mode 100644 index 00000000000..2f7e4157d72 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/main/resources/transform-style.xsl @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JavaSourceUtilsOptionsTest.java b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JavaSourceUtilsOptionsTest.java new file mode 100644 index 00000000000..34f68448183 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JavaSourceUtilsOptionsTest.java @@ -0,0 +1,71 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.microsoft.android; + +import java.io.File; +import java.io.IOException; +import java.io.*; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class JavaSourceUtilsOptionsTest { + + @Test public void testParse_HelpOptionReturnsNull() throws IOException { + JavaSourceUtilsOptions options; + options = JavaSourceUtilsOptions.parse(new String[]{"--help"}); + assertNull(options); + options = JavaSourceUtilsOptions.parse(new String[]{"-h"}); + assertNull(options); + } + + @Test public void testParse_ResponseFiles() throws IOException { + JavaSourceUtilsOptions options; + + final File responseFile = File.createTempFile("jsu-test", ".java"); + final String responseFilePath = responseFile.getAbsolutePath(); + + try (PrintWriter contents = new PrintWriter(responseFile)) { + contents.println("--help"); + } + + options = JavaSourceUtilsOptions.parse(new String[]{"@" + responseFilePath}); + responseFile.delete(); + assertNull(options); + + try (PrintWriter contents = new PrintWriter(responseFile)) { + contents.println("# aar?"); + contents.println("-a"); + contents.println(responseFilePath); + contents.println("# jar?"); + contents.println("-j"); + contents.println(responseFilePath); + contents.println("# source?"); + contents.println("-s"); + contents.println(responseFilePath); + contents.println("-bootclasspath"); + contents.println(responseFilePath + File.pathSeparator + responseFilePath); + contents.println("# params output?"); + contents.println("-P"); + contents.println("params.txt"); + contents.println("# xml javadoc output?"); + contents.println("-D"); + contents.println("javadoc.xml"); + contents.println("# comment; FILEs…"); + contents.println(responseFilePath); + } + + options = JavaSourceUtilsOptions.parse(new String[]{"@" + responseFilePath}); + responseFile.delete(); + + assertEquals(responseFilePath, options.aarFiles.get(0).getAbsolutePath()); + assertEquals(responseFilePath, options.jarFiles.get(0).getAbsolutePath()); + assertEquals("params.txt", options.outputParamsTxt); + assertEquals("javadoc.xml", options.outputJavadocXml); + assertEquals(1, options.inputFiles.size()); + assertEquals(responseFilePath, options.inputFiles.iterator().next().getAbsolutePath()); + assertTrue(options.haveBootClassPath); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java new file mode 100644 index 00000000000..9215ad69a77 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java @@ -0,0 +1,110 @@ +package com.microsoft.android; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.io.FileOutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.junit.Assume; +import org.junit.Test; +import static org.junit.Assert.*; + +import com.github.javaparser.JavaParser; +import com.microsoft.android.ast.*; + +public final class JavadocXmlGeneratorTest { + @Test(expected = FileNotFoundException.class) + public void init_invalidFileThrows() throws FileNotFoundException, ParserConfigurationException, TransformerException, UnsupportedEncodingException { + String invalidFilePath = "/this/file/does/not/exist"; + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) { + invalidFilePath = System.getenv("ProgramFiles") + "\\this\\file\\does\\not\\exist"; + // Ignore if running on an Azure Pipelines Microsoft hosted agent by only running when %AGENT_NAME% is not set. + Assume.assumeTrue(System.getenv("AGENT_NAME") == null); + } + try (JavadocXmlGenerator g = new JavadocXmlGenerator(invalidFilePath)) { + } + } + + @Test(expected = IllegalArgumentException.class) + public void testWritePackages_nullPackages() throws ParserConfigurationException, TransformerException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + JavadocXmlGenerator generator = new JavadocXmlGenerator(new PrintStream(bytes)); + + generator.writePackages(null); + } + + @Test + public void testWritePackages_noPackages() throws ParserConfigurationException, TransformerException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + JavadocXmlGenerator generator = new JavadocXmlGenerator(new PrintStream(bytes)); + + JniPackagesInfo packages = new JniPackagesInfo(); + generator.writePackages(packages); + generator.close(); + + final String expected = ( + "\n" + + "\n" + ).replace("\n", System.lineSeparator()); + + assertEquals("no packages", expected, bytes.toString()); + } + + + @Test + public void testWritePackages_demo() throws Throwable { + final JniPackagesInfo packages = JniPackagesInfoTest.createDemoInfo(); + + testWritePackages (packages, "global package + example packages", "DemoInfo.xml"); + } + + @Test + public void testWritePackages_Outer_java() throws Throwable { + testWritePackages("Outer.java", "Outer.xml"); + } + + @Test + public void testWritePackages_JavaType_java() throws Throwable { + testWritePackages("../../../com/xamarin/JavaType.java", "JavaType.xml"); + } + + @Test + public void testWritePackages_UnresolvedTypes_txt() throws Throwable { + testWritePackages("../../../UnresolvedTypes.txt", "../../../UnresolvedTypes.xml"); + } + + private static void testWritePackages(final String resourceJava, final String resourceXml) throws Throwable { + final JavaParser parser = JniPackagesInfoFactoryTest.createParser(); + final JniPackagesInfoFactory factory = new JniPackagesInfoFactory(parser); + final File demoSource = new File(JniPackagesInfoFactoryTest.class.getResource(resourceJava).toURI()); + final JniPackagesInfo packagesInfo = factory.parse(Arrays.asList(new File[]{demoSource})); + + int lastSlash = resourceJava.lastIndexOf('/'); + final String assertDesc = resourceJava.substring(lastSlash+1) + " Javadoc XML"; + + testWritePackages(packagesInfo, assertDesc, resourceXml); + } + + private static void testWritePackages(final JniPackagesInfo packagesInfo, final String assertDescription, final String expectedResourceXml) throws Throwable { + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final JavadocXmlGenerator generator = new JavadocXmlGenerator(new PrintStream(bytes)); + + final String expected = JniPackagesInfoTest.getResourceContents(expectedResourceXml); + + generator.writePackages(packagesInfo); + generator.close(); + + final File actual = new File(assertDescription + "-jonp.xml"); + try (FileOutputStream o = new FileOutputStream(actual)) { + bytes.writeTo(o); + } + assertEquals(assertDescription, expected, bytes.toString()); + actual.delete(); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JniPackagesInfoFactoryTest.java b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JniPackagesInfoFactoryTest.java new file mode 100644 index 00000000000..730f14baa44 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JniPackagesInfoFactoryTest.java @@ -0,0 +1,59 @@ +package com.microsoft.android; + +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.Arrays; +import java.io.File; + +import org.junit.Test; +import static org.junit.Assert.*; + +import com.github.javaparser.JavaParser; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.symbolsolver.*; +import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.*; + + +import com.microsoft.android.ast.*; + +public class JniPackagesInfoFactoryTest { + + @Test(expected = IllegalArgumentException.class) + public void testInit_nullParser() { + new JniPackagesInfoFactory(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testParse_nullFiles() throws Throwable { + final JavaParser parser = new JavaParser(); + final JniPackagesInfoFactory factory = new JniPackagesInfoFactory(parser); + factory.parse(null); + } + + @Test + public void testParse_demo() throws Throwable { + final JavaParser parser = createParser(); + final JniPackagesInfoFactory factory = new JniPackagesInfoFactory(parser); + final File demoSource = new File(JniPackagesInfoFactoryTest.class.getResource("Outer.java").toURI()); + final JniPackagesInfo packagesInfo = factory.parse(Arrays.asList(new File[]{demoSource})); + + assertEquals("Only one package processed", 1, packagesInfo.getPackages().size()); + final JniPackageInfo p = packagesInfo.getPackage("example"); + assertNotNull("Should have found `example` package", p); + assertEquals("Outer & Outer.Inner & Outer.Inner.NestedInner & Outer.MyAnnotation types found", 4, p.getTypes().size()); + + JniTypeInfo info = p.getType("Outer"); + assertNotNull(info); + assertEquals("Outer", info.getName()); + } + + static JavaParser createParser() { + final CombinedTypeSolver typeSolver = new CombinedTypeSolver(); + typeSolver.add(new ReflectionTypeSolver()); + final ParserConfiguration config = new ParserConfiguration(); + config.setSymbolResolver(new JavaSymbolSolver(typeSolver)); + return new JavaParser(config); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JniPackagesInfoTest.java b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JniPackagesInfoTest.java new file mode 100644 index 00000000000..845bd091cf3 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/JniPackagesInfoTest.java @@ -0,0 +1,82 @@ +package com.microsoft.android; + +import java.io.*; +import java.net.URISyntaxException; + +import com.microsoft.android.ast.*; + +public class JniPackagesInfoTest { + + static JniPackagesInfo createDemoInfo() { + JniPackagesInfo packages = new JniPackagesInfo(); + JniPackageInfo global = packages.getPackage(null); + + JniTypeInfo type = new JniClassInfo(global, "A"); + type.setJavadocComment("jni-sig=LA;"); + global.add(type); + + JniFieldInfo field = new JniFieldInfo(type, "field"); + field.setJniType("I"); + field.setJavadocComment("jni-sig=field.I"); + type.add(field); + + JniConstructorInfo init = new JniConstructorInfo(type); + init.addParameter(new JniParameterInfo("one", "int", "I")); + init.addParameter(new JniParameterInfo("two", "java.lang.String", "Ljava/lang/String;")); + init.setJavadocComment("jni-sig=.(ILjava/lang/String;)V"); + type.add(init); + + JniMethodInfo method = new JniMethodInfo(type, "m"); + method.addTypeParameter("T", "Ljava/lang/Object;"); + method.addParameter(new JniParameterInfo("value", "T", "Ljava/lang/Object;")); + method.addParameter(new JniParameterInfo("x", "long", "J")); + method.setReturnType("void", "V"); + method.setJavadocComment("jni-sig=m.(Ljava/lang/Object;J)V"); + type.add(method); + + type = new JniInterfaceInfo(global, "I"); + type.addTypeParameter("T", "Ljava/lang/Object;"); + type.setJavadocComment("jni-sig=LI;"); + global.add(type); + method = new JniMethodInfo(type, "m"); + method.addParameter(new JniParameterInfo("x", "java.util.List", "Ljava/util/List;")); + method.setReturnType("T", "Ljava/lang/Object;"); + method.setJavadocComment("jni-sig=m.(Ljava/util/List;)Ljava/lang/Object;"); + type.add(method); + + JniPackageInfo example = packages.getPackage("example"); + type = new JniInterfaceInfo(example, "Exampleable"); + type.setJavadocComment("jni-sig=Lexample/Exampleable;"); + example.add(type); + + method = new JniMethodInfo(type, "noParameters"); + method.setReturnType("void", "V"); + method.setJavadocComment("jni-sig=noParameters.()V"); + type.add(method); + + method = new JniMethodInfo(type, "example"); + method.addParameter(new JniParameterInfo("e", "java.lang.String", "Ljava/lang/String;")); + method.setReturnType("void", "V"); + method.setJavadocComment("jni-sig=example.(Ljava/lang/String;)V"); + type.add(method); + + packages.getPackage("before.example"); + + return packages; + } + + static String getResourceContents(String resourceName) throws IOException, URISyntaxException { + final File resourceFile = new File(JniPackagesInfoTest.class.getResource(resourceName).toURI()); + final StringBuilder contents = new StringBuilder(); + final String lineEnding = System.getProperty("line.separator"); + + String line; + try (final BufferedReader reader = new BufferedReader(new FileReader (resourceFile))) { + while((line = reader.readLine()) != null) { + contents.append(line); + contents.append(lineEnding); + } + } + return contents.toString(); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/ParameterNameGeneratorTest.java b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/ParameterNameGeneratorTest.java new file mode 100644 index 00000000000..5235ab7e7c1 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/java/com/microsoft/android/ParameterNameGeneratorTest.java @@ -0,0 +1,102 @@ +package com.microsoft.android; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; + +import org.junit.Assume; +import org.junit.Test; +import static org.junit.Assert.*; + +import com.github.javaparser.JavaParser; +import com.microsoft.android.ast.*; + +public class ParameterNameGeneratorTest { + + @Test(expected = FileNotFoundException.class) + public void init_invalidFileThrows() throws FileNotFoundException, UnsupportedEncodingException { + String invalidFilePath = "/this/file/does/not/exist"; + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) { + invalidFilePath = System.getenv("ProgramFiles") + "\\this\\file\\does\\not\\exist"; + // Ignore if running on an Azure Pipelines Microsoft hosted agent by only running when %AGENT_NAME% is not set. + Assume.assumeTrue(System.getenv("AGENT_NAME") == null); + } + new ParameterNameGenerator(invalidFilePath); + } + + @Test(expected = IllegalArgumentException.class) + public void testWritePackages_nullPackages() { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + ParameterNameGenerator generator = new ParameterNameGenerator(new PrintStream(bytes)); + + generator.writePackages(null); + } + + @Test + public void testWritePackages_noPackages() { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + ParameterNameGenerator generator = new ParameterNameGenerator(new PrintStream(bytes)); + + JniPackagesInfo packages = new JniPackagesInfo(); + generator.writePackages(packages); + assertEquals("no packages", "", bytes.toString()); + } + + + @Test + public void testWritePackages_demo() { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + ParameterNameGenerator generator = new ParameterNameGenerator(new PrintStream(bytes)); + JniPackagesInfo packages = JniPackagesInfoTest.createDemoInfo(); + + final String expected = ( + ";---------------------------------------\n" + + " class A\n" + + " #ctor(int one, java.lang.String two)\n" + + " m(T value, long x)\n" + + " interface I\n" + + " m(java.util.List x)\n" + + "\n" + + "package before.example\n" + + ";---------------------------------------\n" + + "\n" + + "package example\n" + + ";---------------------------------------\n" + + " interface Exampleable\n" + + " example(java.lang.String e)\n" + + "" + ).replace("\n", System.lineSeparator()); + + generator.writePackages(packages); + assertEquals("global package + example packages", expected, bytes.toString()); + } + + @Test + public void testWritePackages_Outer_java() throws Throwable { + testWritePackages("Outer.java", "Outer.params.txt"); + } + + @Test + public void testWritePackages_JavaType_java() throws Throwable { + testWritePackages("../../../com/xamarin/JavaType.java", "JavaType.params.txt"); + } + + private static void testWritePackages(final String resourceJava, final String resourceParamsTxt) throws Throwable { + final JavaParser parser = JniPackagesInfoFactoryTest.createParser(); + final JniPackagesInfoFactory factory = new JniPackagesInfoFactory(parser); + final File demoSource = new File(JniPackagesInfoFactoryTest.class.getResource(resourceJava).toURI()); + final JniPackagesInfo packagesInfo = factory.parse(Arrays.asList(new File[]{demoSource})); + + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final ParameterNameGenerator generator = new ParameterNameGenerator(new PrintStream(bytes)); + + final String expected = JniPackagesInfoTest.getResourceContents(resourceParamsTxt); + + generator.writePackages(packagesInfo); + assertEquals(resourceJava + " parameter names", expected, bytes.toString()); + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/UnresolvedTypes.txt b/external/Java.Interop/tools/java-source-utils/src/test/resources/UnresolvedTypes.txt new file mode 100644 index 00000000000..4988cc9b6d1 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/UnresolvedTypes.txt @@ -0,0 +1,11 @@ +package example; + +public class UnresolvedTypes { + /** + * Method using unresolvable types. As such, we make do. + * + * JNI Sig: method.([L.*example.name.UnresolvedParameterType;)L.*UnresolvedReturnType; + */ + public static UnresolvedReturnType method(example.name.UnresolvedParameterType... parameter) { + } +} \ No newline at end of file diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/UnresolvedTypes.xml b/external/Java.Interop/tools/java-source-utils/src/test/resources/UnresolvedTypes.xml new file mode 100644 index 00000000000..89762f5924d --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/UnresolvedTypes.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/.gitignore b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/.gitignore new file mode 100644 index 00000000000..f815dd72bbb --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/.gitignore @@ -0,0 +1 @@ +xamarin diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/.gitignore b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/.gitignore new file mode 100644 index 00000000000..6b468b62a98 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/DemoInfo.xml b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/DemoInfo.xml new file mode 100644 index 00000000000..04670d3ea21 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/DemoInfo.xml @@ -0,0 +1,41 @@ + + + + + + + + + .(ILjava/lang/String;)V]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/JavaType.params.txt b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/JavaType.params.txt new file mode 100644 index 00000000000..6e529d545a7 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/JavaType.params.txt @@ -0,0 +1,21 @@ +package com.xamarin +;--------------------------------------- + class JavaEnum + class JavaType + #ctor(java.lang.String value) + action(java.lang.Object value) + compareTo(com.xamarin.JavaType value) + finalize(int value) + func(java.lang.StringBuilder value) + func(java.lang.String[] values) + instanceActionWithGenerics(T value1, E value2) + staticActionWithGenerics(T value1, TExtendsNumber value2, java.util.List unboundedList, java.util.List extendsList, java.util.List superList) + sum(int first, int... remaining) + class JavaType.ASC + class JavaType.PSC + class JavaType.RNC + #ctor(E value1, E2 value2) + fromE(E value) + class JavaType.RNC.RPNC + #ctor(E value1, E2 value2, E3 value3) + fromE2(E2 value) diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/JavaType.xml b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/JavaType.xml new file mode 100644 index 00000000000..873dc42bebf --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/JavaType.xml @@ -0,0 +1,174 @@ + + + + + + + Paragraphs of text? + +@return some value]]> + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.java b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.java new file mode 100644 index 00000000000..c2f9ad9e764 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.java @@ -0,0 +1,121 @@ +package example; + +import java.util.List; +import java.util.Map; + + +/** + * Yay, Javadoc! + * + * JNI sig: Lexample/Outer; + */ +// Cause the above Javadoc block to be orphaned from the below class declaration + @Outer.MyAnnotation(keys={"a", "b", "c"}) +public class Outer { + + /** + * (java.lang.Object value) + * + * JNI sig: (Ljava/lang/Object;)V + */ + + public Outer(T value) { + value.run(); + } + + /** + * isU(java.util.List list) + * + *

    This is a paragraph. Yay?

    + * + * JNI sig: (Ljava/util/List;)Ljava/lang/Error; + * + * @param list just some random items + * @return some value + */ + + public U isU(List list) { + return null; + } + + /** + * Just an example annotation, for use later… + * + * JNI sig: Lexample/Outer$MyAnnotation; + */ + + @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) + public static @interface MyAnnotation { + + /** + * JNI sig: ()[Ljava/lang/String; + * + * @return some random keys + */ + + String[] keys() default {}; + } + + /** + * JNI sig: Lexample/Outer$Inner; + */ + public static interface Inner { + /** + * m(U value) + * + * JNI sig: ([[Ljava/lang/Readable;)V + * + * @throws Throwable never, just because + */ + public default void m(V[][] values) throws Throwable { + for (V[] vs : values) { + for (V v : vs) { + v.read(null); + } + } + } + + /** + * JNI sig: J + */ + public static final long COUNT = 42; + + /** + * JNI sig: Lexample/Outer$Inner$NestedInner; + */ + public static class NestedInner { + + /** + * JNI sig: S + */ + public static final short S = 64; + + /** + * map(java.util.Map map) + * + * JNI sig: map(Ljava/util/Map;)V + * @param map + */ + public void map(Map m) { + } + } + } + + /** + * method(java.lang.CharSequence a, short[] b, T[] values) + * + * JNI sig: (Ljava/lang/CharSequence;[S[Ljava/lang/Appendable;)Ljava/lang/Appendable; + */ + public T method(CharSequence a, short[] b, T[] values) { + return null; + } + + /** + * main(java.lang.String[] args) + * + * JNI sig: ([Ljava/lang/String;)V + */ + public static void main(String[] args) { + } +} diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.params.txt b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.params.txt new file mode 100644 index 00000000000..fc2a52c4602 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.params.txt @@ -0,0 +1,12 @@ +package example +;--------------------------------------- + class Outer + #ctor(T value) + isU(java.util.List list) + main(java.lang.String[] args) + method(java.lang.CharSequence a, short[] b, T[] values) + interface Outer.Inner + m(V[][] values) + class Outer.Inner.NestedInner + map(java.util.Map m) + interface Outer.MyAnnotation diff --git a/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.xml b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.xml new file mode 100644 index 00000000000..e073732d191 --- /dev/null +++ b/external/Java.Interop/tools/java-source-utils/src/test/resources/com/microsoft/android/Outer.xml @@ -0,0 +1,79 @@ + + + + + + + + (java.lang.Object value) + +JNI sig: (Ljava/lang/Object;)V]]> + + + + list) + +

    This is a paragraph. Yay?

    + +JNI sig: (Ljava/util/List;)Ljava/lang/Error; + +@param list just some random items +@return some value]]>
    +
    + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + map) + +JNI sig: map(Ljava/util/Map;)V + +@param map]]> + + + + + + + + +
    +
    diff --git a/external/Java.Interop/tools/jcw-gen/App.cs b/external/Java.Interop/tools/jcw-gen/App.cs new file mode 100644 index 00000000000..0eb606902fb --- /dev/null +++ b/external/Java.Interop/tools/jcw-gen/App.cs @@ -0,0 +1,104 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.IO; +using System.Threading.Tasks; + +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Diagnostics; +using Java.Interop.Tools.JavaCallableWrappers; +using Mono.Cecil; +using Mono.Options; +using Java.Interop.Tools.JavaCallableWrappers.Adapters; + +namespace Java.Interop.Tools +{ + class App + { + public static int Main (string [] args) + { + var resolver = new DirectoryAssemblyResolver (logger: Diagnostic.CreateConsoleLogger (), loadDebugSymbols: false); + + bool help = false; + string outputPath = null; + int verbosity = 0; + var style = JavaPeerStyle.XAJavaInterop1; + + var options = new OptionSet { + "Usage: jcw-gen.exe OPTIONS* ASSEMBLY+ [@RESPONSE-FILES]", + "", + "Generates Java Callable Wrappers from specified assemblies.", + "", + "Copyright 2016 Xamarin Inc.", + "", + "Options:", + { "L=", + "{DIRECTORY} to resolve assemblies from.", + v => resolver.SearchDirectories.Add (v) }, + { "o=", + "{DIRECTORY} to write Java source code to.", + v => outputPath = v }, + { "codegen-target=", + "STYLE of Java Callable Wrappers to generate", + (JavaPeerStyle? v) => style = v.HasValue ? v.Value : style }, + { "v:", + "Logging verbosity.", + (int? v) => verbosity = v.HasValue ? v.Value : verbosity + 1 }, + { "h|help|?", + "Show this message and exit", + v => help = v != null }, + new ResponseFileSource (), + }; + var cache = new TypeDefinitionCache (); + var scanner = new JavaTypeScanner (Diagnostic.CreateConsoleLogger (), cache); + try { + var assemblies = options.Parse (args); + if (assemblies.Count == 0 || outputPath == null || help) { + int r = 0; + if (assemblies.Count == 0) { + Console.Error.WriteLine ("jcw-gen: No assemblies specified."); + r = 1; + } + else if (outputPath == null) { + Console.Error.WriteLine ("jcw-gen: No output directory specified. Use `jcw-gen -o PATH`."); + r = 1; + } + options.WriteOptionDescriptions (Console.Out); + return r; + } + foreach (var assembly in assemblies) { + resolver.SearchDirectories.Add (Path.GetDirectoryName (assembly)); + resolver.Load (assembly); + } + var types = scanner.GetJavaTypes (assemblies, resolver) + .Where (td => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (td, cache)); + foreach (var type in types) { + GenerateJavaCallableWrapper (type, outputPath, cache, style); + } + return 0; + } + catch (Exception e) { + Console.Error.Write ("jcw-gen: {0}", verbosity > 0 ? e.ToString () : e.Message); + return 1; + } + finally { + resolver.Dispose (); + } + } + + static void GenerateJavaCallableWrapper (TypeDefinition type, string outputPath, TypeDefinitionCache cache, JavaPeerStyle style) + { + if (type.IsInterface) { + return; + } + + var t = CecilImporter.CreateType (type, cache); + + var options = new CallableWrapperWriterOptions { + CodeGenerationTarget = style, + }; + + t.Generate (outputPath, options); + } + } +} diff --git a/external/Java.Interop/tools/jcw-gen/jcw-gen.csproj b/external/Java.Interop/tools/jcw-gen/jcw-gen.csproj new file mode 100644 index 00000000000..f99367616b8 --- /dev/null +++ b/external/Java.Interop/tools/jcw-gen/jcw-gen.csproj @@ -0,0 +1,31 @@ + + + + $(DotNetTargetFramework) + Exe + + + + + + $(UtilityOutputFullPath) + + + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/jcw-gen/jcw-gen.slnf b/external/Java.Interop/tools/jcw-gen/jcw-gen.slnf new file mode 100644 index 00000000000..b8e3a83f9e4 --- /dev/null +++ b/external/Java.Interop/tools/jcw-gen/jcw-gen.slnf @@ -0,0 +1,13 @@ +{ + "solution": { + "path": "..\\..\\Java.Interop.sln", + "projects": [ + "src\\Java.Interop.Localization\\Java.Interop.Localization.csproj", + "src\\Java.Interop.Tools.Cecil\\Java.Interop.Tools.Cecil.csproj", + "src\\Java.Interop.Tools.Diagnostics\\Java.Interop.Tools.Diagnostics.csproj", + "src\\Java.Interop.Tools.JavaCallableWrappers\\Java.Interop.Tools.JavaCallableWrappers.csproj", + "tests\\Java.Interop.Tools.JavaCallableWrappers-Tests\\Java.Interop.Tools.JavaCallableWrappers-Tests.csproj", + "tools\\jcw-gen\\jcw-gen.csproj" + ] + } +} \ No newline at end of file diff --git a/external/Java.Interop/tools/logcat-parse/GrefParseOptions.cs b/external/Java.Interop/tools/logcat-parse/GrefParseOptions.cs new file mode 100644 index 00000000000..7720a8d1fb7 --- /dev/null +++ b/external/Java.Interop/tools/logcat-parse/GrefParseOptions.cs @@ -0,0 +1,20 @@ +using System; + +namespace Xamarin.Android.Tools.LogcatParse { + + [Flags] + public enum GrefParseOptions { + None, + + LogWarningOnMismatch = 1 << 0, + ThrowExceptionOnMismatch = 1 << 1, + + CheckCounts = 1 << 2, + WarnOnCountMismatch = CheckCounts | LogWarningOnMismatch, + ThrowOnCountMismatch = CheckCounts | ThrowExceptionOnMismatch, + + CheckAlivePeers = 1 << 3, + WarnOnAlivePeerMismatch = CheckAlivePeers | LogWarningOnMismatch, + ThrowOnAlivePeerMismatch = CheckAlivePeers | ThrowExceptionOnMismatch, + } +} diff --git a/external/Java.Interop/tools/logcat-parse/Grefs.cs b/external/Java.Interop/tools/logcat-parse/Grefs.cs new file mode 100644 index 00000000000..dcce7e2c4d9 --- /dev/null +++ b/external/Java.Interop/tools/logcat-parse/Grefs.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Xamarin.Android.Tools.LogcatParse { + + public class Grefs { + + const string FilePrefix = @"\[monodroid-gref\] "; + const string AndroidPrefix = @"(\d\d-\d\d \d\d:\d\d:[^:]+: )?I/monodroid-gref\(\s*(?{0})\): "; + const string Android10Prefix = @"(\d\d-\d\d \d\d:\d\d:[^ ]+ (?{0}) \d+ )?I monodroid-gref: "; + + const string Prefix = "^(" + FilePrefix + + "|" + AndroidPrefix + + "|" + Android10Prefix + + ")?"; + const string ThreadAndStack = @"(thread (?'[^']+'\([^)]+\)))?(?.*)$"; + const string AddGrefFormat = Prefix + @"\+g\+ grefc (?\d+) gwrefc (?\d+) obj-handle (?0x[0-9A-Fa-f]+)/(?.) -> new-handle (?0x[0-9A-Fa-f]+)/(?.) from " + ThreadAndStack; + const string AddWgrefFormat = Prefix + @"\+w\+ grefc (?\d+) gwrefc (?\d+) obj-handle (?0x[0-9A-Fa-f]+)/(?.) -> new-handle (?0x[0-9A-Fa-f]+)/(?.) from " + ThreadAndStack; + const string AtFormat = Prefix + @"(?\s+at.*$)"; + const string DisposingFormat = Prefix + @"Disposing handle (?0x[0-9A-Fa-f]+)$"; + const string FinalizingFormat = Prefix + @"Finalizing (?[^ ]+) handle (?0x[0-9A-Fa-f]+)$"; + const string HandleFormat = Prefix + @"handle (?0x[0-9A-Fa-f]+); key_handle (?0x[0-9A-Fa-f]+): Java Type: `(?[^`]+)`; MCW type: `(?.*)`$"; + const string RemoveGrefFormat = Prefix + @"-g- grefc (?\d+) gwrefc (?\d+) handle (?0x[0-9A-Fa-f]+)/(?.) from " + ThreadAndStack; + const string RemoveWgrefFormat = Prefix + @"-w- grefc (?\d+) gwrefc (?\d+) handle (?0x[0-9A-Fa-f]+)/(?.) from " + ThreadAndStack; + + public static Grefs Parse (string filename, int? pid = null, GrefParseOptions options = 0) + { + using (var source = new StreamReader (filename)) + return Parse (source, pid, options); + } + + public static Grefs Parse (TextReader reader, int? pid = null, GrefParseOptions options = 0) + { + var r = new Grefs () { + ParseOptions = options, + }; + var h = r.CreateHandlers (pid); + + int lineNumber = 0; + string line; + while ((line = reader.ReadLine ()) != null) { + lineNumber++; + foreach (var e in h) { + var m = e.Key.Match (line); + if (m.Success) { + e.Value (m, lineNumber); + break; + } + } + } + + return r; + } + + HashSet GlobalRefs = new HashSet(); + HashSet WeakRefs = new HashSet(); + + List allocated = new List (); + List alive = new List (); + + public GrefParseOptions ParseOptions {get; private set;} + public IList AllocatedPeers {get; private set;} + public IEnumerable AlivePeers { + get {return alive;} + } + + public int GrefCount { + get {return GlobalRefs.Count;} + } + public int WeakGrefCount { + get {return WeakRefs.Count;} + } + + public Grefs () + { + AllocatedPeers = new ReadOnlyCollection (allocated); + } + + public Dictionary GetAliveJniTypeCounts () + { + return AlivePeers.Select (p => p.JniType) + .Distinct() + .ToDictionary (t => t ?? "", t => AlivePeers.Count (p => p.JniType == t)); + } + + public IEnumerable GetDistinctStacksForJniType (string jniType) + { + return AllocatedPeers.Where (p => p.JniType == jniType) + .SelectMany (p => p.Handles.Select (h => p.GetStackTraceForHandle (h))) + .Distinct (); + } + + Dictionary> CreateHandlers (int? pid) + { + string pidv = pid.HasValue ? pid.ToString () : @"\d+"; + + string addGm = string.Format (AddGrefFormat, pidv); + string addWm = string.Format (AddWgrefFormat, pidv); + string atm = string.Format (AtFormat, pidv); + string dm = string.Format (DisposingFormat, pidv); + string fm = string.Format (FinalizingFormat, pidv); + string hm = string.Format (HandleFormat, pidv); + string remGm = string.Format (RemoveGrefFormat, pidv); + string remWm = string.Format (RemoveWgrefFormat, pidv); + + PeerInfo curPeer = null; + + JniHandleInfo curHandle = default (JniHandleInfo); + + return new Dictionary> { + { new Regex (addGm), (m, l) => { + var h = GetHandle (m, "ghandle"); + var p = GetLastOrCreatePeerInfo (m, h); + p.AppendStackTraceForHandle (h, m.Groups ["stack"].Value); + GlobalRefs.Add (h); + CheckCounts (m, l); + + curPeer = p; + curHandle = h; + } }, + { new Regex (addWm), (m, l) => { + var h = GetHandle (m, "whandle"); + var p = GetLastOrCreatePeerInfo (m, h); + p.AppendStackTraceForHandle (h, m.Groups ["stack"].Value); + WeakRefs.Add (h); + CheckCounts (m, l); + + curPeer = p; + curHandle = h; + } }, + { new Regex (dm), (m, l) => { + var p = GetAlivePeerInfo (m); + if (p == null) { + LogWarning (GrefParseOptions.CheckAlivePeers, $"at line {l}: could not find PeerInfo for disposed handle {GetHandle (m, "handle")}"); + return; + } + p.Disposed = true; + } }, + { new Regex (fm), (m, l) => { + var p = GetAlivePeerInfo (m); + if (p == null) { + LogWarning (GrefParseOptions.CheckAlivePeers, $"at line {l}: could not find PeerInfo for finalized handle {GetHandle (m, "handle")}"); + return; + } + p.Finalized = true; + } }, + { new Regex (hm), (m, l) => { + var p = GetAlivePeerInfo (m); + if (p == null) { + LogWarning (GrefParseOptions.CheckAlivePeers, $"at line {l}: could not find PeerInfo for handle {GetHandle (m, "handle")}"); + return; + } + if (!string.IsNullOrEmpty (p.KeyHandle)) { + LogWarning (GrefParseOptions.CheckAlivePeers, $"at line {l}: Attempting to re-set p.KeyHandle {p.KeyHandle} for `{p.JniType}` to {m.Groups ["key_handle"].Value} for {m.Groups ["jtype"].Value}"); + return; + } + p.KeyHandle = m.Groups ["key_handle"].Value; + p.JniType = m.Groups ["jtype"].Value; + p.McwType = m.Groups ["mtype"].Value; + } }, + { new Regex (remGm), (m, l) => { + var h = GetHandle (m, "handle"); + var p = GetAlivePeerInfo (m); + if (p == null) { + LogWarning (GrefParseOptions.CheckAlivePeers, $"at line {l}: could not find PeerInfo to remove gref for handle {h}"); + } + GlobalRefs.Remove (h); + if (p != null) { + p.Handles.Remove (h); + p.RemovedHandles.Add (h); + } + if (p != null && !WeakRefs.Any (w => p.Handles.Contains (w))) { + p.Collected = true; + p.DestroyedOnThread = m.Groups ["thread"].Value; + alive.Remove (p); + } + CheckCounts (m, l); + + curPeer = null; + curHandle = default (JniHandleInfo); + } }, + { new Regex (remWm), (m, l) => { + var h = GetHandle (m, "handle"); + var p = GetAlivePeerInfo (m); + WeakRefs.Remove (h); + if (p == null) { + // Means that the instance has been collected; this is fine. + } else { + p.Handles.Remove (h); + p.RemovedHandles.Add (h); + if (!GlobalRefs.Any (g => p.Handles.Contains (g))) { + p.Collected = true; + p.DestroyedOnThread = m.Groups ["thread"].Value; + alive.Remove (p); + } + } + CheckCounts (m, l); + + curPeer = null; + curHandle = default (JniHandleInfo); + } }, + { new Regex (atm), (m, l) => { + if (curPeer == null || curHandle == null) + return; + curPeer.AppendStackTraceForHandle (curHandle, m.Groups ["stack"].Value); + } }, + }; + } + + static JniHandleInfo GetHandle (Match m, string handleGroup) + { + var handle = m.Groups [handleGroup].Value; + var type = m.Groups [handleGroup + "_type"].Value; + var thread = m.Groups ["thread"].Value; + return new JniHandleInfo ( + handle, + string.IsNullOrEmpty (type) || type.Length < 1? JniHandleType.None : JniHandleInfo.GetHandleType (type [0]), + thread); + } + + void CheckCounts (Match m, int lineNumber) + { + if ((ParseOptions & GrefParseOptions.CheckCounts) == 0) + return; + string message = null; + int gc; + if (int.TryParse (m.Groups ["gcount"].Value, out gc) && gc != GrefCount) { + message = string.Format (" grefc mismatch at line {0}: expected {1,5}, actual {2,5}; line: {3}", + lineNumber, GrefCount, gc, m.Groups[0]); + } + if (int.TryParse (m.Groups ["wgcount"].Value, out gc) && gc != WeakGrefCount) { + message = string.Format ("wgrefc mismatch at line {0}; expected {1,5}, actual {2,5}; line: {3}", + lineNumber, WeakGrefCount, gc, m.Groups[0]); + } + if (message != null) { + LogWarning (GrefParseOptions.CheckCounts, message); + } + } + + void LogWarning (GrefParseOptions type, string message) + { + Console.WriteLine ("Warning: {0}", message); + + GrefParseOptions shouldThrow = type | GrefParseOptions.ThrowExceptionOnMismatch; + if ((ParseOptions & shouldThrow) == shouldThrow) + throw new InvalidOperationException (message); + } + + PeerInfo GetAlivePeerInfo (Match m) + { + var h = GetHandle (m, "handle"); + var i = alive.FindLastIndex (p => p.Handles.Contains(h)); + if (i >= 0) + return alive [i]; + return null; + } + + PeerInfo GetLastOrCreatePeerInfo (Match m, JniHandleInfo newHandle) + { + var h = GetHandle (m, "handle"); + var i = alive.FindLastIndex (p => p.Handles.Contains (h)); + if (i >= 0) + return alive [i]; + var pid = m.Groups ["pid"].Value; + var peer = new PeerInfo (pid) { + CreatedOnThread = m.Groups ["thread"].Value, + Handles = { + newHandle, + }, + // Not *technically* removed, but `h` can't appear in Handles either, because of possible handle "reuse" + RemovedHandles = { + h, + }, + }; + allocated.Add (peer); + alive.Add (peer); + return peer; + } + } +} diff --git a/external/Java.Interop/tools/logcat-parse/PeerInfo.cs b/external/Java.Interop/tools/logcat-parse/PeerInfo.cs new file mode 100644 index 00000000000..63370e27c90 --- /dev/null +++ b/external/Java.Interop/tools/logcat-parse/PeerInfo.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace Xamarin.Android.Tools.LogcatParse { + + public enum JniHandleType { + None, + Local, + Global, + WeakGlobal, + } + + public struct JniHandleInfo : IEquatable { + + public readonly string Handle; + public readonly JniHandleType Type; + public readonly string CreatedOnThread; + + public JniHandleInfo (string handle, JniHandleType type = JniHandleType.None, string createdOnThread = null) + { + Handle = handle; + Type = type; + CreatedOnThread = createdOnThread; + + if (handle.Length > 2 && handle [handle.Length - 2] == '/') { + var t = handle [handle.Length - 1]; + Type = GetHandleType (t); + Handle = handle.Substring (0, handle.Length - 2); + } + } + + public override int GetHashCode () + { + return Handle.GetHashCode (); + } + + public override bool Equals (object value) + { + var v = value as JniHandleInfo?; + if (!v.HasValue) + return false; + return Equals (v.Value); + } + + public bool Equals (JniHandleInfo value) + { + return Handle == value.Handle; + } + + public override string ToString () + { + var suffix = ""; + switch (Type) { + case JniHandleType.Local: + suffix = "/L"; + break; + case JniHandleType.Global: + suffix = "/G"; + break; + case JniHandleType.WeakGlobal: + suffix = "/W"; + break; + } + var thread = string.IsNullOrEmpty (CreatedOnThread) + ? "" + : " from thread " + CreatedOnThread; + return Handle + suffix + thread; + } + + internal static JniHandleType GetHandleType (char c) + { + switch (c) { + case 'L': return JniHandleType.Local; + case 'G': return JniHandleType.Global; + case 'W': return JniHandleType.WeakGlobal; + } + return JniHandleType.None; + } + + public static implicit operator JniHandleInfo (string handle) + { + return new JniHandleInfo (handle); + } + + public static bool operator==(JniHandleInfo lhs, JniHandleInfo rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!=(JniHandleInfo lhs, JniHandleInfo rhs) + { + return !lhs.Equals (rhs); + } + + public static bool operator==(JniHandleInfo lhs, string rhs) + { + if (string.IsNullOrEmpty (rhs)) + return lhs.Handle == rhs; + return lhs == new JniHandleInfo (rhs); + } + + public static bool operator!=(JniHandleInfo lhs, string rhs) + { + if (string.IsNullOrEmpty (rhs)) + return lhs.Handle != rhs; + return lhs != new JniHandleInfo (rhs); + } + + public static bool operator==(string lhs, JniHandleInfo rhs) + { + if (string.IsNullOrEmpty (lhs)) + return lhs == rhs.Handle; + return new JniHandleInfo (lhs) == rhs; + } + + public static bool operator!=(string lhs, JniHandleInfo rhs) + { + if (string.IsNullOrEmpty (lhs)) + return lhs != rhs.Handle; + return new JniHandleInfo (lhs) != rhs; + } + } + + [Flags] + enum PeerInfoState { + Alive, + Collected = 1 << 0, + Disposed = 1 << 1, + Finalized = 1 << 2, + } + + public class PeerInfo { + + PeerInfoState state; + + public int? Pid {get; internal set;} + + // Collected & Disposed can occur for any Peer type + public bool Collected { + get {return (state & PeerInfoState.Collected) != 0;} + set {state |= PeerInfoState.Collected;} + } + public bool Disposed { + get {return (state & PeerInfoState.Disposed) != 0;} + set {state |= PeerInfoState.Disposed;} + } + + // Finalized will only occur for IGCUserPeer types + public bool Finalized { + get {return (state & PeerInfoState.Finalized) != 0;} + set {state |= PeerInfoState.Finalized;} + } + + public bool Alive { + get {return state == PeerInfoState.Alive;} + } + + public string JniType {get; internal set;} + public string McwType {get; internal set;} + + public string KeyHandle {get; internal set;} + public IList Handles {get; private set;} + + public IList RemovedHandles {get; private set;} + + public string CreatedOnThread { get; internal set; } + public string DestroyedOnThread { get; internal set; } + + public IEnumerable StackTraces { + get {return stacks.Values.Select (b => b.ToString ());} + } + + Dictionary stacks = new Dictionary (); + + public PeerInfo (string pid) + { + Handles = new List (); + KeyHandle = JniType = McwType = ""; + RemovedHandles = new List (); + int p; + if (int.TryParse (pid, NumberStyles.Integer, CultureInfo.InvariantCulture, out p)) + Pid = p; + } + + public string GetStackTraceForHandle (JniHandleInfo handle) + { + StringBuilder stack; + if (stacks.TryGetValue (handle, out stack)) + return stack.ToString (); + return null; + } + + internal void AppendStackTraceForHandle (JniHandleInfo handle, string append) + { + if (!Handles.Contains (handle)) + Handles.Add (handle); + + StringBuilder stack; + if (!stacks.TryGetValue (handle, out stack)) { + stacks.Add (handle, new StringBuilder (append)); + return; + } + if (stack.Length > 0) + stack.Append ("\n"); + stack.Append (append); + + if (append.Contains (".get_class_ref()")) { + SetTypesFromStackTraceEntry (append, append.LastIndexOf (".get_class_ref()", StringComparison.Ordinal)); + } else if (append.EndsWith ("..cctor()", StringComparison.Ordinal)) { + SetTypesFromStackTraceEntry (append, append.LastIndexOf ("..cctor()", StringComparison.Ordinal)); + } else if (append.Contains ("..ctor(")) { + SetTypesFromStackTraceEntry (append, append.LastIndexOf ("..ctor(", StringComparison.Ordinal)); + } + } + + void SetTypesFromStackTraceEntry (string entry, int end) + { + // Don't clobber previously auto-detected entries. Allows .ctor() -> .cctor() to preserve .cctor(). + if (!string.IsNullOrEmpty (JniType) && !string.IsNullOrEmpty (McwType)) + return; + + if (end < 0) + return; + int start = entry.IndexOf (" at ", StringComparison.Ordinal); + if (start < 0) + return; + start += " at ".Length; + var t = entry.Substring (start, end - start); + JniType = t + ".class"; + McwType = "typeof(" + t + ")"; + } + + public override string ToString () + { + return string.Format ("PeerInfo(State='{0}' JniType='{1}' McwType='{2}' KeyHandle={3} Handles={4})", + state, JniType, McwType, KeyHandle, Handles.Count); + } + } +} diff --git a/external/Java.Interop/tools/logcat-parse/Program.cs b/external/Java.Interop/tools/logcat-parse/Program.cs new file mode 100644 index 00000000000..d338702b093 --- /dev/null +++ b/external/Java.Interop/tools/logcat-parse/Program.cs @@ -0,0 +1,69 @@ +using System; +using System.Globalization; +using Mono.Options; +using Mono.CSharp; + +namespace Xamarin.Android.Tools.LogcatParse { + + public class Program { + + public static int Main (string[] args) + { + bool help = false; + int? pid = null; + var options = new OptionSet () { + "logcat-parse: Parse `adb logcat` output to analyze GREF information.", + "", + "usage: logcat-parse [-p PID] FILE [@RESPONSE-FILES]", + { "p|pid=", + "The {PID} to filter GREF output.", + v => pid = int.Parse (v, CultureInfo.InvariantCulture) + }, + { "h|?|help", + "Show this message and exit.", + v => help = v != null }, + new ResponseFileSource (), + }; + var files = options.Parse (args); + if (help) { + options.WriteOptionDescriptions (Console.Out); + return 0; + } + + Console.WriteLine ("// `adb logcat` GREF parsing utility"); + Console.WriteLine ("//"); + Console.WriteLine ("// Use `Grefs.Parse(stream)` to parse a file containing `adb logcat` output."); + Console.WriteLine ("// Grefs.AllocatedPeers contains all exposed Java.Lang.Object instances."); + Console.WriteLine ("// Grefs.AlivePeers contains those still alive by the end of parsing."); + + var settings = new CompilerSettings () { + Unsafe = true + }; + + var printer = new ConsoleReportPrinter (); + + var eval = new Evaluator (new CompilerContext (settings, printer)); + eval.ReferenceAssembly (typeof(Program).Assembly); + eval.Run ("using Xamarin.Android.Tools.LogcatParse;"); + if (files.Count > 0) { + if (files.Count > 1) + Console.Error.WriteLine ("logcat-parse: More than one file is unsupported. Loading: {0}", files [0]); + Console.WriteLine ("var grefs = Grefs.Parse(@\"{0}\"{1});", files [0], + pid.HasValue ? ", " + pid.Value : ""); + eval.Run ("Grefs grefs;"); + eval.Run ( + "using (var __source = new System.IO.StreamReader(@\"" + + files [0] + + "\")) grefs = Grefs.Parse(__source" + + (pid.HasValue ? (", " + pid.ToString ()) : "") + ");"); + } + + eval.InteractiveBaseClass = typeof (Mono.InteractiveBaseShell); + eval.DescribeTypeExpressions = true; + eval.WaitOnTask = true; + + var shell = new Mono.CSharpShell (eval); + return shell.Run (new string[0]); + } + } +} diff --git a/external/Java.Interop/tools/logcat-parse/logcat-parse.csproj b/external/Java.Interop/tools/logcat-parse/logcat-parse.csproj new file mode 100644 index 00000000000..8dc666e13be --- /dev/null +++ b/external/Java.Interop/tools/logcat-parse/logcat-parse.csproj @@ -0,0 +1,29 @@ + + + + $(DotNetTargetFramework) + Exe + + + + + + $(UtilityOutputFullPath) + + + + + + + + + + + + + + + + + + diff --git a/external/Java.Interop/tools/logcat-parse/logcat-parse.targets b/external/Java.Interop/tools/logcat-parse/logcat-parse.targets new file mode 100644 index 00000000000..ed4636dd672 --- /dev/null +++ b/external/Java.Interop/tools/logcat-parse/logcat-parse.targets @@ -0,0 +1,13 @@ + + + + + + + diff --git a/external/Java.Interop/tools/logcat-parse/repl.cs b/external/Java.Interop/tools/logcat-parse/repl.cs new file mode 100644 index 00000000000..4a342e7ff43 --- /dev/null +++ b/external/Java.Interop/tools/logcat-parse/repl.cs @@ -0,0 +1,423 @@ +// +// repl.cs: Support for using the compiler in interactive mode (read-eval-print loop) +// +// Authors: +// Miguel de Icaza (miguel@gnome.org) +// +// Dual licensed under the terms of the MIT X11 or GNU GPL +// +// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com) +// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc +// Copyright 2011-2013 Xamarin Inc +// +// +// TODO: +// Do not print results in Evaluate, do that elsewhere in preparation for Eval refactoring. +// Driver.PartialReset should not reset the coretypes, nor the optional types, to avoid +// computing that on every call. +// +using System; +using System.IO; +using System.Text; +using System.Globalization; +using System.Collections; +using System.Reflection; +using System.Reflection.Emit; +using System.Threading; +using System.Net; +using System.Net.Sockets; +using System.Collections.Generic; + +using Mono.CSharp; + +namespace Mono { + + public class InteractiveBaseShell : InteractiveBase { + static bool tab_at_start_completes; + + static InteractiveBaseShell () + { + tab_at_start_completes = false; + } + + internal static Mono.Terminal.LineEditor Editor; + + public static bool TabAtStartCompletes { + get { + return tab_at_start_completes; + } + + set { + tab_at_start_completes = value; + if (Editor != null) + Editor.TabAtStartCompletes = value; + } + } + + public static new string help { + get { + return InteractiveBase.help + + " TabAtStartCompletes - Whether tab will complete even on empty lines\n"; + } + } + } + + public class CSharpShell { + static bool isatty = true, is_unix = false; + protected string [] startup_files; + + Mono.Terminal.LineEditor editor; + bool dumb; + readonly Evaluator evaluator; + + public CSharpShell (Evaluator evaluator) + { + this.evaluator = evaluator; + } + + protected virtual void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a) + { + // Do not about our program + a.Cancel = true; + + evaluator.Interrupt (); + } + + void SetupConsole () + { + if (is_unix){ + string term = Environment.GetEnvironmentVariable ("TERM"); + dumb = term == "dumb" || term == null || isatty == false; + } else + dumb = false; + + editor = new Mono.Terminal.LineEditor ("csharp", 300); + InteractiveBaseShell.Editor = editor; + + editor.AutoCompleteEvent += delegate (string s, int pos){ + string prefix = null; + + string complete = s.Substring (0, pos); + + string [] completions = evaluator.GetCompletions (complete, out prefix); + + return new Mono.Terminal.LineEditor.Completion (prefix, completions); + }; + + #if false + // + // This is a sample of how completions sould be implemented. + // + editor.AutoCompleteEvent += delegate (string s, int pos){ + + // Single match: "Substring": Sub-string + if (s.EndsWith ("Sub")){ + return new string [] { "string" }; + } + + // Multiple matches: "ToString" and "ToLower" + if (s.EndsWith ("T")){ + return new string [] { "ToString", "ToLower" }; + } + return null; + }; + #endif + + Console.CancelKeyPress += ConsoleInterrupt; + } + + string GetLine (bool primary) + { + string prompt = primary ? InteractiveBase.Prompt : InteractiveBase.ContinuationPrompt; + + if (dumb){ + if (isatty) + Console.Write (prompt); + + return Console.ReadLine (); + } else { + return editor.Edit (prompt, ""); + } + } + + delegate string ReadLiner (bool primary); + + void InitializeUsing () + { + Evaluate ("using System; using System.Linq; using System.Collections.Generic; using System.Collections;"); + } + + void InitTerminal (bool show_banner) + { + int p = (int) Environment.OSVersion.Platform; + is_unix = (p == 4) || (p == 128); + + isatty = !Console.IsInputRedirected && !Console.IsOutputRedirected; + + // Work around, since Console is not accounting for + // cursor position when writing to Stderr. It also + // has the undesirable side effect of making + // errors plain, with no coloring. + // Report.Stderr = Console.Out; + SetupConsole (); + + if (isatty && show_banner) + Console.WriteLine ("Mono C# Shell, type \"help;\" for help\n\nEnter statements below."); + + } + + void ExecuteSources (IEnumerable sources, bool ignore_errors) + { + foreach (string file in sources){ + try { + try { + bool first = true; + + using (System.IO.StreamReader r = System.IO.File.OpenText (file)){ + ReadEvalPrintLoopWith (p => { + var line = r.ReadLine (); + if (first){ + if (line.StartsWith ("#!", StringComparison.Ordinal)) + line = r.ReadLine (); + first = false; + } + return line; + }); + } + } catch (FileNotFoundException){ + Console.Error.WriteLine ("cs2001: Source file `{0}' not found", file); + return; + } + } catch { + if (!ignore_errors) + throw; + } + } + } + + protected virtual void LoadStartupFiles () + { + string dir = Path.Combine ( + Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), + "csharp"); + if (!Directory.Exists (dir)) + return; + + List sources = new List (); + List libraries = new List (); + + foreach (string file in System.IO.Directory.GetFiles (dir)){ + string l = file.ToLower (); + + if (l.EndsWith (".cs", StringComparison.OrdinalIgnoreCase)) + sources.Add (file); + else if (l.EndsWith (".dll", StringComparison.OrdinalIgnoreCase)) + libraries.Add (file); + } + + foreach (string file in libraries) + evaluator.LoadAssembly (file); + + ExecuteSources (sources, true); + } + + void ReadEvalPrintLoopWith (ReadLiner readline) + { + string expr = null; + while (!InteractiveBase.QuitRequested){ + string input = readline (expr == null); + if (input == null) + return; + + if (input == "") + continue; + + expr = expr == null ? input : expr + "\n" + input; + + expr = Evaluate (expr); + } + } + + public int ReadEvalPrintLoop () + { + if (startup_files != null && startup_files.Length == 0) + InitTerminal (startup_files.Length == 0); + + InitializeUsing (); + + LoadStartupFiles (); + + if (startup_files != null && startup_files.Length != 0) { + ExecuteSources (startup_files, false); + } else { + ReadEvalPrintLoopWith (GetLine); + + editor.SaveHistory (); + } + + Console.CancelKeyPress -= ConsoleInterrupt; + + return 0; + } + + protected virtual string Evaluate (string input) + { + bool result_set; + object result; + + try { + input = evaluator.Evaluate (input, out result, out result_set); + + if (result_set){ + PrettyPrint (Console.Out, result); + Console.WriteLine (); + } + } catch (Exception e){ + Console.WriteLine (e); + return null; + } + + return input; + } + + static void p (TextWriter output, string s) + { + output.Write (s); + } + + static string EscapeString (string s) + { + return s.Replace ("\"", "\\\""); + } + + static void EscapeChar (TextWriter output, char c) + { + if (c == '\''){ + output.Write ("'\\''"); + return; + } + if (c > 32){ + output.Write ("'{0}'", c); + return; + } + switch (c){ + case '\a': + output.Write ("'\\a'"); + break; + + case '\b': + output.Write ("'\\b'"); + break; + + case '\n': + output.Write ("'\\n'"); + break; + + case '\v': + output.Write ("'\\v'"); + break; + + case '\r': + output.Write ("'\\r'"); + break; + + case '\f': + output.Write ("'\\f'"); + break; + + case '\t': + output.Write ("'\\t"); + break; + + default: + output.Write ("'\\x{0:x}", (int) c); + break; + } + } + + // Some types (System.Json.JsonPrimitive) implement + // IEnumerator and yet, throw an exception when we + // try to use them, helper function to check for that + // condition + static internal bool WorksAsEnumerable (object obj) + { + IEnumerable enumerable = obj as IEnumerable; + if (enumerable != null){ + try { + enumerable.GetEnumerator (); + return true; + } catch { + // nothing, we return false below + } + } + return false; + } + + internal static void PrettyPrint (TextWriter output, object result) + { + if (result == null){ + p (output, "null"); + return; + } + + if (result is Array){ + Array a = (Array) result; + + p (output, "{ "); + int top = a.GetUpperBound (0); + for (int i = a.GetLowerBound (0); i <= top; i++){ + PrettyPrint (output, a.GetValue (i)); + if (i != top) + p (output, ", "); + } + p (output, " }"); + } else if (result is bool){ + if ((bool) result) + p (output, "true"); + else + p (output, "false"); + } else if (result is string){ + p (output, String.Format ("\"{0}\"", EscapeString ((string)result))); + } else if (result is IDictionary){ + IDictionary dict = (IDictionary) result; + int top = dict.Count, count = 0; + + p (output, "{"); + foreach (DictionaryEntry entry in dict){ + count++; + p (output, "{ "); + PrettyPrint (output, entry.Key); + p (output, ", "); + PrettyPrint (output, entry.Value); + if (count != top) + p (output, " }, "); + else + p (output, " }"); + } + p (output, "}"); + } else if (WorksAsEnumerable (result)) { + int i = 0; + p (output, "{ "); + foreach (object item in (IEnumerable) result) { + if (i++ != 0) + p (output, ", "); + + PrettyPrint (output, item); + } + p (output, " }"); + } else if (result is char) { + EscapeChar (output, (char) result); + } else { + p (output, result.ToString ()); + } + } + + public virtual int Run (string [] startup_files) + { + this.startup_files = startup_files; + return ReadEvalPrintLoop (); + } + + } +} + diff --git a/external/Java.Interop/tools/param-name-importer/DealingWithJavaApiDescription.md b/external/Java.Interop/tools/param-name-importer/DealingWithJavaApiDescription.md new file mode 100644 index 00000000000..cf64ab9f093 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/DealingWithJavaApiDescription.md @@ -0,0 +1,103 @@ + +# Dealing with Java API description + +## Java API XML description files: how it exists nowadays + +Historically, Google used to ship Android Framework API information as in XML format, and to build Mono.Android.dll we parsed and interpreted these description files. Those files defined most of our API XML description format that we use nowadays. + +As of Android 3.0, Google had not shipped the source code including these XML description files for long time, so we had been unable to build new API. Therefore we ended up to change our approach so that we built API description XML from android.jar by ourselves. At that time, the API extraction tool "jar2xml" was written in Java using Java reflection API (java.lang.reflect) and bytecode manipulator (asm). + +And that turned to become the first core part of our Java Bindings support. + +Java reflection API dependency caused several problems, especially on that we cannot extract correct java.* framework API (because with reflection API they always report java.* structure from the Java framework that the tool executes). Thus at some stage we ended up to change our strategy again and implemented bytecode parser "class-parse". + +Unfortunately, class-parse was written in the way that it only reflects bytecode information, which means the outcome was totally different from the API information that Java reflection API offered. There is no type hierarchy, therefore no method overrides are resolved (which caused a lot of differences between the old and the new API information). + +Therefore we needed to "adjust" the API description to match the old one, otherwise our C# binding generator ("generator.exe") and Metadata.xml don't work at all. This part is called "api-xml-adjuster" (implemented as Xamarin.Android.Tools.ApiXmlAdjuster.dll). + + +## Java API parsers + +We have many Java parsers (unfortunately) within xamarin-android SDK and its own build system. They exist for different purposes and reasons. + +(1) class-parse + api-xml-adjuster (Xamarin.Android.Tools.ApiXmlAdjuster) + +class-parse is the bytecode parser tool (I wrote "the", which means that it is the only implementation) that parses class library jars into api.xml.class-parse. + +api-xml-adjuster exists for the reason we described earlier. It has no other reason to exist. Since it also needs to retrieve Java API information from reference binding DLLs, it is tied to binding generator's type system. + +(2) JavaDocScraper + +Java bytecode does not contain method parameter names by design. We can still bind Java API without them, but the resulting API becomes awkward (a set of methods with parameter names "p0", "p1", ...). + +Our solution for that is JavaDoc parsers. + +JavaDoc is not great for retrieving information because it is not well structured. And it can be actually in any format, depending on "doclet"; Google indeed offers its own Android API Reference with its own "DroidDoc" doclet. But there is no other way, so we have different parser implementations for each "standard" doclet. + +Doclet had changed in each Java releases: Java6, Java7 and Java8 had each doclet format that are different enough to confuse our document scraper. To make things worse, DroidDoc, the Google doclet, had also changed for each big API releases. We have three different JavaDoc scrapers up to 8 (note that it does not even include Java9 as of writing time) and two different DroidDoc scrapers (which may become three, depending on the upcoming work). + +DroidDoc parsers are used for two different purposes: + +* Build Mono.Android.dll: this requires from the ancient API documentation parser up to the latest parser, because we unify all the support API levels. +* Build Android support libraries: their API information is offered through developer.android.com and the docs are based on DroidDoc. For this purpose we don't need older API parsers. + +JavaDoc parsers are used for generic Java Binding projects. + +(We should probably support external doclet parsers so that users can provide and specify any kind of doclets, but we have heard of any requests for that. There is no plan to stabilize JavaDoc scraper API either.) + +(JavaDocScraper in this context had been implemented in Java in jar2xml before, and now it is rewritten in C# in class-parse.) + +(3) JavaDoc to C# Documentation converter (javadoc-to-mdoc) + +Apart from JavaDocScraper for parameter names, we still have another reason to parse JavaDocs and DroidDocs. Bindings need API documentation, and they should be in our .NET API manner. It helps IDEs provide API information. + +That means, we need almost entire API information including details. + +It has been implemented in mono/mcs/tools/javadoc-to-mdoc. And it had been used only to generate Xamarin.Android API documentation i.e. it supported only DroidDocs. It was extended to support JavaDocs when we brought in this feature to xamarin-android to support any Java Binding projects. Yet, that is limited to the standard doclets for exactly the same reason as JavaDocScraper for method parameter names. + +(Nowadays there should be almost no reason to have different JavaDoc scrapers, but as explained above, JavaDocScraper used to be Java, while javadoc-to-mdoc has been C# since its beginning.) + +(4) DroidDoc parser for parameter names + +JavaDocScraper for parameter names is problematic, not only because it always needs to renew the implementation whenever DroidDocs are updated, but also because it is not efficient to parse HTML docs every time we build the bindings. And that annoyed our Components team because unlike Xamarin.Android itself, they have to run JavaDoc Scraper every time (we don't run class-parse and api-xml-adjuster every time; we generate api-XY.xml.in only when new APIs get released). + +Since the only information we/they need is method parameter names, they could be generated only once whenever new versions of the components get released. So the team had implemented support for "parameter names only" XML description format in class-parse. + +It was part of Xamarin private repo, but now it is extracted at https://github.com/atsushieno/xamarin-android-docimporter (which was expected to be forked under xamarin, but it did not happen yet). + +It is limited to DroidDoc as it was only for Android Components (support libraries and Google Play services). And it's not ready for xamarin-android that needs to build and run on Linux (this doesn't). + +(5) Java stub API source parser for parameter names + +DroidDoc support has been getting more and more problematic as Google stopped shipping "docs" SDK components anymore, and new API documentations are available only via the web. + +Since Google ships "stub sources" in each platform (API Level) package, it is possible to parse Java sources and extract parameter names from each type. So as a replacement to DroidDoc parameter name parser, we now have a prototype of Java source parser implementation that exactly does this job. + +It is part of xamarin-android-docimporter-ng in Java.Interop. + +The stub sources are expected to have full type names almost everywhere so that we don't have to "resolve" type names (although we have detected that "@Deprecated" is used without "java.lang." which smells... hopefully not any more). It is safer scheme that we use it only to generate parameter names, not the entire API structure. That task can still be done by class-parse. + +(6) DroidDoc parser for parameter names, reimplemented + +The implementation at (4) was quite incomplete and did not try to parse all Android API, which exposes various issues. Thus it was rewritten to try to do better thing. The new DroidDoc scraper at https://github.com/atsushieno/xamarin-android-docimporter-ng generates the same parameter name description file as Java stub parser. It only targets Android API up to 23 because (5) covers the rest. + +However this exposes further issues - some API documentations cannot be parsed because of Google's buggy HTML generation (e.g. android/content/ContentProvider.html significantly breaks its documentation structure. We parse the docs in extraneous way (e.g. inspecting descendants of certain elements instead of just children). + +It is part of xamarin-android-docimporter-ng in Java.Interop. + + + +*** List of parsers and their roles + +| parser | info to generate | target libs | target versions | how often | +|-----------------------------|-----------------------|-----|---|---| +|class-parse+api-xml-adjuster | entire API definition | all | all ages | every build +|JavaDocScraper | parameter names | all | all ages | android.jar - every API release +|JavaDocScraper | parameter names | all | all ages | others - every build +|javadoc-to-mdoc | docs | all | latest | android.jar - every API release +|javadoc-to-mdoc | docs | all | latest | others - every release build +|xamarin-android-docimporter | parameter names | support/GPS | latest | every components release +|java-stub-parser | parameter names | android.jar | API 24 or later | every API release +|new DroidDoc parser | parameter names | android.jar | API 23 or earlier | only once, or every parser bugfixes + + diff --git a/external/Java.Interop/tools/param-name-importer/DroidDocImporter.cs b/external/Java.Interop/tools/param-name-importer/DroidDocImporter.cs new file mode 100644 index 00000000000..dabc3039974 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/DroidDocImporter.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using Xamarin.Android.Tools.ApiXmlAdjuster; + +namespace Xamarin.Android.ApiTools.DroidDocImporter +{ + public class DroidDocScrapingImporter + { + static bool ClassContains (XElement e, string cls) + { + return e.Attribute ("class")?.Value?.Split (' ')?.Contains (cls) == true; + } + + static readonly string [] excludes = new string [] { + "classes.html", + "hierarchy.html", + "index.html", + "package-summary.html", + "packages-wearable-support.html", + "packages-wearable-support.html", + }; + static readonly string [] non_frameworks = new string [] { + "android.support.", + "com.google.android.gms.", + "renderscript." + }; + + /* + + The DroidDoc format from API Level 16 to 23, the format is: + + - All pages have ToC links and body (unlike standard JavaDoc which is based on HTML frames). + - The actual doc section is a div element whose id is "doc-col". + - The "doc-col" div element has a section div element whose id is "jd-header" and another one with id "jd-content". + - "jd-header" div element contains the type signature (modifiers, name, and inheritance). + - Here we care only about type name and kind (whether it is a class or interface). + - Generic arguments are insignificant. + - In the following terms I explain the "correct" (or "expected") document structure, but in fact + Google completely broke it and it is impossible to retrieve the document tree like this. + We workaround this issue by changing the strategy "iterate children of 'jd-content'" + with "iterate descendants of 'jd-content'"... It occurs only in API Level 15 or later. + - "jd-content" div element contains a collection of sections. Each section consists of: + - an "h2" element whose value text indicates the section name ("Public Constructors", "Protected Methods" etc.) + - There was an issue in javax/xml/validation/SchemaFactory.html in API Level 15 that the method details contain + "h2" and confuses the parser. To workaround this, we accept only limited kind of values. + - the content, which follows the h2 element. + - The section content is a collection of members. Each member consists of: + - an anchor ("A") element with "name" attribute, and + - a div element which contains an h4 child element whose class contains "jd-details-title". + - The h4 element contains the member signature. We parse it and retrieve the method name and list of parameters. + - Parameters are tokenized by ", ". + - Note that the splitter contains a white space which disambiguates any use of generic arguments (we don't want to split "Foo bar" as "Foo bar") + + API Level 10 to 15 has slightly different format: + + - There is no "doc-col" element. But "jd-header" and "jd-content" are still alive. + + */ + public void Import (ImporterOptions options) + { + options.DiagnosticWriter.WriteLine (options.DocumentDirectory); + + string referenceDocsTopDir = Path.Combine (options.DocumentDirectory, "reference"); + var htmlFiles = Directory.GetDirectories (referenceDocsTopDir).SelectMany (d => Directory.GetFiles (d, "*.html", SearchOption.AllDirectories)); + + var api = new JavaApi (); + + foreach (var htmlFile in htmlFiles) { + + // skip irrelevant files. + if (excludes.Any (x => htmlFile.EndsWith (x, StringComparison.OrdinalIgnoreCase))) + continue; + var packageName = Path.GetDirectoryName (htmlFile).Substring (referenceDocsTopDir.Length + 1).Replace ('/', '.'); + if (options.FrameworkOnly && non_frameworks.Any (n => packageName.StartsWith (n, StringComparison.Ordinal))) + continue; + + options.DiagnosticWriter.WriteLine ("-- " + htmlFile); + + var doc = new HtmlLoader ().GetJavaDocFile (htmlFile); + + var header = doc.Descendants ().FirstOrDefault (e => e.Attribute ("id")?.Value == "jd-header"); + var content = doc.Descendants ().FirstOrDefault (e => e.Attribute ("id")?.Value == "jd-content"); + + if (header == null || content == null) + continue; + + var apiSignatureTokens = header.Value.Replace ('\r', ' ').Replace ('\n', ' ').Replace ('\t', ' ').Trim (); + if (apiSignatureTokens.Contains ("extends ")) + apiSignatureTokens = apiSignatureTokens.Substring (0, apiSignatureTokens.IndexOf ("extends ", StringComparison.Ordinal)).Trim (); + if (apiSignatureTokens.Contains ("implements ")) + apiSignatureTokens = apiSignatureTokens.Substring (0, apiSignatureTokens.IndexOf ("implements ", StringComparison.Ordinal)).Trim (); + bool isClass = apiSignatureTokens.Contains ("class"); + options.DiagnosticWriter.WriteLine (apiSignatureTokens); + + var javaPackage = api.AllPackages.FirstOrDefault (p => p.Name == packageName); + if (javaPackage == null) { + javaPackage = new JavaPackage (api) { Name = packageName }; + api.Packages.Add (packageName, javaPackage); + } + + var javaType = isClass ? (JavaType)new JavaClass (javaPackage) : new JavaInterface (javaPackage); + javaType.Name = apiSignatureTokens.Substring (apiSignatureTokens.LastIndexOf (' ') + 1); + javaPackage.AddType (javaType); + + string sectionType = null; + var sep = new string [] { ", " }; + var ssep = new char [] { ' ' }; + foreach (var child in content.Descendants ()) { + if (child.Name == "h2") { + var value = child.Value; + switch (value) { + case "Public Constructors": + case "Protected Constructors": + case "Public Methods": + case "Protected Methods": + sectionType = value; + break; + } + continue; + } + + if (sectionType == null) + continue; + + if (child.Name != "a" || child.Attribute ("name") == null) + continue; + + var h4 = child.XPathSelectElement ("following-sibling::div/h4[contains(@class, 'jd-details-title')]"); + if (h4 == null) + continue; + + string sigTypeOnly = child.Attribute ("name").Value; + string sigTypeAndName = h4.Value.Replace ('\n', ' ').Replace ('\r', ' ').Trim (); + if (!sigTypeAndName.Contains ('(')) + continue; + JavaMethodBase javaMethod = null; + string name = sigTypeAndName.Substring (0, sigTypeAndName.IndexOf ('(')).Split (ssep, StringSplitOptions.RemoveEmptyEntries).Last (); + switch (sectionType) { + case "Public Constructors": + case "Protected Constructors": + javaMethod = new JavaConstructor (javaType) { Name = name }; + break; + case "Public Methods": + case "Protected Methods": + string mname = sigTypeAndName.Substring (0, sigTypeAndName.IndexOf ('(')); + javaMethod = new JavaMethod (javaType) { Name = name }; + break; + } + javaType.Members.Add (javaMethod); + + var paramTypes = SplitTypes (sigTypeOnly.Substring (sigTypeOnly.IndexOf ('(') + 1).TrimEnd (')'), 0).ToArray (); + var parameters = sigTypeAndName.Substring (sigTypeAndName.IndexOf ('(') + 1).TrimEnd (')') + .Split (sep, StringSplitOptions.RemoveEmptyEntries) + .Select (s => s.Trim ()) + .ToArray (); + foreach (var p in paramTypes.Zip (parameters, (to, tn) => new { Type = to, TypeAndName = tn }) + .Select (pp => new { Type = pp.Type, Name = pp.TypeAndName.Split (' ') [1] })) + javaMethod.Parameters.Add (new JavaParameter (javaMethod) { Name = p.Name, Type = p.Type }); + } + javaType.Members = javaType.Members.OfType () + .OrderBy (m => m.Name + "(" + string.Join (",", m.Parameters.Select (p => p.Type)) + ")") + .ToArray (); + } + + if (options.OutputTextFile != null) + api.WriteParameterNamesText (options.OutputTextFile); + if (options.OutputXmlFile != null) + api.WriteParameterNamesXml (options.OutputXmlFile); + } + + IEnumerable SplitTypes (string types, int start) + { + if (start == types.Length) + yield break; + var p2 = types.IndexOf (',', start); + if (p2 < 0) { + yield return types.Substring (start); + yield break; + } + + var p1 = types.IndexOf ('<', start); + if (p1 < 0 || p2 < p1) { + yield return types.Substring (start, p2 - start); + foreach (var s in SplitTypes (types, p2 + ", ".Length)) + yield return s; + yield break; + } + + int open = 1; + for (int i = p1 + 1; i < types.Length; i++) { + switch (types [i]) { + case '<': + open++; + break; + case '>': + open--; + if (open == 0) { + i++; // will be positioned either at ',' or at the end. + yield return types.Substring (start, i - start); + if (i + 2 < types.Length && types [i] == ',' && types [i + 1] == ' ') // skip ", " + i += 2; + if (i < types.Length) + foreach (var s in SplitTypes (types, i)) + yield return s; + yield break; + } + break; + } + } + throw new ArgumentException ("Unexpected list of parameters: " + types); + } + } + +} diff --git a/external/Java.Interop/tools/param-name-importer/HTMLlat1.ent b/external/Java.Interop/tools/param-name-importer/HTMLlat1.ent new file mode 100644 index 00000000000..c6444860477 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/HTMLlat1.ent @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tools/param-name-importer/HTMLspecial.ent b/external/Java.Interop/tools/param-name-importer/HTMLspecial.ent new file mode 100644 index 00000000000..5ce5c6ad01f --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/HTMLspecial.ent @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tools/param-name-importer/HTMLsymbol.ent b/external/Java.Interop/tools/param-name-importer/HTMLsymbol.ent new file mode 100644 index 00000000000..524bfe11bc4 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/HTMLsymbol.ent @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tools/param-name-importer/HtmlLoader.cs b/external/Java.Interop/tools/param-name-importer/HtmlLoader.cs new file mode 100644 index 00000000000..095ed90200e --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/HtmlLoader.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using Sgml; + +namespace Xamarin.Android.ApiTools.DroidDocImporter +{ + + class HtmlLoader + { + // okay, SgmlReader itself has something similar, but I need something that makes sure to resolve only embedded resources. + class EmbeddedResourceEntityResolver : Sgml.IEntityResolver + { + public IEntityContent GetContent (Uri uri) + { + return new EmbeddedResourceEntityContent (uri.LocalPath); + } + + class EmbeddedResourceEntityContent : Sgml.IEntityContent + { + public EmbeddedResourceEntityContent (string name) + { + if (name == null) + throw new ArgumentNullException (nameof (name)); + this.name = Path.GetFileName (name); + } + + string name; + + public Encoding Encoding { + get { return Encoding.UTF8; } + } + + public string MimeType { + get { return "text/plain"; } + } + + public Uri Redirect { + get { return new Uri ("file:///" + this.name); } + } + + public Stream Open () + { + return typeof (HtmlLoader).Assembly.GetManifestResourceStream (name); + } + } + } + + enum JavaDocKind + { + DroidDoc, + DroidDoc2, + Java6, + Java7, + Java8 + } + + Sgml.SgmlDtd HtmlDtd; + + public HtmlLoader () + { + HtmlDtd = LoadHtmlDtd (); + } + + Sgml.SgmlDtd LoadHtmlDtd () + { + return Sgml.SgmlDtd.Parse (new Uri ("file:///"), + "HTML", + "-//W3C//DTD HTML 4.01//EN", + "file:///strict.dtd", + string.Empty, new EmbeddedResourceEntityResolver ()); + } + + public XElement GetJavaDocFile (string path) + { + JavaDocKind kind; + return GetJavaDocFile (path, out kind); + } + + XElement GetJavaDocFile (string path, out JavaDocKind kind) + { + kind = JavaDocKind.DroidDoc; + string rawHTML = ReadAndSanitizeHtmlFile (path); + if (rawHTML.Substring (0, 500).IndexOf ("Generated by javadoc (build 1.6", StringComparison.Ordinal) > 0) + kind = JavaDocKind.Java6; + if (rawHTML.Substring (0, 500).IndexOf ("Generated by javadoc (version 1.7", StringComparison.Ordinal) > 0) + kind = JavaDocKind.Java7; + if (rawHTML.Substring (0, 500).IndexOf ("Generated by javadoc (1.8", StringComparison.Ordinal) > 0) + kind = JavaDocKind.Java8; + var html = new Sgml.SgmlReader () { + InputStream = new StringReader (rawHTML), + CaseFolding = Sgml.CaseFolding.ToLower, + Dtd = HtmlDtd + }; + var doc = XDocument.Load (html, LoadOptions.SetLineInfo | LoadOptions.SetBaseUri); + return doc.Root; + } + + string ReadAndSanitizeHtmlFile (string path) + { + var info = new FileInfo (path); + var contents = new StringBuilder (checked((int)info.Length)); + bool veryFirstChar = true; + bool in_tag = false; + char in_quote = '\0'; + using (var r = info.OpenText ()) { + + int ch; + while ((ch = r.Read ()) >= 0) { + if (ch == '<') { + // Some of the HTML files are invalid, containing constructs such as + // 'foo <0', which should be 'foo <0'. + // There are also which needs to be replaced by <?>. + // + // We check the next char to '<' so that those with only valid NCName are treated as start tag. + char next = (char)r.Peek (); + if (!in_tag && (next == '/' || next == '!' || XmlConvert.IsStartNCNameChar (next))) { + in_tag = true; + contents.Append ('<'); + } else { + contents.Append ("<"); + } + } else if (ch == '>' && in_tag) { + if (in_quote != '\0') + contents.Append (">"); + else { + in_tag = false; + contents.Append ('>'); + } + } else if (in_tag && (ch == '"' || ch == '\'')) { + if (in_quote == ch) + in_quote = '\0'; + else if (in_quote == '\0') + in_quote = (char) ch; + contents.Append ((char) ch); + } else if (ch == '&') { + var b = new List (); + while ((ch = r.Read ()) >= 0 && ch != ';' && ch != ' ') // sometimes the input HTML contains '&' as a standalone character (i.e. Google emits invalid HTML... android/support/test/espresso/idling/CountingIdlingResource.html has that problem.) + b.Add ((char)ch); + var entity = new string (b.ToArray ()); + switch (entity) { + case "#124": + contents.Append ("|"); + break; + case "#160": + case "#xA0": + case "nbsp": + contents.Append ("\u00A0"); + break; + case "8211": + contents.Append ("\u2011"); + break; + default: + contents.Append ("&").Append (entity).Append (";"); + break; + } + } else if (ch == '\0') + contents.Append ("NUL"); + else + contents.Append ((char)ch); + if (veryFirstChar) + veryFirstChar = false; + } + } + + var firstPass = contents.ToString (); + contents.Clear (); + int open_count = 0; + bool in_quot = false, in_apos = false; + foreach (char ch in firstPass) { + if (ch == '"' && open_count > 0) { + if (in_quot) + open_count = 1; // reset. Something like <... ...="...<..." (without '>') happened + in_quot = !in_quot; + } + if (ch == '\'' && open_count > 0) { + if (in_quot) + open_count = 1; // reset. Something like <... ...='...<...' (without '>') happened + in_apos = !in_apos; + } + + if (ch == '<') { + if (open_count > 0) + contents.Append ("<"); + else + contents.Append ((char)ch); + open_count++; + } else if (ch == '>') { + if (open_count > 0) + open_count--; + if (open_count > 0) + contents.Append (">"); + else + contents.Append ((char)ch); + } else + contents.Append ((char)ch); + } + + // In some documents (e.g. java/util/prefs/Preferences.html) there are invalid !DOCTYPE in the middle, which breaks SgmlReader. Kill them. + contents.Replace ("", "<?>").ToString (); + } + } +} diff --git a/external/Java.Interop/tools/param-name-importer/ImporterOptions.cs b/external/Java.Interop/tools/param-name-importer/ImporterOptions.cs new file mode 100644 index 00000000000..3cdc440907a --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/ImporterOptions.cs @@ -0,0 +1,15 @@ +using System; +using System.IO; + +namespace Xamarin.Android.ApiTools +{ + public class ImporterOptions + { + public string InputZipArchive { get; set; } + public string DocumentDirectory { get; set; } + public string OutputTextFile { get; set; } + public string OutputXmlFile { get; set; } + public TextWriter DiagnosticWriter { get; set; } + public bool FrameworkOnly { get; set; } + } +} diff --git a/external/Java.Interop/tools/param-name-importer/JavaApiParameterNamesExporter.cs b/external/Java.Interop/tools/param-name-importer/JavaApiParameterNamesExporter.cs new file mode 100644 index 00000000000..2dd5947e9a2 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/JavaApiParameterNamesExporter.cs @@ -0,0 +1,143 @@ +using System; +using System.IO; +using System.Linq; +using System.Xml; +using Xamarin.Android.Tools.ApiXmlAdjuster; + +namespace Xamarin.Android.Tools.ApiXmlAdjuster +{ + public static class JavaApiParameterNamesExporter + { + public static void WriteParameterNamesXml (this JavaApi api, string file) + { + using (var xw = XmlWriter.Create (file, new XmlWriterSettings { Indent = true })) + WriteParameterNamesXml (api, xw); + } + + public static void WriteParameterNamesXml (this JavaApi api, XmlWriter writer) + { + writer.WriteStartElement ("parameter-names"); + + Action writeTypeParameters = tps => { + if (tps != null && tps.TypeParameters.Any ()) { + writer.WriteStartElement ("type-parameters"); + foreach (var gt in tps.TypeParameters) { + writer.WriteStartElement ("type-parameter"); + writer.WriteAttributeString ("name", gt.Name); + // no need to supply constraints. + writer.WriteEndElement (); + } + writer.WriteEndElement (); + } + }; + + foreach (var package in api.AllPackages.OrderBy (p => p.Name)) { + writer.WriteStartElement ("package"); + writer.WriteAttributeString ("name", package.Name); + + foreach (var type in package.AllTypes.OrderBy (t => t.Name)) { + if (!type.Members.OfType ().Any (m => m.Parameters.Any ())) + continue; // we care only about types that has any methods that have parameters. + + writer.WriteStartElement (type is JavaClass ? "class" : "interface"); + writer.WriteAttributeString ("name", type.Name); + + writeTypeParameters (type.TypeParameters); + + // we care only about methods that have parameters. + foreach (var mb in type.Members.OfType ().Where (m => m.Parameters.Any ())) { + if (mb is JavaConstructor) + writer.WriteStartElement ("constructor"); + else { + writer.WriteStartElement ("method"); + writer.WriteAttributeString ("name", mb.Name); + } + + writeTypeParameters (mb.TypeParameters); + + foreach (var para in mb.Parameters) { + writer.WriteStartElement ("parameter"); + // For possible generic instances in parameter type, we replace all ", " with "," to ease parsing. + writer.WriteAttributeString ("type", para.Type.Replace (", ", ",")); + writer.WriteAttributeString ("name", para.Name); + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + +/* + * The Text Format is: + * + * package {packagename} + * ;--------------------------------------- + * interface {interfacename}{optional_type_parameters} -or- + * class {classname}{optional_type_parameters} + * {optional_type_parameters}{methodname}({parameters}) + * + * Anything after ; is treated as comment. + * + * optional_type_parameters: "" -or- "" (no constraints allowed) + * parameters: type1 p0, type2 p1 (pairs of {type} {name}, joined by ", ") + * + * It is with strict indentations. two spaces for types, four spaces for methods. + * + * Constructors are named as "#ctor". + * + * Commas are used by both parameter types and parameter separators, + * but only parameter separators can be followed by a whitespace. + * It is useful when writing text parsers for this format. + * + * Type names may contain whitespaces in case it is with generic constraints (e.g. "? extends FooBar"), + * so when parsing a parameter type-name pair, the only trustworthy whitespace for tokenizing name is the *last* one. + */ + + public static void WriteParameterNamesText (this JavaApi api, string file) + { + using (var sw = new StreamWriter (file)) + WriteParameterNamesText (api, sw); + } + + public static void WriteParameterNamesText (this JavaApi api, TextWriter writer) + { + Action writeTypeParameters = (indent, tps) => { + if (tps != null && tps.TypeParameters.Any ()) + writer.Write ($"{indent}<{string.Join (",", tps.TypeParameters.Select (p => p.Name))}>"); + }; + + foreach (var package in api.AllPackages.OrderBy (p => p.Name)) { + writer.WriteLine (); + writer.WriteLine ($"package {package.Name}"); + writer.WriteLine (";---------------------------------------"); + + foreach (var type in package.AllTypes.OrderBy (t => t.Name)) { + if (!type.Members.OfType ().Any (m => m.Parameters.Any ())) + continue; // we care only about types that has any methods that have parameters. + writer.Write (type is JavaClass ? " class " : " interface "); + writer.Write (type.Name); + writeTypeParameters ("", type.TypeParameters); + writer.WriteLine (); + + // we care only about methods that have parameters. + foreach (var mb in type.Members.OfType ().Where (m => m.Parameters.Any ())) { + writer.Write (" "); + writeTypeParameters (" ", mb.TypeParameters); + var name = mb is JavaConstructor ? "#ctor" : mb.Name; + // For possible generic instances in parameter type, we replace all ", " with "," to ease parsing. + writer.WriteLine ($" {name}({string.Join (", ", mb.Parameters.Select (p => p.Type.Replace (", ", ",") + ' ' + p.Name))})"); + } + } + } + } + } +} diff --git a/external/Java.Interop/tools/param-name-importer/JavaStubSourceImporter.cs b/external/Java.Interop/tools/param-name-importer/JavaStubSourceImporter.cs new file mode 100644 index 00000000000..0a8b84b12b5 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/JavaStubSourceImporter.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; + +using Irony.Parsing; + +using Java.Interop.Tools.JavaSource; + +using Xamarin.Android.Tools.ApiXmlAdjuster; + +namespace Xamarin.Android.ApiTools.JavaStubImporter +{ + public class JavaStubSourceImporter + { + public void Import (ImporterOptions options) + { + ZipArchive zip; + using (var stream = File.OpenRead (options.InputZipArchive)) { + zip = new ZipArchive (stream); + foreach (var ent in zip.Entries) { + options.DiagnosticWriter.WriteLine (ent.FullName); + if (!ent.Name.EndsWith (".java", StringComparison.OrdinalIgnoreCase)) + continue; + var java = new StreamReader (ent.Open ()).ReadToEnd (); + if (!ParseJava (java)) + break; + } + } + foreach (var pkg in api.AllPackages) { + foreach (var t in pkg.AllTypes.OrderBy (t => t.Name)) { + // Our API definitions don't contain non-public members, so remove those (but it does contain non-public types). + t.Members = t.Members.Where (m => m != null && m.Visibility != "").ToList (); + // Constructor "type" is the full name of the class. + foreach (var c in t.Members.OfType ()) + c.Type = (pkg.Name.Length > 0 ? (pkg.Name + '.') : string.Empty) + t.Name; + // Pupulated enum fields need type to be filled + var cls = t as JavaClass; + if (cls != null && cls.Extends == "java.lang.Enum") { + cls.ExtendsGeneric = "java.lang.Enum<" + pkg.Name + "." + t.Name + ">"; + foreach (var m in cls.Members.OfType ()) { + if (m.Type == null) { + m.Type = pkg.Name + "." + t.Name; + m.TypeGeneric = pkg.Name + "." + t.Name; + } + } + foreach (var m in cls.Members.OfType ()) { + if (m.Name == "valueOf") + m.Return = pkg.Name + "." + t.Name; + else if (m.Name == "values") + m.Return = pkg.Name + "." + t.Name + "[]"; + } + } + t.Members = t.Members.OfType () + .OrderBy (m => m.Name + "(" + string.Join (",", m.Parameters.Select (p => p.Type)) + ")") + .ToArray (); + } + } + + if (options.OutputTextFile != null) + api.WriteParameterNamesText (options.OutputTextFile); + if (options.OutputXmlFile != null) + api.WriteParameterNamesXml (options.OutputXmlFile); + } + + JavaStubParser parser = new JavaStubParser (); + JavaApi api = new JavaApi (); + + bool ParseJava (string javaSourceText) + { + var parsedPackage = parser.TryParse (javaSourceText, out var parseTree); + foreach (var m in parseTree.ParserMessages) { + Console.WriteLine ($"{m.Level} {m.Location} {m.Message}"); + } + if (parsedPackage == null) { + return false; + } + var pkg = api.AllPackages.FirstOrDefault (p => p.Name == parsedPackage.Name); + if (pkg == null) { + api.Packages.Add (parsedPackage.Name, parsedPackage); + pkg = parsedPackage; + } else + foreach (var t in parsedPackage.AllTypes) + pkg.AddType (t); + + return true; + } + } +} diff --git a/external/Java.Interop/tools/param-name-importer/Program.cs b/external/Java.Interop/tools/param-name-importer/Program.cs new file mode 100644 index 00000000000..ac74ea23f84 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/Program.cs @@ -0,0 +1,41 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using Mono.Options; +using Xamarin.Android.ApiTools.DroidDocImporter; +using Xamarin.Android.ApiTools.JavaStubImporter; + +namespace Xamarin.Android.ApiTools +{ + public class Driver + { + public static void Main (string [] args) + { + var options = CreateOptions (args); + if (options.DocumentDirectory != null) + new DroidDocScrapingImporter ().Import (options); + if (options.InputZipArchive != null) + new JavaStubSourceImporter ().Import (options); + } + + static ImporterOptions CreateOptions (string [] args) + { + var ret = new ImporterOptions (); + var options = new OptionSet { + {"droiddoc=", v => ret.DocumentDirectory = v }, + {"source-stub-zip=", v => ret.InputZipArchive = v }, + {"output-text=", v => ret.OutputTextFile = v }, + {"output-xml=", v => ret.OutputXmlFile = v }, + {"verbose", v => ret.DiagnosticWriter = Console.Error }, + {"framework-only", v => ret.FrameworkOnly = true }, + new ResponseFileSource (), + }; + options.Parse (args); + return ret; + } + } +} diff --git a/external/Java.Interop/tools/param-name-importer/README.md b/external/Java.Interop/tools/param-name-importer/README.md new file mode 100644 index 00000000000..fcfbbf56d38 --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/README.md @@ -0,0 +1,8 @@ +New droiddoc importer that works not only on OSX but works everywhere. + +HtmlLoader.cs and those HTML DTD resources are from +https://github.com/xamarin/xamarin-android/tree/master/src/Xamarin.Android.Tools.JavadocImporter + +JavaApi.XmlModel.cs is from here, with some minor changes: +https://github.com/dotnet/java-interop/blob/0cb8e2d3701d213bf3d662daa014707f53f96637/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaApi.XmlModel.cs + diff --git a/external/Java.Interop/tools/param-name-importer/generate.sh b/external/Java.Interop/tools/param-name-importer/generate.sh new file mode 100755 index 00000000000..db8480e7d9e --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/generate.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +ANDROID_TOOLCHAIN="$HOME/android-toolchain" + +DROID_DOC_API_LEVELS="10 15 16 17 18 19 20 21 22 23" +JAVA_STUB_API_LEVELS="24 25 26 27 28 29" + +THISDIR=$(cd `dirname "$0"` && pwd) +TOPDIR=$(cd `dirname "$0"`/../.. && pwd) +if [ -z "$CONFIGURATION" ] ; then + CONFIGURATION=Debug +fi + +APP="$TOPDIR/bin/$CONFIGURATION/param-name-importer.exe" + +if [ ! -f "$APP" ]; then + msbuild /restore /p:Configuration=$CONFIGURATION "$THISDIR/param-name-importer.csproj" +fi + +for n in $JAVA_STUB_API_LEVELS +do + time mono --debug "$APP" -source-stub-zip "$ANDROID_TOOLCHAIN/sdk/platforms/android-$n/android-stubs-src.jar" -output-text "api-$n.params.txt" -output-xml "api-$n.params.xml" -verbose -framework-only +done + +for API_LEVEL in $DROID_DOC_API_LEVELS +do + time mono --debug "$APP" -droiddoc "$ANDROID_TOOLCHAIN/docs/docs-api-$API_LEVEL/" -output-text "api-$API_LEVEL.params.txt" -output-xml "api-$API_LEVEL.params.xml" -verbose -framework-only +done diff --git a/external/Java.Interop/tools/param-name-importer/param-name-importer.csproj b/external/Java.Interop/tools/param-name-importer/param-name-importer.csproj new file mode 100644 index 00000000000..e5993270fde --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/param-name-importer.csproj @@ -0,0 +1,32 @@ + + + + $(DotNetTargetFramework) + Exe + + + + + + $(UtilityOutputFullPath) + + + + + + + $(PkgMicrosoft_Xml_SgmlReader)\lib\netstandard2.0\SgmlReaderDll.dll + + + + + + + + + + + + \ No newline at end of file diff --git a/external/Java.Interop/tools/param-name-importer/strict.dtd b/external/Java.Interop/tools/param-name-importer/strict.dtd new file mode 100644 index 00000000000..b27455943fc --- /dev/null +++ b/external/Java.Interop/tools/param-name-importer/strict.dtd @@ -0,0 +1,870 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%HTMLlat1; + + +%HTMLsymbol; + + +%HTMLspecial; + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets index b2547a30810..6c562f5378c 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets @@ -137,7 +137,7 @@ + Replacements="@JAVA_INTEROP_COMMIT@=in-tree;@SQLITE_COMMIT@=$(_BuildInfo_SqliteCommit);@XAMARIN_ANDROID_TOOLS_COMMIT@=$(_BuildInfo_XamarinAndroidToolsCommit);"> <_XACommonPropsReplacement Include="@COMMAND_LINE_TOOLS_VERSION@=$(CommandLineToolsFolder)" />