diff --git a/Directory.Build.props b/Directory.Build.props
index d16e14e619ba..78893a532efa 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -17,6 +17,15 @@
4.7.2
8.0.0
+
+ 21.1.8.2
+ 5.5.1
+ 21.1.8
+ 17.14.0
+ 0.11.6
+ 5.0.0
+ 4.7.0
+ 4.3.2
diff --git a/NOTICE.txt b/NOTICE.txt
index 24c428f06732..36747ddd79a0 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -733,3 +733,293 @@ Redistribution and use in source and binary forms, with or without modification,
* Neither the name of Industrial Light & Magic 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.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+libclang 21.1.8 - Apache-2.0 WITH LLVM-exception
+
+
+Copyright (c) LLVM Project
+Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign
+
+==============================================================================
+The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
+==============================================================================
+
+ 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 [yyyy] [name of copyright owner]
+
+ 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.
+
+
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
+==============================================================================
+Software from third parties included in the LLVM Project:
+==============================================================================
+The LLVM Project contains third party software which is under different license
+terms. All such code will be identified clearly using at least one of two
+mechanisms:
+1) It will be in a separate directory tree with its own `LICENSE.txt` or
+ `LICENSE` file at the top containing the specific license and restrictions
+ which apply to that software, or
+2) It will contain specific license and restriction terms at the top of every
+ file.
+
+==============================================================================
+Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+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:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+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
+CONTRIBUTORS 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 WITH THE
+SOFTWARE.
+
diff --git a/dotnet/Workloads/SignList.xml b/dotnet/Workloads/SignList.xml
index 16b672eb1642..27d0080395f0 100644
--- a/dotnet/Workloads/SignList.xml
+++ b/dotnet/Workloads/SignList.xml
@@ -130,6 +130,8 @@
+
+
diff --git a/tests/common/Configuration.cs b/tests/common/Configuration.cs
index 5bf45dd44bcd..e4313eb46264 100644
--- a/tests/common/Configuration.cs
+++ b/tests/common/Configuration.cs
@@ -683,7 +683,7 @@ public static void FixupTestFiles (string directory, string mode)
public static Dictionary GetBuildEnvironment (ApplePlatform platform)
{
- Dictionary environment = new Dictionary ();
+ var environment = new Dictionary ();
SetBuildVariables (platform, ref environment);
return environment;
}
diff --git a/tests/sharpie/Sharpie.Bind.Tests/Extensions.cs b/tests/sharpie/Sharpie.Bind.Tests/Extensions.cs
new file mode 100644
index 000000000000..3eb55e85a97e
--- /dev/null
+++ b/tests/sharpie/Sharpie.Bind.Tests/Extensions.cs
@@ -0,0 +1,189 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind.Tests;
+
+using System.Diagnostics;
+using System.Drawing;
+using ICSharpCode.NRefactory.CSharp;
+using Sharpie.Bind;
+using Xamarin.Tests;
+using Xamarin.Utils;
+
+public static class Extensions {
+
+ static Dictionary platformAssemblyPaths = new ();
+ public static string GetPlatformAssemblyPath (ApplePlatform platform)
+ {
+ if (!platformAssemblyPaths.TryGetValue (platform, out var path))
+ platformAssemblyPaths [platform] = path = Configuration.GetBaseLibrary (platform);
+ return path;
+ }
+
+ public static string GetClangResourceDirectory ()
+ {
+ return Path.Combine (Configuration.SourceRoot, "tools", "sharpie", "clang");
+ }
+
+ // Running out-of-process is useful when there's something causing clang to crash, in which case
+ // running out-of-process will only fail the single test that's running, and not the entire test run.
+ public static bool UseOutOfProcessBinding = true;
+
+ public static BindingResult BindInOrOut (this ObjectiveCBinder binder)
+ {
+ BindingResult rv;
+ if (UseOutOfProcessBinding && !Debugger.IsAttached) {
+ rv = binder.ExecuteOutOfProcess ();
+ } else {
+ rv = binder.Bind ();
+ }
+
+ return rv;
+ }
+
+ ///
+ /// Asserts that the binding was successful and that the generated binding code matches the expected binding code.
+ ///
+ ///
+ ///
+ ///
+ public static void AssertSuccess (this BindingResult bindings, string? expectedBindingCode, params string [] additionalInfo)
+ {
+ bindings.Warnings.ForEach (Console.WriteLine);
+ bindings.Errors.ForEach (Console.Error.WriteLine);
+
+ if (bindings.ExitCode == 139) {
+ Console.Error.WriteLine ("Binding process crashed with exit code 139 (SIGSEGV).");
+ Assert.Fail ("Binding process crashed with exit code 139 (SIGSEGV).");
+ }
+
+ Assert.That (bindings.ExitCode, Is.EqualTo (0), "Expected success");
+ Assert.That (bindings.Errors.Count, Is.EqualTo (0), $"Unexpected number of errors\n\t{string.Join ("\n\t", bindings.Errors)}");
+
+ if (expectedBindingCode is null)
+ return;
+
+ var expected = expectedBindingCode.Replace ("\r\n", "\n").Trim ();
+ var actual = bindings.BindingCode?.Replace ("\r\n", "\n").Trim () ?? "";
+ if (expected != actual) {
+ const string splitter = "===========================";
+ Console.WriteLine ("Expected Binding Code:");
+ Console.WriteLine (splitter);
+ Console.WriteLine (expected);
+ Console.WriteLine (splitter);
+ Console.WriteLine ("Actual Binding Code:");
+ Console.WriteLine (splitter);
+ Console.WriteLine (actual);
+ Console.WriteLine (splitter);
+ var diff = ComputeDiff (expected, actual).Split ('\n');
+ Console.WriteLine ("Diff:");
+ Console.WriteLine (splitter);
+ foreach (var line in diff) {
+ var colorized = false;
+ if (line.Length >= 2) {
+ if (line [0] == '+' && line [1] != '+') {
+ Console.Write (Color.Green);
+ colorized = true;
+ } else if (line [0] == '-' && line [1] != '-') {
+ Console.Write (Color.Red);
+ colorized = true;
+ }
+ }
+ Console.Write (line);
+ if (colorized)
+ Console.Write (Color.Reset);
+ Console.WriteLine ();
+ }
+ Console.WriteLine (splitter);
+ foreach (var line in additionalInfo)
+ Console.WriteLine (line);
+ Assert.That (actual, Is.EqualTo (expected), "Expected binding code");
+ }
+ }
+
+ static string ComputeDiff (string a, string b)
+ {
+ var fa = Path.Combine (Path.GetTempPath (), "sharpie", "tests", "a.cs");
+ var fb = Path.Combine (Path.GetTempPath (), "sharpie", "tests", "b.cs");
+ if (File.Exists (fa))
+ File.Delete (fa);
+ if (File.Exists (fb))
+ File.Delete (fb);
+ Directory.CreateDirectory (Path.GetDirectoryName (fa)!);
+ File.WriteAllText (fa, a);
+ File.WriteAllText (fb, b);
+
+ var rv = Execution.RunAsync ("diff", new [] { "-u", fa, fb }, timeout: TimeSpan.FromSeconds (10)).Result;
+
+ File.Delete (fa);
+ File.Delete (fb);
+
+ return rv.Output.MergedOutput;
+ }
+
+ public static void AssertErrors (this BindingResult bindings, params (int Code, string Message, string? FileName, long? LineNumber) [] expectedErrors)
+ {
+ Assert.That (bindings.ExitCode, Is.EqualTo (1), "Expected failure");
+ Assert.That (bindings.BindingCode, Is.Empty.Or.Null, "Expected no binding code");
+ AssertMessages ("error", bindings.Errors, expectedErrors);
+ }
+
+ public static void AssertWarnings (this BindingResult bindings, params (int Code, string Message, string? FileName, long? LineNumber) [] expectedWarnings)
+ {
+ AssertMessages ("warning", bindings.Warnings, expectedWarnings);
+ }
+
+ public static void AssertNoWarnings (this BindingResult bindings)
+ {
+ AssertWarnings (bindings);
+ }
+
+ static void AssertMessages (string type, IList messages, params (int Code, string Message, string? FileName, long? LineNumber) [] expectedMessages)
+ {
+ Assert.That (messages.Count, Is.EqualTo (expectedMessages.Length), $"Unexpected number of {type}s ({messages.Count})\n\t{string.Join ("\n\t", messages)}");
+ for (int i = 0; i < expectedMessages.Length; i++) {
+ Assert.That (messages [i].Code, Is.EqualTo (expectedMessages [i].Code), $"Code for {type} #{i}");
+ Assert.That (messages [i].Message, Is.EqualTo (expectedMessages [i].Message), $"Message for {type} #{i}");
+ if (expectedMessages [i].FileName is not null)
+ Assert.That (messages [i].FileName, Is.EqualTo (expectedMessages [i].FileName), $"FileName for {type} #{i}");
+ if (expectedMessages [i].LineNumber is not null)
+ Assert.That (messages [i].LineNumber, Is.EqualTo (expectedMessages [i].LineNumber!.Value), $"LineNumber for {type} #{i}");
+ }
+ }
+}
+
+static class Color {
+ internal const char ESC_Char = '\u001b';
+ internal const string ESC = $"\u001b"; /* \033 - https://github.com/dotnet/csharplang/issues/7400 */
+ internal const string ST = ESC + "\\";
+ internal const string OSC = ESC + "]";
+
+ public const string DarkBlack = ESC + "[30m";
+ public const string DarkRed = ESC + "[31m";
+ public const string DarkGreen = ESC + "[32m";
+ public const string DarkYellow = ESC + "[33m";
+ public const string DarkBlue = ESC + "[34m";
+ public const string DarkMagenta = ESC + "[35m";
+ public const string DarkCyan = ESC + "[36m";
+ public const string DarkWhite = ESC + "[37m";
+
+ public const string Black = ESC + "[90m";
+ public const string Red = ESC + "[91m";
+ public const string Green = ESC + "[92m";
+ public const string Yellow = ESC + "[93m";
+ public const string Blue = ESC + "[94m";
+ public const string Magenta = ESC + "[95m";
+ public const string Cyan = ESC + "[96m";
+ public const string White = ESC + "[97m";
+ public const string Reset = ESC + "[0m";
+
+ public const string Bold = ESC + "[1m";
+ public const string Italicize = ESC + "[3m";
+ public const string Underline = ESC + "[4m";
+ public const string Strikethrough = ESC + "[9m";
+
+ public const string NotBold = ESC + "[22m";
+ public const string NotItalic = ESC + "[23m";
+ public const string NotUnderline = ESC + "[24m";
+ public const string NotStrikethrough = ESC + "[29m";
+}
diff --git a/tests/sharpie/Sharpie.Bind.Tests/GlobalUsings.cs b/tests/sharpie/Sharpie.Bind.Tests/GlobalUsings.cs
new file mode 100644
index 000000000000..71013a1ac234
--- /dev/null
+++ b/tests/sharpie/Sharpie.Bind.Tests/GlobalUsings.cs
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+global using System.Runtime.InteropServices;
diff --git a/tests/sharpie/Sharpie.Bind.Tests/ObjectiveCClass.cs b/tests/sharpie/Sharpie.Bind.Tests/ObjectiveCClass.cs
new file mode 100644
index 000000000000..839e682c8404
--- /dev/null
+++ b/tests/sharpie/Sharpie.Bind.Tests/ObjectiveCClass.cs
@@ -0,0 +1,446 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Xamarin;
+using Xamarin.Utils;
+
+namespace Sharpie.Bind.Tests;
+
+public class Tests {
+ [Test]
+ public void ErrorNoNSObject ()
+ {
+ var binder = new BindTool ();
+ var code =
+ """
+ @interface MyClass : NSObject {
+ }
+ @property int Pi1;
+ @end
+ int main () { return 0; }
+ """;
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var tmpfile = Path.Combine (tmpdir, "test.m");
+ File.WriteAllText (tmpfile, code);
+ binder.SourceFile = tmpfile;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ bindings.AssertErrors ((5, $"Compilation failed with error: cannot find interface declaration for 'NSObject', superclass of 'MyClass'", tmpfile, 1));
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void ObjectiveCClass ()
+ {
+ var binder = new BindTool ();
+ var code =
+ """
+ @interface MyClass {
+ }
+ @property int P1;
+ @end
+ """;
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var tmpfile = Path.Combine (tmpdir, "test.m");
+ File.WriteAllText (tmpfile, code);
+ binder.SplitDocuments = false;
+ binder.SourceFile = tmpfile;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ var expectedBindings =
+"""
+using Foundation;
+
+// @interface MyClass
+interface MyClass {
+ // @property int P1;
+ [Export ("P1")]
+ int P1 { get; set; }
+}
+
+""";
+ bindings.AssertSuccess (expectedBindings);
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework ()
+ {
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "MyFramework.framework");
+ var headersDir = Path.Combine (frameworkDir, "Headers");
+ Directory.CreateDirectory (headersDir);
+ var umbrellaHeader = Path.Combine (headersDir, "MyFramework.h");
+ File.WriteAllText (umbrellaHeader,
+ """
+ @interface MyClass {
+ }
+ @property int P1;
+ @end
+ """);
+ binder.SplitDocuments = false;
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ var expectedBindings =
+"""
+using Foundation;
+
+namespace MyFramework {
+ // @interface MyClass
+ interface MyClass {
+ // @property int P1;
+ [Export ("P1")]
+ int P1 { get; set; }
+ }
+}
+
+""";
+ bindings.AssertSuccess (expectedBindings);
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_ImpliedNamespace ()
+ {
+ // Verify that the namespace is set to the framework name when not explicitly specified.
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "CustomKit.framework");
+ var headersDir = Path.Combine (frameworkDir, "Headers");
+ Directory.CreateDirectory (headersDir);
+ var umbrellaHeader = Path.Combine (headersDir, "CustomKit.h");
+ File.WriteAllText (umbrellaHeader,
+ """
+ @interface Widget {
+ }
+ @property int Width;
+ @end
+ """);
+ binder.SplitDocuments = false;
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ var expectedBindings =
+"""
+using Foundation;
+
+namespace CustomKit {
+ // @interface Widget
+ interface Widget {
+ // @property int Width;
+ [Export ("Width")]
+ int Width { get; set; }
+ }
+}
+
+""";
+ bindings.AssertSuccess (expectedBindings);
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_ExplicitNamespace ()
+ {
+ // Verify that an explicitly specified namespace overrides the framework name.
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "MyFramework.framework");
+ var headersDir = Path.Combine (frameworkDir, "Headers");
+ Directory.CreateDirectory (headersDir);
+ var umbrellaHeader = Path.Combine (headersDir, "MyFramework.h");
+ File.WriteAllText (umbrellaHeader,
+ """
+ @interface MyClass {
+ }
+ @property int P1;
+ @end
+ """);
+ binder.SplitDocuments = false;
+ binder.SourceFramework = frameworkDir;
+ binder.Namespace = "CustomNamespace";
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ var expectedBindings =
+"""
+using Foundation;
+
+namespace CustomNamespace {
+ // @interface MyClass
+ interface MyClass {
+ // @property int P1;
+ [Export ("P1")]
+ int P1 { get; set; }
+ }
+}
+
+""";
+ bindings.AssertSuccess (expectedBindings);
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_ErrorBothSourceFileAndFramework ()
+ {
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "MyFramework.framework");
+ Directory.CreateDirectory (frameworkDir);
+ var tmpfile = Path.Combine (tmpdir, "test.m");
+ File.WriteAllText (tmpfile, "@interface MyClass @end");
+ binder.SourceFile = tmpfile;
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ bindings.AssertErrors ((16, "Cannot specify both a source framework and a source file.", null, null));
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_ErrorNonExistentFramework ()
+ {
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "NonExistent.framework");
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ bindings.AssertErrors ((17, $"The framework '{frameworkDir}' doesn't exist.", null, null));
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_ErrorNoUmbrellaHeaderOrModuleMap ()
+ {
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "Empty.framework");
+ Directory.CreateDirectory (frameworkDir);
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ var fullPath = Path.GetFullPath (frameworkDir);
+ bindings.AssertErrors ((18, $"The framework '{fullPath}' does not have an umbrella header or module map.", null, null));
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_SdkFromInfoPlist ()
+ {
+ // Verify that the Sdk value is computed from the framework's Info.plist when not explicitly set.
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "MyFramework.framework");
+ var headersDir = Path.Combine (frameworkDir, "Headers");
+ Directory.CreateDirectory (headersDir);
+ var umbrellaHeader = Path.Combine (headersDir, "MyFramework.h");
+ File.WriteAllText (umbrellaHeader,
+ """
+ @interface MyClass {
+ }
+ @property int P1;
+ @end
+ """);
+ // Create an Info.plist with DTSDKName
+ var infoPlist = Path.Combine (frameworkDir, "Info.plist");
+ File.WriteAllText (infoPlist,
+ """
+
+
+
+
+ DTSDKName
+ macosx15.0
+
+
+ """);
+ binder.SplitDocuments = false;
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (ApplePlatform.MacOSX);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ // Don't set binder.Sdk - it should be read from the Info.plist
+ var bindings = binder.BindInOrOut ();
+ var expectedBindings =
+"""
+using Foundation;
+
+namespace MyFramework {
+ // @interface MyClass
+ interface MyClass {
+ // @property int P1;
+ [Export ("P1")]
+ int P1 { get; set; }
+ }
+}
+
+""";
+ bindings.AssertSuccess (expectedBindings);
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_SdkVersionStripped ()
+ {
+ // Verify that the version number is stripped from the DTSDKName value (e.g. "macosx11.0" → "macosx").
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "MyFramework.framework");
+ var headersDir = Path.Combine (frameworkDir, "Headers");
+ Directory.CreateDirectory (headersDir);
+ var umbrellaHeader = Path.Combine (headersDir, "MyFramework.h");
+ File.WriteAllText (umbrellaHeader,
+ """
+ @interface MyClass {
+ }
+ @property int P1;
+ @end
+ """);
+ var infoPlist = Path.Combine (frameworkDir, "Info.plist");
+ File.WriteAllText (infoPlist,
+ """
+
+
+
+
+ DTSDKName
+ macosx11.0
+
+
+ """);
+ binder.SplitDocuments = false;
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (ApplePlatform.MacOSX);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ // The SDK should be "macosx" (version stripped), not "macosx11.0" which doesn't exist.
+ Assert.That (binder.Sdk, Is.EqualTo ("macosx"), "SDK version should be stripped");
+ bindings.AssertSuccess (null);
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void BindFramework_ModuleMap ()
+ {
+ // Verify that a framework with a module map can be bound,
+ // and that the framework search path (-F) is automatically configured.
+ var binder = new BindTool ();
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var frameworkDir = Path.Combine (tmpdir, "ModKit.framework");
+ var headersDir = Path.Combine (frameworkDir, "Headers");
+ var modulesDir = Path.Combine (frameworkDir, "Modules");
+ Directory.CreateDirectory (headersDir);
+ Directory.CreateDirectory (modulesDir);
+ var header = Path.Combine (headersDir, "ModKit.h");
+ File.WriteAllText (header,
+ """
+ @interface MKWidget {
+ }
+ @property int Height;
+ @end
+ """);
+ File.WriteAllText (Path.Combine (modulesDir, "module.modulemap"),
+ """
+ framework module ModKit {
+ umbrella header "ModKit.h"
+ export *
+ module * { export * }
+ }
+ """);
+ binder.SplitDocuments = false;
+ binder.SourceFramework = frameworkDir;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ // Do NOT manually set ClangArguments with -F — it should be auto-added.
+ var bindings = binder.BindInOrOut ();
+ var expectedBindings =
+"""
+using Foundation;
+
+namespace ModKit {
+ // @interface MKWidget
+ interface MKWidget {
+ // @property int Height;
+ [Export ("Height")]
+ int Height { get; set; }
+ }
+}
+
+""";
+ bindings.AssertSuccess (expectedBindings);
+ bindings.AssertNoWarnings ();
+ }
+
+ [Test]
+ public void SplitDocuments ()
+ {
+ var binder = new BindTool ();
+ var code =
+ """
+ struct MyStruct {
+ int X;
+ int Y;
+ };
+ @interface MyClass {
+ }
+ @property int P1;
+ @end
+ """;
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var tmpfile = Path.Combine (tmpdir, "test.m");
+ File.WriteAllText (tmpfile, code);
+ binder.SourceFile = tmpfile;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var bindings = binder.BindInOrOut ();
+ var expectedApiDefinitionBindings =
+"""
+using Foundation;
+
+// @interface MyClass
+interface MyClass {
+ // @property int P1;
+ [Export ("P1")]
+ int P1 { get; set; }
+}
+
+""";
+ var expectedStructAndEnumsBindings =
+ """
+ using System.Runtime.InteropServices;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct MyStruct {
+ public int X;
+
+ public int Y;
+ }
+
+ """;
+ bindings.AssertSuccess (null);
+ bindings.AssertNoWarnings ();
+ Assert.That (bindings.AdditionalFiles.Count, Is.EqualTo (2), "Additional files");
+ Assert.That (bindings.AdditionalFiles ["ApiDefinition.cs"].Trim (), Is.EqualTo (expectedApiDefinitionBindings.Trim ()), "Api definition");
+ Assert.That (bindings.AdditionalFiles ["StructsAndEnums.cs"].Trim (), Is.EqualTo (expectedStructAndEnumsBindings.Trim ()), "Struct and enums");
+ }
+}
diff --git a/tests/sharpie/Sharpie.Bind.Tests/OnDiskTests.cs b/tests/sharpie/Sharpie.Bind.Tests/OnDiskTests.cs
new file mode 100644
index 000000000000..f663fb33052a
--- /dev/null
+++ b/tests/sharpie/Sharpie.Bind.Tests/OnDiskTests.cs
@@ -0,0 +1,165 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Text.RegularExpressions;
+using ClangSharp.Interop;
+using NUnit.Framework.Constraints;
+using Xamarin;
+
+namespace Sharpie.Bind.Tests;
+
+public class OnDiskTests {
+ static readonly string testsDir;
+
+ static OnDiskTests ()
+ {
+ // from there we walk up the tree until we find the Tests directory
+ testsDir = Environment.CurrentDirectory;
+
+ while (!string.IsNullOrEmpty (testsDir)) {
+ if (Directory.Exists (Path.Combine (testsDir, ".git")))
+ break;
+
+ var subdir = Path.Combine (testsDir, "Tests");
+ if (Directory.Exists (subdir)) {
+ testsDir = subdir;
+ break;
+ }
+
+ testsDir = Path.GetDirectoryName (testsDir)!;
+ }
+ }
+
+ public static IEnumerable GetRunTests ()
+ {
+ return GetTests (true);
+ }
+
+ public static IEnumerable GetNoRunTests ()
+ {
+ return GetTests (false);
+ }
+
+
+ public static IEnumerable GetTests (bool runTests = true)
+ {
+ var testsToRun = new HashSet (Environment
+ .GetEnvironmentVariable ("SHARPIE_PARSEBIND_TESTS")
+ ?.Split (new [] { ',', ';', ':' }, StringSplitOptions.RemoveEmptyEntries)
+ ?? Array.Empty ());
+
+ foreach (var file in Directory.EnumerateFiles (testsDir, "*.h", SearchOption.AllDirectories).OrderBy (v => v)) {
+ var testsDirLength = testsDir.Length;
+ var relativePath = file.Substring (testsDirLength + 1);
+
+ var testCategory = Path.GetDirectoryName (relativePath);
+ var testName = Path.GetFileNameWithoutExtension (relativePath);
+ if (!string.IsNullOrEmpty (testCategory))
+ testName = Path.Combine (testCategory, testName);
+
+ if (testsToRun.Count > 0 && !testsToRun.Contains (testName))
+ continue;
+
+ var isRunTest = false;
+ foreach (var line in File.ReadLines (file)) {
+ var match = Regex.Match (line, @"\s*//\s*RUN(\s+[^:]+)?:(.*)$");
+ isRunTest |= match.Success;
+ if (match.Success && runTests)
+ yield return new object [] {
+ relativePath,
+ match.Groups [1].Value.Trim (), // name
+ match.Groups [2].Value // bind arguments
+ };
+ }
+
+ if (runTests)
+ continue;
+
+ if (!runTests && isRunTest)
+ continue;
+
+ yield return new object []
+ {
+ relativePath,
+ "",
+ };
+ }
+ }
+
+ [TestCaseSource (nameof (GetNoRunTests))]
+ public void ParseNoRunTest (string path, string bindArguments)
+ {
+ ParseBindTestImpl (path, "", "-x objective-c");
+ }
+
+ [TestCaseSource (nameof (GetRunTests))]
+ public void ParseRunTest (string path, string variant, string bindArguments)
+ {
+ ParseBindTestImpl (path, variant, bindArguments);
+ }
+
+ void ParseBindTestImpl (string path, string variant, string bindArguments)
+ {
+ var inputPath = Path.Combine (testsDir, path);
+ var expectedOutputPath = Path.Combine (Path.GetDirectoryName (inputPath)!, Path.GetFileNameWithoutExtension (path));
+
+ if (!string.IsNullOrEmpty (variant))
+ expectedOutputPath += "." + variant.Replace (' ', '_');
+
+ expectedOutputPath += ".cs";
+
+ var binder = new BindTool ();
+ binder.SplitDocuments = false;
+ binder.DirectoriesInScope.Add (testsDir);
+
+ var clangArguments = new List ();
+ var bindArgs = bindArguments.Split (' ', StringSplitOptions.RemoveEmptyEntries); // FIXME: better splitting
+ for (var i = 0; i < bindArgs.Length; i++) {
+ switch (bindArgs [i]) {
+ case "-sdk":
+ binder.Sdk = bindArgs [i + 1];
+ i++;
+ break;
+ case "-namespace":
+ binder.Namespace = bindArgs [i + 1];
+ i++;
+ break;
+ case string s when s.StartsWith ("-massage="):
+ var massagerName = s.Substring ("-massage=".Length);
+ var enable = massagerName [0] == '+';
+ binder.Massagers.Add ((massagerName.TrimStart ('+', '-'), enable));
+ break;
+ case "-massage":
+ massagerName = bindArgs [i + 1];
+ enable = massagerName.StartsWith ("+");
+ binder.Massagers.Add ((massagerName.TrimStart ('+', '-'), enable));
+ i++;
+ break;
+ default:
+ clangArguments.Add (bindArgs [i]);
+ break;
+ }
+ }
+
+ var outputdir = Cache.CreateTemporaryDirectory ();
+ var output = File.ReadAllText (expectedOutputPath);
+
+ binder.OutputDirectory = outputdir;
+ binder.SourceFile = inputPath;
+ binder.ClangArguments.AddRange (clangArguments);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ var result = binder.BindInOrOut ();
+
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var csharpCode = Path.Combine (tmpdir, "ApiDefinition.cs");
+ File.WriteAllText (csharpCode, result.BindingCode);
+
+ result.AssertSuccess (output,
+ $"Input file: {inputPath}",
+ $"Expected Output file: {expectedOutputPath}",
+ $"Actual Output file: {binder.OutputApiDefinitionPath}");
+ result.AssertNoWarnings ();
+ }
+}
diff --git a/tests/sharpie/Sharpie.Bind.Tests/SdkDbTest.cs b/tests/sharpie/Sharpie.Bind.Tests/SdkDbTest.cs
new file mode 100644
index 000000000000..9f6332daa2ed
--- /dev/null
+++ b/tests/sharpie/Sharpie.Bind.Tests/SdkDbTest.cs
@@ -0,0 +1,78 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Xamarin;
+
+namespace Sharpie.Bind.Tests;
+
+public class SdkDbTest {
+
+ static IEnumerable TestCases {
+ get {
+ var desktopCompilerArguments = new string [] {
+ "-DGL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED",
+ };
+
+ var desktopExcludeNoModules = new string [] {
+ "Kerberos",
+ };
+
+ var macOSExclude = new string [] {
+ "AccessorySetupKit", // not available on macOS
+ "DriverKit", // must be compiled as C++?
+ "Tk", // depends on X11 headers, which don't exist anymore
+ };
+
+ var macCatalystExclude = new string [] {
+ // most of these frameworks are not available on Mac Catalyst
+ "AccessorySetupKit",
+ "AudioVideoBridging",
+ "Carbon",
+ "CompositorServices",
+ "DiscRecordingUI",
+ "DriverKit", // must be compiled as C++?
+ "FSKit",
+ "GLKit",
+ "Hypervisor",
+ "InputMethodKit",
+ "InstallerPlugins",
+ "LDAP",
+ "Tk", // depends on X11 headers, which don't exist anymore
+ "Quartz",
+ "QuickLookUI",
+ "Virtualization",
+ };
+
+ var sdkNames = new [] {
+ ( Platform: "iOS", Sdk: "iphoneos" + SdkVersions.iOS, ExcludedFrameworks: [], NoModulesExcludedFrameworks: [], ClangArguments: [] ),
+ ( Platform: "tvOS", Sdk: "appletvos" + SdkVersions.TVOS, ExcludedFrameworks: [], NoModulesExcludedFrameworks: [], ClangArguments: [] ),
+ ( Platform: "macOS", Sdk: "macosx" + SdkVersions.OSX, ExcludedFrameworks: macOSExclude, NoModulesExcludedFrameworks: desktopExcludeNoModules, ClangArguments: desktopCompilerArguments ),
+ ( Platform: "MacCatalyst", Sdk: "ios" + SdkVersions.MacCatalyst + "-macabi", ExcludedFrameworks: macCatalystExclude, NoModulesExcludedFrameworks: desktopExcludeNoModules, ClangArguments: desktopCompilerArguments ),
+ };
+
+ foreach (var sdk in sdkNames) {
+ yield return new TestCaseData (false, sdk.Sdk, sdk.ExcludedFrameworks.Union (sdk.NoModulesExcludedFrameworks).ToArray (), sdk.ClangArguments).SetName ($"{sdk.Platform} (no modules)");
+ yield return new TestCaseData (true, sdk.Sdk, sdk.ExcludedFrameworks, sdk.ClangArguments).SetName ($"{sdk.Platform} (with modules)");
+ }
+ }
+ }
+
+ [Test]
+ [TestCaseSource (nameof (TestCases))]
+ public void TestSdkPath (bool usingModules, string sdk, string []? excludedFrameworks = null, string []? clangArguments = null)
+ {
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ var binder = new SdkDbTool ();
+ if (clangArguments is not null)
+ binder.ClangArguments.AddRange (clangArguments);
+ binder.EnableModules = usingModules;
+ binder.ExcludedFrameworks.AddRange (excludedFrameworks ?? Array.Empty ());
+ binder.Sdk = sdk;
+ binder.OutputDirectory = tmpdir;
+ binder.PlatformAssembly = Extensions.GetPlatformAssemblyPath (binder.Platform);
+ binder.ClangResourceDirectory = Extensions.GetClangResourceDirectory ();
+ var rv = binder.BindInOrOut ();
+ rv.AssertSuccess (null);
+ rv.AssertNoWarnings ();
+ }
+}
diff --git a/tests/sharpie/Sharpie.Bind.Tests/Sharpie.Bind.Tests.csproj b/tests/sharpie/Sharpie.Bind.Tests/Sharpie.Bind.Tests.csproj
new file mode 100644
index 000000000000..ed7b97497bbe
--- /dev/null
+++ b/tests/sharpie/Sharpie.Bind.Tests/Sharpie.Bind.Tests.csproj
@@ -0,0 +1,50 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)
+ latest
+ enable
+ enable
+ false
+
+ $(NETCoreSdkRuntimeIdentifier)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ external/tools/common/SdkVersions.cs
+
+
+ external/tools/common/StringUtils.cs
+
+
+ external/tools/common/TargetFramework.cs
+
+
+ external/tests/common/Configuration.cs
+
+
+ external/tests/common/ConfigurationNUnit.cs
+
+
+ external/tests/common/ExecutionHelper.cs
+
+
+ external/tests/mtouch/Cache.cs
+
+
+
+
diff --git a/tests/sharpie/Tests/Availability.h b/tests/sharpie/Tests/Availability.h
new file mode 100644
index 000000000000..48627ca26392
--- /dev/null
+++ b/tests/sharpie/Tests/Availability.h
@@ -0,0 +1,71 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN iphoneos: -x objective-c -sdk iphoneos
+// RUN macosx: -x objective-c -sdk macosx
+
+#if !__has_feature(attribute_availability_watchos)
+#error "compiler does not support attribute_availability_watchos"
+#endif
+
+#if !__has_feature(attribute_availability_tvos)
+#error "compiler does not support attribute_availability_tvos"
+#endif
+
+__attribute__((availability(watchos,unavailable)))
+@interface UnavailableWatchOS
+@end
+
+__attribute__((availability(tvos,unavailable)))
+@interface UnavailableTvOS
+@end
+
+__attribute__((availability(ios,introduced=9.1)))
+__attribute__((availability(macosx,introduced=10.11)))
+__attribute__((availability(watchos,unavailable)))
+__attribute__((availability(tvos,unavailable)))
+@interface iOSAndMacOnly
+@end
+
+__attribute__((availability(macosx,introduced=10.8)))
+__attribute__((availability(ios,introduced=7.0)))
+@interface Availability
+
+-(void)thisIsDeprecated
+ __attribute__((availability(macosx,deprecated=10.10.3,message="Don't use this in Mac homie")))
+ __attribute__((availability(ios,deprecated=8.3,message="Don't use this in iOS homie")));
+
+-(void)thisWasIntroducedThenDeprecatedThenObsoletedMacOnly
+ __attribute__((availability(macosx,introduced=10.8.1,message="Introduced Message")))
+ __attribute__((availability(macosx,deprecated=10.9,message="Deprecated Message")))
+ __attribute__((availability(macosx,obsoleted=10.10,message="Obsoleted Message")));
+
+-(void)thisWasIntroducedThenDeprecatedThenObsoletedInBothMacAndIos
+ __attribute__((availability(macosx,introduced=10.8.1,message="Mac Introduced Message")))
+ __attribute__((availability(macosx,deprecated=10.9,message="Mac Deprecated Message")))
+ __attribute__((availability(macosx,obsoleted=10.10,message="Mac Obsoleted Message")))
+ __attribute__((availability(ios,introduced=7.0,message="iOS Introduced Message")))
+ __attribute__((availability(ios,deprecated=7.1,message="iOS Deprecated Message")))
+ __attribute__((availability(ios,obsoleted=8.0,message="iOS Obsoleted Message")));
+
+-(void)thisShouldBeShorthandMac
+ __attribute__((availability(macosx,introduced=10.10.3)));
+
+-(void)thisShouldBeShorthandMacOnlyOn64
+ __attribute__((availability(macosx,introduced=10.13.4)));
+
+-(void)thisShouldBeShorthandIos
+ __attribute__((availability(ios,introduced=8.3.1)));
+
+-(void)thisIsUnavailableOnMac
+ __attribute__((availability(macosx,unavailable)));
+
+-(void)thisIsUnavailableOnMacAndIos
+ __attribute__((availability(macosx,unavailable)))
+ __attribute__((availability(ios,unavailable)));
+
+-(void)introducedOnMac64BitOnlyAndLaterDeprecated
+ __attribute__((availability(macosx,introduced=10.13.4)))
+ __attribute__((availability(macosx,deprecated=10.13.5)));
+
+@end
diff --git a/tests/sharpie/Tests/Availability.iphoneos.cs b/tests/sharpie/Tests/Availability.iphoneos.cs
new file mode 100644
index 000000000000..0af20c816cb5
--- /dev/null
+++ b/tests/sharpie/Tests/Availability.iphoneos.cs
@@ -0,0 +1,75 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface UnavailableWatchOS
+[NoWatch]
+interface UnavailableWatchOS {
+}
+
+// @interface UnavailableTvOS
+[NoTV]
+interface UnavailableTvOS {
+}
+
+// @interface iOSAndMacOnly
+[NoWatch, NoTV, Mac (10, 11), iOS (9, 1)]
+interface iOSAndMacOnly {
+}
+
+// @interface Availability
+[Mac (10, 8), iOS (7, 0)]
+interface Availability {
+ // -(void)thisIsDeprecated __attribute__((availability(macos, deprecated=10.10.3))) __attribute__((availability(ios, deprecated=8.3)));
+ [Deprecated (PlatformName.MacOSX, 10, 10, 3, message: "Don't use this in Mac homie")]
+ [Deprecated (PlatformName.iOS, 8, 3, message: "Don't use this in iOS homie")]
+ [Export ("thisIsDeprecated")]
+ void ThisIsDeprecated ();
+
+ // -(void)thisWasIntroducedThenDeprecatedThenObsoletedMacOnly __attribute__((availability(macos, introduced=10.8.1))) __attribute__((availability(macos, deprecated=10.9))) __attribute__((availability(macos, obsoleted=10.10)));
+ [Introduced (PlatformName.MacOSX, 10, 8, 1)]
+ [Deprecated (PlatformName.MacOSX, 10, 9, message: "Deprecated Message")]
+ [Obsoleted (PlatformName.MacOSX, 10, 10, message: "Obsoleted Message")]
+ [Export ("thisWasIntroducedThenDeprecatedThenObsoletedMacOnly")]
+ void ThisWasIntroducedThenDeprecatedThenObsoletedMacOnly ();
+
+ // -(void)thisWasIntroducedThenDeprecatedThenObsoletedInBothMacAndIos __attribute__((availability(macos, introduced=10.8.1))) __attribute__((availability(macos, deprecated=10.9))) __attribute__((availability(macos, obsoleted=10.10))) __attribute__((availability(ios, introduced=7.0))) __attribute__((availability(ios, deprecated=7.1))) __attribute__((availability(ios, obsoleted=8.0)));
+ [Introduced (PlatformName.MacOSX, 10, 8, 1)]
+ [Deprecated (PlatformName.MacOSX, 10, 9, message: "Mac Deprecated Message")]
+ [Obsoleted (PlatformName.MacOSX, 10, 10, message: "Mac Obsoleted Message")]
+ [Introduced (PlatformName.iOS, 7, 0)]
+ [Deprecated (PlatformName.iOS, 7, 1, message: "iOS Deprecated Message")]
+ [Obsoleted (PlatformName.iOS, 8, 0, message: "iOS Obsoleted Message")]
+ [Export ("thisWasIntroducedThenDeprecatedThenObsoletedInBothMacAndIos")]
+ void ThisWasIntroducedThenDeprecatedThenObsoletedInBothMacAndIos ();
+
+ // -(void)thisShouldBeShorthandMac __attribute__((availability(macos, introduced=10.10.3)));
+ [Mac (10, 10, 3)]
+ [Export ("thisShouldBeShorthandMac")]
+ void ThisShouldBeShorthandMac ();
+
+ // -(void)thisShouldBeShorthandMacOnlyOn64 __attribute__((availability(macos, introduced=10.13.4)));
+ [Mac (10, 13, 4)]
+ [Export ("thisShouldBeShorthandMacOnlyOn64")]
+ void ThisShouldBeShorthandMacOnlyOn64 ();
+
+ // -(void)thisShouldBeShorthandIos __attribute__((availability(ios, introduced=8.3.1)));
+ [iOS (8, 3, 1)]
+ [Export ("thisShouldBeShorthandIos")]
+ void ThisShouldBeShorthandIos ();
+
+ // -(void)thisIsUnavailableOnMac __attribute__((availability(macos, unavailable)));
+ [NoMac]
+ [Export ("thisIsUnavailableOnMac")]
+ void ThisIsUnavailableOnMac ();
+
+ // -(void)thisIsUnavailableOnMacAndIos __attribute__((availability(macos, unavailable))) __attribute__((availability(ios, unavailable)));
+ [NoMac, NoiOS]
+ [Export ("thisIsUnavailableOnMacAndIos")]
+ void ThisIsUnavailableOnMacAndIos ();
+
+ // -(void)introducedOnMac64BitOnlyAndLaterDeprecated __attribute__((availability(macos, introduced=10.13.4))) __attribute__((availability(macos, deprecated=10.13.5)));
+ [Deprecated (PlatformName.MacOSX, 10, 13, 5)]
+ [Mac (10, 13, 4)]
+ [Export ("introducedOnMac64BitOnlyAndLaterDeprecated")]
+ void IntroducedOnMac64BitOnlyAndLaterDeprecated ();
+}
diff --git a/tests/sharpie/Tests/Availability.macosx.cs b/tests/sharpie/Tests/Availability.macosx.cs
new file mode 100644
index 000000000000..0af20c816cb5
--- /dev/null
+++ b/tests/sharpie/Tests/Availability.macosx.cs
@@ -0,0 +1,75 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface UnavailableWatchOS
+[NoWatch]
+interface UnavailableWatchOS {
+}
+
+// @interface UnavailableTvOS
+[NoTV]
+interface UnavailableTvOS {
+}
+
+// @interface iOSAndMacOnly
+[NoWatch, NoTV, Mac (10, 11), iOS (9, 1)]
+interface iOSAndMacOnly {
+}
+
+// @interface Availability
+[Mac (10, 8), iOS (7, 0)]
+interface Availability {
+ // -(void)thisIsDeprecated __attribute__((availability(macos, deprecated=10.10.3))) __attribute__((availability(ios, deprecated=8.3)));
+ [Deprecated (PlatformName.MacOSX, 10, 10, 3, message: "Don't use this in Mac homie")]
+ [Deprecated (PlatformName.iOS, 8, 3, message: "Don't use this in iOS homie")]
+ [Export ("thisIsDeprecated")]
+ void ThisIsDeprecated ();
+
+ // -(void)thisWasIntroducedThenDeprecatedThenObsoletedMacOnly __attribute__((availability(macos, introduced=10.8.1))) __attribute__((availability(macos, deprecated=10.9))) __attribute__((availability(macos, obsoleted=10.10)));
+ [Introduced (PlatformName.MacOSX, 10, 8, 1)]
+ [Deprecated (PlatformName.MacOSX, 10, 9, message: "Deprecated Message")]
+ [Obsoleted (PlatformName.MacOSX, 10, 10, message: "Obsoleted Message")]
+ [Export ("thisWasIntroducedThenDeprecatedThenObsoletedMacOnly")]
+ void ThisWasIntroducedThenDeprecatedThenObsoletedMacOnly ();
+
+ // -(void)thisWasIntroducedThenDeprecatedThenObsoletedInBothMacAndIos __attribute__((availability(macos, introduced=10.8.1))) __attribute__((availability(macos, deprecated=10.9))) __attribute__((availability(macos, obsoleted=10.10))) __attribute__((availability(ios, introduced=7.0))) __attribute__((availability(ios, deprecated=7.1))) __attribute__((availability(ios, obsoleted=8.0)));
+ [Introduced (PlatformName.MacOSX, 10, 8, 1)]
+ [Deprecated (PlatformName.MacOSX, 10, 9, message: "Mac Deprecated Message")]
+ [Obsoleted (PlatformName.MacOSX, 10, 10, message: "Mac Obsoleted Message")]
+ [Introduced (PlatformName.iOS, 7, 0)]
+ [Deprecated (PlatformName.iOS, 7, 1, message: "iOS Deprecated Message")]
+ [Obsoleted (PlatformName.iOS, 8, 0, message: "iOS Obsoleted Message")]
+ [Export ("thisWasIntroducedThenDeprecatedThenObsoletedInBothMacAndIos")]
+ void ThisWasIntroducedThenDeprecatedThenObsoletedInBothMacAndIos ();
+
+ // -(void)thisShouldBeShorthandMac __attribute__((availability(macos, introduced=10.10.3)));
+ [Mac (10, 10, 3)]
+ [Export ("thisShouldBeShorthandMac")]
+ void ThisShouldBeShorthandMac ();
+
+ // -(void)thisShouldBeShorthandMacOnlyOn64 __attribute__((availability(macos, introduced=10.13.4)));
+ [Mac (10, 13, 4)]
+ [Export ("thisShouldBeShorthandMacOnlyOn64")]
+ void ThisShouldBeShorthandMacOnlyOn64 ();
+
+ // -(void)thisShouldBeShorthandIos __attribute__((availability(ios, introduced=8.3.1)));
+ [iOS (8, 3, 1)]
+ [Export ("thisShouldBeShorthandIos")]
+ void ThisShouldBeShorthandIos ();
+
+ // -(void)thisIsUnavailableOnMac __attribute__((availability(macos, unavailable)));
+ [NoMac]
+ [Export ("thisIsUnavailableOnMac")]
+ void ThisIsUnavailableOnMac ();
+
+ // -(void)thisIsUnavailableOnMacAndIos __attribute__((availability(macos, unavailable))) __attribute__((availability(ios, unavailable)));
+ [NoMac, NoiOS]
+ [Export ("thisIsUnavailableOnMacAndIos")]
+ void ThisIsUnavailableOnMacAndIos ();
+
+ // -(void)introducedOnMac64BitOnlyAndLaterDeprecated __attribute__((availability(macos, introduced=10.13.4))) __attribute__((availability(macos, deprecated=10.13.5)));
+ [Deprecated (PlatformName.MacOSX, 10, 13, 5)]
+ [Mac (10, 13, 4)]
+ [Export ("introducedOnMac64BitOnlyAndLaterDeprecated")]
+ void IntroducedOnMac64BitOnlyAndLaterDeprecated ();
+}
diff --git a/tests/sharpie/Tests/CFRelatedType.cs b/tests/sharpie/Tests/CFRelatedType.cs
new file mode 100644
index 000000000000..008670857654
--- /dev/null
+++ b/tests/sharpie/Tests/CFRelatedType.cs
@@ -0,0 +1,3 @@
+// @interface NSParagraphStyle
+interface NSParagraphStyle {
+}
diff --git a/tests/sharpie/Tests/CFRelatedType.h b/tests/sharpie/Tests/CFRelatedType.h
new file mode 100644
index 000000000000..b07445fcb897
--- /dev/null
+++ b/tests/sharpie/Tests/CFRelatedType.h
@@ -0,0 +1,7 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@interface NSParagraphStyle @end
+#define CF_RELATED_TYPE(T,C,I) __attribute__((objc_bridge_related(T,C,I)))
+typedef const struct CF_RELATED_TYPE(NSParagraphStyle,,) __CTParagraphStyle * CTParagraphStyleRef;
+
diff --git a/tests/sharpie/Tests/Category.cs b/tests/sharpie/Tests/Category.cs
new file mode 100644
index 000000000000..cd7b047c899d
--- /dev/null
+++ b/tests/sharpie/Tests/Category.cs
@@ -0,0 +1,61 @@
+using Foundation;
+
+// @interface Interface
+interface Interface {
+}
+
+// @protocol SomeProtocol
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface SomeProtocol {
+}
+
+// @interface Category (Interface)
+[Category]
+[BaseType (typeof (Interface))]
+interface Interface_Category {
+}
+
+// @interface CategoryWithProtocol (Interface)
+[Category]
+[BaseType (typeof (Interface))]
+interface Interface_CategoryWithProtocol : ISomeProtocol {
+}
+
+// @interface CategoryWithInstanceType (Interface)
+[Category]
+[BaseType (typeof (Interface))]
+interface Interface_CategoryWithInstanceType {
+ // +(instancetype)hello;
+ [Static]
+ [Export ("hello")]
+ Interface Hello ();
+}
+
+// @interface NSString
+interface NSString {
+}
+
+// @interface NSData
+interface NSData {
+}
+
+// @interface Extensions (NSString)
+[Category]
+[BaseType (typeof (NSString))]
+interface NSString_Extensions {
+}
+
+// @interface Extensions (NSData)
+[Category]
+[BaseType (typeof (NSData))]
+interface NSData_Extensions {
+}
diff --git a/tests/sharpie/Tests/Category.h b/tests/sharpie/Tests/Category.h
new file mode 100644
index 000000000000..e05e1c5e3629
--- /dev/null
+++ b/tests/sharpie/Tests/Category.h
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@interface Interface
+@end
+
+@protocol SomeProtocol
+@end
+
+@interface Interface (Category)
+@end
+
+@interface Interface (CategoryWithProtocol)
+@end
+
+@interface Interface (CategoryWithInstanceType)
++(instancetype)hello;
+@end
+
+@interface NSString
+@end
+
+@interface NSData
+@end
+
+@interface NSString (Extensions)
+@end
+
+@interface NSData (Extensions)
+@end
diff --git a/tests/sharpie/Tests/CodeAuditedAttribute.cs b/tests/sharpie/Tests/CodeAuditedAttribute.cs
new file mode 100644
index 000000000000..864d945f7419
--- /dev/null
+++ b/tests/sharpie/Tests/CodeAuditedAttribute.cs
@@ -0,0 +1,8 @@
+using System.Runtime.InteropServices;
+
+static class CFunctions {
+ // extern void DoSomething () ;
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void DoSomething ();
+}
diff --git a/tests/sharpie/Tests/CodeAuditedAttribute.h b/tests/sharpie/Tests/CodeAuditedAttribute.h
new file mode 100644
index 000000000000..2143c703b43c
--- /dev/null
+++ b/tests/sharpie/Tests/CodeAuditedAttribute.h
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// Printing attributes results in clang 20 crashing:
+// UNREACHABLE executed at llvm/bin/tools/clang/include/clang/Sema/AttrSpellingListIndex.inc:14!
+#pragma clang arc_cf_code_audited begin
+void DoSomething();
+#pragma clang arc_cf_code_audited end
diff --git a/tests/sharpie/Tests/CustomMarshalTypes.h b/tests/sharpie/Tests/CustomMarshalTypes.h
new file mode 100644
index 000000000000..82335ab10ea6
--- /dev/null
+++ b/tests/sharpie/Tests/CustomMarshalTypes.h
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN iphoneos: -sdk iphoneos -x objective-c
+// RUN macosx: -sdk macosx -x objective-c
+
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+
+typedef id __nonnull NS_RETURNS_RETAINED (^AHorribleType)( MPSKernel * __nonnull filter, id __nonnull commandBuffer, id __nonnull sourceTexture);
+
+@interface TestObject : NSObject
+
+@property(assign) CGColorRef color;
+@property(assign) CGPathRef path;
+@property(assign) CGGradientRef gradient;
+@property(assign) CGContextRef context;
+@property(assign) CGImageRef image;
+@property(assign) CGImageSourceRef imageSource;
+@property(assign) CGColorSpaceRef colorSpace;
+@property(assign) CGPDFDocumentRef pdfDocument;
+@property(assign) CGPDFPageRef pdfPage;
+
+@property(assign) dispatch_data_t dispatchDataObject;
+@property(assign) sec_identity_t identity2;
+@property(assign) sec_trust_t trust2;
+@property(assign) sec_protocol_options_t protocolOptions;
+@property(assign) sec_protocol_metadata_t protocolMetadata;
+
+@property(assign) CFRunLoopRef runLoop;
+@property(assign) MIDIEndpointRef endpoint;
+@property(assign) CMTimebaseRef timebase;
+@property(assign) CMClockRef clock;
+@property(assign) CMSampleBufferRef sampleBuffer;
+@property(assign) CVImageBufferRef imageBuffer;
+@property(assign) CVPixelBufferRef pixelBuffer;
+@property(assign) CGLayerRef layer;
+@property(assign) CMFormatDescriptionRef formatDescription;
+@property(assign) CMAudioFormatDescriptionRef audioFormatDescription;
+@property(assign) CMVideoFormatDescriptionRef videoFormatDescription;
+@property(assign) SecIdentityRef identity;
+@property(assign) SecTrustRef trust;
+@property(assign) SecAccessControlRef accessControl;
+
+@end
diff --git a/tests/sharpie/Tests/CustomMarshalTypes.iphoneos.cs b/tests/sharpie/Tests/CustomMarshalTypes.iphoneos.cs
new file mode 100644
index 000000000000..429f339c7a11
--- /dev/null
+++ b/tests/sharpie/Tests/CustomMarshalTypes.iphoneos.cs
@@ -0,0 +1,130 @@
+using CoreFoundation;
+using CoreGraphics;
+using CoreMedia;
+using CoreMidi;
+using CoreVideo;
+using Foundation;
+using ImageIO;
+using Metal;
+using MetalPerformanceShaders;
+using ObjCRuntime;
+using Security;
+
+// typedef NS_RETURNS_RETAINED NS_RETURNS_RETAINED id ((^))(MPSKernel * _Nonnull, id _Nonnull, id _Nonnull) AHorribleType;
+delegate IMTLTexture AHorribleType (MPSKernel arg0, IMTLCommandBuffer arg1, IMTLTexture arg2);
+
+// @interface TestObject : NSObject
+[BaseType (typeof (NSObject))]
+interface TestObject {
+ // @property (assign) CGColorRef color;
+ [Export ("color", ArgumentSemantic.Assign)]
+ CGColor Color { get; set; }
+
+ // @property (assign) CGPathRef path;
+ [Export ("path", ArgumentSemantic.Assign)]
+ CGPath Path { get; set; }
+
+ // @property (assign) CGGradientRef gradient;
+ [Export ("gradient", ArgumentSemantic.Assign)]
+ CGGradient Gradient { get; set; }
+
+ // @property (assign) CGContextRef context;
+ [Export ("context", ArgumentSemantic.Assign)]
+ CGContext Context { get; set; }
+
+ // @property (assign) CGImageRef image;
+ [Export ("image", ArgumentSemantic.Assign)]
+ CGImage Image { get; set; }
+
+ // @property (assign) CGImageSourceRef imageSource;
+ [Export ("imageSource", ArgumentSemantic.Assign)]
+ CGImageSource ImageSource { get; set; }
+
+ // @property (assign) CGColorSpaceRef colorSpace;
+ [Export ("colorSpace", ArgumentSemantic.Assign)]
+ CGColorSpace ColorSpace { get; set; }
+
+ // @property (assign) CGPDFDocumentRef pdfDocument;
+ [Export ("pdfDocument", ArgumentSemantic.Assign)]
+ CGPDFDocument PdfDocument { get; set; }
+
+ // @property (assign) CGPDFPageRef pdfPage;
+ [Export ("pdfPage", ArgumentSemantic.Assign)]
+ CGPDFPage PdfPage { get; set; }
+
+ // @property (assign) dispatch_data_t dispatchDataObject;
+ [Export ("dispatchDataObject", ArgumentSemantic.Assign)]
+ DispatchData DispatchDataObject { get; set; }
+
+ // @property (assign) sec_identity_t identity2;
+ [Export ("identity2", ArgumentSemantic.Assign)]
+ SecIdentity2 Identity2 { get; set; }
+
+ // @property (assign) sec_trust_t trust2;
+ [Export ("trust2", ArgumentSemantic.Assign)]
+ SecTrust2 Trust2 { get; set; }
+
+ // @property (assign) sec_protocol_options_t protocolOptions;
+ [Export ("protocolOptions", ArgumentSemantic.Assign)]
+ SecProtocolOptions ProtocolOptions { get; set; }
+
+ // @property (assign) sec_protocol_metadata_t protocolMetadata;
+ [Export ("protocolMetadata", ArgumentSemantic.Assign)]
+ SecProtocolMetadata ProtocolMetadata { get; set; }
+
+ // @property (assign) CFRunLoopRef runLoop;
+ [Export ("runLoop", ArgumentSemantic.Assign)]
+ CFRunLoop RunLoop { get; set; }
+
+ // @property (assign) MIDIEndpointRef endpoint;
+ [Export ("endpoint", ArgumentSemantic.Assign)]
+ MidiEndpoint Endpoint { get; set; }
+
+ // @property (assign) CMTimebaseRef timebase;
+ [Export ("timebase", ArgumentSemantic.Assign)]
+ CMTimebase Timebase { get; set; }
+
+ // @property (assign) CMClockRef clock;
+ [Export ("clock", ArgumentSemantic.Assign)]
+ CMClock Clock { get; set; }
+
+ // @property (assign) CMSampleBufferRef sampleBuffer;
+ [Export ("sampleBuffer", ArgumentSemantic.Assign)]
+ CMSampleBuffer SampleBuffer { get; set; }
+
+ // @property (assign) CVImageBufferRef imageBuffer;
+ [Export ("imageBuffer", ArgumentSemantic.Assign)]
+ CVImageBuffer ImageBuffer { get; set; }
+
+ // @property (assign) CVPixelBufferRef pixelBuffer;
+ [Export ("pixelBuffer", ArgumentSemantic.Assign)]
+ CVPixelBuffer PixelBuffer { get; set; }
+
+ // @property (assign) CGLayerRef layer;
+ [Export ("layer", ArgumentSemantic.Assign)]
+ CGLayer Layer { get; set; }
+
+ // @property (assign) CMFormatDescriptionRef formatDescription;
+ [Export ("formatDescription", ArgumentSemantic.Assign)]
+ CMFormatDescription FormatDescription { get; set; }
+
+ // @property (assign) CMAudioFormatDescriptionRef audioFormatDescription;
+ [Export ("audioFormatDescription", ArgumentSemantic.Assign)]
+ CMAudioFormatDescription AudioFormatDescription { get; set; }
+
+ // @property (assign) CMVideoFormatDescriptionRef videoFormatDescription;
+ [Export ("videoFormatDescription", ArgumentSemantic.Assign)]
+ CMVideoFormatDescription VideoFormatDescription { get; set; }
+
+ // @property (assign) SecIdentityRef identity;
+ [Export ("identity", ArgumentSemantic.Assign)]
+ SecIdentity Identity { get; set; }
+
+ // @property (assign) SecTrustRef trust;
+ [Export ("trust", ArgumentSemantic.Assign)]
+ SecTrust Trust { get; set; }
+
+ // @property (assign) SecAccessControlRef accessControl;
+ [Export ("accessControl", ArgumentSemantic.Assign)]
+ SecAccessControl AccessControl { get; set; }
+}
diff --git a/tests/sharpie/Tests/CustomMarshalTypes.macosx.cs b/tests/sharpie/Tests/CustomMarshalTypes.macosx.cs
new file mode 100644
index 000000000000..429f339c7a11
--- /dev/null
+++ b/tests/sharpie/Tests/CustomMarshalTypes.macosx.cs
@@ -0,0 +1,130 @@
+using CoreFoundation;
+using CoreGraphics;
+using CoreMedia;
+using CoreMidi;
+using CoreVideo;
+using Foundation;
+using ImageIO;
+using Metal;
+using MetalPerformanceShaders;
+using ObjCRuntime;
+using Security;
+
+// typedef NS_RETURNS_RETAINED NS_RETURNS_RETAINED id ((^))(MPSKernel * _Nonnull, id _Nonnull, id _Nonnull) AHorribleType;
+delegate IMTLTexture AHorribleType (MPSKernel arg0, IMTLCommandBuffer arg1, IMTLTexture arg2);
+
+// @interface TestObject : NSObject
+[BaseType (typeof (NSObject))]
+interface TestObject {
+ // @property (assign) CGColorRef color;
+ [Export ("color", ArgumentSemantic.Assign)]
+ CGColor Color { get; set; }
+
+ // @property (assign) CGPathRef path;
+ [Export ("path", ArgumentSemantic.Assign)]
+ CGPath Path { get; set; }
+
+ // @property (assign) CGGradientRef gradient;
+ [Export ("gradient", ArgumentSemantic.Assign)]
+ CGGradient Gradient { get; set; }
+
+ // @property (assign) CGContextRef context;
+ [Export ("context", ArgumentSemantic.Assign)]
+ CGContext Context { get; set; }
+
+ // @property (assign) CGImageRef image;
+ [Export ("image", ArgumentSemantic.Assign)]
+ CGImage Image { get; set; }
+
+ // @property (assign) CGImageSourceRef imageSource;
+ [Export ("imageSource", ArgumentSemantic.Assign)]
+ CGImageSource ImageSource { get; set; }
+
+ // @property (assign) CGColorSpaceRef colorSpace;
+ [Export ("colorSpace", ArgumentSemantic.Assign)]
+ CGColorSpace ColorSpace { get; set; }
+
+ // @property (assign) CGPDFDocumentRef pdfDocument;
+ [Export ("pdfDocument", ArgumentSemantic.Assign)]
+ CGPDFDocument PdfDocument { get; set; }
+
+ // @property (assign) CGPDFPageRef pdfPage;
+ [Export ("pdfPage", ArgumentSemantic.Assign)]
+ CGPDFPage PdfPage { get; set; }
+
+ // @property (assign) dispatch_data_t dispatchDataObject;
+ [Export ("dispatchDataObject", ArgumentSemantic.Assign)]
+ DispatchData DispatchDataObject { get; set; }
+
+ // @property (assign) sec_identity_t identity2;
+ [Export ("identity2", ArgumentSemantic.Assign)]
+ SecIdentity2 Identity2 { get; set; }
+
+ // @property (assign) sec_trust_t trust2;
+ [Export ("trust2", ArgumentSemantic.Assign)]
+ SecTrust2 Trust2 { get; set; }
+
+ // @property (assign) sec_protocol_options_t protocolOptions;
+ [Export ("protocolOptions", ArgumentSemantic.Assign)]
+ SecProtocolOptions ProtocolOptions { get; set; }
+
+ // @property (assign) sec_protocol_metadata_t protocolMetadata;
+ [Export ("protocolMetadata", ArgumentSemantic.Assign)]
+ SecProtocolMetadata ProtocolMetadata { get; set; }
+
+ // @property (assign) CFRunLoopRef runLoop;
+ [Export ("runLoop", ArgumentSemantic.Assign)]
+ CFRunLoop RunLoop { get; set; }
+
+ // @property (assign) MIDIEndpointRef endpoint;
+ [Export ("endpoint", ArgumentSemantic.Assign)]
+ MidiEndpoint Endpoint { get; set; }
+
+ // @property (assign) CMTimebaseRef timebase;
+ [Export ("timebase", ArgumentSemantic.Assign)]
+ CMTimebase Timebase { get; set; }
+
+ // @property (assign) CMClockRef clock;
+ [Export ("clock", ArgumentSemantic.Assign)]
+ CMClock Clock { get; set; }
+
+ // @property (assign) CMSampleBufferRef sampleBuffer;
+ [Export ("sampleBuffer", ArgumentSemantic.Assign)]
+ CMSampleBuffer SampleBuffer { get; set; }
+
+ // @property (assign) CVImageBufferRef imageBuffer;
+ [Export ("imageBuffer", ArgumentSemantic.Assign)]
+ CVImageBuffer ImageBuffer { get; set; }
+
+ // @property (assign) CVPixelBufferRef pixelBuffer;
+ [Export ("pixelBuffer", ArgumentSemantic.Assign)]
+ CVPixelBuffer PixelBuffer { get; set; }
+
+ // @property (assign) CGLayerRef layer;
+ [Export ("layer", ArgumentSemantic.Assign)]
+ CGLayer Layer { get; set; }
+
+ // @property (assign) CMFormatDescriptionRef formatDescription;
+ [Export ("formatDescription", ArgumentSemantic.Assign)]
+ CMFormatDescription FormatDescription { get; set; }
+
+ // @property (assign) CMAudioFormatDescriptionRef audioFormatDescription;
+ [Export ("audioFormatDescription", ArgumentSemantic.Assign)]
+ CMAudioFormatDescription AudioFormatDescription { get; set; }
+
+ // @property (assign) CMVideoFormatDescriptionRef videoFormatDescription;
+ [Export ("videoFormatDescription", ArgumentSemantic.Assign)]
+ CMVideoFormatDescription VideoFormatDescription { get; set; }
+
+ // @property (assign) SecIdentityRef identity;
+ [Export ("identity", ArgumentSemantic.Assign)]
+ SecIdentity Identity { get; set; }
+
+ // @property (assign) SecTrustRef trust;
+ [Export ("trust", ArgumentSemantic.Assign)]
+ SecTrust Trust { get; set; }
+
+ // @property (assign) SecAccessControlRef accessControl;
+ [Export ("accessControl", ArgumentSemantic.Assign)]
+ SecAccessControl AccessControl { get; set; }
+}
diff --git a/tests/sharpie/Tests/Enums.cxx11.cs b/tests/sharpie/Tests/Enums.cxx11.cs
new file mode 100644
index 000000000000..1c7fdba3210b
--- /dev/null
+++ b/tests/sharpie/Tests/Enums.cxx11.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Runtime.InteropServices;
+using ObjCRuntime;
+
+[Native]
+public enum StronglyTypedObjCOrCXXEnum : long {
+ Zero = 0,
+ One = 1
+}
+
+public enum TypedefEnum : uint {
+ One,
+ Two,
+ Three
+}
+
+public enum TestNameFixOne : uint {
+ A,
+ B,
+ C
+}
+
+public enum ThisWasRenamedByATypedef : uint {
+ A,
+ B
+}
+
+static class CFunctions {
+ // enum TestNameFixOne GetTestNameFixOne ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern TestNameFixOne GetTestNameFixOne ();
+
+ // extern void ConsumeForwardDeclaredCxx11ScopedEnum (ForwardDeclaredCxx11ScopedEnum e);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void ConsumeForwardDeclaredCxx11ScopedEnum (ForwardDeclaredCxx11ScopedEnum e);
+}
+
+public enum ConstantExpressionEnum : uint {
+ Implicit,
+ One = 1,
+ OneChar = 97,
+ FourChars = 1633837924,
+ Maths = (1 + 2) / 3 * 10,
+ MathsWithChars = (122 - 119) * 542070098,
+ EscapeChars = 571017762
+}
+
+[Native]
+public enum DeclRefExprEnum : long {
+ One = 1,
+ Two = 2,
+ Three = One + Two
+}
+
+public enum UnaryExprOrTypeTraitExprEnum : uint {
+ SizeOf = 8
+}
+
+public enum TypedefFirstAnonEnum : uint {
+ All = 0,
+ One,
+ Two
+}
+
+public enum TypedefSecondAnonEnum : uint {
+ All = 0,
+ One,
+ Two
+}
+
+public enum TypedefFirstNamedEnum : uint {
+ TdFirstNamedAll = 0
+}
+
+public enum AnonymousEnum1 : uint {
+ AnonEnumFollowingTypedefedEnum
+}
+
+public enum LongAndUnsignedConstants : ulong {
+ Int32Max = 2147483647,
+ Int32MaxPlusOne = 2147483648L,
+ Int64Max = 9223372036854775807L,
+ Int64MaxPlusOne = 9223372036854775808uL
+}
+
+public enum Shifts : uint {
+ Sh1 = 1u << 1,
+ Sh2 = 1u << 2,
+ Sh3 = 1u << 3,
+ Sh4 = 1u << 4
+}
+
+[Verify (InferredFromMemberPrefix)]
+public enum FullyAnonEnum : uint {
+ Zero,
+ One
+}
+
+public enum TypedefAnonCEnum : uint {
+ Zero,
+ One,
+ Two = 1 + 1
+}
+
+public enum NamedCEnum : uint {
+ NamedCEnumZero
+}
+
+public enum NamedCEnumRenamedByTypedef : uint {
+ NamedCEnumToBeRenamedByTypedefZero
+}
+
+public enum NamedCEnumRenamedByInlineTypedef : uint {
+ NamedCEnumToBeRenamedByInlineTypedefZero
+}
+
+public enum SugarLevelFourEnum : uint {
+ FullyDesugaredEnumZero
+}
+
+public enum Cxx11EnumClass {
+ Zero,
+ One,
+ Two
+}
+
+[Native]
+public enum Cxx11TypedEnumClass : ulong {
+ Zero,
+ One,
+ Two
+}
+
+public enum Cxx11EnumStruct {
+ Zero,
+ One,
+ Two
+}
+
+[Native]
+public enum Cxx11TypedEnumStruct : long {
+ Zero
+}
+
+[Flags]
+public enum NSActivityOptions : ulong {
+ IdleDisplaySleepDisabled = (1uL << 40),
+ IdleSystemSleepDisabled = (1uL << 20),
+ SuddenTerminationDisabled = (1uL << 14),
+ AutomaticTerminationDisabled = (1uL << 15),
+ UserInitiated = (0xffffff | IdleSystemSleepDisabled),
+ UserInitiatedAllowingIdleSystemSleep = (UserInitiated & ~IdleSystemSleepDisabled),
+ Background = 0xff,
+ LatencyCritical = 0xff00000000L
+}
diff --git a/tests/sharpie/Tests/Enums.h b/tests/sharpie/Tests/Enums.h
new file mode 100644
index 000000000000..cf13bd7e6110
--- /dev/null
+++ b/tests/sharpie/Tests/Enums.h
@@ -0,0 +1,175 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN cxx11: -xc++ -std=c++11 -Wno-elaborated-enum-base
+// RUN objc: -xobjective-c
+
+typedef long NSInteger;
+
+enum StronglyTypedObjCOrCXXEnum : NSInteger {
+ Zero = 0,
+ One = 1
+};
+
+typedef enum {
+ TypedefEnumOne,
+ TypedefEnumTwo,
+ TypedefEnumThree
+} TypedefEnum;
+
+enum TestNameFixOne {
+ kTestNameFixOneA,
+ kTestNameFixOneB,
+ kTestNameFixOneC
+};
+
+enum ToBeRenamedByTypedef {
+ ToBeRenamedByTypedefA,
+ ToBeRenamedByTypedefB
+};
+
+extern enum TestNameFixOne GetTestNameFixOne ();
+
+enum ConstantExpressionEnum {
+ ConstantExpressionEnumImplicit,
+ ConstantExpressionEnumOne = 1,
+ ConstantExpressionEnum_OneChar = 'a',
+ ConstantExpressionEnum_FourChars = 'abcd',
+ ConstantExpressionEnum_Maths = (1 + 2) / 3 * 10,
+ ConstantExpressionEnum_MathsWithChars = ('z' - 'w') * ' OUR',
+ ConstantExpressionEnum_EscapeChars = '"\t\n"'
+};
+
+typedef enum ToBeRenamedByTypedef ThisWasRenamedByATypedef;
+
+enum DeclRefExprEnum : NSInteger {
+ DREOne = 1,
+ DRETwo = 2,
+ DREThree = DREOne + DRETwo
+};
+
+enum UnaryExprOrTypeTraitExprEnum {
+ SizeOf = sizeof (long)
+};
+
+typedef enum {
+ TD_FIRST_ANON_ALL = 0,
+ TD_FIRST_ANON_ONE,
+ TD_FIRST_ANON_TWO
+} TYPEDEF_FIRST_ANON_ENUM;
+
+typedef enum {
+ TD_SECOND_ANON_ALL = 0,
+ TD_SECOND_ANON_ONE,
+ TD_SECOND_ANON_TWO
+} TYPEDEF_SECOND_ANON_ENUM;
+
+typedef enum TD_FIRST_NAMED_ENUM {
+ TD_FIRST_NAMED_ALL = 0
+} TYPEDEF_FIRST_NAMED_ENUM;
+
+enum {
+ ANON_ENUM_FOLLOWING_TYPEDEFED_ENUM
+};
+
+enum LongAndUnsignedConstants : unsigned long long {
+ Int32Max = 2147483647U, // should be written as Int32
+ Int32MaxPlusOne = 2147483648U, // should be written as UInt32
+ Int64Max = 9223372036854775807ULL, // should be written as Int64
+ Int64MaxPlusOne = 9223372036854775808ULL, // should be written as Int64
+};
+
+enum Shifts : unsigned {
+ Sh1 = 1 << 1,
+ Sh2 = 1 << 2,
+ Sh3 = 1 << 3,
+ Sh4 = 1 << 4
+};
+
+enum {
+ FullyAnonEnumZero,
+ FullyAnonEnumOne
+};
+
+typedef enum {
+ TypedefAnonCEnumZero,
+ TypedefAnonCEnumOne,
+ TypedefAnonCEnumTwo = 1 + 1
+} TypedefAnonCEnum;
+
+enum NamedCEnum {
+ NamedCEnumZero
+};
+
+enum NamedCEnumToBeRenamedByTypedef {
+ NamedCEnumToBeRenamedByTypedefZero
+};
+
+typedef enum NamedCEnumToBeRenamedByTypedef NamedCEnumRenamedByTypedef;
+
+typedef enum NamedCEnumToBeRenamedByInlineTypedef {
+ NamedCEnumToBeRenamedByInlineTypedefZero
+} NamedCEnumRenamedByInlineTypedef;
+
+// Sugaring Test - should be bound as 'SugarLevelFourEnum'
+enum FullyDesugaredEnum {
+ FullyDesugaredEnumZero
+};
+
+typedef enum FullyDesugaredEnum SugarLevelOneEnum;
+typedef SugarLevelOneEnum SugarLevelTwoEnum;
+typedef SugarLevelTwoEnum SugarLevelThreeEnum;
+typedef SugarLevelThreeEnum SugarLevelFourEnum;
+
+#if defined(__cplusplus)
+
+enum class Cxx11EnumClass {
+ Zero,
+ One,
+ Two
+};
+
+enum class Cxx11TypedEnumClass : unsigned long {
+ Zero,
+ One,
+ Two
+};
+
+enum struct Cxx11EnumStruct {
+ Zero,
+ One,
+ Two
+};
+
+enum struct Cxx11TypedEnumStruct : long {
+ Zero
+};
+
+enum class ForwardDeclaredCxx11ScopedEnum : long;
+
+extern "C" void ConsumeForwardDeclaredCxx11ScopedEnum (ForwardDeclaredCxx11ScopedEnum e);
+
+#else
+
+enum ForwardDeclaredCEnum;
+
+extern void ConsumeForwardDeclaredCEnum (enum ForwardDeclaredCEnum e);
+
+#endif
+
+typedef unsigned long long uint64_t;
+
+// https://github.com/xamarin/ObjectiveSharpie/issues/106
+
+typedef enum __attribute__((flag_enum,enum_extensibility(open))) NSActivityOptions : uint64_t NSActivityOptions;
+
+enum NSActivityOptions : uint64_t {
+ NSActivityIdleDisplaySleepDisabled = (1ULL << 40),
+ NSActivityIdleSystemSleepDisabled = (1ULL << 20),
+ NSActivitySuddenTerminationDisabled = (1ULL << 14),
+ NSActivityAutomaticTerminationDisabled = (1ULL << 15),
+ NSActivityUserInitiated = (0x00FFFFFFULL | NSActivityIdleSystemSleepDisabled),
+ NSActivityUserInitiatedAllowingIdleSystemSleep = (NSActivityUserInitiated & ~NSActivityIdleSystemSleepDisabled),
+ NSActivityBackground = 0x000000FFULL,
+ NSActivityLatencyCritical = 0xFF00000000ULL
+};
diff --git a/tests/sharpie/Tests/Enums.objc.cs b/tests/sharpie/Tests/Enums.objc.cs
new file mode 100644
index 000000000000..5ce4b5c3d8cf
--- /dev/null
+++ b/tests/sharpie/Tests/Enums.objc.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Runtime.InteropServices;
+using ObjCRuntime;
+
+[Native]
+public enum StronglyTypedObjCOrCXXEnum : long {
+ Zero = 0,
+ One = 1
+}
+
+public enum TypedefEnum : uint {
+ One,
+ Two,
+ Three
+}
+
+public enum TestNameFixOne : uint {
+ A,
+ B,
+ C
+}
+
+public enum ThisWasRenamedByATypedef : uint {
+ A,
+ B
+}
+
+static class CFunctions {
+ // extern enum TestNameFixOne GetTestNameFixOne ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern TestNameFixOne GetTestNameFixOne ();
+
+ // extern void ConsumeForwardDeclaredCEnum (enum ForwardDeclaredCEnum e);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void ConsumeForwardDeclaredCEnum (ForwardDeclaredCEnum e);
+}
+
+public enum ConstantExpressionEnum : uint {
+ Implicit,
+ One = 1,
+ OneChar = 97,
+ FourChars = 1633837924,
+ Maths = (1 + 2) / 3 * 10,
+ MathsWithChars = (122 - 119) * 542070098,
+ EscapeChars = 571017762
+}
+
+[Native]
+public enum DeclRefExprEnum : long {
+ One = 1,
+ Two = 2,
+ Three = One + Two
+}
+
+public enum UnaryExprOrTypeTraitExprEnum : uint {
+ SizeOf = 8
+}
+
+public enum TypedefFirstAnonEnum : uint {
+ All = 0,
+ One,
+ Two
+}
+
+public enum TypedefSecondAnonEnum : uint {
+ All = 0,
+ One,
+ Two
+}
+
+public enum TypedefFirstNamedEnum : uint {
+ TdFirstNamedAll = 0
+}
+
+public enum AnonymousEnum1 : uint {
+ AnonEnumFollowingTypedefedEnum
+}
+
+public enum LongAndUnsignedConstants : ulong {
+ Int32Max = 2147483647,
+ Int32MaxPlusOne = 2147483648L,
+ Int64Max = 9223372036854775807L,
+ Int64MaxPlusOne = 9223372036854775808uL
+}
+
+public enum Shifts : uint {
+ Sh1 = 1u << 1,
+ Sh2 = 1u << 2,
+ Sh3 = 1u << 3,
+ Sh4 = 1u << 4
+}
+
+[Verify (InferredFromMemberPrefix)]
+public enum FullyAnonEnum : uint {
+ Zero,
+ One
+}
+
+public enum TypedefAnonCEnum : uint {
+ Zero,
+ One,
+ Two = 1 + 1
+}
+
+public enum NamedCEnum : uint {
+ NamedCEnumZero
+}
+
+public enum NamedCEnumRenamedByTypedef : uint {
+ NamedCEnumToBeRenamedByTypedefZero
+}
+
+public enum NamedCEnumRenamedByInlineTypedef : uint {
+ NamedCEnumToBeRenamedByInlineTypedefZero
+}
+
+public enum SugarLevelFourEnum : uint {
+ FullyDesugaredEnumZero
+}
+
+[Flags]
+public enum NSActivityOptions : ulong {
+ IdleDisplaySleepDisabled = (1uL << 40),
+ IdleSystemSleepDisabled = (1uL << 20),
+ SuddenTerminationDisabled = (1uL << 14),
+ AutomaticTerminationDisabled = (1uL << 15),
+ UserInitiated = (0xffffff | IdleSystemSleepDisabled),
+ UserInitiatedAllowingIdleSystemSleep = (UserInitiated & ~IdleSystemSleepDisabled),
+ Background = 0xff,
+ LatencyCritical = 0xff00000000L
+}
diff --git a/tests/sharpie/Tests/Expressions.h b/tests/sharpie/Tests/Expressions.h
new file mode 100644
index 000000000000..a39a2bf0ba9b
--- /dev/null
+++ b/tests/sharpie/Tests/Expressions.h
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx_x86_64: -sdk macosx -arch x86_64
+// RUN iphoneos_arm64: -sdk iphoneos -arch arm64
+// RUN macosx_arm64: -sdk macosx -arch arm64
+
+#define Celcius
+
+struct SomeStruct {
+ char buf [32];
+};
+
+enum Expressions
+{
+ // Literals
+ One = 1,
+ Char = 'a',
+ FourCC = 'beer',
+
+ // Binary
+ Add = 1 + 2,
+ Subtract = 5 - 3,
+ Multiply = 10 * 4,
+ Divide = 50 / 5,
+ Modulus = 100 % 2,
+ ShiftLeft = 200 << 4,
+ ShiftRight = 16 >> 2,
+ LessThan = 2 < 4,
+ GreaterThan = 4 > 2,
+ LessThanOrEqual = 50 <= 100,
+ GreaterThanOrEqual = 100 >= 50,
+ Equality = 200 == 200,
+ InEquality = 200 != 400,
+ BitwiseAnd = 8 & 4,
+ BitwiseOr = 2 | 1,
+ ExclusiveOr = 4 ^ 2,
+ ConditionalAnd = 2 && 0,
+ ConditionalOr = 2 || 0,
+
+ // Unary
+ Plus = +10,
+ Minus = (int)-273.15 Celcius, // 0 Kelvin, of course
+ Not = !100,
+ BitNot = ~200,
+
+ // C-C-C-C-Combo Breaker!
+ BinaryTreeSimple = 1 + 2 * 3,
+ BinaryTreeParen = ((2 + (3 * (4 / 1) + 8))),
+ ParenSubExpr = (0),
+
+ // TypeTraitExpr
+ SizeofChar = sizeof (char),
+ SizeofShort = sizeof (short),
+ SizeofInt = sizeof (int),
+ SizeofLong = sizeof (long),
+ SizeofLongLong = sizeof (long long),
+ SizeofFloat = sizeof (float),
+ SizeofDouble = sizeof (double),
+ SizeofLongDouble = sizeof (long double),
+ SizeofPointer = sizeof (void *),
+ SizeofSomeStruct = sizeof (struct SomeStruct),
+ SizeofConstArray = sizeof (int [400])
+};
diff --git a/tests/sharpie/Tests/Expressions.iphoneos_arm64.cs b/tests/sharpie/Tests/Expressions.iphoneos_arm64.cs
new file mode 100644
index 000000000000..b839fe2a2bb2
--- /dev/null
+++ b/tests/sharpie/Tests/Expressions.iphoneos_arm64.cs
@@ -0,0 +1,48 @@
+using System.Runtime.InteropServices;
+
+[StructLayout (LayoutKind.Sequential)]
+public struct SomeStruct {
+ public sbyte [] buf;
+}
+
+public enum Expressions {
+ One = 1,
+ Char = 97,
+ FourCC = 1650812274,
+ Add = 1 + 2,
+ Subtract = 5 - 3,
+ Multiply = 10 * 4,
+ Divide = 50 / 5,
+ Modulus = 100 % 2,
+ ShiftLeft = 200 << 4,
+ ShiftRight = 16 >> 2,
+ LessThan = 2 < 4,
+ GreaterThan = 4 > 2,
+ LessThanOrEqual = 50 <= 100,
+ GreaterThanOrEqual = 100 >= 50,
+ Equality = 200 == 200,
+ InEquality = 200 != 400,
+ BitwiseAnd = 8 & 4,
+ BitwiseOr = 2 | 1,
+ ExclusiveOr = 4 ^ 2,
+ ConditionalAnd = 2 && 0,
+ ConditionalOr = 2 || 0,
+ Plus = +10,
+ Minus = (int) -273.15,
+ Not = !100,
+ BitNot = ~200,
+ BinaryTreeSimple = 1 + 2 * 3,
+ BinaryTreeParen = ((2 + (3 * (4 / 1) + 8))),
+ ParenSubExpr = (0),
+ SizeofChar = sizeof (sbyte),
+ SizeofShort = sizeof (short),
+ SizeofInt = sizeof (int),
+ SizeofLong = 8,
+ SizeofLongLong = sizeof (long),
+ SizeofFloat = sizeof (float),
+ SizeofDouble = sizeof (double),
+ SizeofLongDouble = 8,
+ SizeofPointer = 8,
+ SizeofSomeStruct = 32,
+ SizeofConstArray = 1600
+}
diff --git a/tests/sharpie/Tests/Expressions.macosx_arm64.cs b/tests/sharpie/Tests/Expressions.macosx_arm64.cs
new file mode 100644
index 000000000000..b839fe2a2bb2
--- /dev/null
+++ b/tests/sharpie/Tests/Expressions.macosx_arm64.cs
@@ -0,0 +1,48 @@
+using System.Runtime.InteropServices;
+
+[StructLayout (LayoutKind.Sequential)]
+public struct SomeStruct {
+ public sbyte [] buf;
+}
+
+public enum Expressions {
+ One = 1,
+ Char = 97,
+ FourCC = 1650812274,
+ Add = 1 + 2,
+ Subtract = 5 - 3,
+ Multiply = 10 * 4,
+ Divide = 50 / 5,
+ Modulus = 100 % 2,
+ ShiftLeft = 200 << 4,
+ ShiftRight = 16 >> 2,
+ LessThan = 2 < 4,
+ GreaterThan = 4 > 2,
+ LessThanOrEqual = 50 <= 100,
+ GreaterThanOrEqual = 100 >= 50,
+ Equality = 200 == 200,
+ InEquality = 200 != 400,
+ BitwiseAnd = 8 & 4,
+ BitwiseOr = 2 | 1,
+ ExclusiveOr = 4 ^ 2,
+ ConditionalAnd = 2 && 0,
+ ConditionalOr = 2 || 0,
+ Plus = +10,
+ Minus = (int) -273.15,
+ Not = !100,
+ BitNot = ~200,
+ BinaryTreeSimple = 1 + 2 * 3,
+ BinaryTreeParen = ((2 + (3 * (4 / 1) + 8))),
+ ParenSubExpr = (0),
+ SizeofChar = sizeof (sbyte),
+ SizeofShort = sizeof (short),
+ SizeofInt = sizeof (int),
+ SizeofLong = 8,
+ SizeofLongLong = sizeof (long),
+ SizeofFloat = sizeof (float),
+ SizeofDouble = sizeof (double),
+ SizeofLongDouble = 8,
+ SizeofPointer = 8,
+ SizeofSomeStruct = 32,
+ SizeofConstArray = 1600
+}
diff --git a/tests/sharpie/Tests/Expressions.macosx_x86_64.cs b/tests/sharpie/Tests/Expressions.macosx_x86_64.cs
new file mode 100644
index 000000000000..bb562cb5569e
--- /dev/null
+++ b/tests/sharpie/Tests/Expressions.macosx_x86_64.cs
@@ -0,0 +1,48 @@
+using System.Runtime.InteropServices;
+
+[StructLayout (LayoutKind.Sequential)]
+public struct SomeStruct {
+ public sbyte [] buf;
+}
+
+public enum Expressions {
+ One = 1,
+ Char = 97,
+ FourCC = 1650812274,
+ Add = 1 + 2,
+ Subtract = 5 - 3,
+ Multiply = 10 * 4,
+ Divide = 50 / 5,
+ Modulus = 100 % 2,
+ ShiftLeft = 200 << 4,
+ ShiftRight = 16 >> 2,
+ LessThan = 2 < 4,
+ GreaterThan = 4 > 2,
+ LessThanOrEqual = 50 <= 100,
+ GreaterThanOrEqual = 100 >= 50,
+ Equality = 200 == 200,
+ InEquality = 200 != 400,
+ BitwiseAnd = 8 & 4,
+ BitwiseOr = 2 | 1,
+ ExclusiveOr = 4 ^ 2,
+ ConditionalAnd = 2 && 0,
+ ConditionalOr = 2 || 0,
+ Plus = +10,
+ Minus = (int) -273.15,
+ Not = !100,
+ BitNot = ~200,
+ BinaryTreeSimple = 1 + 2 * 3,
+ BinaryTreeParen = ((2 + (3 * (4 / 1) + 8))),
+ ParenSubExpr = (0),
+ SizeofChar = sizeof (sbyte),
+ SizeofShort = sizeof (short),
+ SizeofInt = sizeof (int),
+ SizeofLong = 8,
+ SizeofLongLong = sizeof (long),
+ SizeofFloat = sizeof (float),
+ SizeofDouble = sizeof (double),
+ SizeofLongDouble = 16,
+ SizeofPointer = 8,
+ SizeofSomeStruct = 32,
+ SizeofConstArray = 1600
+}
diff --git a/tests/sharpie/Tests/Fields.h b/tests/sharpie/Tests/Fields.h
new file mode 100644
index 000000000000..d13a6b206622
--- /dev/null
+++ b/tests/sharpie/Tests/Fields.h
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+
+#import
+
+extern NSString *kFirstField;
+extern int *kNextField;
+
+@interface FirstInterface
+@end
+
+extern int64_t FirstFieldAfterFirstInterface;
+extern NSString *SecondFieldAfterFirstInterface;
+
+typedef enum : long {
+ FirstEnumZero,
+ FirstEnumOne = FirstEnumZero + 1
+} FirstEnum;
+
+extern bool FirstFieldAfterFirstEnum;
+
+typedef long LooselyCoupledEnum;
+enum {
+ LooselyCoupledEnumZero,
+ LooselyCoupledEnumOne
+};
+
+extern LooselyCoupledEnum EnumField;
diff --git a/tests/sharpie/Tests/Fields.iphoneos.cs b/tests/sharpie/Tests/Fields.iphoneos.cs
new file mode 100644
index 000000000000..f0da988a65f0
--- /dev/null
+++ b/tests/sharpie/Tests/Fields.iphoneos.cs
@@ -0,0 +1,59 @@
+using System;
+using Foundation;
+using ObjCRuntime;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSString * kFirstField;
+ [Field ("kFirstField", "__Internal")]
+ NSString kFirstField { get; }
+
+ // extern int * kNextField;
+ [Field ("kNextField", "__Internal")]
+ unsafe int* kNextField { get; }
+}
+
+// @interface FirstInterface
+interface FirstInterface {
+}
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern int64_t FirstFieldAfterFirstInterface;
+ [Field ("FirstFieldAfterFirstInterface", "__Internal")]
+ long FirstFieldAfterFirstInterface { get; }
+
+ // extern NSString * SecondFieldAfterFirstInterface;
+ [Field ("SecondFieldAfterFirstInterface", "__Internal")]
+ NSString SecondFieldAfterFirstInterface { get; }
+}
+
+[Native]
+public enum FirstEnum : long {
+ Zero,
+ One = Zero + 1
+}
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool FirstFieldAfterFirstEnum;
+ [Field ("FirstFieldAfterFirstEnum", "__Internal")]
+ bool FirstFieldAfterFirstEnum { get; }
+}
+
+[Verify (InferredFromMemberPrefix)]
+public enum LooselyCoupledEnum : uint {
+ Zero,
+ One
+}
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern LooselyCoupledEnum EnumField;
+ [Field ("EnumField", "__Internal")]
+ nint EnumField { get; }
+}
diff --git a/tests/sharpie/Tests/Fields.macosx.cs b/tests/sharpie/Tests/Fields.macosx.cs
new file mode 100644
index 000000000000..f0da988a65f0
--- /dev/null
+++ b/tests/sharpie/Tests/Fields.macosx.cs
@@ -0,0 +1,59 @@
+using System;
+using Foundation;
+using ObjCRuntime;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSString * kFirstField;
+ [Field ("kFirstField", "__Internal")]
+ NSString kFirstField { get; }
+
+ // extern int * kNextField;
+ [Field ("kNextField", "__Internal")]
+ unsafe int* kNextField { get; }
+}
+
+// @interface FirstInterface
+interface FirstInterface {
+}
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern int64_t FirstFieldAfterFirstInterface;
+ [Field ("FirstFieldAfterFirstInterface", "__Internal")]
+ long FirstFieldAfterFirstInterface { get; }
+
+ // extern NSString * SecondFieldAfterFirstInterface;
+ [Field ("SecondFieldAfterFirstInterface", "__Internal")]
+ NSString SecondFieldAfterFirstInterface { get; }
+}
+
+[Native]
+public enum FirstEnum : long {
+ Zero,
+ One = Zero + 1
+}
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool FirstFieldAfterFirstEnum;
+ [Field ("FirstFieldAfterFirstEnum", "__Internal")]
+ bool FirstFieldAfterFirstEnum { get; }
+}
+
+[Verify (InferredFromMemberPrefix)]
+public enum LooselyCoupledEnum : uint {
+ Zero,
+ One
+}
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern LooselyCoupledEnum EnumField;
+ [Field ("EnumField", "__Internal")]
+ nint EnumField { get; }
+}
diff --git a/tests/sharpie/Tests/Functions.h b/tests/sharpie/Tests/Functions.h
new file mode 100644
index 000000000000..a2059b9ce49d
--- /dev/null
+++ b/tests/sharpie/Tests/Functions.h
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -x objective-c -sdk macosx
+// RUN iphoneos: -x objective-c -sdk iphoneos
+
+#include
+
+extern void Action ();
+extern void ActionTakingInt (int i);
+extern void ActionTakingIntAndCString (int i, const char *str);
+extern char *FuncTakingInt (int i);
+
+// interesting - if you redeclare this as 'snprintf' even if you do not
+// include stdio.h, Clang provides a builtin Decl to preceed it.
+extern int __snprintf (char * restrict str, size_t size, const char * restrict format, ...);
+
+@interface ObjCMethods
+-(void)action;
+-(void)actionTakingInt:(int)i;
+-(void)actionTakingInt:(int)i andCString:(const char *)str;
+-(char *)funcTakingInt:(int)i;
+
++(int)snprintf:(char * restrict)str ofSize:(size_t)size withFormat:(const char * restrict) format, ...;
+@end
diff --git a/tests/sharpie/Tests/Functions.iphoneos.cs b/tests/sharpie/Tests/Functions.iphoneos.cs
new file mode 100644
index 000000000000..5943c3824867
--- /dev/null
+++ b/tests/sharpie/Tests/Functions.iphoneos.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.InteropServices;
+using Foundation;
+
+static class CFunctions {
+ // extern void Action ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void Action ();
+
+ // extern void ActionTakingInt (int i);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void ActionTakingInt (int i);
+
+ // extern void ActionTakingIntAndCString (int i, const char *str);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe void ActionTakingIntAndCString (int i, sbyte* str);
+
+ // extern char * FuncTakingInt (int i);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe sbyte* FuncTakingInt (int i);
+
+ // extern int __snprintf (char *restrict str, size_t size, const char *restrict format, ...);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int __snprintf (sbyte* str, nuint size, sbyte* format, IntPtr varArgs);
+}
+
+// @interface ObjCMethods
+interface ObjCMethods {
+ // -(void)action;
+ [Export ("action")]
+ void Action ();
+
+ // -(void)actionTakingInt:(int)i;
+ [Export ("actionTakingInt:")]
+ void ActionTakingInt (int i);
+
+ // -(void)actionTakingInt:(int)i andCString:(const char *)str;
+ [Export ("actionTakingInt:andCString:")]
+ unsafe void ActionTakingInt (int i, sbyte* str);
+
+ // -(char *)funcTakingInt:(int)i;
+ [Export ("funcTakingInt:")]
+ unsafe sbyte* FuncTakingInt (int i);
+
+ // +(int)snprintf:(char *restrict)str ofSize:(size_t)size withFormat:(const char *restrict)format, ...;
+ [Static, Internal]
+ [Export ("snprintf:ofSize:withFormat:", IsVariadic = true)]
+ unsafe int Snprintf (sbyte* str, nuint size, sbyte* format, IntPtr varArgs);
+}
diff --git a/tests/sharpie/Tests/Functions.macosx.cs b/tests/sharpie/Tests/Functions.macosx.cs
new file mode 100644
index 000000000000..5943c3824867
--- /dev/null
+++ b/tests/sharpie/Tests/Functions.macosx.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.InteropServices;
+using Foundation;
+
+static class CFunctions {
+ // extern void Action ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void Action ();
+
+ // extern void ActionTakingInt (int i);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void ActionTakingInt (int i);
+
+ // extern void ActionTakingIntAndCString (int i, const char *str);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe void ActionTakingIntAndCString (int i, sbyte* str);
+
+ // extern char * FuncTakingInt (int i);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe sbyte* FuncTakingInt (int i);
+
+ // extern int __snprintf (char *restrict str, size_t size, const char *restrict format, ...);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int __snprintf (sbyte* str, nuint size, sbyte* format, IntPtr varArgs);
+}
+
+// @interface ObjCMethods
+interface ObjCMethods {
+ // -(void)action;
+ [Export ("action")]
+ void Action ();
+
+ // -(void)actionTakingInt:(int)i;
+ [Export ("actionTakingInt:")]
+ void ActionTakingInt (int i);
+
+ // -(void)actionTakingInt:(int)i andCString:(const char *)str;
+ [Export ("actionTakingInt:andCString:")]
+ unsafe void ActionTakingInt (int i, sbyte* str);
+
+ // -(char *)funcTakingInt:(int)i;
+ [Export ("funcTakingInt:")]
+ unsafe sbyte* FuncTakingInt (int i);
+
+ // +(int)snprintf:(char *restrict)str ofSize:(size_t)size withFormat:(const char *restrict)format, ...;
+ [Static, Internal]
+ [Export ("snprintf:ofSize:withFormat:", IsVariadic = true)]
+ unsafe int Snprintf (sbyte* str, nuint size, sbyte* format, IntPtr varArgs);
+}
diff --git a/tests/sharpie/Tests/Interface.cs b/tests/sharpie/Tests/Interface.cs
new file mode 100644
index 000000000000..4bbeeab519a5
--- /dev/null
+++ b/tests/sharpie/Tests/Interface.cs
@@ -0,0 +1,57 @@
+using Foundation;
+
+// @interface Root
+interface Root {
+}
+
+// @interface Sub : Root
+[BaseType (typeof (Root))]
+interface Sub {
+}
+
+// @interface Members
+interface Members {
+ // -(void)instanceMethod;
+ [Export ("instanceMethod")]
+ void InstanceMethod ();
+
+ // -(int)instanceMethod:(int *)takingIntPtr andOutSub:(Sub **)sub;
+ [Export ("instanceMethod:andOutSub:")]
+ unsafe int InstanceMethod (int* takingIntPtr, out Sub sub);
+
+ // +(void)staticMethod;
+ [Static]
+ [Export ("staticMethod")]
+ void StaticMethod ();
+
+ // @property int intProperty;
+ [Export ("intProperty")]
+ int IntProperty { get; set; }
+
+ // @property (readonly) int intPropertyReadonly;
+ [Export ("intPropertyReadonly")]
+ int IntPropertyReadonly { get; }
+
+ // +(int)staticCsharpProperty;
+ [Static]
+ [Export ("staticCsharpProperty")]
+ [Verify (MethodToProperty)]
+ int StaticCsharpProperty { get; }
+
+ // +(void)staticCsharpProperty:(int)value;
+ [Static]
+ [Export ("staticCsharpProperty:")]
+ void StaticCsharpProperty (int value);
+}
+
+// @interface Fields
+interface Fields {
+ // -(int)getIntField;
+ [Export ("getIntField")]
+ [Verify (MethodToProperty)]
+ int IntField { get; }
+
+ // -(void)setIntField:(int)value;
+ [Export ("setIntField:")]
+ void SetIntField (int value);
+}
diff --git a/tests/sharpie/Tests/Interface.h b/tests/sharpie/Tests/Interface.h
new file mode 100644
index 000000000000..d794a40691d5
--- /dev/null
+++ b/tests/sharpie/Tests/Interface.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@interface Root
+@end
+
+@interface Sub : Root
+@end
+
+@interface Members
+-(void)instanceMethod;
+-(int)instanceMethod:(int *)takingIntPtr andOutSub:(Sub **)sub;
++(void)staticMethod;
+@property int intProperty;
+@property (readonly) int intPropertyReadonly;
++(int)staticCsharpProperty;
++(void)staticCsharpProperty:(int)value;
+@end
+
+@interface Fields
+{
+ int intField;
+}
+
+-(int)getIntField;
+-(void)setIntField:(int)value;
+@end
diff --git a/tests/sharpie/Tests/Massagers/BlockReturn.cs b/tests/sharpie/Tests/Massagers/BlockReturn.cs
new file mode 100644
index 000000000000..6844041d8771
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/BlockReturn.cs
@@ -0,0 +1,10 @@
+using System;
+using Foundation;
+
+// @interface Blocks
+interface Blocks {
+ // -(Blocks *(^)(id))get_Func_NSObject_Blocks;
+ [Export ("get_Func_NSObject_Blocks")]
+ [Verify (MethodToProperty)]
+ Func Get_Func_NSObject_Blocks { get; }
+}
diff --git a/tests/sharpie/Tests/Massagers/BlockReturn.h b/tests/sharpie/Tests/Massagers/BlockReturn.h
new file mode 100644
index 000000000000..ccd834b1768f
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/BlockReturn.h
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+//
+// This tests MethodWithNoParametersReturningABlockMassager
+// and GenerateUsingStatementsMassager (to ensure that
+// MemberType's generic type arguments are also visited)
+
+@interface Blocks
+-(Blocks *(^)(id))get_Func_NSObject_Blocks;
+@end
diff --git a/tests/sharpie/Tests/Massagers/DefaultConstructor.cs b/tests/sharpie/Tests/Massagers/DefaultConstructor.cs
new file mode 100644
index 000000000000..4bb5459fbf7c
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/DefaultConstructor.cs
@@ -0,0 +1,8 @@
+// @interface DefaultCtor
+interface DefaultCtor {
+}
+
+// @interface DefaultCtorUnavailable
+[DisableDefaultCtor]
+interface DefaultCtorUnavailable {
+}
diff --git a/tests/sharpie/Tests/Massagers/DefaultConstructor.h b/tests/sharpie/Tests/Massagers/DefaultConstructor.h
new file mode 100644
index 000000000000..056da6b18b10
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/DefaultConstructor.h
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@interface DefaultCtor
+ -(instancetype)init;
+@end
+
+@interface DefaultCtorUnavailable
+ -(instancetype)init __attribute__((availability(macosx,unavailable)));
+@end
diff --git a/tests/sharpie/Tests/Massagers/Delegate.cs b/tests/sharpie/Tests/Massagers/Delegate.cs
new file mode 100644
index 000000000000..f6396fd8e834
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Delegate.cs
@@ -0,0 +1,27 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface PrimaryDelegate
+interface PrimaryDelegate {
+}
+
+// @interface SecondaryDelegate
+interface SecondaryDelegate {
+}
+
+// @interface DelegateConsumer
+interface DelegateConsumer {
+ [Wrap ("WeakDelegate")]
+ PrimaryDelegate Delegate { get; set; }
+
+ // @property (assign) PrimaryDelegate * delegate;
+ [NullAllowed, Export ("delegate", ArgumentSemantic.Assign)]
+ NSObject WeakDelegate { get; set; }
+
+ [Wrap ("WeakSecondaryDelegate")]
+ SecondaryDelegate SecondaryDelegate { get; set; }
+
+ // @property (assign) SecondaryDelegate * secondaryDelegate;
+ [NullAllowed, Export ("secondaryDelegate", ArgumentSemantic.Assign)]
+ NSObject WeakSecondaryDelegate { get; set; }
+}
diff --git a/tests/sharpie/Tests/Massagers/Delegate.h b/tests/sharpie/Tests/Massagers/Delegate.h
new file mode 100644
index 000000000000..a6b7ae835c44
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Delegate.h
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@interface PrimaryDelegate
+@end
+
+@interface SecondaryDelegate
+@end
+
+@interface DelegateConsumer
+ @property (assign) PrimaryDelegate *delegate;
+ @property (assign) SecondaryDelegate *secondaryDelegate;
+@end
diff --git a/tests/sharpie/Tests/Massagers/EnumName.cs b/tests/sharpie/Tests/Massagers/EnumName.cs
new file mode 100644
index 000000000000..1c5a5c942cf2
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/EnumName.cs
@@ -0,0 +1,24 @@
+using System.Runtime.InteropServices;
+using ObjCRuntime;
+
+[Native]
+public enum NintEnum : long {
+ One = 1,
+ Two,
+ Three
+}
+
+static class CFunctions {
+ // extern NINT_ENUM AddOneToNintEnum (NINT_ENUM in);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern NintEnum AddOneToNintEnum (NintEnum @in);
+}
+
+[Native]
+public enum POPAnimationClampFlags : ulong {
+ None = 0,
+ Start = 0uL << 1,
+ End = 1uL << 1,
+ Both = End | Start
+}
diff --git a/tests/sharpie/Tests/Massagers/EnumName.h b/tests/sharpie/Tests/Massagers/EnumName.h
new file mode 100644
index 000000000000..85dd2f78d947
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/EnumName.h
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN: -x objective-c
+
+typedef enum : long {
+ NINT_ENUM_ONE = 1,
+ NINT_ENUM_TWO,
+ NINT_ENUM_THREE
+} NINT_ENUM;
+
+extern NINT_ENUM AddOneToNintEnum (NINT_ENUM in);
+
+typedef enum : unsigned long
+{
+ kPOPAnimationClampNone = 0,
+ kPOPAnimationClampStart = 0 << 1,
+ kPOPAnimationClampEnd = 1 << 1,
+ kPOPAnimationClampBoth = kPOPAnimationClampEnd | kPOPAnimationClampStart
+} POPAnimationClampFlags;
diff --git a/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.h b/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.h
new file mode 100644
index 000000000000..590db3347d48
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.h
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -massage +ExplicitBaseTypeName -x objective-c
+// RUN iphoneos: -sdk iphoneos -massage +ExplicitBaseTypeName -x objective-c
+
+#import
+
+@interface ExplicitBaseType : NSObject
+
+@end
diff --git a/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.iphoneos.cs b/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.iphoneos.cs
new file mode 100644
index 000000000000..a52cd973745c
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.iphoneos.cs
@@ -0,0 +1,4 @@
+// @interface ExplicitBaseType : NSObject
+[BaseType (typeof (NSObject), Name = "ExplicitBaseType")]
+interface ExplicitBaseType {
+}
diff --git a/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.macosx.cs b/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.macosx.cs
new file mode 100644
index 000000000000..a52cd973745c
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ExplicitBaseTypeName.macosx.cs
@@ -0,0 +1,4 @@
+// @interface ExplicitBaseType : NSObject
+[BaseType (typeof (NSObject), Name = "ExplicitBaseType")]
+interface ExplicitBaseType {
+}
diff --git a/tests/sharpie/Tests/Massagers/GroupedAttribute.cs b/tests/sharpie/Tests/Massagers/GroupedAttribute.cs
new file mode 100644
index 000000000000..fe61d736193f
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/GroupedAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using Foundation;
+
+// @protocol Foo
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Mac (10, 9)]
+[Protocol]
+interface Foo {
+ // @required +(id)availability_StaticAbstractInternal_Export:(int)n, ... __attribute__((availability(macos, introduced=10.10))) __attribute__((availability(ios, introduced=8.0)));
+ [Mac (10, 10), iOS (8, 0)]
+ [Static, Internal, Abstract]
+ [Export ("availability_StaticAbstractInternal_Export:", IsVariadic = true)]
+ NSObject Availability_StaticAbstractInternal_Export (int n, IntPtr varArgs);
+}
diff --git a/tests/sharpie/Tests/Massagers/GroupedAttribute.h b/tests/sharpie/Tests/Massagers/GroupedAttribute.h
new file mode 100644
index 000000000000..b10d3da1de1a
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/GroupedAttribute.h
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+__attribute__((availability(macosx,introduced=10.9)))
+@protocol Foo
+@required
++(id)availability_StaticAbstractInternal_Export:(int)n, ...
+ __attribute__((availability(macosx,introduced=10.10)))
+ __attribute__((availability(ios,introduced=8.0)))
+ ;
+@end
diff --git a/tests/sharpie/Tests/Massagers/MethodToProperty.disabled.cs b/tests/sharpie/Tests/Massagers/MethodToProperty.disabled.cs
new file mode 100644
index 000000000000..4a7d9f96ab2c
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/MethodToProperty.disabled.cs
@@ -0,0 +1,24 @@
+using Foundation;
+
+// @interface MethodToProperty
+interface MethodToProperty {
+ // -(bool)isEnabled;
+ [Export ("isEnabled")]
+ bool IsEnabled ();
+
+ // -(void)enable;
+ [Export ("enable")]
+ void Enable ();
+
+ // -(bool)visible;
+ [Export ("visible")]
+ bool Visible ();
+
+ // -(void)setVisible:(bool)visible;
+ [Export ("setVisible:")]
+ void SetVisible (bool visible);
+
+ // -(bool)getState:(int)foo;
+ [Export ("getState:")]
+ bool GetState (int foo);
+}
diff --git a/tests/sharpie/Tests/Massagers/MethodToProperty.enabled.cs b/tests/sharpie/Tests/Massagers/MethodToProperty.enabled.cs
new file mode 100644
index 000000000000..59ec3b625736
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/MethodToProperty.enabled.cs
@@ -0,0 +1,23 @@
+using Foundation;
+
+// @interface MethodToProperty
+interface MethodToProperty {
+ // -(bool)isEnabled;
+ [Export ("isEnabled")]
+ [Verify (MethodToProperty)]
+ bool IsEnabled { get; }
+
+ // -(void)enable;
+ [Export ("enable")]
+ void Enable ();
+
+ // -(bool)visible;
+ // -(void)setVisible:(bool)visible;
+ [Export ("visible")]
+ [Verify (MethodToProperty)]
+ bool Visible { get; set; }
+
+ // -(bool)getState:(int)foo;
+ [Export ("getState:")]
+ bool GetState (int foo);
+}
diff --git a/tests/sharpie/Tests/Massagers/MethodToProperty.h b/tests/sharpie/Tests/Massagers/MethodToProperty.h
new file mode 100644
index 000000000000..a003ae6b81db
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/MethodToProperty.h
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN enabled: -x objective-c
+// RUN disabled: -x objective-c -massage=-MethodToProperty
+
+typedef _Bool bool;
+
+@interface MethodToProperty
+// should become a readonly property
+-(bool)isEnabled;
+
+// should remain a method
+-(void)enable;
+
+// should become a readwrite property
+-(bool)visible;
+-(void)setVisible:(bool)visible;
+
+// should remain a method
+-(bool)getState:(int)foo;
+@end
diff --git a/tests/sharpie/Tests/Massagers/NSArray.h b/tests/sharpie/Tests/Massagers/NSArray.h
new file mode 100644
index 000000000000..ebd5e4c6188a
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/NSArray.h
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+
+#import
+
+@interface NSArrayToArrayOfNSObjectTest
+-(NSArray *)getNSArray;
+@end
diff --git a/tests/sharpie/Tests/Massagers/NSArray.iphoneos.cs b/tests/sharpie/Tests/Massagers/NSArray.iphoneos.cs
new file mode 100644
index 000000000000..f9c9d89853e0
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/NSArray.iphoneos.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+// @interface NSArrayToArrayOfNSObjectTest
+interface NSArrayToArrayOfNSObjectTest {
+ // -(NSArray *)getNSArray;
+ [Export ("getNSArray")]
+ [Verify (MethodToProperty), Verify (StronglyTypedNSArray)]
+ NSObject [] NSArray { get; }
+}
diff --git a/tests/sharpie/Tests/Massagers/NSArray.macosx.cs b/tests/sharpie/Tests/Massagers/NSArray.macosx.cs
new file mode 100644
index 000000000000..f9c9d89853e0
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/NSArray.macosx.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+// @interface NSArrayToArrayOfNSObjectTest
+interface NSArrayToArrayOfNSObjectTest {
+ // -(NSArray *)getNSArray;
+ [Export ("getNSArray")]
+ [Verify (MethodToProperty), Verify (StronglyTypedNSArray)]
+ NSObject [] NSArray { get; }
+}
diff --git a/tests/sharpie/Tests/Massagers/NSUnavailable.h b/tests/sharpie/Tests/Massagers/NSUnavailable.h
new file mode 100644
index 000000000000..2f65b074e9d1
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/NSUnavailable.h
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx
+// RUN iphoneos: -sdk iphoneos
+
+@import Foundation;
+
+@interface DisableDefaultCtorTest
+-(instancetype)init NS_UNAVAILABLE;
+-(instancetype)initWithString:(nonnull NSString *)str;
+@end
diff --git a/tests/sharpie/Tests/Massagers/NSUnavailable.iphoneos.cs b/tests/sharpie/Tests/Massagers/NSUnavailable.iphoneos.cs
new file mode 100644
index 000000000000..89527b35f276
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/NSUnavailable.iphoneos.cs
@@ -0,0 +1,10 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface DisableDefaultCtorTest
+[DisableDefaultCtor]
+interface DisableDefaultCtorTest {
+ // -(instancetype)initWithString:(NSString * _Nonnull)str;
+ [Export ("initWithString:")]
+ NativeHandle Constructor (string str);
+}
diff --git a/tests/sharpie/Tests/Massagers/NSUnavailable.macosx.cs b/tests/sharpie/Tests/Massagers/NSUnavailable.macosx.cs
new file mode 100644
index 000000000000..89527b35f276
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/NSUnavailable.macosx.cs
@@ -0,0 +1,10 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface DisableDefaultCtorTest
+[DisableDefaultCtor]
+interface DisableDefaultCtorTest {
+ // -(instancetype)initWithString:(NSString * _Nonnull)str;
+ [Export ("initWithString:")]
+ NativeHandle Constructor (string str);
+}
diff --git a/tests/sharpie/Tests/Massagers/Namespace.cs b/tests/sharpie/Tests/Massagers/Namespace.cs
new file mode 100644
index 000000000000..931ce4b17f21
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Namespace.cs
@@ -0,0 +1,16 @@
+using Foundation;
+using ObjCRuntime;
+
+namespace CatOverflow {
+ // @interface SuperCats
+ interface SuperCats {
+ // -(void)meow;
+ [Export ("meow")]
+ void Meow ();
+ }
+
+ [Native]
+ public enum CatBehavior : long {
+ CatBehaviorEvil
+ }
+}
diff --git a/tests/sharpie/Tests/Massagers/Namespace.h b/tests/sharpie/Tests/Massagers/Namespace.h
new file mode 100644
index 000000000000..e1035d9ea6d9
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Namespace.h
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN: -namespace CatOverflow -x objective-c
+
+@interface SuperCats
+-(void)meow;
+@end
+
+typedef enum : long {
+ CatBehaviorEvil
+} CatBehavior;
diff --git a/tests/sharpie/Tests/Massagers/ObjCTypes.h b/tests/sharpie/Tests/Massagers/ObjCTypes.h
new file mode 100644
index 000000000000..5468fa131f39
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ObjCTypes.h
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+
+#import
+
+@interface NSArrayToArrayOfNSObjectTest
+-(NSArray *)getNSArray;
+@end
+
+@interface NSArrayOfNSStringToArrayOfStringTest
+-(NSArray *)getStrings;
+@end
+
+@interface NSStringPropertyTest
+@property (copy, readonly) NSString *someString;
+@end
+
+extern NSString * __nullable CFunctionWithNSStringTest (NSString * __nonnull, int c, NSString * __nullable);
diff --git a/tests/sharpie/Tests/Massagers/ObjCTypes.iphoneos.cs b/tests/sharpie/Tests/Massagers/ObjCTypes.iphoneos.cs
new file mode 100644
index 000000000000..734991b8659a
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ObjCTypes.iphoneos.cs
@@ -0,0 +1,33 @@
+using System.Runtime.InteropServices;
+using Foundation;
+
+// @interface NSArrayToArrayOfNSObjectTest
+interface NSArrayToArrayOfNSObjectTest {
+ // -(NSArray *)getNSArray;
+ [Export ("getNSArray")]
+ [Verify (MethodToProperty), Verify (StronglyTypedNSArray)]
+ NSObject [] NSArray { get; }
+}
+
+// @interface NSArrayOfNSStringToArrayOfStringTest
+interface NSArrayOfNSStringToArrayOfStringTest {
+ // -(NSArray *)getStrings;
+ [Export ("getStrings")]
+ [Verify (MethodToProperty)]
+ string [] Strings { get; }
+}
+
+// @interface NSStringPropertyTest
+interface NSStringPropertyTest {
+ // @property (readonly, copy) NSString * someString;
+ [Export ("someString")]
+ string SomeString { get; }
+}
+
+static class CFunctions {
+ // extern NSString * _Nullable CFunctionWithNSStringTest (NSString * _Nonnull , int c, NSString * _Nullable );
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ [return: NullAllowed]
+ static extern NSString CFunctionWithNSStringTest (NSString unnamedParameter0, int c, [NullAllowed] NSString unnamedParameter2);
+}
diff --git a/tests/sharpie/Tests/Massagers/ObjCTypes.macosx.cs b/tests/sharpie/Tests/Massagers/ObjCTypes.macosx.cs
new file mode 100644
index 000000000000..734991b8659a
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ObjCTypes.macosx.cs
@@ -0,0 +1,33 @@
+using System.Runtime.InteropServices;
+using Foundation;
+
+// @interface NSArrayToArrayOfNSObjectTest
+interface NSArrayToArrayOfNSObjectTest {
+ // -(NSArray *)getNSArray;
+ [Export ("getNSArray")]
+ [Verify (MethodToProperty), Verify (StronglyTypedNSArray)]
+ NSObject [] NSArray { get; }
+}
+
+// @interface NSArrayOfNSStringToArrayOfStringTest
+interface NSArrayOfNSStringToArrayOfStringTest {
+ // -(NSArray *)getStrings;
+ [Export ("getStrings")]
+ [Verify (MethodToProperty)]
+ string [] Strings { get; }
+}
+
+// @interface NSStringPropertyTest
+interface NSStringPropertyTest {
+ // @property (readonly, copy) NSString * someString;
+ [Export ("someString")]
+ string SomeString { get; }
+}
+
+static class CFunctions {
+ // extern NSString * _Nullable CFunctionWithNSStringTest (NSString * _Nonnull , int c, NSString * _Nullable );
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ [return: NullAllowed]
+ static extern NSString CFunctionWithNSStringTest (NSString unnamedParameter0, int c, [NullAllowed] NSString unnamedParameter2);
+}
diff --git a/tests/sharpie/Tests/Massagers/PlatformTypeMapping.h b/tests/sharpie/Tests/Massagers/PlatformTypeMapping.h
new file mode 100644
index 000000000000..4ab1a8a53daf
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/PlatformTypeMapping.h
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN iphoneos: -sdk iphoneos
+// RUN macosx: -sdk macosx
+
+@import Foundation;
+
+@interface WebFetcher : NSObject
+@property (nonatomic, readonly, copy) NSURL *url;
+-(NSURLResponse *)getResponseForUrl:(NSURL *)url withCredential:(NSURLCredential *)credential;
+@end
diff --git a/tests/sharpie/Tests/Massagers/PlatformTypeMapping.iphoneos.cs b/tests/sharpie/Tests/Massagers/PlatformTypeMapping.iphoneos.cs
new file mode 100644
index 000000000000..bd219fe54ae0
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/PlatformTypeMapping.iphoneos.cs
@@ -0,0 +1,14 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface WebFetcher : NSObject
+[BaseType (typeof (NSObject))]
+interface WebFetcher : INSUrlConnectionDelegate {
+ // @property (readonly, copy, nonatomic) NSURL * url;
+ [Export ("url", ArgumentSemantic.Copy)]
+ NSUrl Url { get; }
+
+ // -(NSURLResponse *)getResponseForUrl:(NSURL *)url withCredential:(NSURLCredential *)credential;
+ [Export ("getResponseForUrl:withCredential:")]
+ NSUrlResponse GetResponseForUrl (NSUrl url, NSUrlCredential credential);
+}
diff --git a/tests/sharpie/Tests/Massagers/PlatformTypeMapping.macosx.cs b/tests/sharpie/Tests/Massagers/PlatformTypeMapping.macosx.cs
new file mode 100644
index 000000000000..bd219fe54ae0
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/PlatformTypeMapping.macosx.cs
@@ -0,0 +1,14 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface WebFetcher : NSObject
+[BaseType (typeof (NSObject))]
+interface WebFetcher : INSUrlConnectionDelegate {
+ // @property (readonly, copy, nonatomic) NSURL * url;
+ [Export ("url", ArgumentSemantic.Copy)]
+ NSUrl Url { get; }
+
+ // -(NSURLResponse *)getResponseForUrl:(NSURL *)url withCredential:(NSURLCredential *)credential;
+ [Export ("getResponseForUrl:withCredential:")]
+ NSUrlResponse GetResponseForUrl (NSUrl url, NSUrlCredential credential);
+}
diff --git a/tests/sharpie/Tests/Massagers/ProtocolAbstract.cs b/tests/sharpie/Tests/Massagers/ProtocolAbstract.cs
new file mode 100644
index 000000000000..9cf347fa36ea
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ProtocolAbstract.cs
@@ -0,0 +1,28 @@
+using Foundation;
+
+// @protocol ProtocolAbstract
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface ProtocolAbstract {
+ // @required -(void)implicitRequired;
+ [Abstract]
+ [Export ("implicitRequired")]
+ void ImplicitRequired ();
+
+ // @optional -(void)explicitOptional;
+ [Export ("explicitOptional")]
+ void ExplicitOptional ();
+
+ // @required -(void)explicitRequired;
+ [Abstract]
+ [Export ("explicitRequired")]
+ void ExplicitRequired ();
+}
diff --git a/tests/sharpie/Tests/Massagers/ProtocolAbstract.h b/tests/sharpie/Tests/Massagers/ProtocolAbstract.h
new file mode 100644
index 000000000000..24beeb52d111
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ProtocolAbstract.h
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@protocol ProtocolAbstract
+ -(void)implicitRequired;
+
+ @optional
+ -(void)explicitOptional;
+
+ @required
+ -(void)explicitRequired;
+@end
diff --git a/tests/sharpie/Tests/Massagers/ProtocolSameFirstSlotNames.cs b/tests/sharpie/Tests/Massagers/ProtocolSameFirstSlotNames.cs
new file mode 100644
index 000000000000..0ee3d09e2beb
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ProtocolSameFirstSlotNames.cs
@@ -0,0 +1,34 @@
+using Foundation;
+
+// @protocol ProtocolSameFirstSlotNames
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface ProtocolSameFirstSlotNames {
+ // @required -(void)firstSlot;
+ [Abstract]
+ [Export ("firstSlot")]
+ void FirstSlot ();
+
+ // @required -(void)firstSlot:(int)s1;
+ [Abstract]
+ [Export ("firstSlot:")]
+ void FirstSlot (int s1);
+
+ // @required -(void)firstSlot:(int)s1 a:(int)s2;
+ [Abstract]
+ [Export ("firstSlot:a:")]
+ void A (int s1, int s2);
+
+ // @required -(void)firstSlot:(int)s1 b:(int)s2;
+ [Abstract]
+ [Export ("firstSlot:b:")]
+ void B (int s1, int s2);
+}
diff --git a/tests/sharpie/Tests/Massagers/ProtocolSameFirstSlotNames.h b/tests/sharpie/Tests/Massagers/ProtocolSameFirstSlotNames.h
new file mode 100644
index 000000000000..8f87a0593b74
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/ProtocolSameFirstSlotNames.h
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@protocol ProtocolSameFirstSlotNames
+ -(void)firstSlot;
+ -(void)firstSlot:(int)s1;
+ -(void)firstSlot:(int)s1 a:(int)s2;
+ -(void)firstSlot:(int)s1 b:(int)s2;
+@end
diff --git a/tests/sharpie/Tests/Massagers/Unavailable.h b/tests/sharpie/Tests/Massagers/Unavailable.h
new file mode 100644
index 000000000000..2f5e364133ee
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Unavailable.h
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx
+// RUN iphoneos: -sdk iphoneos
+
+@import Foundation;
+
+@interface UnavailableCtors
+-(instancetype)init NS_UNAVAILABLE;
+-(instancetype)initWithFoo:(const char *)foo NS_UNAVAILABLE;
+-(instancetype)initWithBar:(int)bar NS_DESIGNATED_INITIALIZER;
+@end
diff --git a/tests/sharpie/Tests/Massagers/Unavailable.iphoneos.cs b/tests/sharpie/Tests/Massagers/Unavailable.iphoneos.cs
new file mode 100644
index 000000000000..c2860d1308b2
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Unavailable.iphoneos.cs
@@ -0,0 +1,11 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface UnavailableCtors
+[DisableDefaultCtor]
+interface UnavailableCtors {
+ // -(instancetype)initWithBar:(int)bar __attribute__((objc_designated_initializer));
+ [Export ("initWithBar:")]
+ [DesignatedInitializer]
+ NativeHandle Constructor (int bar);
+}
diff --git a/tests/sharpie/Tests/Massagers/Unavailable.macosx.cs b/tests/sharpie/Tests/Massagers/Unavailable.macosx.cs
new file mode 100644
index 000000000000..c2860d1308b2
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Unavailable.macosx.cs
@@ -0,0 +1,11 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface UnavailableCtors
+[DisableDefaultCtor]
+interface UnavailableCtors {
+ // -(instancetype)initWithBar:(int)bar __attribute__((objc_designated_initializer));
+ [Export ("initWithBar:")]
+ [DesignatedInitializer]
+ NativeHandle Constructor (int bar);
+}
diff --git a/tests/sharpie/Tests/Massagers/Unsafe.cs b/tests/sharpie/Tests/Massagers/Unsafe.cs
new file mode 100644
index 000000000000..faa1e572a734
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Unsafe.cs
@@ -0,0 +1,22 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface UnsafeMassagerTest
+interface UnsafeMassagerTest {
+ // -(int *)returnPointerMethod;
+ [Export ("returnPointerMethod")]
+ [Verify (MethodToProperty)]
+ unsafe int* ReturnPointerMethod { get; }
+
+ // -(void)acceptPointerMethod:(int *)ptr;
+ [Export ("acceptPointerMethod:")]
+ unsafe void AcceptPointerMethod (int* ptr);
+
+ // @property (readonly) int * readonlyPtrProperty;
+ [Export ("readonlyPtrProperty")]
+ unsafe int* ReadonlyPtrProperty { get; }
+
+ // @property int * readWritePtrProperty;
+ [Export ("readWritePtrProperty", ArgumentSemantic.Assign)]
+ unsafe int* ReadWritePtrProperty { get; set; }
+}
diff --git a/tests/sharpie/Tests/Massagers/Unsafe.h b/tests/sharpie/Tests/Massagers/Unsafe.h
new file mode 100644
index 000000000000..6495c5d0b584
--- /dev/null
+++ b/tests/sharpie/Tests/Massagers/Unsafe.h
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@interface UnsafeMassagerTest
+-(int *)returnPointerMethod;
+-(void)acceptPointerMethod:(int *)ptr;
+@property (readonly) int * readonlyPtrProperty;
+@property int *readWritePtrProperty;
+@end
diff --git a/tests/sharpie/Tests/Modules.h b/tests/sharpie/Tests/Modules.h
new file mode 100644
index 000000000000..96a9ad721467
--- /dev/null
+++ b/tests/sharpie/Tests/Modules.h
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx
+// RUN iphoneos: -sdk iphoneos
+
+@import Foundation;
+
+@interface HelloModules
+-(NSString *)hello;
+@end
diff --git a/tests/sharpie/Tests/Modules.iphoneos.cs b/tests/sharpie/Tests/Modules.iphoneos.cs
new file mode 100644
index 000000000000..11524d2295de
--- /dev/null
+++ b/tests/sharpie/Tests/Modules.iphoneos.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+// @interface HelloModules
+interface HelloModules {
+ // -(NSString *)hello;
+ [Export ("hello")]
+ [Verify (MethodToProperty)]
+ string Hello { get; }
+}
diff --git a/tests/sharpie/Tests/Modules.macosx.cs b/tests/sharpie/Tests/Modules.macosx.cs
new file mode 100644
index 000000000000..11524d2295de
--- /dev/null
+++ b/tests/sharpie/Tests/Modules.macosx.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+// @interface HelloModules
+interface HelloModules {
+ // -(NSString *)hello;
+ [Export ("hello")]
+ [Verify (MethodToProperty)]
+ string Hello { get; }
+}
diff --git a/tests/sharpie/Tests/NSObjCRuntime.h b/tests/sharpie/Tests/NSObjCRuntime.h
new file mode 100644
index 000000000000..a92a818a0293
--- /dev/null
+++ b/tests/sharpie/Tests/NSObjCRuntime.h
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx x86_64 c: -sdk macosx -arch x86_64 -x c
+// RUN macosx x86_64 objc: -sdk macosx -arch x86_64 -x objective-c
+// RUN macosx arm64 c: -sdk macosx -arch arm64 -x c
+// RUN macosx arm64 objc: -sdk macosx -arch arm64 -x objective-c
+// RUN iphoneos arm64 c: -sdk iphoneos -arch arm64 -x c
+// RUN iphoneos arm64 objc: -sdk iphoneos -arch arm64 -x objective-c
+
+#include
+
+extern NSInteger NSIntegerType;
+extern NSUInteger NSUIntegerType;
diff --git a/tests/sharpie/Tests/NSObjCRuntime.iphoneos_arm64_c.cs b/tests/sharpie/Tests/NSObjCRuntime.iphoneos_arm64_c.cs
new file mode 100644
index 000000000000..617e483c3aa7
--- /dev/null
+++ b/tests/sharpie/Tests/NSObjCRuntime.iphoneos_arm64_c.cs
@@ -0,0 +1,14 @@
+using System;
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSInteger NSIntegerType;
+ [Field ("NSIntegerType", "__Internal")]
+ nint NSIntegerType { get; }
+
+ // extern NSUInteger NSUIntegerType;
+ [Field ("NSUIntegerType", "__Internal")]
+ nuint NSUIntegerType { get; }
+}
diff --git a/tests/sharpie/Tests/NSObjCRuntime.iphoneos_arm64_objc.cs b/tests/sharpie/Tests/NSObjCRuntime.iphoneos_arm64_objc.cs
new file mode 100644
index 000000000000..617e483c3aa7
--- /dev/null
+++ b/tests/sharpie/Tests/NSObjCRuntime.iphoneos_arm64_objc.cs
@@ -0,0 +1,14 @@
+using System;
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSInteger NSIntegerType;
+ [Field ("NSIntegerType", "__Internal")]
+ nint NSIntegerType { get; }
+
+ // extern NSUInteger NSUIntegerType;
+ [Field ("NSUIntegerType", "__Internal")]
+ nuint NSUIntegerType { get; }
+}
diff --git a/tests/sharpie/Tests/NSObjCRuntime.macosx_arm64_c.cs b/tests/sharpie/Tests/NSObjCRuntime.macosx_arm64_c.cs
new file mode 100644
index 000000000000..617e483c3aa7
--- /dev/null
+++ b/tests/sharpie/Tests/NSObjCRuntime.macosx_arm64_c.cs
@@ -0,0 +1,14 @@
+using System;
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSInteger NSIntegerType;
+ [Field ("NSIntegerType", "__Internal")]
+ nint NSIntegerType { get; }
+
+ // extern NSUInteger NSUIntegerType;
+ [Field ("NSUIntegerType", "__Internal")]
+ nuint NSUIntegerType { get; }
+}
diff --git a/tests/sharpie/Tests/NSObjCRuntime.macosx_arm64_objc.cs b/tests/sharpie/Tests/NSObjCRuntime.macosx_arm64_objc.cs
new file mode 100644
index 000000000000..617e483c3aa7
--- /dev/null
+++ b/tests/sharpie/Tests/NSObjCRuntime.macosx_arm64_objc.cs
@@ -0,0 +1,14 @@
+using System;
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSInteger NSIntegerType;
+ [Field ("NSIntegerType", "__Internal")]
+ nint NSIntegerType { get; }
+
+ // extern NSUInteger NSUIntegerType;
+ [Field ("NSUIntegerType", "__Internal")]
+ nuint NSUIntegerType { get; }
+}
diff --git a/tests/sharpie/Tests/NSObjCRuntime.macosx_x86_64_c.cs b/tests/sharpie/Tests/NSObjCRuntime.macosx_x86_64_c.cs
new file mode 100644
index 000000000000..617e483c3aa7
--- /dev/null
+++ b/tests/sharpie/Tests/NSObjCRuntime.macosx_x86_64_c.cs
@@ -0,0 +1,14 @@
+using System;
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSInteger NSIntegerType;
+ [Field ("NSIntegerType", "__Internal")]
+ nint NSIntegerType { get; }
+
+ // extern NSUInteger NSUIntegerType;
+ [Field ("NSUIntegerType", "__Internal")]
+ nuint NSUIntegerType { get; }
+}
diff --git a/tests/sharpie/Tests/NSObjCRuntime.macosx_x86_64_objc.cs b/tests/sharpie/Tests/NSObjCRuntime.macosx_x86_64_objc.cs
new file mode 100644
index 000000000000..617e483c3aa7
--- /dev/null
+++ b/tests/sharpie/Tests/NSObjCRuntime.macosx_x86_64_objc.cs
@@ -0,0 +1,14 @@
+using System;
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern NSInteger NSIntegerType;
+ [Field ("NSIntegerType", "__Internal")]
+ nint NSIntegerType { get; }
+
+ // extern NSUInteger NSUIntegerType;
+ [Field ("NSUIntegerType", "__Internal")]
+ nuint NSUIntegerType { get; }
+}
diff --git a/tests/sharpie/Tests/Nullability.cs b/tests/sharpie/Tests/Nullability.cs
new file mode 100644
index 000000000000..80c205ab609b
--- /dev/null
+++ b/tests/sharpie/Tests/Nullability.cs
@@ -0,0 +1,31 @@
+using System.Runtime.InteropServices;
+using Foundation;
+using ObjCRuntime;
+
+static class CFunctions {
+ // extern void Func (const char * _Nullable str);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe void Func ([NullAllowed] sbyte* str);
+}
+
+// @interface Foo
+interface Foo {
+ // @property SEL _Nullable selector;
+ [NullAllowed, Export ("selector", ArgumentSemantic.Assign)]
+ Selector Selector { get; set; }
+
+ // @property (readonly) id _Nullable someObject;
+ [NullAllowed, Export ("someObject")]
+ NSObject SomeObject { get; }
+
+ // -(id _Nullable)nullableReturnPointer;
+ [NullAllowed, Export ("nullableReturnPointer")]
+ [Verify (MethodToProperty)]
+ NSObject NullableReturnPointer { get; }
+
+ // -(id _Nullable)nullableReturnPointer:(int)arg withNullable:(id _Nullable)obj;
+ [Export ("nullableReturnPointer:withNullable:")]
+ [return: NullAllowed]
+ NSObject NullableReturnPointer (int arg, [NullAllowed] NSObject obj);
+}
diff --git a/tests/sharpie/Tests/Nullability.h b/tests/sharpie/Tests/Nullability.h
new file mode 100644
index 000000000000..87c2af23c6f7
--- /dev/null
+++ b/tests/sharpie/Tests/Nullability.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN iphoneos: -sdk iphoneos -x objective-c
+// RUN macosx: -sdk macosx -x objective-c
+
+#import
+
+#if __has_feature(nullability)
+#else
+# error nullability feature should be defined
+#endif
+
+void Func (const char * __nullable str);
+
+@interface Foo
+
+@property (nullable) SEL selector;
+@property (nullable, readonly) id someObject;
+@property (nonatomic, readonly, nullable) __kindof NSObject *presentedObject;
+
+-(__nullable id)nullableReturnPointer;
+-(nullable id)nullableReturnPointer:(int)arg withNullable:(nullable id)obj;
+-(__kindof NSObject * _Nullable) AnObject;
+-(__kindof NSObject * _Nullable) createObjectWithObject:(__kindof NSObject * _Nullable)otherObject;
+
+@end
diff --git a/tests/sharpie/Tests/Nullability.iphoneos.cs b/tests/sharpie/Tests/Nullability.iphoneos.cs
new file mode 100644
index 000000000000..81dc7a469a4c
--- /dev/null
+++ b/tests/sharpie/Tests/Nullability.iphoneos.cs
@@ -0,0 +1,45 @@
+using System.Runtime.InteropServices;
+using Foundation;
+using ObjCRuntime;
+
+static class CFunctions {
+ // extern void Func (const char * _Nullable str);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe void Func ([NullAllowed] sbyte* str);
+}
+
+// @interface Foo
+interface Foo {
+ // @property SEL _Nullable selector;
+ [NullAllowed, Export ("selector", ArgumentSemantic.Assign)]
+ Selector Selector { get; set; }
+
+ // @property (readonly) id _Nullable someObject;
+ [NullAllowed, Export ("someObject")]
+ NSObject SomeObject { get; }
+
+ // @property (readonly, nonatomic) __kindof NSObject * _Nullable presentedObject;
+ [NullAllowed, Export ("presentedObject")]
+ NSObject PresentedObject { get; }
+
+ // -(id _Nullable)nullableReturnPointer;
+ [NullAllowed, Export ("nullableReturnPointer")]
+ [Verify (MethodToProperty)]
+ NSObject NullableReturnPointer { get; }
+
+ // -(id _Nullable)nullableReturnPointer:(int)arg withNullable:(id _Nullable)obj;
+ [Export ("nullableReturnPointer:withNullable:")]
+ [return: NullAllowed]
+ NSObject NullableReturnPointer (int arg, [NullAllowed] NSObject obj);
+
+ // -(__kindof NSObject * _Nullable)AnObject;
+ [NullAllowed, Export ("AnObject")]
+ [Verify (MethodToProperty)]
+ NSObject AnObject { get; }
+
+ // -(__kindof NSObject * _Nullable)createObjectWithObject:(__kindof NSObject * _Nullable)otherObject;
+ [Export ("createObjectWithObject:")]
+ [return: NullAllowed]
+ NSObject CreateObjectWithObject ([NullAllowed] NSObject otherObject);
+}
diff --git a/tests/sharpie/Tests/Nullability.macosx.cs b/tests/sharpie/Tests/Nullability.macosx.cs
new file mode 100644
index 000000000000..81dc7a469a4c
--- /dev/null
+++ b/tests/sharpie/Tests/Nullability.macosx.cs
@@ -0,0 +1,45 @@
+using System.Runtime.InteropServices;
+using Foundation;
+using ObjCRuntime;
+
+static class CFunctions {
+ // extern void Func (const char * _Nullable str);
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe void Func ([NullAllowed] sbyte* str);
+}
+
+// @interface Foo
+interface Foo {
+ // @property SEL _Nullable selector;
+ [NullAllowed, Export ("selector", ArgumentSemantic.Assign)]
+ Selector Selector { get; set; }
+
+ // @property (readonly) id _Nullable someObject;
+ [NullAllowed, Export ("someObject")]
+ NSObject SomeObject { get; }
+
+ // @property (readonly, nonatomic) __kindof NSObject * _Nullable presentedObject;
+ [NullAllowed, Export ("presentedObject")]
+ NSObject PresentedObject { get; }
+
+ // -(id _Nullable)nullableReturnPointer;
+ [NullAllowed, Export ("nullableReturnPointer")]
+ [Verify (MethodToProperty)]
+ NSObject NullableReturnPointer { get; }
+
+ // -(id _Nullable)nullableReturnPointer:(int)arg withNullable:(id _Nullable)obj;
+ [Export ("nullableReturnPointer:withNullable:")]
+ [return: NullAllowed]
+ NSObject NullableReturnPointer (int arg, [NullAllowed] NSObject obj);
+
+ // -(__kindof NSObject * _Nullable)AnObject;
+ [NullAllowed, Export ("AnObject")]
+ [Verify (MethodToProperty)]
+ NSObject AnObject { get; }
+
+ // -(__kindof NSObject * _Nullable)createObjectWithObject:(__kindof NSObject * _Nullable)otherObject;
+ [Export ("createObjectWithObject:")]
+ [return: NullAllowed]
+ NSObject CreateObjectWithObject ([NullAllowed] NSObject otherObject);
+}
diff --git a/tests/sharpie/Tests/OSObject.h b/tests/sharpie/Tests/OSObject.h
new file mode 100644
index 000000000000..c4acde021eb5
--- /dev/null
+++ b/tests/sharpie/Tests/OSObject.h
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx x86_64 c: -sdk macosx -arch x86_64 -x c
+// RUN macosx x86_64 objc: -sdk macosx -arch x86_64 -x objective-c
+// RUN macosx arm64 c: -sdk macosx -arch arm64 -x c
+// RUN macosx arm64 objc: -sdk macosx -arch arm64 -x objective-c
+// RUN iphoneos arm64 c: -sdk iphoneos -arch arm64 -x c
+// RUN iphoneos arm64 objc: -sdk iphoneos -arch arm64 -x objective-c
+
+#include
+
+#if OS_OBJECT_HAVE_OBJC_SUPPORT
+extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__True;
+#else
+extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__False;
+#endif
+
+#if OS_OBJECT_USE_OBJC
+extern _Bool OS_OBJECT_USE_OBJC__True;
+#else
+extern _Bool OS_OBJECT_USE_OBJC__False;
+#endif
diff --git a/tests/sharpie/Tests/OSObject.iphoneos_arm64_c.cs b/tests/sharpie/Tests/OSObject.iphoneos_arm64_c.cs
new file mode 100644
index 000000000000..a7db0a7cea42
--- /dev/null
+++ b/tests/sharpie/Tests/OSObject.iphoneos_arm64_c.cs
@@ -0,0 +1,13 @@
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__False;
+ [Field ("OS_OBJECT_HAVE_OBJC_SUPPORT__False", "__Internal")]
+ bool OS_OBJECT_HAVE_OBJC_SUPPORT__False { get; }
+
+ // extern _Bool OS_OBJECT_USE_OBJC__False;
+ [Field ("OS_OBJECT_USE_OBJC__False", "__Internal")]
+ bool OS_OBJECT_USE_OBJC__False { get; }
+}
diff --git a/tests/sharpie/Tests/OSObject.iphoneos_arm64_objc.cs b/tests/sharpie/Tests/OSObject.iphoneos_arm64_objc.cs
new file mode 100644
index 000000000000..69adaa52c5e2
--- /dev/null
+++ b/tests/sharpie/Tests/OSObject.iphoneos_arm64_objc.cs
@@ -0,0 +1,13 @@
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__True;
+ [Field ("OS_OBJECT_HAVE_OBJC_SUPPORT__True", "__Internal")]
+ bool OS_OBJECT_HAVE_OBJC_SUPPORT__True { get; }
+
+ // extern _Bool OS_OBJECT_USE_OBJC__True;
+ [Field ("OS_OBJECT_USE_OBJC__True", "__Internal")]
+ bool OS_OBJECT_USE_OBJC__True { get; }
+}
diff --git a/tests/sharpie/Tests/OSObject.macosx_arm64_c.cs b/tests/sharpie/Tests/OSObject.macosx_arm64_c.cs
new file mode 100644
index 000000000000..a7db0a7cea42
--- /dev/null
+++ b/tests/sharpie/Tests/OSObject.macosx_arm64_c.cs
@@ -0,0 +1,13 @@
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__False;
+ [Field ("OS_OBJECT_HAVE_OBJC_SUPPORT__False", "__Internal")]
+ bool OS_OBJECT_HAVE_OBJC_SUPPORT__False { get; }
+
+ // extern _Bool OS_OBJECT_USE_OBJC__False;
+ [Field ("OS_OBJECT_USE_OBJC__False", "__Internal")]
+ bool OS_OBJECT_USE_OBJC__False { get; }
+}
diff --git a/tests/sharpie/Tests/OSObject.macosx_arm64_objc.cs b/tests/sharpie/Tests/OSObject.macosx_arm64_objc.cs
new file mode 100644
index 000000000000..69adaa52c5e2
--- /dev/null
+++ b/tests/sharpie/Tests/OSObject.macosx_arm64_objc.cs
@@ -0,0 +1,13 @@
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__True;
+ [Field ("OS_OBJECT_HAVE_OBJC_SUPPORT__True", "__Internal")]
+ bool OS_OBJECT_HAVE_OBJC_SUPPORT__True { get; }
+
+ // extern _Bool OS_OBJECT_USE_OBJC__True;
+ [Field ("OS_OBJECT_USE_OBJC__True", "__Internal")]
+ bool OS_OBJECT_USE_OBJC__True { get; }
+}
diff --git a/tests/sharpie/Tests/OSObject.macosx_x86_64_c.cs b/tests/sharpie/Tests/OSObject.macosx_x86_64_c.cs
new file mode 100644
index 000000000000..a7db0a7cea42
--- /dev/null
+++ b/tests/sharpie/Tests/OSObject.macosx_x86_64_c.cs
@@ -0,0 +1,13 @@
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__False;
+ [Field ("OS_OBJECT_HAVE_OBJC_SUPPORT__False", "__Internal")]
+ bool OS_OBJECT_HAVE_OBJC_SUPPORT__False { get; }
+
+ // extern _Bool OS_OBJECT_USE_OBJC__False;
+ [Field ("OS_OBJECT_USE_OBJC__False", "__Internal")]
+ bool OS_OBJECT_USE_OBJC__False { get; }
+}
diff --git a/tests/sharpie/Tests/OSObject.macosx_x86_64_objc.cs b/tests/sharpie/Tests/OSObject.macosx_x86_64_objc.cs
new file mode 100644
index 000000000000..69adaa52c5e2
--- /dev/null
+++ b/tests/sharpie/Tests/OSObject.macosx_x86_64_objc.cs
@@ -0,0 +1,13 @@
+using Foundation;
+
+[Static]
+[Verify (ConstantsInterfaceAssociation)]
+partial interface Constants {
+ // extern _Bool OS_OBJECT_HAVE_OBJC_SUPPORT__True;
+ [Field ("OS_OBJECT_HAVE_OBJC_SUPPORT__True", "__Internal")]
+ bool OS_OBJECT_HAVE_OBJC_SUPPORT__True { get; }
+
+ // extern _Bool OS_OBJECT_USE_OBJC__True;
+ [Field ("OS_OBJECT_USE_OBJC__True", "__Internal")]
+ bool OS_OBJECT_USE_OBJC__True { get; }
+}
diff --git a/tests/sharpie/Tests/ObjCDesignatedInitializer.h b/tests/sharpie/Tests/ObjCDesignatedInitializer.h
new file mode 100644
index 000000000000..019d4e044b4c
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCDesignatedInitializer.h
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx
+// RUN iphoneos: -sdk iphoneos
+
+@import Foundation;
+
+@interface NSDesignatedInitializerTest
+-(instancetype)init NS_UNAVAILABLE;
+-(instancetype)initWithInt:(int)value;
+-(instancetype)initWithString:(nonnull NSString *)value NS_DESIGNATED_INITIALIZER;
+@end
+
+@interface ObjDesignatedInitializerAttributeTest
+-(instancetype)init NS_UNAVAILABLE;
+-(instancetype)initWithInt:(int)value;
+-(instancetype)initWithString:(nonnull NSString *)value __attribute__((objc_designated_initializer));
+@end
diff --git a/tests/sharpie/Tests/ObjCDesignatedInitializer.iphoneos.cs b/tests/sharpie/Tests/ObjCDesignatedInitializer.iphoneos.cs
new file mode 100644
index 000000000000..2435be9d32cf
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCDesignatedInitializer.iphoneos.cs
@@ -0,0 +1,28 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface NSDesignatedInitializerTest
+[DisableDefaultCtor]
+interface NSDesignatedInitializerTest {
+ // -(instancetype)initWithInt:(int)value;
+ [Export ("initWithInt:")]
+ NativeHandle Constructor (int value);
+
+ // -(instancetype)initWithString:(NSString * _Nonnull)value __attribute__((objc_designated_initializer));
+ [Export ("initWithString:")]
+ [DesignatedInitializer]
+ NativeHandle Constructor (string value);
+}
+
+// @interface ObjDesignatedInitializerAttributeTest
+[DisableDefaultCtor]
+interface ObjDesignatedInitializerAttributeTest {
+ // -(instancetype)initWithInt:(int)value;
+ [Export ("initWithInt:")]
+ NativeHandle Constructor (int value);
+
+ // -(instancetype)initWithString:(NSString * _Nonnull)value __attribute__((objc_designated_initializer));
+ [Export ("initWithString:")]
+ [DesignatedInitializer]
+ NativeHandle Constructor (string value);
+}
diff --git a/tests/sharpie/Tests/ObjCDesignatedInitializer.macosx.cs b/tests/sharpie/Tests/ObjCDesignatedInitializer.macosx.cs
new file mode 100644
index 000000000000..2435be9d32cf
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCDesignatedInitializer.macosx.cs
@@ -0,0 +1,28 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface NSDesignatedInitializerTest
+[DisableDefaultCtor]
+interface NSDesignatedInitializerTest {
+ // -(instancetype)initWithInt:(int)value;
+ [Export ("initWithInt:")]
+ NativeHandle Constructor (int value);
+
+ // -(instancetype)initWithString:(NSString * _Nonnull)value __attribute__((objc_designated_initializer));
+ [Export ("initWithString:")]
+ [DesignatedInitializer]
+ NativeHandle Constructor (string value);
+}
+
+// @interface ObjDesignatedInitializerAttributeTest
+[DisableDefaultCtor]
+interface ObjDesignatedInitializerAttributeTest {
+ // -(instancetype)initWithInt:(int)value;
+ [Export ("initWithInt:")]
+ NativeHandle Constructor (int value);
+
+ // -(instancetype)initWithString:(NSString * _Nonnull)value __attribute__((objc_designated_initializer));
+ [Export ("initWithString:")]
+ [DesignatedInitializer]
+ NativeHandle Constructor (string value);
+}
diff --git a/tests/sharpie/Tests/ObjCGenerics.h b/tests/sharpie/Tests/ObjCGenerics.h
new file mode 100644
index 000000000000..39ae04d5e879
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCGenerics.h
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx
+// RUN iphoneos: -sdk iphoneos
+
+#if __has_feature(objc_generics_variance)
+#else
+# error objc_generics_variance feature should be defined
+#endif
+
+@import Foundation;
+
+@interface CNLabeledValue, __covariant CovariantValueType> : NSObject
+@property (copy, readonly, nonatomic) ValueType ValueTypeProperty;
+-(nullable ValueType)getValueTypeMethod;
+-(void)setValueTypeMethod:(nullable ValueType)obj;
+@end
+
+@protocol A
+@end
+
+@protocol B
+@end
+
+@interface GenericTypesTest
+-(NSDictionary *)NSDictionaryOfNSStringToNSNumber;
+-(NSDictionary, NSString *> *)NSDictionaryOfNSObjectConformingToAANDBToNSString;
+-(NSArray *)NSArrayOfNSString;
+-(NSSet *> *)NSSetOfNSArrayOfNSString;
+-(NSDictionary *> *> *> *)NSDictionaryOfNSStringToNSSetOfNSDictionaryOfNSStringToNSArrayOfNSNumber;
+@end
diff --git a/tests/sharpie/Tests/ObjCGenerics.iphoneos.cs b/tests/sharpie/Tests/ObjCGenerics.iphoneos.cs
new file mode 100644
index 000000000000..a11273618fde
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCGenerics.iphoneos.cs
@@ -0,0 +1,75 @@
+using Foundation;
+using ObjCRuntime;
+
+// audit-objc-generics: @interface CNLabeledValue, __covariant CovariantValueType> : NSObject
+[BaseType (typeof (NSObject))]
+interface CNLabeledValue : INSCopying, INSSecureCoding {
+ // @property (readonly, copy, nonatomic) ValueType ValueTypeProperty;
+ [Export ("ValueTypeProperty", ArgumentSemantic.Copy)]
+ NSObject ValueTypeProperty { get; }
+
+ // -(ValueType _Nullable)getValueTypeMethod;
+ [NullAllowed, Export ("getValueTypeMethod")]
+ [Verify (MethodToProperty)]
+ NSObject ValueTypeMethod { get; }
+
+ // -(void)setValueTypeMethod:(ValueType _Nullable)obj;
+ [Export ("setValueTypeMethod:")]
+ void SetValueTypeMethod ([NullAllowed] NSObject obj);
+}
+
+// @protocol A
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface A {
+}
+
+// @protocol B
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface B {
+}
+
+// @interface GenericTypesTest
+interface GenericTypesTest {
+ // -(NSDictionary *)NSDictionaryOfNSStringToNSNumber;
+ [Export ("NSDictionaryOfNSStringToNSNumber")]
+ [Verify (MethodToProperty)]
+ NSDictionary NSDictionaryOfNSStringToNSNumber { get; }
+
+ // -(NSDictionary,NSString *> *)NSDictionaryOfNSObjectConformingToAANDBToNSString;
+ [Export ("NSDictionaryOfNSObjectConformingToAANDBToNSString")]
+ [Verify (MethodToProperty)]
+ NSDictionary, NSString> NSDictionaryOfNSObjectConformingToAANDBToNSString { get; }
+
+ // -(NSArray *)NSArrayOfNSString;
+ [Export ("NSArrayOfNSString")]
+ [Verify (MethodToProperty)]
+ string [] NSArrayOfNSString { get; }
+
+ // -(NSSet *> *)NSSetOfNSArrayOfNSString;
+ [Export ("NSSetOfNSArrayOfNSString")]
+ [Verify (MethodToProperty)]
+ NSSet> NSSetOfNSArrayOfNSString { get; }
+
+ // -(NSDictionary *> *> *> *)NSDictionaryOfNSStringToNSSetOfNSDictionaryOfNSStringToNSArrayOfNSNumber;
+ [Export ("NSDictionaryOfNSStringToNSSetOfNSDictionaryOfNSStringToNSArrayOfNSNumber")]
+ [Verify (MethodToProperty)]
+ NSDictionary>>> NSDictionaryOfNSStringToNSSetOfNSDictionaryOfNSStringToNSArrayOfNSNumber { get; }
+}
diff --git a/tests/sharpie/Tests/ObjCGenerics.macosx.cs b/tests/sharpie/Tests/ObjCGenerics.macosx.cs
new file mode 100644
index 000000000000..a11273618fde
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCGenerics.macosx.cs
@@ -0,0 +1,75 @@
+using Foundation;
+using ObjCRuntime;
+
+// audit-objc-generics: @interface CNLabeledValue, __covariant CovariantValueType> : NSObject
+[BaseType (typeof (NSObject))]
+interface CNLabeledValue : INSCopying, INSSecureCoding {
+ // @property (readonly, copy, nonatomic) ValueType ValueTypeProperty;
+ [Export ("ValueTypeProperty", ArgumentSemantic.Copy)]
+ NSObject ValueTypeProperty { get; }
+
+ // -(ValueType _Nullable)getValueTypeMethod;
+ [NullAllowed, Export ("getValueTypeMethod")]
+ [Verify (MethodToProperty)]
+ NSObject ValueTypeMethod { get; }
+
+ // -(void)setValueTypeMethod:(ValueType _Nullable)obj;
+ [Export ("setValueTypeMethod:")]
+ void SetValueTypeMethod ([NullAllowed] NSObject obj);
+}
+
+// @protocol A
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface A {
+}
+
+// @protocol B
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface B {
+}
+
+// @interface GenericTypesTest
+interface GenericTypesTest {
+ // -(NSDictionary *)NSDictionaryOfNSStringToNSNumber;
+ [Export ("NSDictionaryOfNSStringToNSNumber")]
+ [Verify (MethodToProperty)]
+ NSDictionary NSDictionaryOfNSStringToNSNumber { get; }
+
+ // -(NSDictionary,NSString *> *)NSDictionaryOfNSObjectConformingToAANDBToNSString;
+ [Export ("NSDictionaryOfNSObjectConformingToAANDBToNSString")]
+ [Verify (MethodToProperty)]
+ NSDictionary, NSString> NSDictionaryOfNSObjectConformingToAANDBToNSString { get; }
+
+ // -(NSArray *)NSArrayOfNSString;
+ [Export ("NSArrayOfNSString")]
+ [Verify (MethodToProperty)]
+ string [] NSArrayOfNSString { get; }
+
+ // -(NSSet *> *)NSSetOfNSArrayOfNSString;
+ [Export ("NSSetOfNSArrayOfNSString")]
+ [Verify (MethodToProperty)]
+ NSSet> NSSetOfNSArrayOfNSString { get; }
+
+ // -(NSDictionary *> *> *> *)NSDictionaryOfNSStringToNSSetOfNSDictionaryOfNSStringToNSArrayOfNSNumber;
+ [Export ("NSDictionaryOfNSStringToNSSetOfNSDictionaryOfNSStringToNSArrayOfNSNumber")]
+ [Verify (MethodToProperty)]
+ NSDictionary>>> NSDictionaryOfNSStringToNSSetOfNSDictionaryOfNSStringToNSArrayOfNSNumber { get; }
+}
diff --git a/tests/sharpie/Tests/ObjCRequiresSuper.cs b/tests/sharpie/Tests/ObjCRequiresSuper.cs
new file mode 100644
index 000000000000..c9ef6791a6f8
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCRequiresSuper.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+// @interface RequiresSuperTest
+interface RequiresSuperTest {
+ // -(void)foo __attribute__((objc_requires_super));
+ [Export ("foo")]
+ [RequiresSuper]
+ void Foo ();
+}
diff --git a/tests/sharpie/Tests/ObjCRequiresSuper.h b/tests/sharpie/Tests/ObjCRequiresSuper.h
new file mode 100644
index 000000000000..31f2d7c58a80
--- /dev/null
+++ b/tests/sharpie/Tests/ObjCRequiresSuper.h
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#define NS_REQUIRES_SUPER __attribute__((objc_requires_super))
+
+@interface RequiresSuperTest
+-(void)foo NS_REQUIRES_SUPER;
+@end
diff --git a/tests/sharpie/Tests/OutParameters.h b/tests/sharpie/Tests/OutParameters.h
new file mode 100644
index 000000000000..80642ac51209
--- /dev/null
+++ b/tests/sharpie/Tests/OutParameters.h
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+
+#import
+
+@interface OutParams
+-(void)foo:(id)foo withError:(NSError **)error;
+-(void)bar:(NSNumber *)num withOutObject:(id *)obj;
+@end
diff --git a/tests/sharpie/Tests/OutParameters.iphoneos.cs b/tests/sharpie/Tests/OutParameters.iphoneos.cs
new file mode 100644
index 000000000000..927efd2ab14a
--- /dev/null
+++ b/tests/sharpie/Tests/OutParameters.iphoneos.cs
@@ -0,0 +1,12 @@
+using Foundation;
+
+// @interface OutParams
+interface OutParams {
+ // -(void)foo:(id)foo withError:(NSError **)error;
+ [Export ("foo:withError:")]
+ void Foo (NSObject foo, out NSError error);
+
+ // -(void)bar:(NSNumber *)num withOutObject:(id *)obj;
+ [Export ("bar:withOutObject:")]
+ void Bar (NSNumber num, out NSObject obj);
+}
diff --git a/tests/sharpie/Tests/OutParameters.macosx.cs b/tests/sharpie/Tests/OutParameters.macosx.cs
new file mode 100644
index 000000000000..927efd2ab14a
--- /dev/null
+++ b/tests/sharpie/Tests/OutParameters.macosx.cs
@@ -0,0 +1,12 @@
+using Foundation;
+
+// @interface OutParams
+interface OutParams {
+ // -(void)foo:(id)foo withError:(NSError **)error;
+ [Export ("foo:withError:")]
+ void Foo (NSObject foo, out NSError error);
+
+ // -(void)bar:(NSNumber *)num withOutObject:(id *)obj;
+ [Export ("bar:withOutObject:")]
+ void Bar (NSNumber num, out NSObject obj);
+}
diff --git a/tests/sharpie/Tests/Properties.h b/tests/sharpie/Tests/Properties.h
new file mode 100644
index 000000000000..b36f0912bd6b
--- /dev/null
+++ b/tests/sharpie/Tests/Properties.h
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+
+#import
+
+@interface PropertyTests
+@property (readonly) int readonly;
+@property int readWrite;
+@property (getter=customGetter) int readWriteCustomGetterInt32;
+@property (setter=customSetter:) int readWriteCustomSetterInt32;
+@property (getter=customGetter, setter=customSetterInt32:) int readWriteCustomGetterAndSetter;
+@property (readonly, copy) PropertyTests *clone;
+@property (readonly, copy) NSString *stringValue;
+@property (class) int staticInt;
+@property (readonly, class) int staticReadonlyInt;
+@property (nonatomic, copy, null_resettable) NSDate *nullResettableDate;
+@end
diff --git a/tests/sharpie/Tests/Properties.iphoneos.cs b/tests/sharpie/Tests/Properties.iphoneos.cs
new file mode 100644
index 000000000000..9384676c969f
--- /dev/null
+++ b/tests/sharpie/Tests/Properties.iphoneos.cs
@@ -0,0 +1,47 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface PropertyTests
+interface PropertyTests {
+ // @property (readonly) int readonly;
+ [Export ("readonly")]
+ int Readonly { get; }
+
+ // @property int readWrite;
+ [Export ("readWrite")]
+ int ReadWrite { get; set; }
+
+ // @property (getter = customGetter) int readWriteCustomGetterInt32;
+ [Export ("readWriteCustomGetterInt32")]
+ int ReadWriteCustomGetterInt32 { [Bind ("customGetter")] get; set; }
+
+ // @property (setter = customSetter:) int readWriteCustomSetterInt32;
+ [Export ("readWriteCustomSetterInt32")]
+ int ReadWriteCustomSetterInt32 { get; [Bind ("customSetter:")] set; }
+
+ // @property (getter = customGetter, setter = customSetterInt32:) int readWriteCustomGetterAndSetter;
+ [Export ("readWriteCustomGetterAndSetter")]
+ int ReadWriteCustomGetterAndSetter { [Bind ("customGetter")] get; [Bind ("customSetterInt32:")] set; }
+
+ // @property (readonly, copy) PropertyTests * clone;
+ [Export ("clone", ArgumentSemantic.Copy)]
+ PropertyTests Clone { get; }
+
+ // @property (readonly, copy) NSString * stringValue;
+ [Export ("stringValue")]
+ string StringValue { get; }
+
+ // @property (class) int staticInt;
+ [Static]
+ [Export ("staticInt")]
+ int StaticInt { get; set; }
+
+ // @property (readonly, class) int staticReadonlyInt;
+ [Static]
+ [Export ("staticReadonlyInt")]
+ int StaticReadonlyInt { get; }
+
+ // @property (copy, nonatomic, null_resettable) NSDate * _Null_unspecified nullResettableDate;
+ [NullAllowed, Export ("nullResettableDate", ArgumentSemantic.Copy)]
+ NSDate NullResettableDate { get; set; }
+}
diff --git a/tests/sharpie/Tests/Properties.macosx.cs b/tests/sharpie/Tests/Properties.macosx.cs
new file mode 100644
index 000000000000..9384676c969f
--- /dev/null
+++ b/tests/sharpie/Tests/Properties.macosx.cs
@@ -0,0 +1,47 @@
+using Foundation;
+using ObjCRuntime;
+
+// @interface PropertyTests
+interface PropertyTests {
+ // @property (readonly) int readonly;
+ [Export ("readonly")]
+ int Readonly { get; }
+
+ // @property int readWrite;
+ [Export ("readWrite")]
+ int ReadWrite { get; set; }
+
+ // @property (getter = customGetter) int readWriteCustomGetterInt32;
+ [Export ("readWriteCustomGetterInt32")]
+ int ReadWriteCustomGetterInt32 { [Bind ("customGetter")] get; set; }
+
+ // @property (setter = customSetter:) int readWriteCustomSetterInt32;
+ [Export ("readWriteCustomSetterInt32")]
+ int ReadWriteCustomSetterInt32 { get; [Bind ("customSetter:")] set; }
+
+ // @property (getter = customGetter, setter = customSetterInt32:) int readWriteCustomGetterAndSetter;
+ [Export ("readWriteCustomGetterAndSetter")]
+ int ReadWriteCustomGetterAndSetter { [Bind ("customGetter")] get; [Bind ("customSetterInt32:")] set; }
+
+ // @property (readonly, copy) PropertyTests * clone;
+ [Export ("clone", ArgumentSemantic.Copy)]
+ PropertyTests Clone { get; }
+
+ // @property (readonly, copy) NSString * stringValue;
+ [Export ("stringValue")]
+ string StringValue { get; }
+
+ // @property (class) int staticInt;
+ [Static]
+ [Export ("staticInt")]
+ int StaticInt { get; set; }
+
+ // @property (readonly, class) int staticReadonlyInt;
+ [Static]
+ [Export ("staticReadonlyInt")]
+ int StaticReadonlyInt { get; }
+
+ // @property (copy, nonatomic, null_resettable) NSDate * _Null_unspecified nullResettableDate;
+ [NullAllowed, Export ("nullResettableDate", ArgumentSemantic.Copy)]
+ NSDate NullResettableDate { get; set; }
+}
diff --git a/tests/sharpie/Tests/Protocol.cs b/tests/sharpie/Tests/Protocol.cs
new file mode 100644
index 000000000000..4305996fb436
--- /dev/null
+++ b/tests/sharpie/Tests/Protocol.cs
@@ -0,0 +1,127 @@
+using Foundation;
+
+// @protocol ProtocolA
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface ProtocolA {
+}
+
+// @protocol ProtocolB
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface ProtocolB {
+}
+
+// @protocol ProtocolC
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface ProtocolC : IProtocolB {
+}
+
+// @interface Impl_A
+interface Impl_A : IProtocolA {
+}
+
+// @interface Impl_A_C
+interface Impl_A_C : IProtocolA, IProtocolC {
+}
+
+// @interface Root
+interface Root {
+}
+
+// @interface Sub : Root
+[BaseType (typeof (Root))]
+interface Sub : IProtocolA, IProtocolB {
+}
+
+// @interface Usage
+interface Usage {
+ // -(Root *)root_A_C;
+ [Export ("root_A_C")]
+ [Verify (MethodToProperty)]
+ Root Root_A_C { get; }
+
+ // -(Root *)root_A;
+ [Export ("root_A")]
+ [Verify (MethodToProperty)]
+ ProtocolA Root_A { get; }
+
+ // -(id)proto_A;
+ [Export ("proto_A")]
+ [Verify (MethodToProperty)]
+ ProtocolA Proto_A { get; }
+}
+
+// @protocol RequiredAndOptional
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface RequiredAndOptional {
+ // @required -(void)implicitRequiredMethod;
+ [Abstract]
+ [Export ("implicitRequiredMethod")]
+ void ImplicitRequiredMethod ();
+
+ // @required @property int implicitRequiredProperty;
+ [Abstract]
+ [Export ("implicitRequiredProperty")]
+ int ImplicitRequiredProperty { get; set; }
+
+ // @optional -(void)firstOptionalMethod;
+ [Export ("firstOptionalMethod")]
+ void FirstOptionalMethod ();
+
+ // @optional @property int firstOptionalProperty;
+ [Export ("firstOptionalProperty")]
+ int FirstOptionalProperty { get; set; }
+
+ // @required -(void)explicitRequiredMethod;
+ [Abstract]
+ [Export ("explicitRequiredMethod")]
+ void ExplicitRequiredMethod ();
+
+ // @required @property int explicitRequiredProperty;
+ [Abstract]
+ [Export ("explicitRequiredProperty")]
+ int ExplicitRequiredProperty { get; set; }
+
+ // @optional -(void)secondOptionalMethod;
+ [Export ("secondOptionalMethod")]
+ void SecondOptionalMethod ();
+
+ // @optional @property int secondOptionalProperty;
+ [Export ("secondOptionalProperty")]
+ int SecondOptionalProperty { get; set; }
+}
diff --git a/tests/sharpie/Tests/Protocol.h b/tests/sharpie/Tests/Protocol.h
new file mode 100644
index 000000000000..fea5eb311f03
--- /dev/null
+++ b/tests/sharpie/Tests/Protocol.h
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@protocol ProtocolA
+@end
+
+@protocol ProtocolB
+@end
+
+@protocol ProtocolC
+@end
+
+@interface Impl_A
+@end
+
+@interface Impl_A_C
+@end
+
+@interface Root
+@end
+
+@interface Sub : Root
+@end
+
+@interface Usage
+-(Root *)root_A_C;
+-(Root *)root_A;
+-(id)proto_A;
+@end
+
+@protocol RequiredAndOptional
+-(void)implicitRequiredMethod;
+@property int implicitRequiredProperty;
+
+@optional
+-(void)firstOptionalMethod;
+@property int firstOptionalProperty;
+
+@required
+-(void)explicitRequiredMethod;
+@property int explicitRequiredProperty;
+
+@optional
+-(void)secondOptionalMethod;
+@property int secondOptionalProperty;
+@end
diff --git a/tests/sharpie/Tests/Struct.c.cs b/tests/sharpie/Tests/Struct.c.cs
new file mode 100644
index 000000000000..508ff7e8dd6e
--- /dev/null
+++ b/tests/sharpie/Tests/Struct.c.cs
@@ -0,0 +1,402 @@
+using System;
+using System.Runtime.InteropServices;
+
+[StructLayout (LayoutKind.Sequential)]
+public struct ElaboratedNameOnlyStruct {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct AnonStructRenamedByTypedef {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct ElaboratedNameStructRenamedByTypedef {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct Parent {
+ public int fully_anon_struct;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct Parent {
+ public sbyte first;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct ChildStruct {
+ public int a;
+
+ public sbyte b;
+ }
+
+
+ public ChildStruct second;
+
+ public nuint third;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct AnotherChild {
+ public int foo;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct AndAnotherChild {
+ public unsafe sbyte* name;
+
+ public int age;
+ }
+
+
+ public AndAnotherChild andAnotherChild;
+
+ public int bar;
+ }
+
+
+ public AnotherChild anotherChild;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct NXTabletPointData {
+ public int x;
+
+ public int y;
+
+ public int z;
+
+ public ushort buttons;
+
+ public ushort pressure;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tilt {
+ public short x;
+
+ public short y;
+ }
+
+
+ public tilt tilt;
+
+ public ushort rotation;
+
+ public short tangentialPressure;
+
+ public ushort deviceID;
+
+ public short vendor1;
+
+ public short vendor2;
+
+ public short vendor3;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct NXTabletProximityData {
+ public ushort vendorID;
+
+ public ushort tabletID;
+
+ public ushort pointerID;
+
+ public ushort deviceID;
+
+ public ushort systemTabletID;
+
+ public ushort vendorPointerType;
+
+ public uint pointerSerialNumber;
+
+ public ulong uniqueID;
+
+ public uint capabilityMask;
+
+ public byte pointerType;
+
+ public byte enterProximity;
+
+ public short reserved1;
+}
+
+[StructLayout (LayoutKind.Explicit)]
+public struct NXEventData {
+ [StructLayout (LayoutKind.Sequential)]
+ public struct mouse {
+ public byte subx;
+
+ public byte suby;
+
+ public short eventNum;
+
+ public int click;
+
+ public byte pressure;
+
+ public byte buttonNumber;
+
+ public byte subType;
+
+ public byte reserved2;
+
+ public int reserved3;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct tablet {
+ [FieldOffset (0)]
+ public NXTabletPointData point;
+
+ [FieldOffset (0)]
+ public NXTabletProximityData proximity;
+ }
+
+
+ public tablet tablet;
+ }
+
+
+ [FieldOffset (0)]
+ public mouse mouse;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct mouseMove {
+ public int dx;
+
+ public int dy;
+
+ public byte subx;
+
+ public byte suby;
+
+ public byte subType;
+
+ public byte reserved1;
+
+ public int reserved2;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct tablet {
+ [FieldOffset (0)]
+ public NXTabletPointData point;
+
+ [FieldOffset (0)]
+ public NXTabletProximityData proximity;
+ }
+
+
+ public tablet tablet;
+ }
+
+
+ [FieldOffset (0)]
+ public mouseMove mouseMove;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct key {
+ public ushort origCharSet;
+
+ public short repeat;
+
+ public ushort charSet;
+
+ public ushort charCode;
+
+ public ushort keyCode;
+
+ public ushort origCharCode;
+
+ public int reserved1;
+
+ public uint keyboardType;
+
+ public int reserved2;
+
+ public int reserved3;
+
+ public int reserved4;
+
+ public int [] reserved5;
+ }
+
+
+ [FieldOffset (0)]
+ public key key;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tracking {
+ public short reserved;
+
+ public short eventNum;
+
+ public int trackingNum;
+
+ public int userData;
+
+ public int reserved1;
+
+ public int reserved2;
+
+ public int reserved3;
+
+ public int reserved4;
+
+ public int reserved5;
+
+ public int [] reserved6;
+ }
+
+
+ [FieldOffset (0)]
+ public tracking tracking;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct scrollWheel {
+ public short deltaAxis1;
+
+ public short deltaAxis2;
+
+ public short deltaAxis3;
+
+ public short reserved1;
+
+ public int fixedDeltaAxis1;
+
+ public int fixedDeltaAxis2;
+
+ public int fixedDeltaAxis3;
+
+ public int pointDeltaAxis1;
+
+ public int pointDeltaAxis2;
+
+ public int pointDeltaAxis3;
+
+ public int [] reserved8;
+ }
+
+
+ [FieldOffset (0)]
+ public scrollWheel scrollWheel;
+
+ [FieldOffset (0)]
+ public scrollWheel zoom;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct compound {
+ public short reserved;
+
+ public short subType;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct misc {
+ [FieldOffset (0)]
+ public float [] F;
+
+ [FieldOffset (0)]
+ public int [] L;
+
+ [FieldOffset (0)]
+ public short [] S;
+
+ [FieldOffset (0)]
+ public sbyte [] C;
+ }
+
+
+ public misc misc;
+ }
+
+
+ [FieldOffset (0)]
+ public compound compound;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tablet {
+ public int x;
+
+ public int y;
+
+ public int z;
+
+ public ushort buttons;
+
+ public ushort pressure;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tilt {
+ public short x;
+
+ public short y;
+ }
+
+
+ public tilt tilt;
+
+ public ushort rotation;
+
+ public short tangentialPressure;
+
+ public ushort deviceID;
+
+ public short vendor1;
+
+ public short vendor2;
+
+ public short vendor3;
+
+ public int [] reserved;
+ }
+
+
+ [FieldOffset (0)]
+ public tablet tablet;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct proximity {
+ public ushort vendorID;
+
+ public ushort tabletID;
+
+ public ushort pointerID;
+
+ public ushort deviceID;
+
+ public ushort systemTabletID;
+
+ public ushort vendorPointerType;
+
+ public uint pointerSerialNumber;
+
+ public ulong uniqueID;
+
+ public uint capabilityMask;
+
+ public byte pointerType;
+
+ public byte enterProximity;
+
+ public short reserved1;
+
+ public int [] reserved2;
+ }
+
+
+ [FieldOffset (0)]
+ public proximity proximity;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct BluetoothHCIEventReturnLinkKeysResults {
+ public int numLinkKeys;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct linkKeys {
+ public int deviceAddress;
+
+ public int linkKey;
+ }
+
+
+ public linkKeys [] linkKeys;
+}
diff --git a/tests/sharpie/Tests/Struct.cxx11.cs b/tests/sharpie/Tests/Struct.cxx11.cs
new file mode 100644
index 000000000000..604dd70632a8
--- /dev/null
+++ b/tests/sharpie/Tests/Struct.cxx11.cs
@@ -0,0 +1,402 @@
+using System;
+using System.Runtime.InteropServices;
+
+[StructLayout (LayoutKind.Sequential)]
+public struct ElaboratedNameOnlyStruct {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct AnonStructRenamedByTypedef {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct ElaboratedNameStructRenamedByTypedef {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct PODNonC {
+ public int hello;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct Parent {
+ public sbyte first;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct ChildStruct {
+ public int a;
+
+ public sbyte b;
+ }
+
+
+ public ChildStruct second;
+
+ public nuint third;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct AnotherChild {
+ public int foo;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct AndAnotherChild {
+ public unsafe sbyte* name;
+
+ public int age;
+ }
+
+
+ public AndAnotherChild andAnotherChild;
+
+ public int bar;
+ }
+
+
+ public AnotherChild anotherChild;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct NXTabletPointData {
+ public int x;
+
+ public int y;
+
+ public int z;
+
+ public ushort buttons;
+
+ public ushort pressure;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tilt {
+ public short x;
+
+ public short y;
+ }
+
+
+ public tilt tilt;
+
+ public ushort rotation;
+
+ public short tangentialPressure;
+
+ public ushort deviceID;
+
+ public short vendor1;
+
+ public short vendor2;
+
+ public short vendor3;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct NXTabletProximityData {
+ public ushort vendorID;
+
+ public ushort tabletID;
+
+ public ushort pointerID;
+
+ public ushort deviceID;
+
+ public ushort systemTabletID;
+
+ public ushort vendorPointerType;
+
+ public uint pointerSerialNumber;
+
+ public ulong uniqueID;
+
+ public uint capabilityMask;
+
+ public byte pointerType;
+
+ public byte enterProximity;
+
+ public short reserved1;
+}
+
+[StructLayout (LayoutKind.Explicit)]
+public struct NXEventData {
+ [StructLayout (LayoutKind.Sequential)]
+ public struct mouse {
+ public byte subx;
+
+ public byte suby;
+
+ public short eventNum;
+
+ public int click;
+
+ public byte pressure;
+
+ public byte buttonNumber;
+
+ public byte subType;
+
+ public byte reserved2;
+
+ public int reserved3;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct tablet {
+ [FieldOffset (0)]
+ public NXTabletPointData point;
+
+ [FieldOffset (0)]
+ public NXTabletProximityData proximity;
+ }
+
+
+ public tablet tablet;
+ }
+
+
+ [FieldOffset (0)]
+ public mouse mouse;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct mouseMove {
+ public int dx;
+
+ public int dy;
+
+ public byte subx;
+
+ public byte suby;
+
+ public byte subType;
+
+ public byte reserved1;
+
+ public int reserved2;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct tablet {
+ [FieldOffset (0)]
+ public NXTabletPointData point;
+
+ [FieldOffset (0)]
+ public NXTabletProximityData proximity;
+ }
+
+
+ public tablet tablet;
+ }
+
+
+ [FieldOffset (0)]
+ public mouseMove mouseMove;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct key {
+ public ushort origCharSet;
+
+ public short repeat;
+
+ public ushort charSet;
+
+ public ushort charCode;
+
+ public ushort keyCode;
+
+ public ushort origCharCode;
+
+ public int reserved1;
+
+ public uint keyboardType;
+
+ public int reserved2;
+
+ public int reserved3;
+
+ public int reserved4;
+
+ public int [] reserved5;
+ }
+
+
+ [FieldOffset (0)]
+ public key key;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tracking {
+ public short reserved;
+
+ public short eventNum;
+
+ public int trackingNum;
+
+ public int userData;
+
+ public int reserved1;
+
+ public int reserved2;
+
+ public int reserved3;
+
+ public int reserved4;
+
+ public int reserved5;
+
+ public int [] reserved6;
+ }
+
+
+ [FieldOffset (0)]
+ public tracking tracking;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct scrollWheel {
+ public short deltaAxis1;
+
+ public short deltaAxis2;
+
+ public short deltaAxis3;
+
+ public short reserved1;
+
+ public int fixedDeltaAxis1;
+
+ public int fixedDeltaAxis2;
+
+ public int fixedDeltaAxis3;
+
+ public int pointDeltaAxis1;
+
+ public int pointDeltaAxis2;
+
+ public int pointDeltaAxis3;
+
+ public int [] reserved8;
+ }
+
+
+ [FieldOffset (0)]
+ public scrollWheel scrollWheel;
+
+ [FieldOffset (0)]
+ public scrollWheel zoom;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct compound {
+ public short reserved;
+
+ public short subType;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct misc {
+ [FieldOffset (0)]
+ public float [] F;
+
+ [FieldOffset (0)]
+ public int [] L;
+
+ [FieldOffset (0)]
+ public short [] S;
+
+ [FieldOffset (0)]
+ public sbyte [] C;
+ }
+
+
+ public misc misc;
+ }
+
+
+ [FieldOffset (0)]
+ public compound compound;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tablet {
+ public int x;
+
+ public int y;
+
+ public int z;
+
+ public ushort buttons;
+
+ public ushort pressure;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tilt {
+ public short x;
+
+ public short y;
+ }
+
+
+ public tilt tilt;
+
+ public ushort rotation;
+
+ public short tangentialPressure;
+
+ public ushort deviceID;
+
+ public short vendor1;
+
+ public short vendor2;
+
+ public short vendor3;
+
+ public int [] reserved;
+ }
+
+
+ [FieldOffset (0)]
+ public tablet tablet;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct proximity {
+ public ushort vendorID;
+
+ public ushort tabletID;
+
+ public ushort pointerID;
+
+ public ushort deviceID;
+
+ public ushort systemTabletID;
+
+ public ushort vendorPointerType;
+
+ public uint pointerSerialNumber;
+
+ public ulong uniqueID;
+
+ public uint capabilityMask;
+
+ public byte pointerType;
+
+ public byte enterProximity;
+
+ public short reserved1;
+
+ public int [] reserved2;
+ }
+
+
+ [FieldOffset (0)]
+ public proximity proximity;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct BluetoothHCIEventReturnLinkKeysResults {
+ public int numLinkKeys;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct linkKeys {
+ public int deviceAddress;
+
+ public int linkKey;
+ }
+
+
+ public linkKeys [] linkKeys;
+}
diff --git a/tests/sharpie/Tests/Struct.h b/tests/sharpie/Tests/Struct.h
new file mode 100644
index 000000000000..570e099d1a84
--- /dev/null
+++ b/tests/sharpie/Tests/Struct.h
@@ -0,0 +1,224 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN c: -xc -std=c11
+// RUN objc: -xobjective-c
+// RUN cxx11: -xc++ -std=c++11
+
+struct ElaboratedNameOnlyStruct {
+ int foo;
+};
+
+typedef struct {
+ int foo;
+} AnonStructRenamedByTypedef;
+
+struct ElaboratedNameStructToBeRenamedByTypedef {
+ int foo;
+};
+
+typedef struct ElaboratedNameStructToBeRenamedByTypedef
+ ElaboratedNameStructRenamedByTypedef;
+
+#if defined(__cplusplus)
+
+struct NonPODVirtual {
+ int hello;
+ virtual void pureVirtual () = 0;
+};
+
+struct PODNonC {
+ int hello;
+ void nonVirtual ();
+};
+
+#else
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-declarations"
+
+struct {
+ int fully_anon_struct;
+};
+
+#pragma clang diagnostic pop
+#endif
+
+struct Parent {
+ char first;
+ struct ChildStruct {
+ int a;
+ char b;
+ } second;
+ unsigned long third;
+ struct AnotherChild {
+ int foo;
+ struct AndAnotherChild {
+ char *name;
+ int age;
+ } andAnotherChild;
+ int bar;
+ } anotherChild;
+};
+
+#include
+typedef struct _NXTabletPointData {
+ SInt32 x; /* absolute x coordinate in tablet space at full tablet resolution */
+ SInt32 y; /* absolute y coordinate in tablet space at full tablet resolution */
+ SInt32 z; /* absolute z coordinate in tablet space at full tablet resolution */
+ UInt16 buttons; /* one bit per button - bit 0 is first button - 1 = closed */
+ UInt16 pressure; /* scaled pressure value; MAX=(2^16)-1, MIN=0 */
+ struct { /* tilt range is -((2^15)-1) to (2^15)-1 (-32767 to 32767) */
+ SInt16 x; /* scaled tilt x value */
+ SInt16 y; /* scaled tilt y value */
+ } tilt;
+ UInt16 rotation; /* Fixed-point representation of device rotation in a 10.6 format */
+ SInt16 tangentialPressure; /* tangential pressure on the device; same range as tilt */
+ UInt16 deviceID; /* system-assigned unique device ID */
+ SInt16 vendor1; /* vendor-defined signed 16-bit integer */
+ SInt16 vendor2; /* vendor-defined signed 16-bit integer */
+ SInt16 vendor3; /* vendor-defined signed 16-bit integer */
+} NXTabletPointData, *NXTabletPointDataPtr;
+
+/* TabletProximityData type: defines the tablet data for proximity
+ * events included in mouse events created by a tablet driver.
+ */
+
+typedef struct _NXTabletProximityData {
+ UInt16 vendorID; /* vendor-defined ID - typically the USB vendor ID */
+ UInt16 tabletID; /* vendor-defined tablet ID - typically the USB product ID */
+ UInt16 pointerID; /* vendor-defined ID of the specific pointing device */
+ UInt16 deviceID; /* system-assigned unique device ID */
+ UInt16 systemTabletID; /* system-assigned unique tablet ID */
+ UInt16 vendorPointerType; /* vendor-defined pointer type */
+ UInt32 pointerSerialNumber; /* vendor-defined serial number */
+ UInt64 uniqueID __attribute__ ((packed)); /* vendor-defined unique ID */
+ UInt32 capabilityMask; /* capabilities mask of the device */
+ UInt8 pointerType; /* type of pointing device */
+ UInt8 enterProximity; /* non-zero = entering; zero = leaving */
+ SInt16 reserved1;
+} NXTabletProximityData, *NXTabletProximityDataPtr;
+
+/* EventData type: defines the data field of an event */
+
+typedef union {
+ struct { /* For mouse-down and mouse-up events */
+ UInt8 subx; /* sub-pixel position for x */
+ UInt8 suby; /* sub-pixel position for y */
+ SInt16 eventNum; /* unique identifier for this button */
+ SInt32 click; /* click state of this event */
+ UInt8 pressure; /* pressure value: 0=none, 255=full */
+ UInt8 buttonNumber;/* button generating other button event (0-31) */
+ UInt8 subType;
+ UInt8 reserved2;
+ SInt32 reserved3;
+ union {
+ NXTabletPointData point; /* tablet point data */
+ NXTabletProximityData proximity; /* tablet proximity data */
+ } tablet;
+ } mouse;
+ struct {
+ SInt32 dx;
+ SInt32 dy;
+ UInt8 subx;
+ UInt8 suby;
+ UInt8 subType;
+ UInt8 reserved1;
+ SInt32 reserved2;
+ union {
+ NXTabletPointData point; /* tablet point data */
+ NXTabletProximityData proximity; /* tablet proximity data */
+ } tablet;
+ } mouseMove;
+ struct { /* For key-down and key-up events */
+ UInt16 origCharSet; /* unmodified character set code */
+ SInt16 repeat; /* for key-down: nonzero if really a repeat */
+ UInt16 charSet; /* character set code */
+ UInt16 charCode; /* character code in that set */
+ UInt16 keyCode; /* device-dependent key number */
+ UInt16 origCharCode; /* unmodified character code */
+ SInt32 reserved1;
+ UInt32 keyboardType;
+ SInt32 reserved2;
+ SInt32 reserved3;
+ SInt32 reserved4;
+ SInt32 reserved5[4];
+ } key;
+ struct { /* For mouse-entered and mouse-exited events */
+ SInt16 reserved;
+ SInt16 eventNum; /* unique identifier from mouse down event */
+ SInt32 trackingNum; /* unique identifier from settrackingrect */
+ SInt32 userData; /* uninterpreted integer from settrackingrect */
+ SInt32 reserved1;
+ SInt32 reserved2;
+ SInt32 reserved3;
+ SInt32 reserved4;
+ SInt32 reserved5;
+ SInt32 reserved6[4];
+ } tracking;
+ struct {
+ SInt16 deltaAxis1;
+ SInt16 deltaAxis2;
+ SInt16 deltaAxis3;
+ SInt16 reserved1;
+ SInt32 fixedDeltaAxis1;
+ SInt32 fixedDeltaAxis2;
+ SInt32 fixedDeltaAxis3;
+ SInt32 pointDeltaAxis1;
+ SInt32 pointDeltaAxis2;
+ SInt32 pointDeltaAxis3;
+ SInt32 reserved8[4];
+ } scrollWheel, zoom;
+ struct { /* For window-changed, sys-defined, and app-defined events */
+ SInt16 reserved;
+ SInt16 subType; /* event subtype for compound events */
+ union {
+ float F[11]; /* for use in compound events */
+ SInt32 L[11]; /* for use in compound events */
+ SInt16 S[22]; /* for use in compound events */
+ char C[44]; /* for use in compound events */
+ } misc;
+ } compound;
+ struct {
+ SInt32 x; /* absolute x coordinate in tablet space at full tablet resolution */
+ SInt32 y; /* absolute y coordinate in tablet space at full tablet resolution */
+ SInt32 z; /* absolute z coordinate in tablet space at full tablet resolution */
+ UInt16 buttons; /* one bit per button - bit 0 is first button - 1 = closed */
+ UInt16 pressure; /* scaled pressure value; MAX=(2^16)-1, MIN=0 */
+ struct { /* tilt range is -((2^15)-1) to (2^15)-1 (-32767 to 32767) */
+ SInt16 x; /* scaled tilt x value */
+ SInt16 y; /* scaled tilt y value */
+ } tilt;
+ UInt16 rotation; /* Fixed-point representation of device rotation in a 10.6 format */
+ SInt16 tangentialPressure; /* tangential pressure on the device; same range as tilt */
+ UInt16 deviceID; /* system-assigned unique device ID */
+ SInt16 vendor1; /* vendor-defined signed 16-bit integer */
+ SInt16 vendor2; /* vendor-defined signed 16-bit integer */
+ SInt16 vendor3; /* vendor-defined signed 16-bit integer */
+ SInt32 reserved[4];
+ } tablet;
+ struct {
+ UInt16 vendorID; /* vendor-defined ID - typically the USB vendor ID */
+ UInt16 tabletID; /* vendor-defined tablet ID - typically the USB product ID */
+ UInt16 pointerID; /* vendor-defined ID of the specific pointing device */
+ UInt16 deviceID; /* system-assigned unique device ID */
+ UInt16 systemTabletID; /* system-assigned unique tablet ID */
+ UInt16 vendorPointerType; /* vendor-defined pointer type */
+ UInt32 pointerSerialNumber; /* vendor-defined serial number */
+ UInt64 uniqueID __attribute__ ((packed)); /* vendor-defined unique ID */
+ UInt32 capabilityMask; /* capabilities mask of the device */
+ UInt8 pointerType; /* type of pointing device */
+ UInt8 enterProximity; /* non-zero = entering; zero = leaving */
+ SInt16 reserved1;
+ SInt32 reserved2[4];
+ } proximity;
+} NXEventData;
+
+//typedef struct BluetoothHCIEventReturnLinkKeysResults BluetoothHCIEventReturnLinkKeysResults;
+struct BluetoothHCIEventReturnLinkKeysResults
+{
+ int numLinkKeys;
+ struct {
+ int deviceAddress;
+ int linkKey;
+ } linkKeys[1];
+};
diff --git a/tests/sharpie/Tests/Struct.objc.cs b/tests/sharpie/Tests/Struct.objc.cs
new file mode 100644
index 000000000000..508ff7e8dd6e
--- /dev/null
+++ b/tests/sharpie/Tests/Struct.objc.cs
@@ -0,0 +1,402 @@
+using System;
+using System.Runtime.InteropServices;
+
+[StructLayout (LayoutKind.Sequential)]
+public struct ElaboratedNameOnlyStruct {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct AnonStructRenamedByTypedef {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct ElaboratedNameStructRenamedByTypedef {
+ public int foo;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct Parent {
+ public int fully_anon_struct;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct Parent {
+ public sbyte first;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct ChildStruct {
+ public int a;
+
+ public sbyte b;
+ }
+
+
+ public ChildStruct second;
+
+ public nuint third;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct AnotherChild {
+ public int foo;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct AndAnotherChild {
+ public unsafe sbyte* name;
+
+ public int age;
+ }
+
+
+ public AndAnotherChild andAnotherChild;
+
+ public int bar;
+ }
+
+
+ public AnotherChild anotherChild;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct NXTabletPointData {
+ public int x;
+
+ public int y;
+
+ public int z;
+
+ public ushort buttons;
+
+ public ushort pressure;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tilt {
+ public short x;
+
+ public short y;
+ }
+
+
+ public tilt tilt;
+
+ public ushort rotation;
+
+ public short tangentialPressure;
+
+ public ushort deviceID;
+
+ public short vendor1;
+
+ public short vendor2;
+
+ public short vendor3;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct NXTabletProximityData {
+ public ushort vendorID;
+
+ public ushort tabletID;
+
+ public ushort pointerID;
+
+ public ushort deviceID;
+
+ public ushort systemTabletID;
+
+ public ushort vendorPointerType;
+
+ public uint pointerSerialNumber;
+
+ public ulong uniqueID;
+
+ public uint capabilityMask;
+
+ public byte pointerType;
+
+ public byte enterProximity;
+
+ public short reserved1;
+}
+
+[StructLayout (LayoutKind.Explicit)]
+public struct NXEventData {
+ [StructLayout (LayoutKind.Sequential)]
+ public struct mouse {
+ public byte subx;
+
+ public byte suby;
+
+ public short eventNum;
+
+ public int click;
+
+ public byte pressure;
+
+ public byte buttonNumber;
+
+ public byte subType;
+
+ public byte reserved2;
+
+ public int reserved3;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct tablet {
+ [FieldOffset (0)]
+ public NXTabletPointData point;
+
+ [FieldOffset (0)]
+ public NXTabletProximityData proximity;
+ }
+
+
+ public tablet tablet;
+ }
+
+
+ [FieldOffset (0)]
+ public mouse mouse;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct mouseMove {
+ public int dx;
+
+ public int dy;
+
+ public byte subx;
+
+ public byte suby;
+
+ public byte subType;
+
+ public byte reserved1;
+
+ public int reserved2;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct tablet {
+ [FieldOffset (0)]
+ public NXTabletPointData point;
+
+ [FieldOffset (0)]
+ public NXTabletProximityData proximity;
+ }
+
+
+ public tablet tablet;
+ }
+
+
+ [FieldOffset (0)]
+ public mouseMove mouseMove;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct key {
+ public ushort origCharSet;
+
+ public short repeat;
+
+ public ushort charSet;
+
+ public ushort charCode;
+
+ public ushort keyCode;
+
+ public ushort origCharCode;
+
+ public int reserved1;
+
+ public uint keyboardType;
+
+ public int reserved2;
+
+ public int reserved3;
+
+ public int reserved4;
+
+ public int [] reserved5;
+ }
+
+
+ [FieldOffset (0)]
+ public key key;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tracking {
+ public short reserved;
+
+ public short eventNum;
+
+ public int trackingNum;
+
+ public int userData;
+
+ public int reserved1;
+
+ public int reserved2;
+
+ public int reserved3;
+
+ public int reserved4;
+
+ public int reserved5;
+
+ public int [] reserved6;
+ }
+
+
+ [FieldOffset (0)]
+ public tracking tracking;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct scrollWheel {
+ public short deltaAxis1;
+
+ public short deltaAxis2;
+
+ public short deltaAxis3;
+
+ public short reserved1;
+
+ public int fixedDeltaAxis1;
+
+ public int fixedDeltaAxis2;
+
+ public int fixedDeltaAxis3;
+
+ public int pointDeltaAxis1;
+
+ public int pointDeltaAxis2;
+
+ public int pointDeltaAxis3;
+
+ public int [] reserved8;
+ }
+
+
+ [FieldOffset (0)]
+ public scrollWheel scrollWheel;
+
+ [FieldOffset (0)]
+ public scrollWheel zoom;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct compound {
+ public short reserved;
+
+ public short subType;
+
+ [StructLayout (LayoutKind.Explicit)]
+ public struct misc {
+ [FieldOffset (0)]
+ public float [] F;
+
+ [FieldOffset (0)]
+ public int [] L;
+
+ [FieldOffset (0)]
+ public short [] S;
+
+ [FieldOffset (0)]
+ public sbyte [] C;
+ }
+
+
+ public misc misc;
+ }
+
+
+ [FieldOffset (0)]
+ public compound compound;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tablet {
+ public int x;
+
+ public int y;
+
+ public int z;
+
+ public ushort buttons;
+
+ public ushort pressure;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct tilt {
+ public short x;
+
+ public short y;
+ }
+
+
+ public tilt tilt;
+
+ public ushort rotation;
+
+ public short tangentialPressure;
+
+ public ushort deviceID;
+
+ public short vendor1;
+
+ public short vendor2;
+
+ public short vendor3;
+
+ public int [] reserved;
+ }
+
+
+ [FieldOffset (0)]
+ public tablet tablet;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct proximity {
+ public ushort vendorID;
+
+ public ushort tabletID;
+
+ public ushort pointerID;
+
+ public ushort deviceID;
+
+ public ushort systemTabletID;
+
+ public ushort vendorPointerType;
+
+ public uint pointerSerialNumber;
+
+ public ulong uniqueID;
+
+ public uint capabilityMask;
+
+ public byte pointerType;
+
+ public byte enterProximity;
+
+ public short reserved1;
+
+ public int [] reserved2;
+ }
+
+
+ [FieldOffset (0)]
+ public proximity proximity;
+}
+
+[StructLayout (LayoutKind.Sequential)]
+public struct BluetoothHCIEventReturnLinkKeysResults {
+ public int numLinkKeys;
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct linkKeys {
+ public int deviceAddress;
+
+ public int linkKey;
+ }
+
+
+ public linkKeys [] linkKeys;
+}
diff --git a/tests/sharpie/Tests/Types/Blocks.cs b/tests/sharpie/Tests/Types/Blocks.cs
new file mode 100644
index 000000000000..653fed3bb7d4
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Blocks.cs
@@ -0,0 +1,99 @@
+using System;
+using Foundation;
+using ObjCRuntime;
+
+// typedef void (^Action)();
+delegate void Action ();
+
+// typedef int (^Anon_Func_Long_Int)(long long);
+delegate int Anon_Func_Long_Int (long arg0);
+
+// typedef int (^Named_Func_Long_Int)(long long);
+delegate int Named_Func_Long_Int (long arg0);
+
+// typedef void (^Variadic)(int, ...);
+delegate void Variadic (int arg0, IntPtr varArgs);
+
+// @interface TypedefBlockTests
+interface TypedefBlockTests {
+ // -(Action)get_Action;
+ [Export ("get_Action")]
+ [Verify (MethodToProperty)]
+ Action Get_Action { get; }
+
+ // -(Anon_Func_Long_Int)get_Anon_Func_Long_Int;
+ [Export ("get_Anon_Func_Long_Int")]
+ [Verify (MethodToProperty)]
+ Anon_Func_Long_Int Get_Anon_Func_Long_Int { get; }
+
+ // -(Named_Func_Long_Int)get_Named_Func_Long_Int;
+ [Export ("get_Named_Func_Long_Int")]
+ [Verify (MethodToProperty)]
+ Named_Func_Long_Int Get_Named_Func_Long_Int { get; }
+}
+
+// @interface PropertyBlockTests
+interface PropertyBlockTests {
+ // @property (readonly, copy) void (^action)();
+ [Export ("action", ArgumentSemantic.Copy)]
+ Action Action { get; }
+
+ // @property (readonly, copy) void (^action_int)(int);
+ [Export ("action_int", ArgumentSemantic.Copy)]
+ Action Action_int { get; }
+
+ // @property (readonly, copy) void (^action_action)(void (^)());
+ [Export ("action_action", ArgumentSemantic.Copy)]
+ Action Action_action { get; }
+
+ // @property (readonly, copy) void (^action_action_int)(void (^)(int));
+ [Export ("action_action_int", ArgumentSemantic.Copy)]
+ Action> Action_action_int { get; }
+
+ // @property (readonly, copy) void (^action_action_action)(void (^)(void (^)()));
+ [Export ("action_action_action", ArgumentSemantic.Copy)]
+ Action> Action_action_action { get; }
+
+ // @property (readonly, copy) int (^func_int_int)(int);
+ [Export ("func_int_int", ArgumentSemantic.Copy)]
+ Func Func_int_int { get; }
+
+ // @property (readonly, copy) long (^func_short_nint)(short);
+ [Export ("func_short_nint", ArgumentSemantic.Copy)]
+ Func Func_short_nint { get; }
+}
+
+// @interface AnonymousBlockTests
+interface AnonymousBlockTests {
+ // -(void)set_Action:(void (^)())handler;
+ [Export ("set_Action:")]
+ void Set_Action (Action handler);
+
+ // -(void)set_Action_int:(void (^)(int))handler;
+ [Export ("set_Action_int:")]
+ void Set_Action_int (Action handler);
+
+ // -(void)set_Action_short_int_long:(void (^)(short, int, long long))handler;
+ [Export ("set_Action_short_int_long:")]
+ void Set_Action_short_int_long (Action handler);
+
+ // -(void)set_Func_int:(int (^)())handler;
+ [Export ("set_Func_int:")]
+ void Set_Func_int (Func handler);
+
+ // -(void)set_Func_int_int:(int (^)(int))handler;
+ [Export ("set_Func_int_int:")]
+ void Set_Func_int_int (Func handler);
+
+ // -(void)set_Func_short_int_long_bool:(_Bool (^)(short, int, long long))handler;
+ [Export ("set_Func_short_int_long_bool:")]
+ void Set_Func_short_int_long_bool (Func handler);
+
+ // -(void)set_Func_Func_short_Action_long_short_bool:(_Bool (^)(long long (^)(short, void (^)()), short))handler;
+ [Export ("set_Func_Func_short_Action_long_short_bool:")]
+ void Set_Func_Func_short_Action_long_short_bool (Func, short, bool> handler);
+
+ // -(void)set_Func_Func_short_Action_Action_int_nint_long_short_bool:(_Bool (^)(long long (^)(short, void (^)(void (^)(int, long))), short))handler;
+ [Export ("set_Func_Func_short_Action_Action_int_nint_long_short_bool:")]
+ void Set_Func_Func_short_Action_Action_int_nint_long_short_bool (Func>, long>, short, bool> handler);
+}
diff --git a/tests/sharpie/Tests/Types/Blocks.h b/tests/sharpie/Tests/Types/Blocks.h
new file mode 100644
index 000000000000..f75e4297fd88
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Blocks.h
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+typedef void (^Action)();
+typedef int (^Anon_Func_Long_Int)(long long);
+typedef int (^Named_Func_Long_Int)(long long longArg);
+typedef void (^Variadic)(int, ...);
+
+@interface TypedefBlockTests
+-(Action)get_Action;
+-(Anon_Func_Long_Int)get_Anon_Func_Long_Int;
+-(Named_Func_Long_Int)get_Named_Func_Long_Int;
+@end
+
+@interface PropertyBlockTests
+@property (readonly, copy) void (^action)();
+@property (readonly, copy) void (^action_int)(int);
+@property (readonly, copy) void (^action_action)(void (^)());
+@property (readonly, copy) void (^action_action_int)(void (^)(int));
+@property (readonly, copy) void (^action_action_action)(void (^)(void (^)()));
+@property (readonly, copy) int (^func_int_int)(int);
+@property (readonly, copy) long (^func_short_nint)(short);
+@end
+
+@interface AnonymousBlockTests
+-(void)set_Action:(void (^)())handler;
+-(void)set_Action_int:(void (^)(int))handler;
+-(void)set_Action_short_int_long:(void (^)(short, int, long long))handler;
+-(void)set_Func_int:(int (^)())handler;
+-(void)set_Func_int_int:(int (^)(int))handler;
+-(void)set_Func_short_int_long_bool:(_Bool (^)(short, int, long long))handler;
+-(void)set_Func_Func_short_Action_long_short_bool:(_Bool (^)(long long (^)(short, void (^)()), short))handler;
+-(void)set_Func_Func_short_Action_Action_int_nint_long_short_bool:(_Bool (^)(long long (^)(short, void (^)(void (^)(int, long))), short))handler;
+@end
diff --git a/tests/sharpie/Tests/Types/Builtin.cs b/tests/sharpie/Tests/Types/Builtin.cs
new file mode 100644
index 000000000000..e941cd5c1d67
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Builtin.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Runtime.InteropServices;
+
+static class CFunctions {
+ // extern void _void ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void _void ();
+
+ // extern _Bool _bool ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern bool _bool ();
+
+ // extern char _char ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern sbyte _char ();
+
+ // extern unsigned char _unsigned_char ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern byte _unsigned_char ();
+
+ // extern short _short ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern short _short ();
+
+ // extern unsigned short _unsigned_short ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ushort _unsigned_short ();
+
+ // extern int _int ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern int _int ();
+
+ // extern unsigned int _unsigned_int ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern uint _unsigned_int ();
+
+ // extern long _long ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern nint _long ();
+
+ // extern unsigned long _unsigned_long ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern nuint _unsigned_long ();
+
+ // extern long long _long_long ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern long _long_long ();
+
+ // extern unsigned long long _unsigned_long_long ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ulong _unsigned_long_long ();
+
+ // extern float _float ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern float _float ();
+
+ // extern double _double ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern double _double ();
+
+ // extern long double _long_double ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern decimal _long_double ();
+}
diff --git a/tests/sharpie/Tests/Types/Builtin.h b/tests/sharpie/Tests/Types/Builtin.h
new file mode 100644
index 000000000000..fecb2886a7e5
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Builtin.h
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+void _void ();
+_Bool _bool ();
+char _char ();
+unsigned char _unsigned_char ();
+short _short ();
+unsigned short _unsigned_short ();
+int _int ();
+unsigned int _unsigned_int ();
+long _long ();
+unsigned long _unsigned_long ();
+long long _long_long ();
+unsigned long long _unsigned_long_long ();
+float _float ();
+double _double ();
+long double _long_double ();
diff --git a/tests/sharpie/Tests/Types/CommonClang.h b/tests/sharpie/Tests/Types/CommonClang.h
new file mode 100644
index 000000000000..7e66661eb936
--- /dev/null
+++ b/tests/sharpie/Tests/Types/CommonClang.h
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+//
+// These types are "specialized" by clang on ASTContext
+
+#include
+#include
+#include
+
+#import
+
+@interface CommonClang
++(instancetype)_instancetype;
+-(BOOL)_BOOL;
+-(intptr_t)_intptr_t;
+-(uintptr_t)_uintptr_t;
+-(NSString *)_NSString_ptr;
+@end
diff --git a/tests/sharpie/Tests/Types/CommonClang.iphoneos.cs b/tests/sharpie/Tests/Types/CommonClang.iphoneos.cs
new file mode 100644
index 000000000000..72d751e06072
--- /dev/null
+++ b/tests/sharpie/Tests/Types/CommonClang.iphoneos.cs
@@ -0,0 +1,30 @@
+using System;
+using Foundation;
+
+// @interface CommonClang
+interface CommonClang {
+ // +(instancetype)_instancetype;
+ [Static]
+ [Export ("_instancetype")]
+ CommonClang _instancetype ();
+
+ // -(BOOL)_BOOL;
+ [Export ("_BOOL")]
+ [Verify (MethodToProperty)]
+ bool _BOOL { get; }
+
+ // -(intptr_t)_intptr_t;
+ [Export ("_intptr_t")]
+ [Verify (MethodToProperty)]
+ IntPtr _intptr_t { get; }
+
+ // -(uintptr_t)_uintptr_t;
+ [Export ("_uintptr_t")]
+ [Verify (MethodToProperty)]
+ UIntPtr _uintptr_t { get; }
+
+ // -(NSString *)_NSString_ptr;
+ [Export ("_NSString_ptr")]
+ [Verify (MethodToProperty)]
+ string _NSString_ptr { get; }
+}
diff --git a/tests/sharpie/Tests/Types/CommonClang.macosx.cs b/tests/sharpie/Tests/Types/CommonClang.macosx.cs
new file mode 100644
index 000000000000..72d751e06072
--- /dev/null
+++ b/tests/sharpie/Tests/Types/CommonClang.macosx.cs
@@ -0,0 +1,30 @@
+using System;
+using Foundation;
+
+// @interface CommonClang
+interface CommonClang {
+ // +(instancetype)_instancetype;
+ [Static]
+ [Export ("_instancetype")]
+ CommonClang _instancetype ();
+
+ // -(BOOL)_BOOL;
+ [Export ("_BOOL")]
+ [Verify (MethodToProperty)]
+ bool _BOOL { get; }
+
+ // -(intptr_t)_intptr_t;
+ [Export ("_intptr_t")]
+ [Verify (MethodToProperty)]
+ IntPtr _intptr_t { get; }
+
+ // -(uintptr_t)_uintptr_t;
+ [Export ("_uintptr_t")]
+ [Verify (MethodToProperty)]
+ UIntPtr _uintptr_t { get; }
+
+ // -(NSString *)_NSString_ptr;
+ [Export ("_NSString_ptr")]
+ [Verify (MethodToProperty)]
+ string _NSString_ptr { get; }
+}
diff --git a/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.h b/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.h
new file mode 100644
index 000000000000..bd8940931158
--- /dev/null
+++ b/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.h
@@ -0,0 +1,37 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c++
+// RUN iphoneos: -sdk iphoneos -x objective-c++
+
+/*namespace std {
+ class string { };
+}
+
+@interface NSString
+@end
+
+@interface NSString (CxxStringAdditions)
++(NSString *)stringWithCxxStdString:(const std::string&)string;
+@end*/
+
+#import
+
+namespace dp
+{
+ class String
+ {
+
+ };
+}
+
+@interface ForceNSStringRMServicesAdditionsToLoad : NSObject
+@end
+
+@interface NSString (RMServicesAdditions)
+
+#ifdef __cplusplus
+ +(NSString*)stringWithDPString:(const dp::String&)string;
+#endif
+
+@end
diff --git a/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.iphoneos.cs b/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.iphoneos.cs
new file mode 100644
index 000000000000..0d4006e2b8c4
--- /dev/null
+++ b/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.iphoneos.cs
@@ -0,0 +1,16 @@
+using Foundation;
+
+// @interface ForceNSStringRMServicesAdditionsToLoad : NSObject
+[BaseType (typeof (NSObject))]
+interface ForceNSStringRMServicesAdditionsToLoad {
+}
+
+// @interface RMServicesAdditions (NSString)
+[Category]
+[BaseType (typeof (NSString))]
+interface NSString_RMServicesAdditions {
+ // +(NSString *)stringWithDPString:(const dp::String &)string;
+ [Static]
+ [Export ("stringWithDPString:")]
+ string StringWithDPString (PlaceholderType /* Unsupported: CXType_LValueReference: const dp::String & */ @string);
+}
diff --git a/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.macosx.cs b/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.macosx.cs
new file mode 100644
index 000000000000..0d4006e2b8c4
--- /dev/null
+++ b/tests/sharpie/Tests/Types/CxxTypeInObjCSignature.macosx.cs
@@ -0,0 +1,16 @@
+using Foundation;
+
+// @interface ForceNSStringRMServicesAdditionsToLoad : NSObject
+[BaseType (typeof (NSObject))]
+interface ForceNSStringRMServicesAdditionsToLoad {
+}
+
+// @interface RMServicesAdditions (NSString)
+[Category]
+[BaseType (typeof (NSString))]
+interface NSString_RMServicesAdditions {
+ // +(NSString *)stringWithDPString:(const dp::String &)string;
+ [Static]
+ [Export ("stringWithDPString:")]
+ string StringWithDPString (PlaceholderType /* Unsupported: CXType_LValueReference: const dp::String & */ @string);
+}
diff --git a/tests/sharpie/Tests/Types/Decayed.cs b/tests/sharpie/Tests/Types/Decayed.cs
new file mode 100644
index 000000000000..527a94db15bd
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Decayed.cs
@@ -0,0 +1,2 @@
+// typedef void (^decayedBlock)(int[]);
+delegate void decayedBlock (int [] arg0);
diff --git a/tests/sharpie/Tests/Types/Decayed.h b/tests/sharpie/Tests/Types/Decayed.h
new file mode 100644
index 000000000000..28460d12c0e3
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Decayed.h
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+typedef void (^decayedBlock)(int values []);
diff --git a/tests/sharpie/Tests/Types/Dispatch.h b/tests/sharpie/Tests/Types/Dispatch.h
new file mode 100644
index 000000000000..6c1b9f518afd
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Dispatch.h
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+
+#include
+
+@interface DispatchTests
+@property (assign) dispatch_object_t object;
+@property (assign) dispatch_queue_t queue;
+@property (assign) dispatch_group_t group;
+@end
diff --git a/tests/sharpie/Tests/Types/Dispatch.iphoneos.cs b/tests/sharpie/Tests/Types/Dispatch.iphoneos.cs
new file mode 100644
index 000000000000..ac39031956fe
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Dispatch.iphoneos.cs
@@ -0,0 +1,18 @@
+using CoreFoundation;
+using Foundation;
+using ObjCRuntime;
+
+// @interface DispatchTests
+interface DispatchTests {
+ // @property (assign) dispatch_object_t object;
+ [Export ("object", ArgumentSemantic.Assign)]
+ DispatchObject Object { get; set; }
+
+ // @property (assign) dispatch_queue_t queue;
+ [Export ("queue", ArgumentSemantic.Assign)]
+ DispatchQueue Queue { get; set; }
+
+ // @property (assign) dispatch_group_t group;
+ [Export ("group", ArgumentSemantic.Assign)]
+ DispatchGroup Group { get; set; }
+}
diff --git a/tests/sharpie/Tests/Types/Dispatch.macosx.cs b/tests/sharpie/Tests/Types/Dispatch.macosx.cs
new file mode 100644
index 000000000000..ac39031956fe
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Dispatch.macosx.cs
@@ -0,0 +1,18 @@
+using CoreFoundation;
+using Foundation;
+using ObjCRuntime;
+
+// @interface DispatchTests
+interface DispatchTests {
+ // @property (assign) dispatch_object_t object;
+ [Export ("object", ArgumentSemantic.Assign)]
+ DispatchObject Object { get; set; }
+
+ // @property (assign) dispatch_queue_t queue;
+ [Export ("queue", ArgumentSemantic.Assign)]
+ DispatchQueue Queue { get; set; }
+
+ // @property (assign) dispatch_group_t group;
+ [Export ("group", ArgumentSemantic.Assign)]
+ DispatchGroup Group { get; set; }
+}
diff --git a/tests/sharpie/Tests/Types/Dispatch.macosx10.9.cs b/tests/sharpie/Tests/Types/Dispatch.macosx10.9.cs
new file mode 100644
index 000000000000..ac39031956fe
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Dispatch.macosx10.9.cs
@@ -0,0 +1,18 @@
+using CoreFoundation;
+using Foundation;
+using ObjCRuntime;
+
+// @interface DispatchTests
+interface DispatchTests {
+ // @property (assign) dispatch_object_t object;
+ [Export ("object", ArgumentSemantic.Assign)]
+ DispatchObject Object { get; set; }
+
+ // @property (assign) dispatch_queue_t queue;
+ [Export ("queue", ArgumentSemantic.Assign)]
+ DispatchQueue Queue { get; set; }
+
+ // @property (assign) dispatch_group_t group;
+ [Export ("group", ArgumentSemantic.Assign)]
+ DispatchGroup Group { get; set; }
+}
diff --git a/tests/sharpie/Tests/Types/NSGeometry.h b/tests/sharpie/Tests/Types/NSGeometry.h
new file mode 100644
index 000000000000..f832c9287793
--- /dev/null
+++ b/tests/sharpie/Tests/Types/NSGeometry.h
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx
+
+@import CoreGraphics;
+
+typedef CGPoint NSPoint;
+typedef CGSize NSSize;
+typedef CGRect NSRect;
+
+@interface NSGeometryTest
+-(NSPoint)getPoint;
+-(NSSize)getSize;
+-(NSRect)getRect;
+@end
diff --git a/tests/sharpie/Tests/Types/NSGeometry.macosx.cs b/tests/sharpie/Tests/Types/NSGeometry.macosx.cs
new file mode 100644
index 000000000000..0e0c66e5c545
--- /dev/null
+++ b/tests/sharpie/Tests/Types/NSGeometry.macosx.cs
@@ -0,0 +1,20 @@
+using CoreFoundation;
+using Foundation;
+
+// @interface NSGeometryTest
+interface NSGeometryTest {
+ // -(NSPoint)getPoint;
+ [Export ("getPoint")]
+ [Verify (MethodToProperty)]
+ CGPoint Point { get; }
+
+ // -(NSSize)getSize;
+ [Export ("getSize")]
+ [Verify (MethodToProperty)]
+ CGSize Size { get; }
+
+ // -(NSRect)getRect;
+ [Export ("getRect")]
+ [Verify (MethodToProperty)]
+ CGRect Rect { get; }
+}
diff --git a/tests/sharpie/Tests/Types/ObjCObject.cs b/tests/sharpie/Tests/Types/ObjCObject.cs
new file mode 100644
index 000000000000..38e93ea0c730
--- /dev/null
+++ b/tests/sharpie/Tests/Types/ObjCObject.cs
@@ -0,0 +1,100 @@
+using System.Runtime.InteropServices;
+using Foundation;
+using ObjCRuntime;
+
+// @interface NSString
+interface NSString {
+}
+
+static class CFunctions {
+ // extern NSString * _NSString ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern NSString _NSString ();
+
+ // extern NSString ** _Ptr_NSString ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe NSString* _Ptr_NSString ();
+
+ // extern NSString *** _Ptr_Ptr_NSString ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe NSString** _Ptr_Ptr_NSString ();
+
+ // extern id _Id ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern NSObject _Id ();
+
+ // extern Class _Class ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern Class _Class ();
+
+ // extern id _Id_of_ProtoA ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ProtoA _Id_of_ProtoA ();
+
+ // extern Class _Class_of_ProtoA ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ProtoA _Class_of_ProtoA ();
+
+ // extern SEL _SEL ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern Selector _SEL ();
+
+ // extern SEL * _Ptr_SEL ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe Selector* _Ptr_SEL ();
+
+ // extern SEL ** _Ptr_Ptr_SEL ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe Selector** _Ptr_Ptr_SEL ();
+
+ // extern Foo * _Foo_of_ProtoA_and_ProtoB ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern Foo _Foo_of_ProtoA_and_ProtoB ();
+}
+
+// @protocol ProtoA
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface ProtoA {
+}
+
+// @protocol ProtoB
+/*
+ Check whether adding [Model] to this declaration is appropriate.
+ [Model] is used to generate a C# class that implements this protocol,
+ and might be useful for protocols that consumers are supposed to implement,
+ since consumers can subclass the generated class instead of implementing
+ the generated interface. If consumers are not supposed to implement this
+ protocol, then [Model] is redundant and will generate code that will never
+ be used.
+*/
+[Protocol]
+interface ProtoB {
+}
+
+// @interface Foo
+interface Foo {
+ // +(instancetype)create;
+ [Static]
+ [Export ("create")]
+ Foo Create ();
+}
diff --git a/tests/sharpie/Tests/Types/ObjCObject.h b/tests/sharpie/Tests/Types/ObjCObject.h
new file mode 100644
index 000000000000..62b8f9a5307f
--- /dev/null
+++ b/tests/sharpie/Tests/Types/ObjCObject.h
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+@interface NSString
+@end
+
+NSString *_NSString ();
+NSString **_Ptr_NSString ();
+NSString ***_Ptr_Ptr_NSString ();
+
+@protocol ProtoA
+@end
+
+@protocol ProtoB
+@end
+
+id _Id ();
+Class _Class ();
+id _Id_of_ProtoA ();
+Class _Class_of_ProtoA ();
+SEL _SEL ();
+SEL *_Ptr_SEL ();
+SEL **_Ptr_Ptr_SEL ();
+
+@interface Foo
++(instancetype)create;
+@end
+
+Foo *_Foo_of_ProtoA_and_ProtoB ();
diff --git a/tests/sharpie/Tests/Types/Pointers.h b/tests/sharpie/Tests/Types/Pointers.h
new file mode 100644
index 000000000000..658a8838f080
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Pointers.h
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx -x objective-c
+// RUN iphoneos: -sdk iphoneos -x objective-c
+
+#import
+
+void *_void_ptr ();
+int *_int_ptr ();
+int **_int_ptr_ptr ();
+int ***_int_ptr_ptr_ptr ();
+
+@interface ObjCObjectOutPointers
+-(void)getError:(NSError **)error;
+@end
diff --git a/tests/sharpie/Tests/Types/Pointers.iphoneos.cs b/tests/sharpie/Tests/Types/Pointers.iphoneos.cs
new file mode 100644
index 000000000000..f04f054538a8
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Pointers.iphoneos.cs
@@ -0,0 +1,31 @@
+using System.Runtime.InteropServices;
+using Foundation;
+
+static class CFunctions {
+ // extern void * _void_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe void* _void_ptr ();
+
+ // extern int * _int_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int* _int_ptr ();
+
+ // extern int ** _int_ptr_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int** _int_ptr_ptr ();
+
+ // extern int *** _int_ptr_ptr_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int*** _int_ptr_ptr_ptr ();
+}
+
+// @interface ObjCObjectOutPointers
+interface ObjCObjectOutPointers {
+ // -(void)getError:(NSError **)error;
+ [Export ("getError:")]
+ void GetError (out NSError error);
+}
diff --git a/tests/sharpie/Tests/Types/Pointers.macosx.cs b/tests/sharpie/Tests/Types/Pointers.macosx.cs
new file mode 100644
index 000000000000..f04f054538a8
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Pointers.macosx.cs
@@ -0,0 +1,31 @@
+using System.Runtime.InteropServices;
+using Foundation;
+
+static class CFunctions {
+ // extern void * _void_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe void* _void_ptr ();
+
+ // extern int * _int_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int* _int_ptr ();
+
+ // extern int ** _int_ptr_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int** _int_ptr_ptr ();
+
+ // extern int *** _int_ptr_ptr_ptr ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern unsafe int*** _int_ptr_ptr_ptr ();
+}
+
+// @interface ObjCObjectOutPointers
+interface ObjCObjectOutPointers {
+ // -(void)getError:(NSError **)error;
+ [Export ("getError:")]
+ void GetError (out NSError error);
+}
diff --git a/tests/sharpie/Tests/Types/Typedef.cs b/tests/sharpie/Tests/Types/Typedef.cs
new file mode 100644
index 000000000000..e63fd8f8084a
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Typedef.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Runtime.InteropServices;
+
+static class CFunctions {
+ // extern int32_t _int32_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern int _int32_t ();
+
+ // extern e _a_to_e ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void _a_to_e ();
+
+ // extern CGFloat _CGFloat ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern nfloat _CGFloat ();
+
+ // extern BOOL _BOOL ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern bool _BOOL ();
+
+ // extern GLboolean _GLboolean ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern bool _GLboolean ();
+
+ // extern NSTimeInterval _NSTimeInterval ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern double _NSTimeInterval ();
+}
diff --git a/tests/sharpie/Tests/Types/Typedef.h b/tests/sharpie/Tests/Types/Typedef.h
new file mode 100644
index 000000000000..8bd69d320b68
--- /dev/null
+++ b/tests/sharpie/Tests/Types/Typedef.h
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+typedef int int32_t;
+int32_t _int32_t ();
+
+typedef void a;
+typedef a b;
+typedef b c;
+typedef c d;
+typedef d e;
+e _a_to_e ();
+
+typedef double CGFloat;
+CGFloat _CGFloat ();
+
+typedef char BOOL;
+BOOL _BOOL ();
+
+typedef unsigned char uint8_t;
+typedef uint8_t GLboolean;
+GLboolean _GLboolean ();
+
+typedef double NSTimeInterval;
+NSTimeInterval _NSTimeInterval ();
diff --git a/tests/sharpie/Tests/Types/stddef.cs b/tests/sharpie/Tests/Types/stddef.cs
new file mode 100644
index 000000000000..013376aee185
--- /dev/null
+++ b/tests/sharpie/Tests/Types/stddef.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Runtime.InteropServices;
+
+static class CFunctions {
+ // extern ptrdiff_t _ptrdiff_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern IntPtr _ptrdiff_t ();
+
+ // extern size_t _size_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern nuint _size_t ();
+
+ // extern wchar_t _wchar_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern int _wchar_t ();
+}
diff --git a/tests/sharpie/Tests/Types/stddef.h b/tests/sharpie/Tests/Types/stddef.h
new file mode 100644
index 000000000000..548125fd0873
--- /dev/null
+++ b/tests/sharpie/Tests/Types/stddef.h
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include
+
+ptrdiff_t _ptrdiff_t ();
+size_t _size_t ();
+wchar_t _wchar_t ();
diff --git a/tests/sharpie/Tests/Types/stdint.h b/tests/sharpie/Tests/Types/stdint.h
new file mode 100644
index 000000000000..53456105a906
--- /dev/null
+++ b/tests/sharpie/Tests/Types/stdint.h
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// RUN macosx: -sdk macosx
+// RUN iphoneos: -sdk iphoneos
+
+#include
+
+int8_t _int8_t ();
+uint8_t _uint8_t ();
+int16_t _int16_t ();
+uint16_t _uint16_t ();
+int32_t _int32_t ();
+uint32_t _uint32_t ();
+int64_t _int64_t ();
+uint64_t _uint64_t ();
+
+intptr_t _intptr_t ();
+uintptr_t _uintptr_t ();
diff --git a/tests/sharpie/Tests/Types/stdint.iphoneos.cs b/tests/sharpie/Tests/Types/stdint.iphoneos.cs
new file mode 100644
index 000000000000..6a16e9779fcd
--- /dev/null
+++ b/tests/sharpie/Tests/Types/stdint.iphoneos.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.InteropServices;
+
+static class CFunctions {
+ // extern int8_t _int8_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern sbyte _int8_t ();
+
+ // extern uint8_t _uint8_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern byte _uint8_t ();
+
+ // extern int16_t _int16_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern short _int16_t ();
+
+ // extern uint16_t _uint16_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ushort _uint16_t ();
+
+ // extern int32_t _int32_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern int _int32_t ();
+
+ // extern uint32_t _uint32_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern uint _uint32_t ();
+
+ // extern int64_t _int64_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern long _int64_t ();
+
+ // extern uint64_t _uint64_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ulong _uint64_t ();
+
+ // extern intptr_t _intptr_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern IntPtr _intptr_t ();
+
+ // extern uintptr_t _uintptr_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern UIntPtr _uintptr_t ();
+}
diff --git a/tests/sharpie/Tests/Types/stdint.macosx.cs b/tests/sharpie/Tests/Types/stdint.macosx.cs
new file mode 100644
index 000000000000..6a16e9779fcd
--- /dev/null
+++ b/tests/sharpie/Tests/Types/stdint.macosx.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.InteropServices;
+
+static class CFunctions {
+ // extern int8_t _int8_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern sbyte _int8_t ();
+
+ // extern uint8_t _uint8_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern byte _uint8_t ();
+
+ // extern int16_t _int16_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern short _int16_t ();
+
+ // extern uint16_t _uint16_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ushort _uint16_t ();
+
+ // extern int32_t _int32_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern int _int32_t ();
+
+ // extern uint32_t _uint32_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern uint _uint32_t ();
+
+ // extern int64_t _int64_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern long _int64_t ();
+
+ // extern uint64_t _uint64_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern ulong _uint64_t ();
+
+ // extern intptr_t _intptr_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern IntPtr _intptr_t ();
+
+ // extern uintptr_t _uintptr_t ();
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern UIntPtr _uintptr_t ();
+}
diff --git a/tests/sharpie/Tests/VersionTuple.cs b/tests/sharpie/Tests/VersionTuple.cs
new file mode 100644
index 000000000000..115145507ec4
--- /dev/null
+++ b/tests/sharpie/Tests/VersionTuple.cs
@@ -0,0 +1,21 @@
+using System.Runtime.InteropServices;
+
+static class CFunctions {
+ // extern void Version_10 () __attribute__((availability(macos, introduced=10)));
+ [Mac (10, 0)]
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void Version_10 ();
+
+ // extern void Version_10_5 () __attribute__((availability(macos, introduced=10.5)));
+ [Mac (10, 5)]
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void Version_10_5 ();
+
+ // extern void Version_10_5_9 () __attribute__((availability(macos, introduced=10.5.9)));
+ [Mac (10, 5, 9)]
+ [DllImport ("__Internal")]
+ [Verify (PlatformInvoke)]
+ static extern void Version_10_5_9 ();
+}
diff --git a/tests/sharpie/Tests/VersionTuple.h b/tests/sharpie/Tests/VersionTuple.h
new file mode 100644
index 000000000000..d964e0969a67
--- /dev/null
+++ b/tests/sharpie/Tests/VersionTuple.h
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+extern void Version_10 () __attribute__((availability (macosx,introduced=10)));
+extern void Version_10_5 () __attribute__((availability (macosx,introduced=10.5)));
+extern void Version_10_5_9 () __attribute__((availability (macosx,introduced=10.5.9)));
diff --git a/tests/xharness/Harness.cs b/tests/xharness/Harness.cs
index 86fdcfc05302..a281e9f4b701 100644
--- a/tests/xharness/Harness.cs
+++ b/tests/xharness/Harness.cs
@@ -395,6 +395,13 @@ void PopulateUnitTestProjects ()
Timeout = (TimeSpan?) TimeSpan.FromMinutes (165 /* 2h45m: to time out here before the CI job does at 3h */),
Filter = "Category!=Windows",
},
+ new {
+ Label = TestLabel.Sharpie,
+ ProjectPath = Path.GetFullPath (Path.Combine (HarnessConfiguration.RootDirectory, "sharpie", "Sharpie.Bind.Tests", "Sharpie.Bind.Tests.csproj")),
+ Name = "Sharpie tests",
+ Timeout = (TimeSpan?) TimeSpan.FromMinutes (30),
+ Filter = "",
+ },
new {
Label = TestLabel.Xtro,
ProjectPath = Path.GetFullPath (Path.Combine (HarnessConfiguration.RootDirectory, "xtro-sharpie", "UnitTests", "UnitTests.csproj")),
diff --git a/tests/xharness/TestLabel.cs b/tests/xharness/TestLabel.cs
index 712df73a694d..9085a1eb815f 100644
--- a/tests/xharness/TestLabel.cs
+++ b/tests/xharness/TestLabel.cs
@@ -72,6 +72,8 @@ public enum TestLabel : Int64 {
PackagedMacOS = 1 << 28,
[Label ("windows")]
Windows = 1 << 29,
+ [Label ("sharpie")]
+ Sharpie = 1 << 30,
[Label ("all")]
All = Int64.MaxValue,
}
diff --git a/tests/xtro-sharpie/.gitignore b/tests/xtro-sharpie/.gitignore
index c005aa5968ec..52ca93001ec0 100644
--- a/tests/xtro-sharpie/.gitignore
+++ b/tests/xtro-sharpie/.gitignore
@@ -1,8 +1,8 @@
-pch-info.proj
+api
*.results
-*.pch*
*.unclassified
*.raw
*.g.cs
*.html
report/
+*.rsp
diff --git a/tests/xtro-sharpie/.vscode/launch.json b/tests/xtro-sharpie/.vscode/launch.json
new file mode 100644
index 000000000000..45fda885536f
--- /dev/null
+++ b/tests/xtro-sharpie/.vscode/launch.json
@@ -0,0 +1,19 @@
+{
+ // 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": "xtro-sharpie: iOS",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "dotnet: build",
+ "program": "${workspaceFolder}/xtro-sharpie/bin/Debug/xtro-sharpie.dll",
+ "args": [
+ "@xtro-sharpie-iOS.rsp",
+ ],
+ }
+
+ ]
+}
diff --git a/tests/xtro-sharpie/Makefile b/tests/xtro-sharpie/Makefile
index 142ad48c9fed..eb3f4d554531 100644
--- a/tests/xtro-sharpie/Makefile
+++ b/tests/xtro-sharpie/Makefile
@@ -2,9 +2,7 @@ TOP=../..
include $(TOP)/Make.config
-# a 64bits mono is required because of the clang requirement
-MONO ?= mono64 --debug
-SHARPIE ?= sharpie
+SHARPIE ?= $(TOP)/tools/sharpie/Sharpie.Bind.Tool/bin/Release/osx-arm64/publish/Sharpie.Bind.Tool
XCODE=$(abspath $(XCODE_DEVELOPER_ROOT)/../..)
@@ -18,18 +16,17 @@ all-local::
clean-local::
rm -rf */bin */obj
rm -f *.tmp
- rm -rf *os*.pch*
XTRO_REPORT=xtro-report/bin/Debug/xtro-report
XTRO_REPORT_EXEC=$(XTRO_REPORT)
XTRO_SANITY=xtro-sanity/bin/Debug/xtro-sanity
XTRO_SANITY_EXEC=$(XTRO_SANITY)
-XTRO_SHARPIE=xtro-sharpie/bin/Debug/xtro-sharpie.exe
-XTRO_SHARPIE_EXEC=$(MONO) --debug $(XTRO_SHARPIE)
+XTRO_SHARPIE=xtro-sharpie/bin/Debug/xtro-sharpie
+XTRO_SHARPIE_EXEC=$(XTRO_SHARPIE)
build: $(XTRO_SHARPIE) $(XTRO_REPORT) $(XTRO_SANITY)
-$(XTRO_SHARPIE): $(wildcard xtro-sharpie/*.cs) $(wildcard xtro-sharpie/*.csproj) pch-info.proj $(XTRO_REPORT)
+$(XTRO_SHARPIE): $(wildcard xtro-sharpie/*.cs) $(wildcard xtro-sharpie/*.csproj) $(XTRO_REPORT)
$(Q_GEN) unset MSBUILD_EXE_PATH && $(DOTNET) build xtro-sharpie/xtro-sharpie.csproj /bl:xtro-sharpie.binlog $(DOTNET_BUILD_VERBOSITY)
$(XTRO_REPORT): $(wildcard xtro-report/*.cs) $(wildcard xtro-report/*.csproj) xtro-sharpie/Filter.cs Makefile
@@ -38,6 +35,15 @@ $(XTRO_REPORT): $(wildcard xtro-report/*.cs) $(wildcard xtro-report/*.csproj) xt
$(XTRO_SANITY): $(wildcard xtro-sanity/*.cs) $(wildcard xtro-sanity/*.csproj) $(wildcard $(TOP)/tools/common/*.cs) Makefile
$(Q_GEN) unset MSBUILD_EXE_PATH && $(DOTNET) build xtro-sanity/xtro-sanity.csproj /bl:xtro-sanity.binlog $(DOTNET_BUILD_VERBOSITY)
+define DotNetAssemblyPath
+ifdef TESTS_USE_SYSTEM
+X$(2)_DOTNET ?= $(DOTNET_DIR)/packs/$($(2)_NUGET_RUNTIME_MANAGED_NAME)/$($(2)_WORKLOAD_VERSION)/runtimes/$(DOTNET_$(2)_RUNTIME_IDENTIFIERS_NO_ARCH)/lib/$(DOTNET_TFM)/$(DOTNET_$(2)_ASSEMBLY_NAME).dll
+else
+X$(2)_DOTNET ?= $(DOTNET_DESTDIR)/$($(2)_NUGET_RUNTIME_MANAGED_NAME)/runtimes/$(DOTNET_$(2)_RUNTIME_IDENTIFIERS_NO_ARCH)/lib/$(DOTNET_TFM)/$(DOTNET_$(2)_ASSEMBLY_NAME).dll
+endif
+endef
+$(foreach platform,$(XTRO_DOTNET_PLATFORMS),$(eval $(call DotNetAssemblyPath,$(platform),$(shell echo $(platform) | tr a-z A-Z))))
+
CORETELEPHONY_HEADERS = \
-i CoreTelephony/CoreTelephonyDefines.h \
-i CoreTelephony/CTCall.h \
@@ -80,6 +86,11 @@ IGNORED_MACOS_FRAMEWORKS = \
$(COMMON_IGNORED_FRAMEWORKS) \
AccessorySetupKit \
CompositorServices \
+ DriverKit \
+ Kerberos \
+ IOUSBHost \
+ Ruby \
+ Tk \
IGNORED_MACCATALYST_FRAMEWORKS = \
$(COMMON_IGNORED_FRAMEWORKS) \
@@ -92,47 +103,49 @@ IGNORED_MACCATALYST_FRAMEWORKS = \
ClockKit \
CompositorServices \
DiscRecordingUI \
+ DriverKit \
FSKit \
GLKit \
+ Hypervisor \
ICADevices \
InputMethodKit \
InstallerPlugins \
IOBluetooth \
IOBluetoothUI \
+ IOUSBHost \
+ Kerberos \
LDAP \
Python \
Quartz \
QuickLookUI \
+ Ruby \
SecurityInterface \
+ Tk \
Virtualization \
COMMON_SHARPIE_ARGUMENTS = \
- --xcode $(XCODE) \
-a arm64 \
- -modules false \
+ -modules true \
+ --clang-resource-dir $(TOP)/tools/sharpie/clang \
IOS_SHARPIE_ARGUMENTS = \
$(COMMON_SHARPIE_ARGUMENTS) \
$(CORETELEPHONY_HEADERS) \
- --compiler-arguments=-F \
- --compiler-arguments=$(XCODE_DEVELOPER_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(IOS_SDK_VERSION).sdk/System/Library/SubFrameworks
+ --platform-assembly $(XIOS_DOTNET) \
TVOS_SHARPIE_ARGUMENTS = \
$(COMMON_SHARPIE_ARGUMENTS) \
- --compiler-arguments=-F \
- --compiler-arguments=$(XCODE_DEVELOPER_ROOT)/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS$(TVOS_SDK_VERSION).sdk/System/Library/SubFrameworks
+ --platform-assembly $(XTVOS_DOTNET) \
MACCATALYST_SHARPIE_ARGUMENTS = \
$(COMMON_SHARPIE_ARGUMENTS) \
$(CORETELEPHONY_HEADERS) \
- --compiler-arguments=-F \
- --compiler-arguments=$(XCODE_DEVELOPER_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX$(MACOS_SDK_VERSION).sdk/System/Library/SubFrameworks
+ --platform-assembly $(XMACCATALYST_DOTNET) \
MACOS_SHARPIE_ARGUMENTS = \
$(COMMON_SHARPIE_ARGUMENTS) \
$(CORETELEPHONY_HEADERS) \
- --compiler-arguments=-F \
- --compiler-arguments=$(XCODE_DEVELOPER_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX$(MACOS_SDK_VERSION).sdk/System/Library/SubFrameworks
+ --platform-assembly $(XMACOS_DOTNET) \
IOS_PLATFORM=iphoneos$(IOS_SDK_VERSION)
TVOS_PLATFORM=appletvos$(TVOS_SDK_VERSION)
@@ -145,23 +158,16 @@ XMACOS_RID = osx-arm64
XMACCATALYST_RID = maccatalyst-arm64
define DotNetAssembly
-X$(2)_PCH = $($(2)_PLATFORM)-arm64.pch
-$$(X$(2)_PCH): .stamp-check-sharpie
- $(SHARPIE) sdk-db -s $($(2)_PLATFORM) $$($(2)_SHARPIE_ARGUMENTS) $$(foreach framework,$$(IGNORED_$(2)_FRAMEWORKS),-exclude $$(framework))
+$(1).rsp: Makefile
+ $$(Q_GEN) echo \
+ -s $($(2)_PLATFORM) $$($(2)_SHARPIE_ARGUMENTS) $$(foreach framework,$$(IGNORED_$(2)_FRAMEWORKS),-exclude $$(framework)) \
+ --output api/$(1) \
+ > $$@
-pch:: $$(X$(2)_PCH)
+api/$(1)/ApiDefinition.cs: $(1).rsp
+ $$(Q_GEN) $$(SHARPIE) sdk-db @$(1).rsp
-ifdef TESTS_USE_SYSTEM
-X$(2)_DOTNET ?= $(DOTNET_DIR)/packs/$($(2)_NUGET_RUNTIME_MANAGED_NAME)/$($(2)_WORKLOAD_VERSION)/runtimes/$(DOTNET_$(2)_RUNTIME_IDENTIFIERS_NO_ARCH)/lib/$(DOTNET_TFM)/$(DOTNET_$(2)_ASSEMBLY_NAME).dll
-else
-X$(2)_DOTNET ?= $(DOTNET_DESTDIR)/$($(2)_NUGET_RUNTIME_MANAGED_NAME)/runtimes/$(DOTNET_$(2)_RUNTIME_IDENTIFIERS_NO_ARCH)/lib/$(DOTNET_TFM)/$(DOTNET_$(2)_ASSEMBLY_NAME).dll
-endif
-
-$(3)-$($(2)_SDK_VERSION).g.cs: .stamp-check-sharpie $$(X$(2)_PCH)
- $$(Q_GEN) $$(SHARPIE) query -bind $$(X$(2)_PCH) > $$@.tmp
- $$(Q) mv $$@.tmp $$@
-
-gen-$(3): $(3)-$$($(2)_SDK_VERSION).g.cs
+gen-$(3): api/$(1)/ApiDefinition.cs
gen-all:: gen-$(3)
endef
$(foreach platform,$(XTRO_DOTNET_PLATFORMS),$(eval $(call DotNetAssembly,$(platform),$(shell echo $(platform) | tr a-z A-Z),$(shell echo $(platform) | tr A-Z a-z))))
@@ -170,16 +176,6 @@ ifeq ($(XCODE_IS_STABLE),false)
all: gen-all
endif
-pch-info.proj: Makefile
- $(Q) rm -f $@.tmp
- $(Q) printf "\\n" >> $@.tmp
- $(Q) printf "\\t\\n" >> $@.tmp
- $(Q) printf "$(foreach platform,$(ALL_DOTNET_PLATFORMS),\\t\\t<$(platform)_PCH>$(X$(shell echo $(platform) | tr '[:lower:]' '[:upper:]')_PCH)$(platform)_PCH>\\n)" >> $@.tmp
- $(Q) printf "$(foreach platform,$(ALL_DOTNET_PLATFORMS),\\t\\t<$(platform)_DLL>$(X$(shell echo $(platform) | tr '[:lower:]' '[:upper:]')_DOTNET)$(platform)_DLL>\\n)" >> $@.tmp
- $(Q) printf "\\t \\n" >> $@.tmp
- $(Q) printf " \\n" >> $@.tmp
- $(Q_GEN) mv $@.tmp $@
-
report-dotnet/index.html: $(XTRO_REPORT) .stamp-dotnet-classify
$(Q) rm -rf report-dotnet
$(Q_GEN) $(XTRO_REPORT_EXEC) $(DOTNET_ANNOTATIONS_DIR) report-dotnet
@@ -194,9 +190,14 @@ report-short:
JENKINS_SERVER_COOKIE=1 make report
define DotNetClassify
-.stamp-dotnet-classify-$(1): $(XTRO_SHARPIE) $$(X$(2)_PCH) $$(X$(2)_DOTNET)
+xtro-sharpie-$(1).rsp: Makefile $(1).rsp
+ $$(Q_GEN) echo \
+ --output-directory $$(DOTNET_ANNOTATIONS_DIR) --lib $(DOTNET_BCL_DIR) $$(X$(2)_DOTNET) --rsp $(abspath $(1).rsp) \
+ > $$@
+
+.stamp-dotnet-classify-$(1): $(XTRO_SHARPIE) $$(X$(2)_DOTNET) xtro-sharpie-$(1).rsp
$$(Q) rm -f $$(DOTNET_ANNOTATIONS_DIR)/$(1)-*.raw
- $$(Q_GEN) $(XTRO_SHARPIE_EXEC) --output-directory $$(DOTNET_ANNOTATIONS_DIR) --lib $(DOTNET_BCL_DIR) $$(X$(2)_PCH) $$(X$(2)_DOTNET)
+ $$(Q_GEN) $(XTRO_SHARPIE_EXEC) @xtro-sharpie-$(1).rsp
$$(Q) touch $$@
dotnet-classify-$(1): .stamp-dotnet-classify-$(1)
@@ -218,10 +219,6 @@ remove-empty:
all: dotnet-report
-.stamp-check-sharpie:
- @$(TOP)/system-dependencies.sh --ignore-all --enforce-sharpie
- @touch $@
-
remove-empty-files:
find . -empty -exec git rm -f {} \;
@@ -235,3 +232,9 @@ unclassified2todo: $(U2TODO)
run-tests run-unit-tests:
$(Q) $(MAKE) -C UnitTests $@
+
+PROFILE_PATH:=/tmp/clangsharp-$(shell date "+%Y-%m-%d_%H-%M-%S").trace
+profile: MacCatalyst.rsp
+ dotnet publish $(TOP)/tools/sharpie/Sharpie.Bind.Tool
+ xctrace record --output $(PROFILE_PATH) --template 'Time Profiler' --target-stdout - --launch -- $(TOP)/tools/sharpie/Sharpie.Bind.Tool/bin/Release/osx-arm64/publish/Sharpie.Bind.Tool sdk-db @MacCatalyst.rsp
+ @echo "Created: $(PROFILE_PATH)"
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-AuthenticationServices.ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-AuthenticationServices.ignore
index 4525bd799531..2a7d552f9a31 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-AuthenticationServices.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-AuthenticationServices.ignore
@@ -1,2 +1,10 @@
# xtro did not pick up on this enum
!unknown-native-enum! ASCoseAlgorithmIdentifier bound
+
+# updated sharpie results
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialAssertionRequest should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialAssertionRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialProvider should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialProvider (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialRegistrationRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialAssertionRequest should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialAssertionRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialProvider should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialProvider (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialRegistrationRequest should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialRegistrationRequest (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-ImageCaptureCore.todo b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-ImageCaptureCore.todo
index 935dc151f290..12fb78ebdefa 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-ImageCaptureCore.todo
+++ b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-ImageCaptureCore.todo
@@ -174,3 +174,6 @@
!missing-selector! +ICCameraFile::fingerprintForFileAtURL: not bound
!missing-selector! ICCameraFile::fingerprint not bound
!missing-selector! ICCameraFile::requestFingerprintWithCompletion: not bound
+
+# updated sharpie results
+!missing-enum! ICReturnCodeOffset not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-OpenGL[ES].ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-OpenGL[ES].ignore
index 47b96fb2c403..6160120282ff 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-OpenGL[ES].ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-OpenGL[ES].ignore
@@ -391,3 +391,6 @@
# only for iOS and tvOS (not watchOS) and macOS uses OpenGL
## we use OpenTK for bindings
!missing-pinvoke! glProgramParameteriEXT is not bound
+
+# updated sharpie results
+!missing-enum! CGLCPContextPriorityRequest not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-PrintCore.ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-PrintCore.ignore
index 410481b35d3e..154a5b1e52b7 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-PrintCore.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-PrintCore.ignore
@@ -119,3 +119,6 @@
!missing-pinvoke! PMWorkflowCopyItems is not bound
!missing-pinvoke! PMWorkflowSubmitPDFWithOptions is not bound
!missing-pinvoke! PMWorkflowSubmitPDFWithSettings is not bound
+
+# updated sharpie results
+!missing-enum! PMPageToPaperMappingType not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-UIKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-UIKit.ignore
index e6b7fed44fa4..e815630e7b2b 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-UIKit.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-UIKit.ignore
@@ -381,3 +381,8 @@
## This is basically ToString for an enum, which managed code has built-in support for
!missing-pinvoke! UIWritingToolsCoordinatorTextAnimationDebugDescription is not bound
+
+# updated sharpie results
+!missing-protocol-conformance! UIDocument should conform to UINavigationItemRenameDelegate (defined in '' category)
+!missing-protocol-conformance! UITextView should conform to UIFindInteractionDelegate (defined in '' category)
+!missing-protocol-conformance! UITextView should conform to UITextSearching (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-Accelerate.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-Accelerate.ignore
index f560e0b5e13c..9e86b99b1d44 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/common-Accelerate.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-Accelerate.ignore
@@ -1,6 +1,11 @@
##
!unknown-native-enum! vImageError bound
+# updated sharpie results
+!missing-enum! vImage_InterpolationMethod not bound
+!missing-enum! vImageARGBType not bound
+!missing-enum! vImageYpCbCrType not bound
+
## only a subset of this framework is presently supported
!missing-field! kvImage_ARGBToYpCbCrMatrix_ITU_R_601_4 not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-JavaScriptCore.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-JavaScriptCore.ignore
index c5ff65d44ed5..bddef4e6758c 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/common-JavaScriptCore.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-JavaScriptCore.ignore
@@ -122,3 +122,6 @@
!missing-pinvoke! JSValueToInt64 is not bound
!missing-pinvoke! JSValueToUInt32 is not bound
!missing-pinvoke! JSValueToUInt64 is not bound
+
+# updated sharpie results
+!missing-enum! JSTypedArrayType not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-MetalPerformanceShaders.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-MetalPerformanceShaders.ignore
index b9109229ff80..de107db90a13 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/common-MetalPerformanceShaders.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-MetalPerformanceShaders.ignore
@@ -19,3 +19,6 @@
# variadic, maximum number of arguments is 2^31... there's a different overload that is conceptually the same, so there's no need for this particular selector.
!missing-selector! +MPSNDArrayDescriptor::descriptorWithDataType:dimensionSizes: not bound
+
+# updated sharpie results
+!missing-enum! MPSDeviceCapsValues not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-Network.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-Network.ignore
index f3fc35aab456..21a6b7185f5e 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/common-Network.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-Network.ignore
@@ -46,3 +46,33 @@
## the enum is bound as NWParametersAttribution. Apple uses _t for types, probably was an error
## in their part which confuses xtro
!missing-enum! nw_parameters_attribution_t not bound
+
+# updated sharpie results
+!missing-enum! nw_browser_state_t not bound
+!missing-enum! nw_connection_group_state_t not bound
+!missing-enum! nw_connection_state_t not bound
+!missing-enum! nw_data_transfer_report_state_t not bound
+!missing-enum! nw_endpoint_type_t not bound
+!missing-enum! nw_error_domain_t not bound
+!missing-enum! nw_ethernet_channel_state_t not bound
+!missing-enum! nw_framer_start_result_t not bound
+!missing-enum! nw_interface_radio_type_t not bound
+!missing-enum! nw_interface_type_t not bound
+!missing-enum! nw_ip_ecn_flag_t not bound
+!missing-enum! nw_ip_local_address_preference_t not bound
+!missing-enum! nw_ip_version_t not bound
+!missing-enum! nw_listener_state_t not bound
+!missing-enum! nw_multipath_service_t not bound
+!missing-enum! nw_multipath_version_t not bound
+!missing-enum! nw_parameters_expired_dns_behavior_t not bound
+!missing-enum! nw_path_status_t not bound
+!missing-enum! nw_path_unsatisfied_reason_t not bound
+!missing-enum! nw_quic_stream_type_t not bound
+!missing-enum! nw_report_resolution_protocol_t not bound
+!missing-enum! nw_report_resolution_source_t not bound
+!missing-enum! nw_service_class_t not bound
+!missing-enum! nw_txt_record_find_key_t not bound
+!missing-enum! nw_ws_close_code_t not bound
+!missing-enum! nw_ws_opcode_t not bound
+!missing-enum! nw_ws_response_status_t not bound
+!missing-enum! nw_ws_version_t not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-OSLog.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-OSLog.ignore
new file mode 100644
index 000000000000..1361f6ec3c23
--- /dev/null
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-OSLog.ignore
@@ -0,0 +1,2 @@
+# updated sharpie results
+!missing-protocol-conformance! OSLogEntry should conform to NSSecureCoding (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-ObjCRuntime.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-ObjCRuntime.ignore
index c58684c7f79d..b4acac308512 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/common-ObjCRuntime.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-ObjCRuntime.ignore
@@ -40,3 +40,6 @@
!unknown-pinvoke! os_log_create bound
!unknown-pinvoke! os_release bound
!unknown-pinvoke! os_retain bound
+
+# updated sharpie results
+!deprecated-attribute-missing! NXGetLocalArchInfo missing a [Deprecated] attribute
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-Photos.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-Photos.ignore
index 5e9fab1e57a2..d94e25814011 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/common-Photos.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-Photos.ignore
@@ -1 +1,4 @@
!missing-protocol-conformance! PHFetchResult should conform to NSFastEnumeration
+
+# updated sharpie results
+!missing-protocol-conformance! PHCloudIdentifier should conform to NSCopying (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-UIKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-UIKit.ignore
index 552f36033f7c..b5feaecccfc4 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/common-UIKit.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/common-UIKit.ignore
@@ -188,3 +188,7 @@
# empirical evidence shows the UIView parameter can be null for UITableViewDelegate::WillDisplay[Header|Footer]View: https://github.com/dotnet/macios/issues/9814
!extra-null-allowed! 'System.Void UIKit.UITableViewDelegate::WillDisplayFooterView(UIKit.UITableView,UIKit.UIView,System.IntPtr)' has a extraneous [NullAllowed] on parameter #1
!extra-null-allowed! 'System.Void UIKit.UITableViewDelegate::WillDisplayHeaderView(UIKit.UITableView,UIKit.UIView,System.IntPtr)' has a extraneous [NullAllowed] on parameter #1
+
+# updated sharpie results
+!missing-protocol-conformance! UIWindowScene should conform to UITraitEnvironment (defined in '' category)
+
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-AuthenticationServices.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-AuthenticationServices.ignore
index 4525bd799531..2a7d552f9a31 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-AuthenticationServices.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-AuthenticationServices.ignore
@@ -1,2 +1,10 @@
# xtro did not pick up on this enum
!unknown-native-enum! ASCoseAlgorithmIdentifier bound
+
+# updated sharpie results
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialAssertionRequest should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialAssertionRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialProvider should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialProvider (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialRegistrationRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialAssertionRequest should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialAssertionRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialProvider should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialProvider (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialRegistrationRequest should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialRegistrationRequest (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-IOSurface.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-IOSurface.ignore
new file mode 100644
index 000000000000..e43a6fa75ff1
--- /dev/null
+++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-IOSurface.ignore
@@ -0,0 +1,2 @@
+# updated sharpie results
+!deprecated-attribute-missing! IOSurface missing a [Deprecated] attribute
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-ImageCaptureCore.todo b/tests/xtro-sharpie/api-annotations-dotnet/iOS-ImageCaptureCore.todo
index a8b0f46dfb35..23537cefeaa5 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-ImageCaptureCore.todo
+++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-ImageCaptureCore.todo
@@ -3,3 +3,4 @@
!missing-selector! +ICCameraFile::fingerprintForFileAtURL: not bound
!missing-selector! ICCameraFile::fingerprint not bound
!missing-selector! ICCameraFile::requestFingerprintWithCompletion: not bound
+!missing-enum! ICReturnCodeOffset not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-OpenGL[ES].ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-OpenGL[ES].ignore
index 150871760b2a..10c85382cb15 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-OpenGL[ES].ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-OpenGL[ES].ignore
@@ -1,2 +1,67 @@
# OpenAL
!missing-pinvoke! alGetBufferiv is not bound
+
+# updated sharpie results
+!missing-pinvoke! glActiveTexture is not bound
+!missing-pinvoke! glBindBuffer is not bound
+!missing-pinvoke! glBindTexture is not bound
+!missing-pinvoke! glBlendEquationOES is not bound
+!missing-pinvoke! glBlendFunc is not bound
+!missing-pinvoke! glBufferData is not bound
+!missing-pinvoke! glBufferSubData is not bound
+!missing-pinvoke! glClear is not bound
+!missing-pinvoke! glClearColor is not bound
+!missing-pinvoke! glClearDepthf is not bound
+!missing-pinvoke! glClearStencil is not bound
+!missing-pinvoke! glColorMask is not bound
+!missing-pinvoke! glCompressedTexImage2D is not bound
+!missing-pinvoke! glCompressedTexSubImage2D is not bound
+!missing-pinvoke! glCopyTexImage2D is not bound
+!missing-pinvoke! glCopyTexSubImage2D is not bound
+!missing-pinvoke! glCullFace is not bound
+!missing-pinvoke! glDeleteBuffers is not bound
+!missing-pinvoke! glDeleteTextures is not bound
+!missing-pinvoke! glDepthFunc is not bound
+!missing-pinvoke! glDepthMask is not bound
+!missing-pinvoke! glDepthRangef is not bound
+!missing-pinvoke! glDisable is not bound
+!missing-pinvoke! glDrawArrays is not bound
+!missing-pinvoke! glDrawElements is not bound
+!missing-pinvoke! glEnable is not bound
+!missing-pinvoke! glFinish is not bound
+!missing-pinvoke! glFlush is not bound
+!missing-pinvoke! glFrontFace is not bound
+!missing-pinvoke! glGenBuffers is not bound
+!missing-pinvoke! glGenTextures is not bound
+!missing-pinvoke! glGetBooleanv is not bound
+!missing-pinvoke! glGetBufferParameteriv is not bound
+!missing-pinvoke! glGetBufferPointervOES is not bound
+!missing-pinvoke! glGetError is not bound
+!missing-pinvoke! glGetFloatv is not bound
+!missing-pinvoke! glGetIntegerv is not bound
+!missing-pinvoke! glGetString is not bound
+!missing-pinvoke! glGetTexParameterfv is not bound
+!missing-pinvoke! glGetTexParameteriv is not bound
+!missing-pinvoke! glHint is not bound
+!missing-pinvoke! glIsBuffer is not bound
+!missing-pinvoke! glIsEnabled is not bound
+!missing-pinvoke! glIsTexture is not bound
+!missing-pinvoke! glLineWidth is not bound
+!missing-pinvoke! glMapBufferOES is not bound
+!missing-pinvoke! glPixelStorei is not bound
+!missing-pinvoke! glPolygonOffset is not bound
+!missing-pinvoke! glReadPixels is not bound
+!missing-pinvoke! glResolveMultisampleFramebufferAPPLE is not bound
+!missing-pinvoke! glSampleCoverage is not bound
+!missing-pinvoke! glScissor is not bound
+!missing-pinvoke! glStencilFunc is not bound
+!missing-pinvoke! glStencilMask is not bound
+!missing-pinvoke! glStencilOp is not bound
+!missing-pinvoke! glTexImage2D is not bound
+!missing-pinvoke! glTexParameterf is not bound
+!missing-pinvoke! glTexParameterfv is not bound
+!missing-pinvoke! glTexParameteri is not bound
+!missing-pinvoke! glTexParameteriv is not bound
+!missing-pinvoke! glTexSubImage2D is not bound
+!missing-pinvoke! glUnmapBufferOES is not bound
+!missing-pinvoke! glViewport is not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-UIKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-UIKit.ignore
index 2823c9877713..9d5864e86cad 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-UIKit.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-UIKit.ignore
@@ -385,3 +385,8 @@
## This is basically ToString for an enum, which managed code has built-in support for
!missing-pinvoke! UIWritingToolsCoordinatorTextAnimationDebugDescription is not bound
+
+# updated sharpie results
+!missing-protocol-conformance! UIDocument should conform to UINavigationItemRenameDelegate (defined in '' category)
+!missing-protocol-conformance! UITextView should conform to UIFindInteractionDelegate (defined in '' category)
+!missing-protocol-conformance! UITextView should conform to UITextSearching (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-ARKit.todo b/tests/xtro-sharpie/api-annotations-dotnet/macOS-ARKit.todo
index 68a198d6a27d..19f0304ca320 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-ARKit.todo
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-ARKit.todo
@@ -55,3 +55,12 @@
!missing-protocol! OS_ar_world_anchors not bound
!missing-protocol! OS_ar_world_tracking_configuration not bound
!missing-protocol! OS_ar_world_tracking_provider not bound
+
+# updated sharpie results
+!missing-enum! ar_authorization_status_t not bound
+!missing-enum! ar_authorization_type_t not bound
+!missing-enum! ar_data_provider_state_t not bound
+!missing-enum! ar_device_anchor_query_status_t not bound
+!missing-enum! ar_device_anchor_tracking_state_t not bound
+!missing-enum! ar_session_error_code_t not bound
+!missing-enum! ar_world_tracking_error_code_t not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AddressBook.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AddressBook.ignore
index 7d82f3540fd8..815bf054049c 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AddressBook.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AddressBook.ignore
@@ -345,3 +345,6 @@
!missing-field! kABHomeLabel not bound
!missing-field! kABOtherLabel not bound
!missing-field! kABWorkLabel not bound
+
+# updated sharpie results
+!missing-enum! ABPeoplePickerSelectionBehavior not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore
index 3eeb0eb2f481..e275a38d4b9f 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore
@@ -1534,3 +1534,8 @@
# Likely a mistake '_' denotes internal selector
!missing-selector! +NSCell::_bulletStringForString:bulletCharacter: not bound
+
+# updated sharpie results
+!missing-protocol-conformance! NSImage should conform to NSItemProviderReading (defined in '' category)
+!missing-protocol-conformance! NSImage should conform to NSItemProviderWriting (defined in '' category)
+!missing-protocol-conformance! NSLayoutConstraint should conform to NSAnimatablePropertyContainer (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AuthenticationServices.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AuthenticationServices.ignore
index 4525bd799531..d28b9255c3a4 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-AuthenticationServices.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-AuthenticationServices.ignore
@@ -1,2 +1,11 @@
# xtro did not pick up on this enum
!unknown-native-enum! ASCoseAlgorithmIdentifier bound
+
+# updated sharpie results
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialAssertionRequest should conform to ASAuthorizationWebBrowserExternallyAuthenticatableRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialAssertionRequest should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialAssertionRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialProvider should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialProvider (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest should conform to ASAuthorizationWebBrowserPlatformPublicKeyCredentialRegistrationRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialAssertionRequest should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialAssertionRequest (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialProvider should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialProvider (defined in '' category)
+!missing-protocol-conformance! ASAuthorizationSecurityKeyPublicKeyCredentialRegistrationRequest should conform to ASAuthorizationWebBrowserSecurityKeyPublicKeyCredentialRegistrationRequest (defined in '' category)
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-ImageCaptureCore.todo b/tests/xtro-sharpie/api-annotations-dotnet/macOS-ImageCaptureCore.todo
index 78a220fdee83..656eab7dfd05 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-ImageCaptureCore.todo
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-ImageCaptureCore.todo
@@ -6,3 +6,10 @@
!missing-selector! +ICCameraFile::fingerprintForFileAtURL: not bound
!missing-selector! ICCameraFile::fingerprint not bound
!missing-selector! ICCameraFile::requestFingerprintWithCompletion: not bound
+
+# updated sharpie results
+!missing-enum-native! ICReturnCodeOffset
+!missing-enum-value! ICReturnCodeOffset native value ICReturnCodeDeviceConnection = -21400 not bound
+!missing-enum-value! ICReturnCodeOffset native value ICReturnCodeDeviceOffset = -21350 not bound
+!missing-enum-value! ICReturnCodeOffset native value ICReturnCodeObjectOffset = -21450 not bound
+!wrong-enum-size! ICReturnCodeOffset managed 4 vs native 8
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-OpenGL[ES].ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-OpenGL[ES].ignore
index 6e6a9f1a8a7e..a0db0936f6da 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-OpenGL[ES].ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-OpenGL[ES].ignore
@@ -379,3 +379,6 @@
# only for iOS and tvOS (not watchOS) and macOS uses OpenGL
## we use OpenTK for bindings
!missing-pinvoke! glProgramParameteriEXT is not bound
+
+# updated sharpie results
+!missing-enum! CGLCPContextPriorityRequest not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-PrintCore.todo b/tests/xtro-sharpie/api-annotations-dotnet/macOS-PrintCore.todo
index 1d28792f2d5b..cc50a2c17a75 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-PrintCore.todo
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-PrintCore.todo
@@ -1,3 +1,6 @@
!missing-protocol! PDEPanel not bound
!missing-protocol! PDEPlugIn not bound
!missing-protocol! PDEPlugInCallbackProtocol not bound
+
+# updated sharpie results
+!missing-enum! PMPageToPaperMappingType not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-QuartzComposer.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-QuartzComposer.ignore
new file mode 100644
index 000000000000..dba4cc3cd032
--- /dev/null
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-QuartzComposer.ignore
@@ -0,0 +1,3 @@
+# updated sharpie results
+!missing-enum! QCPlugInExecutionMode not bound
+!missing-enum! QCPlugInTimeMode not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-QuickLook.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-QuickLook.ignore
index c201b696970b..e0bbac940694 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-QuickLook.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-QuickLook.ignore
@@ -1 +1,4 @@
!missing-field! kQLPreviewPropertyTextEncodingNameKey not bound
+
+# updated sharpie results
+!missing-enum! QLPreviewPDFStyle not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.todo b/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.todo
index c11c41c3e090..4a23e01921ad 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.todo
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.todo
@@ -111,3 +111,8 @@
!missing-type! SFChooseIdentityTableCellView not bound
!missing-type! SFKeychainSavePanel not bound
!missing-type! SFKeychainSettingsPanel not bound
+
+# updated sharpie results
+!missing-enum! SFAuthorizationViewState not bound
+!missing-enum! SFButtonType not bound
+!missing-enum! SFViewType not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/tvOS-IOSurface.ignore b/tests/xtro-sharpie/api-annotations-dotnet/tvOS-IOSurface.ignore
new file mode 100644
index 000000000000..e43a6fa75ff1
--- /dev/null
+++ b/tests/xtro-sharpie/api-annotations-dotnet/tvOS-IOSurface.ignore
@@ -0,0 +1,2 @@
+# updated sharpie results
+!deprecated-attribute-missing! IOSurface missing a [Deprecated] attribute
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/tvOS-OpenGL[ES].ignore b/tests/xtro-sharpie/api-annotations-dotnet/tvOS-OpenGL[ES].ignore
index 150871760b2a..4a5dcdaa4c5b 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/tvOS-OpenGL[ES].ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/tvOS-OpenGL[ES].ignore
@@ -1,2 +1,6 @@
# OpenAL
!missing-pinvoke! alGetBufferiv is not bound
+
+# updated sharpie results
+!missing-pinvoke! glBlendEquationOES is not bound
+!missing-pinvoke! glResolveMultisampleFramebufferAPPLE is not bound
diff --git a/tests/xtro-sharpie/xtro-sanity/Sanitizer.cs b/tests/xtro-sharpie/xtro-sanity/Sanitizer.cs
index 1c2f82f49402..d55625cf3ef9 100644
--- a/tests/xtro-sharpie/xtro-sanity/Sanitizer.cs
+++ b/tests/xtro-sharpie/xtro-sanity/Sanitizer.cs
@@ -358,7 +358,7 @@ static bool IsFrameworkIncludedInPlatform (string platform, string framework)
// If the framework is registered for the current platform, then it's included.
var frameworks = Frameworks.GetFrameworks (ApplePlatformExtensions.Parse (platform), false);
- if (frameworks.Any (x => string.Equals (x.Key, framework, StringComparison.OrdinalIgnoreCase)))
+ if (frameworks?.Any (x => string.Equals (x.Key, framework, StringComparison.OrdinalIgnoreCase)) == true)
return true;
// found only for platforms that aren't included in the current build
diff --git a/tests/xtro-sharpie/xtro-sharpie.slnx b/tests/xtro-sharpie/xtro-sharpie.slnx
index b06c41702950..78dcdcccc281 100644
--- a/tests/xtro-sharpie/xtro-sharpie.slnx
+++ b/tests/xtro-sharpie/xtro-sharpie.slnx
@@ -4,4 +4,6 @@
+
+
diff --git a/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs b/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs
index 2ab3ab61b953..fac13e358c3e 100644
--- a/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/AttributeHelpers.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Clang;
-using Clang.Ast;
-using Mono.Cecil;
+using Sharpie.Bind;
namespace Extrospection {
public static class AttributeHelpers {
@@ -98,9 +93,9 @@ static bool GetPlatformVersion (CustomAttribute attribute, out Version version)
public static bool FindObjcDeprecated (IEnumerable attrs, out VersionTuple version)
{
- AvailabilityAttr attr = attrs.OfType ().FirstOrDefault (x => !x.Deprecated.IsEmpty && x.Platform.Name == Helpers.ClangPlatformName);
+ var attr = attrs.GetAvailabilityAttributes ().FirstOrDefault (x => x.AvailabilityAttributeDeprecated.HasValue && !x.AvailabilityAttributeDeprecated.Value.IsEmpty && x.AvailabilityAttributePlatformIdentifierName == Helpers.ClangPlatformName);
if (attr is not null) {
- version = attr.Deprecated;
+ version = attr.AvailabilityAttributeDeprecated.Value;
return true;
} else {
version = VersionTuple.Empty;
@@ -122,30 +117,20 @@ public static bool HasAnyDeprecationForCurrentPlatform (ICustomAttributeProvider
}
}
- // This allows us to accept [Deprecated (iOS)] for tv, which many of our bindings currently have
- // If we want to force separate tv attributes remove GetRelatedPlatforms and just check Helpers.Platform
- if (Helpers.IsDotNet) {
- foreach (var attribute in item.CustomAttributes) {
- if (AttributeHelpers.HasObsolete (attribute, Helpers.Platform))
- return true;
-
- // Consider 'HasObsoletedOSPlatform' (Deprecated) and 'UnsupportedOSPlatform' (Obsoleted/Unavailable)
- if (AttributeHelpers.HasObsoletedOSPlatform (attribute, Helpers.Platform) ||
- AttributeHelpers.HasUnsupportedOSPlatform (attribute, Helpers.Platform))
- return true;
-
- // The only related platforms for .NET is iOS for Mac Catalyst
- if (Helpers.Platform == Platforms.MacCatalyst &&
- (AttributeHelpers.HasObsoletedOSPlatform (attribute, Platforms.iOS) ||
- AttributeHelpers.HasUnsupportedOSPlatform (attribute, Platforms.iOS)))
- return true;
- }
- } else {
- Platforms [] platforms = GetRelatedPlatforms ();
- foreach (var attribute in item.CustomAttributes) {
- if (platforms.Any (x => AttributeHelpers.HasDeprecated (attribute, x)) || platforms.Any (x => AttributeHelpers.HasObsoleted (attribute, x)))
- return true;
- }
+ foreach (var attribute in item.CustomAttributes) {
+ if (AttributeHelpers.HasObsolete (attribute, Helpers.Platform))
+ return true;
+
+ // Consider 'HasObsoletedOSPlatform' (Deprecated) and 'UnsupportedOSPlatform' (Obsoleted/Unavailable)
+ if (AttributeHelpers.HasObsoletedOSPlatform (attribute, Helpers.Platform) ||
+ AttributeHelpers.HasUnsupportedOSPlatform (attribute, Helpers.Platform))
+ return true;
+
+ // The only related platforms for .NET is iOS for Mac Catalyst
+ if (Helpers.Platform == Platforms.MacCatalyst &&
+ (AttributeHelpers.HasObsoletedOSPlatform (attribute, Platforms.iOS) ||
+ AttributeHelpers.HasUnsupportedOSPlatform (attribute, Platforms.iOS)))
+ return true;
}
return false;
}
@@ -163,23 +148,6 @@ public static bool HasAnyObsoleted (ICustomAttributeProvider item)
return false;
}
- static Platforms [] GetRelatedPlatforms ()
- {
- // TV also implictly accept iOS
- switch (Helpers.Platform) {
- case Platforms.macOS:
- return new Platforms [] { Platforms.macOS };
- case Platforms.iOS:
- return new Platforms [] { Platforms.iOS };
- case Platforms.tvOS:
- return new Platforms [] { Platforms.iOS, Platforms.tvOS };
- case Platforms.MacCatalyst:
- return new Platforms [] { Platforms.iOS, Platforms.MacCatalyst };
- default:
- throw new InvalidOperationException ($"Unknown {Helpers.Platform} in GetPlatforms");
- }
- }
-
public static bool HasAnyAdvice (ICustomAttributeProvider item)
{
if (Skip (item))
diff --git a/tests/xtro-sharpie/xtro-sharpie/DeprecatedCheck.cs b/tests/xtro-sharpie/xtro-sharpie/DeprecatedCheck.cs
index b750f79879c0..21b8b19e2131 100644
--- a/tests/xtro-sharpie/xtro-sharpie/DeprecatedCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/DeprecatedCheck.cs
@@ -1,10 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Clang;
-using Clang.Ast;
-using Mono.Cecil;
-
namespace Extrospection {
public class DeprecatedCheck : BaseVisitor {
Dictionary ObjCDeprecatedItems = new Dictionary ();
@@ -14,6 +7,11 @@ public class DeprecatedCheck : BaseVisitor {
List ManagedTypes = new List ();
Dictionary dllimports = new Dictionary ();
+ public DeprecatedCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public override void VisitManagedMethod (MethodDefinition method)
{
if (!method.IsPInvokeImpl || !method.HasPInvokeInfo)
@@ -33,7 +31,7 @@ public override void VisitManagedMethod (MethodDefinition method)
dllimports [info.EntryPoint] = method;
}
- public override void End ()
+ public override void EndVisit ()
{
foreach (var objcEntry in ObjCDeprecatedItems)
ProcessObjcEntry (objcEntry.Key, objcEntry.Value);
@@ -140,12 +138,12 @@ public override void VisitManagedType (TypeDefinition type)
ManagedTypes.Add (type);
}
- public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl, VisitKind visitKind) => VisitItem (decl, visitKind);
- public override void VisitObjCInterfaceDecl (ObjCInterfaceDecl decl, VisitKind visitKind) => VisitItem (decl, visitKind);
+ public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl) => VisitItem (decl);
+ public override void VisitObjCInterfaceDecl (ObjCInterfaceDecl decl) => VisitItem (decl);
- void VisitItem (NamedDecl decl, VisitKind visitKind)
+ void VisitItem (NamedDecl decl)
{
- if (visitKind == VisitKind.Enter && AttributeHelpers.FindObjcDeprecated (decl.Attrs, out VersionTuple version)) {
+ if (AttributeHelpers.FindObjcDeprecated (decl.Attrs, out VersionTuple version)) {
// `(anonymous)` has a null name
var name = decl.Name;
if (name is not null)
@@ -153,9 +151,9 @@ void VisitItem (NamedDecl decl, VisitKind visitKind)
}
}
- public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
- if (visitKind == VisitKind.Enter && AttributeHelpers.FindObjcDeprecated (decl.Attrs, out VersionTuple version)) {
+ if (AttributeHelpers.FindObjcDeprecated (decl.Attrs, out VersionTuple version)) {
var qn = decl.QualifiedName;
if (decl.IsClassMethod)
qn = "+" + qn;
@@ -163,9 +161,9 @@ public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKi
}
}
- public override void VisitFunctionDecl (FunctionDecl decl, VisitKind visitKind)
+ public override void VisitFunctionDecl (FunctionDecl decl)
{
- if (visitKind == VisitKind.Enter && AttributeHelpers.FindObjcDeprecated (decl.Attrs, out VersionTuple version))
+ if (AttributeHelpers.FindObjcDeprecated (decl.Attrs, out VersionTuple version))
PlainCDeprecatedFunctions [decl.QualifiedName] = version;
}
}
diff --git a/tests/xtro-sharpie/xtro-sharpie/DesignatedInitializerCheck.cs b/tests/xtro-sharpie/xtro-sharpie/DesignatedInitializerCheck.cs
index 809c0c580fee..5869a2844138 100644
--- a/tests/xtro-sharpie/xtro-sharpie/DesignatedInitializerCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/DesignatedInitializerCheck.cs
@@ -11,16 +11,15 @@
// when a managed constructor has no business to have an [DesignatedInitializer] attribute
//
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
+using Sharpie.Bind;
namespace Extrospection {
public class DesignatedInitializerCheck : BaseVisitor {
+ public DesignatedInitializerCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
static Dictionary types = new Dictionary ();
static Dictionary methods = new Dictionary ();
@@ -49,11 +48,8 @@ public override void VisitManagedMethod (MethodDefinition method)
methods.Add (key, method);
}
- public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
-
// don't process methods (or types) that are unavailable for the current platform
if (!decl.IsAvailable () || !(decl.DeclContext as Decl).IsAvailable ())
return;
diff --git a/tests/xtro-sharpie/xtro-sharpie/DllImportCheck.cs b/tests/xtro-sharpie/xtro-sharpie/DllImportCheck.cs
index c5da895a9b80..3dec9f3c40bd 100644
--- a/tests/xtro-sharpie/xtro-sharpie/DllImportCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/DllImportCheck.cs
@@ -10,18 +10,14 @@
// just be undocumented (or not in the headers)
//
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
// track all [DllImport]
class DllImportCheck : BaseVisitor {
+ public DllImportCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
// dupes :|
Dictionary dllimports = new Dictionary ();
@@ -43,10 +39,8 @@ public override void VisitManagedMethod (MethodDefinition method)
dllimports.Add (name, method);
}
- public override void VisitFunctionDecl (FunctionDecl decl, VisitKind visitKind)
+ public override void VisitFunctionDecl (FunctionDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
// skip macros : we generally implement them but their name is lost (so no matching is possible)
if (!decl.IsExternC)
return;
@@ -75,7 +69,7 @@ public override void VisitFunctionDecl (FunctionDecl decl, VisitKind visitKind)
found.Add (name);
}
- public override void End ()
+ public override void EndVisit ()
{
// at this stage anything else we have is not something we could find in Apple's headers
// e.g. a typo in the name
diff --git a/tests/xtro-sharpie/xtro-sharpie/EnumCheck.cs b/tests/xtro-sharpie/xtro-sharpie/EnumCheck.cs
index f9626c56afbb..40c02a9d8841 100644
--- a/tests/xtro-sharpie/xtro-sharpie/EnumCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/EnumCheck.cs
@@ -1,10 +1,3 @@
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
class EnumCheck : BaseVisitor {
@@ -18,6 +11,11 @@ class ManagedValue {
Dictionary managed_values = new Dictionary ();
Dictionary native_values = new Dictionary ();
+ public EnumCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public override void VisitManagedType (TypeDefinition type)
{
// exclude non enum and nested enums, e.g. bunch of Selector enums in CTFont
@@ -53,11 +51,12 @@ public override void VisitManagedType (TypeDefinition type)
}
}
- public override void VisitEnumDecl (EnumDecl decl, VisitKind visitKind)
+ public override void VisitEnumDecl (EnumDecl decl)
{
- if (visitKind != VisitKind.Enter)
+ if (!decl.IsThisDeclarationADefinition)
return;
- if (!decl.IsDefinition)
+
+ if (decl.GetIsUnnamedOrAnonymous (BindingResult))
return;
string name = decl.Name;
@@ -88,7 +87,7 @@ public override void VisitEnumDecl (EnumDecl decl, VisitKind visitKind)
int native_size = 4;
bool native = false;
// FIXME: this can be simplified
- switch (decl.IntegerQualType.ToString ()) {
+ switch (decl.IntegerType.ToString ()) {
case "NSInteger":
case "NSUInteger":
case "CFIndex":
@@ -133,7 +132,7 @@ public override void VisitEnumDecl (EnumDecl decl, VisitKind visitKind)
native_size = 1;
break;
default:
- throw new NotImplementedException (decl.IntegerQualType.ToString ());
+ throw new NotImplementedException (decl.IntegerType.ToString ());
}
// check correct [Native] decoration
@@ -185,12 +184,12 @@ public override void VisitEnumDecl (EnumDecl decl, VisitKind visitKind)
// collect all the native enum values
var nativeConstant = signed ? (object) 0L : (object) 0UL;
- foreach (var value in decl.Values) {
- if ((value.InitExpr is not null) && value.InitExpr.EvaluateAsInt (decl.AstContext, out var integer)) {
+ foreach (var value in decl.Enumerators) {
+ if ((value.InitExpr is not null) && value.InitExpr.EvaluateAsInt (out var signedValue, out var unsignedValue)) {
if (signed) {
- nativeConstant = integer.SExtValue;
+ nativeConstant = signedValue;
} else {
- nativeConstant = integer.ZExtValue;
+ nativeConstant = unsignedValue;
}
}
@@ -359,7 +358,7 @@ public static TypeReference GetEnumUnderlyingType (TypeDefinition self)
throw new ArgumentException ();
}
- public override void End ()
+ public override void EndVisit ()
{
// report any [Native] decorated enum for which we could not find a match in the header files
// e.g. a typo in the name
diff --git a/tests/xtro-sharpie/xtro-sharpie/FieldCheck.cs b/tests/xtro-sharpie/xtro-sharpie/FieldCheck.cs
index df90c21a0dbd..65e32c45d8e6 100644
--- a/tests/xtro-sharpie/xtro-sharpie/FieldCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/FieldCheck.cs
@@ -14,14 +14,6 @@
// just be undocumented (or not in the headers)
//
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class FieldCheck : BaseVisitor {
@@ -29,6 +21,11 @@ public class FieldCheck : BaseVisitor {
Dictionary fields = new Dictionary ();
HashSet matchedFields = new ();
+ public FieldCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public override void VisitManagedType (TypeDefinition type)
{
if (type.HasProperties) {
@@ -94,7 +91,7 @@ public override void VisitVarDecl (VarDecl decl)
}
}
- public override void End ()
+ public override void EndVisit ()
{
// at this stage anything else we have is not something we could find in Apple's headers
foreach (var key in fields.Keys.Except (matchedFields)) {
diff --git a/tests/xtro-sharpie/xtro-sharpie/GlobalUsings.cs b/tests/xtro-sharpie/xtro-sharpie/GlobalUsings.cs
new file mode 100644
index 000000000000..614a630090b0
--- /dev/null
+++ b/tests/xtro-sharpie/xtro-sharpie/GlobalUsings.cs
@@ -0,0 +1,12 @@
+global using System;
+global using System.Collections.Generic;
+global using System.Linq;
+global using System.IO;
+global using System.Text;
+
+global using Mono.Cecil;
+
+global using ClangSharp;
+global using ClangSharp.Interop;
+
+global using Sharpie.Bind;
diff --git a/tests/xtro-sharpie/xtro-sharpie/Helpers.cs b/tests/xtro-sharpie/xtro-sharpie/Helpers.cs
index ce8dfcf541ce..972eecc035b8 100644
--- a/tests/xtro-sharpie/xtro-sharpie/Helpers.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/Helpers.cs
@@ -1,12 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public enum Platforms {
@@ -55,7 +46,6 @@ public static string ReplaceFirstInstance (this string source, string find, stri
}
public static Platforms Platform { get; set; }
- public static bool IsDotNet { get; set; }
public static int GetPlatformManagedValue (Platforms platform)
{
@@ -161,20 +151,19 @@ public static bool IsAvailable (this Decl decl)
bool? result = null;
foreach (var attr in decl.Attrs) {
// NS_UNAVAILABLE
- if (attr is UnavailableAttr)
+ if (attr.Kind == CX_AttrKind.CX_AttrKind_Unavailable)
return false;
- var avail = (attr as AvailabilityAttr);
- if (avail is null)
+ if (attr.Kind != CX_AttrKind.CX_AttrKind_Availability)
continue;
- var availName = avail.Platform.Name.ToLowerInvariant ();
+ var availName = attr.AvailabilityAttributePlatformIdentifierName.ToLowerInvariant ();
// if the headers says it's not available then we won't report it as missing
- if (avail.Unavailable && (availName == platform))
+ if (attr.AvailabilityAttributeUnavailable && (availName == platform))
return false;
// for iOS we won't report missing members that were deprecated before 5.0
- if (!avail.Deprecated.IsEmpty && availName == "ios" && avail.Deprecated.Major < 5)
+ if (!attr.Deprecated.IsEmpty && availName == "ios" && attr.Deprecated.Major < 5)
return false;
// can't return true right away as it can be deprecated too
- if (!avail.Introduced.IsEmpty && (availName == platform))
+ if (!attr.Introduced.IsEmpty && (availName == platform))
result = true;
}
return result;
@@ -211,25 +200,20 @@ public static bool IsDeprecated (this Decl decl)
{
var platform = platform_value.ToString ().ToLowerInvariant ();
// First check if there are any deprecations
- foreach (var attr in decl.Attrs) {
- var avail = attr as AvailabilityAttr;
- if (avail is null)
- continue;
- var availName = avail.Platform.Name.ToLowerInvariant ();
+ var availabilityAttrs = decl.Attrs.GetAvailabilityAttributes ().ToList ();
+ foreach (var attr in availabilityAttrs) {
+ var availName = attr.AvailabilityAttributePlatformIdentifierName.ToLowerInvariant ();
if (availName != platform)
continue;
- if (!avail.Deprecated.IsEmpty)
+ if (!attr.Deprecated.IsEmpty)
return true;
}
// then check for introduced - there may be both, so we must check *all* attributes for deprecation before checking for introduced
- foreach (var attr in decl.Attrs) {
- var avail = attr as AvailabilityAttr;
- if (avail is null)
- continue;
- var availName = avail.Platform.Name.ToLowerInvariant ();
+ foreach (var attr in availabilityAttrs) {
+ var availName = attr.AvailabilityAttributePlatformIdentifierName.ToLowerInvariant ();
if (availName != platform)
continue;
- if (!avail.Introduced.IsEmpty)
+ if (!attr.Introduced.IsEmpty)
return false;
}
diff --git a/tests/xtro-sharpie/xtro-sharpie/Log.cs b/tests/xtro-sharpie/xtro-sharpie/Log.cs
index 176564ea97b1..a899ea9b7809 100644
--- a/tests/xtro-sharpie/xtro-sharpie/Log.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/Log.cs
@@ -1,8 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
namespace Extrospection {
static class Log {
diff --git a/tests/xtro-sharpie/xtro-sharpie/MapNamesCheck.cs b/tests/xtro-sharpie/xtro-sharpie/MapNamesCheck.cs
index 830c59022124..48124e037064 100644
--- a/tests/xtro-sharpie/xtro-sharpie/MapNamesCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/MapNamesCheck.cs
@@ -3,11 +3,14 @@
// if they have any attributes that tells us the native name is different than the managed name.
//
-using Mono.Cecil;
-
namespace Extrospection {
public class MapNamesVisitor : BaseVisitor {
+ public MapNamesVisitor (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public override void VisitManagedType (TypeDefinition type)
{
var nativeName = type.GetName ();
diff --git a/tests/xtro-sharpie/xtro-sharpie/NullabilityCheck.cs b/tests/xtro-sharpie/xtro-sharpie/NullabilityCheck.cs
index 72b7c73cd2e0..fcbec45a3096 100644
--- a/tests/xtro-sharpie/xtro-sharpie/NullabilityCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/NullabilityCheck.cs
@@ -8,13 +8,6 @@
// when a method parameters or return value does not have an [NullAllowed] when one is present in the ObjC headers
//
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class NullabilityCheck : BaseVisitor {
@@ -29,6 +22,11 @@ enum Null : byte {
static Dictionary types = new Dictionary ();
static Dictionary methods = new Dictionary ();
+ public NullabilityCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
static TypeDefinition GetType (ObjCInterfaceDecl decl)
{
types.TryGetValue (decl.Name, out var td);
@@ -105,11 +103,8 @@ static Null [] GetNullable (ICustomAttributeProvider cap)
return Array.Empty ();
}
- public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
-
// don't process methods (or types) that are unavailable for the current platform
if (!decl.IsAvailable () || !(decl.DeclContext as Decl).IsAvailable ())
return;
@@ -175,17 +170,17 @@ public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKi
}
// match with native and, if needed, report discrepancies
- p.QualType.Type.GetNullability (p.AstContext, out var nullability);
+ var nullability = p.Type.Handle.Nullability;
switch (nullability) {
- case NullabilityKind.NonNull:
+ case CXTypeNullabilityKind.CXTypeNullability_NonNull:
if (parameter_nullable == Null.Annotated)
Log.On (framework).Add ($"!extra-null-allowed! '{method.FullName}' has a extraneous [NullAllowed] on parameter #{i - 1}");
break;
- case NullabilityKind.Nullable:
+ case CXTypeNullabilityKind.CXTypeNullability_Nullable:
if (parameter_nullable != Null.Annotated)
Log.On (framework).Add ($"!missing-null-allowed! '{method.FullName}' is missing an [NullAllowed] on parameter #{i - 1}");
break;
- case NullabilityKind.Unspecified:
+ case CXTypeNullabilityKind.CXTypeNullability_Unspecified:
break;
}
}
@@ -229,18 +224,18 @@ public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKi
}
}
- var rt = decl.ReturnQualType;
- rt.Type.GetNullability (decl.AstContext, out var rnull);
+ var rt = decl.ReturnType;
+ var rnull = rt.Handle.Nullability;
switch (rnull) {
- case NullabilityKind.NonNull:
+ case CXTypeNullabilityKind.CXTypeNullability_NonNull:
if (return_nullable == Null.Annotated)
Log.On (framework).Add ($"!extra-null-allowed! '{method}' has a extraneous [NullAllowed] on return type");
break;
- case NullabilityKind.Nullable:
+ case CXTypeNullabilityKind.CXTypeNullability_Nullable:
if (return_nullable != Null.Annotated)
Log.On (framework).Add ($"!missing-null-allowed! '{method}' is missing an [NullAllowed] on return type");
break;
- case NullabilityKind.Unspecified:
+ case CXTypeNullabilityKind.CXTypeNullability_Unspecified:
break;
}
}
diff --git a/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs b/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs
index 8fd611201ef3..e0e0921085c7 100644
--- a/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/ObjCInterfaceCheck.cs
@@ -1,10 +1,3 @@
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class ObjCInterfaceCheck : BaseVisitor {
@@ -12,6 +5,11 @@ public class ObjCInterfaceCheck : BaseVisitor {
Dictionary type_map = new Dictionary ();
Dictionary type_map_copy = new Dictionary ();
+ public ObjCInterfaceCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public override void VisitManagedType (TypeDefinition type)
{
if (!type.HasCustomAttributes)
@@ -62,11 +60,8 @@ public override void VisitManagedType (TypeDefinition type)
}
}
- public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl, VisitKind visitKind)
+ public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
-
var categoryName = decl.Name;
if (categoryName is null)
return;
@@ -93,11 +88,9 @@ public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl, VisitKind vis
}
}
- public override void VisitObjCInterfaceDecl (ObjCInterfaceDecl decl, VisitKind visitKind)
+ public override void VisitObjCInterfaceDecl (ObjCInterfaceDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
- if (!decl.IsDefinition)
+ if (!decl.IsThisDeclarationADefinition)
return;
var name = decl.Name;
@@ -139,7 +132,7 @@ public override void VisitObjCInterfaceDecl (ObjCInterfaceDecl decl, VisitKind v
type_map.Remove (name);
}
- public override void End ()
+ public override void EndVisit ()
{
// at this stage anything else we have is not something we could find in Apple's headers
foreach (var kvp in type_map) {
diff --git a/tests/xtro-sharpie/xtro-sharpie/ObjCProtocolCheck.cs b/tests/xtro-sharpie/xtro-sharpie/ObjCProtocolCheck.cs
index 53baad54cbc2..aaff81f0f2a7 100644
--- a/tests/xtro-sharpie/xtro-sharpie/ObjCProtocolCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/ObjCProtocolCheck.cs
@@ -22,20 +22,17 @@
// Notes: Both limitations could be _mostly_ lifted by another tests that would check types conformance to a protocol
//
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class ObjCProtocolCheck : BaseVisitor {
Dictionary protocol_map = new Dictionary ();
+ public ObjCProtocolCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public override void VisitManagedType (TypeDefinition type)
{
if (!type.HasCustomAttributes)
@@ -71,11 +68,9 @@ public override void VisitManagedType (TypeDefinition type)
protocol_map.Add (pname, type);
}
- public override void VisitObjCProtocolDecl (ObjCProtocolDecl decl, VisitKind visitKind)
+ public override void VisitObjCProtocolDecl (ObjCProtocolDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
- if (!decl.IsDefinition)
+ if (!decl.IsThisDeclarationADefinition)
return;
// check availability macros to see if the API is available on the OS and not deprecated
@@ -175,7 +170,7 @@ public override void VisitObjCProtocolDecl (ObjCProtocolDecl decl, VisitKind vis
bool is_abstract;
if (map.TryGetValue (selector, out is_abstract)) {
- bool required = method.ImplementationControl == ObjCImplementationControl.Required;
+ bool required = !method.Handle.IsObjCOptional;
if (required) {
if (!is_abstract)
Log.On (framework).Add ($"!incorrect-protocol-member! {GetName (decl, method)} is REQUIRED and should be abstract");
@@ -231,7 +226,7 @@ bool IsInit (string selector)
return Char.IsUpper (selector [4]);
}
- public override void End ()
+ public override void EndVisit ()
{
// at this stage anything else we have is not something we could find in Apple's headers
foreach (var kvp in protocol_map) {
diff --git a/tests/xtro-sharpie/xtro-sharpie/Program.cs b/tests/xtro-sharpie/xtro-sharpie/Program.cs
index fca12deeec75..83706cbb6e88 100644
--- a/tests/xtro-sharpie/xtro-sharpie/Program.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/Program.cs
@@ -4,30 +4,29 @@
using Mono.Options;
namespace Extrospection {
-
- // this is used to be executed from a custom 64bits mono
class MainClass {
static int Main (string [] arguments)
{
var outputDirectory = string.Empty;
var searchDirectories = new List ();
+ var rspFile = string.Empty;
var options = new OptionSet {
{ "output-directory=", (v) => outputDirectory = v },
{ "lib=", (v) => searchDirectories.Add (v) },
+ { "rsp=", (v) => rspFile = v },
+ new ResponseFileSource (),
};
var args = options.Parse (arguments);
- if (args.Count < 2) {
- Console.Error.WriteLine ("Usage: xtro-sharpie.exe [--output-directory=] [--lib=] pch-file dll-file [dll2-file]");
+ if (args.Count < 1) {
+ Console.Error.WriteLine ("Usage: xtro-sharpie.exe [--output-directory=] [--lib=] --rsp= dll-file");
return 1;
}
try {
- var assemblies = new List ();
- for (int i = 1; i < args.Count; i++)
- assemblies.Add (args [i]);
- new Runner ().Execute (args [0], assemblies, outputDirectory, searchDirectories);
+ var assemblies = new List (args);
+ new Runner ().Execute (assemblies, outputDirectory, searchDirectories, rspFile);
return 0;
} catch (Exception e) {
Console.WriteLine (e);
diff --git a/tests/xtro-sharpie/xtro-sharpie/ReleaseAttributeCheck.cs b/tests/xtro-sharpie/xtro-sharpie/ReleaseAttributeCheck.cs
index 0e43e3da3878..4870d88cc7a9 100644
--- a/tests/xtro-sharpie/xtro-sharpie/ReleaseAttributeCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/ReleaseAttributeCheck.cs
@@ -5,16 +5,13 @@
// for methods whose objc family indicates the returned value is retained, and the method doesn't have a [return: Release] attribute.
//
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class ReleaseAttributeCheck : BaseVisitor {
+ public ReleaseAttributeCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
// most selectors will be found in [Export] attributes
public override void VisitManagedMethod (MethodDefinition method)
diff --git a/tests/xtro-sharpie/xtro-sharpie/RequiresSuperCheck.cs b/tests/xtro-sharpie/xtro-sharpie/RequiresSuperCheck.cs
index 1df31fad2d2d..3a162e51fc0d 100644
--- a/tests/xtro-sharpie/xtro-sharpie/RequiresSuperCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/RequiresSuperCheck.cs
@@ -8,19 +8,17 @@
// when a managed member has no business to have an [RequiresSuper] attribute
//
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class RequiresSuperCheck : BaseVisitor {
static Dictionary methods = new Dictionary ();
+ public RequiresSuperCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
static MethodDefinition GetMethod (ObjCMethodDecl decl)
{
methods.TryGetValue (decl.GetName (), out var md);
@@ -38,18 +36,14 @@ public override void VisitManagedMethod (MethodDefinition method)
methods.Add (key, method);
}
- public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl, VisitKind visitKind)
+ public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
foreach (var d in decl.Methods)
Visit (d);
}
- public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
Visit (decl);
}
@@ -67,7 +61,7 @@ void Visit (ObjCMethodDecl decl)
if (framework is null)
return;
- if (!decl.HasAttr ()) {
+ if (!decl.Attrs.IsObjCRequiresSuperAttr ()) {
if (method.RequiresSuper ())
Log.On (framework).Add ($"!extra-requires-super! {method.GetName ()} is incorrectly decorated with an [RequiresSuper] attribute");
} else if (!method.RequiresSuper ()) {
diff --git a/tests/xtro-sharpie/xtro-sharpie/Runner.cs b/tests/xtro-sharpie/xtro-sharpie/Runner.cs
index 5780c79409a2..a8fc41f13624 100644
--- a/tests/xtro-sharpie/xtro-sharpie/Runner.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/Runner.cs
@@ -1,12 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class Runner {
@@ -15,50 +6,52 @@ public Runner ()
{
}
- public void Execute (string pchFile, IEnumerable assemblyNames, string outputDirectory, IEnumerable searchDirectories)
- {
- var managed_reader = new AssemblyReader () {
- new MapNamesVisitor (), // must come first to map managed and native names.
- new ReleaseAttributeCheck (),
- new DesignatedInitializerCheck (),
- new DllImportCheck (),
- new EnumCheck (),
- new FieldCheck (),
- new ObjCInterfaceCheck (),
- new ObjCProtocolCheck (),
- new SelectorCheck (),
- new SimdCheck (),
- new RequiresSuperCheck (),
- new DeprecatedCheck (),
- new NullabilityCheck (),
- new UIAppearanceCheck (),
-// new ListNative (), // for debug
+ public void Execute (IEnumerable assemblyNames, string outputDirectory, IEnumerable searchDirectories, string responseFile)
+ {
+ string [] arguments = new string [] {
+ $"@{responseFile}",
};
- foreach (var assemblyName in assemblyNames) {
- var name = Path.GetFileNameWithoutExtension (assemblyName);
- if (name.EndsWith (".iOS", StringComparison.Ordinal))
- Helpers.Platform = Platforms.iOS;
- else if (name.EndsWith (".Mac", StringComparison.Ordinal) || name.EndsWith (".macOS", StringComparison.Ordinal))
- Helpers.Platform = Platforms.macOS;
- else if (name.EndsWith (".TVOS", StringComparison.Ordinal) || name.EndsWith (".tvOS", StringComparison.Ordinal))
- Helpers.Platform = Platforms.tvOS;
- else if (name.EndsWith (".MacCatalyst", StringComparison.Ordinal))
- Helpers.Platform = Platforms.MacCatalyst;
- Helpers.IsDotNet = assemblyName.Contains ("/runtimes/");
- managed_reader.Load (assemblyName, searchDirectories);
- }
- managed_reader.Process ();
- var reader = new AstReader ();
- foreach (var v in managed_reader) {
- reader.TranslationUnitParsed += tu => {
- tu.Accept (v);
+ var rv = Tools.Visit (arguments, (bindingResult) => {
+ var visitor = new SharpieVisitor (bindingResult) {
+ new MapNamesVisitor (bindingResult), // must come first to map managed and native names.
+ new ReleaseAttributeCheck (bindingResult),
+ new DesignatedInitializerCheck (bindingResult),
+ new DllImportCheck (bindingResult),
+ new EnumCheck (bindingResult),
+ new FieldCheck (bindingResult),
+ new ObjCInterfaceCheck (bindingResult),
+ new ObjCProtocolCheck (bindingResult),
+ new SelectorCheck (bindingResult),
+ new SimdCheck (bindingResult),
+ new RequiresSuperCheck (bindingResult),
+ new DeprecatedCheck (bindingResult),
+ new NullabilityCheck (bindingResult),
+ new UIAppearanceCheck (bindingResult),
+ // new ListNative (bindingResult), // for debug
};
- }
-
- reader.Load (pchFile);
+ foreach (var assemblyName in assemblyNames) {
+ var name = Path.GetFileNameWithoutExtension (assemblyName);
+ if (name.EndsWith (".iOS", StringComparison.Ordinal))
+ Helpers.Platform = Platforms.iOS;
+ else if (name.EndsWith (".macOS", StringComparison.Ordinal))
+ Helpers.Platform = Platforms.macOS;
+ else if (name.EndsWith (".tvOS", StringComparison.Ordinal))
+ Helpers.Platform = Platforms.tvOS;
+ else if (name.EndsWith (".MacCatalyst", StringComparison.Ordinal))
+ Helpers.Platform = Platforms.MacCatalyst;
+ else
+ throw new NotImplementedException ($"Unknown platform for assembly {assemblyName}");
+ visitor.Load (assemblyName, searchDirectories);
+ }
+ visitor.ProcessManaged ();
+ return visitor;
+ }, out var bindingResult);
- managed_reader.End ();
+ if (!rv) {
+ bindingResult?.PrintMessages ();
+ throw new InvalidOperationException ("No visitor was created.");
+ }
Log.Save (outputDirectory);
}
@@ -126,11 +119,16 @@ public void Dispose ()
}
}
- class AssemblyReader : IEnumerable {
+ sealed class SharpieVisitor : BaseVisitor, IEnumerable {
HashSet assemblies = new HashSet ();
AssemblyResolver resolver = new AssemblyResolver ();
+ public SharpieVisitor (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public void Load (string filename, IEnumerable searchDirectories)
{
resolver.AddSearchDirectory (searchDirectories.ToArray ());
@@ -138,7 +136,7 @@ public void Load (string filename, IEnumerable searchDirectories)
assemblies.Add (resolver.Load (filename));
}
- public void Process ()
+ public void ProcessManaged ()
{
foreach (var ad in assemblies) {
foreach (var v in Visitors) {
@@ -175,10 +173,11 @@ public void Add (BaseVisitor visitor)
Visitors.Add (visitor);
}
- public void End ()
+ public override void EndVisit ()
{
+ base.EndVisit ();
foreach (var v in Visitors)
- v.End ();
+ v.EndVisit ();
}
public IEnumerator GetEnumerator ()
@@ -190,9 +189,564 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return Visitors.GetEnumerator ();
}
+
+ public override void VisitAdjustedType (AdjustedType type)
+ {
+ base.VisitAdjustedType (type);
+ foreach (var v in Visitors)
+ v.VisitAdjustedType (type);
+ }
+
+ public override void VisitArrayType (ClangSharp.ArrayType type)
+ {
+ base.VisitArrayType (type);
+ foreach (var v in Visitors)
+ v.VisitArrayType (type);
+ }
+
+ public override void VisitPointerType (ClangSharp.PointerType type)
+ {
+ base.VisitPointerType (type);
+ foreach (var v in Visitors)
+ v.VisitPointerType (type);
+ }
+
+ public override void VisitTypedefType (ClangSharp.TypedefType type)
+ {
+ base.VisitTypedefType (type);
+ foreach (var v in Visitors)
+ v.VisitTypedefType (type);
+ }
+
+ public override void VisitFunctionType (ClangSharp.FunctionType type)
+ {
+ base.VisitFunctionType (type);
+ foreach (var v in Visitors)
+ v.VisitFunctionType (type);
+ }
+
+ public override void VisitAttributedType (ClangSharp.AttributedType type)
+ {
+ base.VisitAttributedType (type);
+ foreach (var v in Visitors)
+ v.VisitAttributedType (type);
+ }
+
+ public override void VisitBuiltinType (ClangSharp.BuiltinType type)
+ {
+ base.VisitBuiltinType (type);
+ foreach (var v in Visitors)
+ v.VisitBuiltinType (type);
+ }
+
+ public override void VisitEnumType (ClangSharp.EnumType type)
+ {
+ base.VisitEnumType (type);
+ foreach (var v in Visitors)
+ v.VisitEnumType (type);
+ }
+
+ public override void VisitRecordType (ClangSharp.RecordType type)
+ {
+ base.VisitRecordType (type);
+ foreach (var v in Visitors)
+ v.VisitRecordType (type);
+ }
+
+ public override void VisitObjCObjectType (ClangSharp.ObjCObjectType type)
+ {
+ base.VisitObjCObjectType (type);
+ foreach (var v in Visitors)
+ v.VisitObjCObjectType (type);
+ }
+
+ public override void VisitUnaryExprOrTypeTraitExpr (UnaryExprOrTypeTraitExpr stmt)
+ {
+ base.VisitUnaryExprOrTypeTraitExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitUnaryExprOrTypeTraitExpr (stmt);
+ }
+
+ public override void VisitAtomicType (AtomicType type)
+ {
+ base.VisitAtomicType (type);
+ foreach (var v in Visitors)
+ v.VisitAtomicType (type);
+ }
+
+ public override void VisitAttr (Attr attr)
+ {
+ base.VisitAttr (attr);
+ foreach (var v in Visitors)
+ v.VisitAttr (attr);
+ }
+
+ public override void VisitBinaryOperator (BinaryOperator stmt)
+ {
+ base.VisitBinaryOperator (stmt);
+ foreach (var v in Visitors)
+ v.VisitBinaryOperator (stmt);
+ }
+
+ public override void VisitBlockPointerType (BlockPointerType type)
+ {
+ base.VisitBlockPointerType (type);
+ foreach (var v in Visitors)
+ v.VisitBlockPointerType (type);
+ }
+
+ public override void VisitCastExpr (CastExpr stmt)
+ {
+ base.VisitCastExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitCastExpr (stmt);
+ }
+
+ public override void VisitCharacterLiteral (CharacterLiteral stmt)
+ {
+ base.VisitCharacterLiteral (stmt);
+ foreach (var v in Visitors)
+ v.VisitCharacterLiteral (stmt);
+ }
+
+ public override void VisitComplexType (ComplexType type)
+ {
+ base.VisitComplexType (type);
+ foreach (var v in Visitors)
+ v.VisitComplexType (type);
+ }
+
+ public override void VisitConstantArrayType (ConstantArrayType type)
+ {
+ base.VisitConstantArrayType (type);
+ foreach (var v in Visitors)
+ v.VisitConstantArrayType (type);
+ }
+
+ public override void VisitConstantExpr (ConstantExpr stmt)
+ {
+ base.VisitConstantExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitConstantExpr (stmt);
+ }
+
+ public override void VisitDecayedType (DecayedType type)
+ {
+ base.VisitDecayedType (type);
+ foreach (var v in Visitors)
+ v.VisitDecayedType (type);
+ }
+
+ public sealed override void VisitDecl (Decl decl)
+ {
+ base.VisitDecl (decl);
+ // If we iterate over all the visitors here, we end up visiting the same nodes multiple times.
+ }
+
+ public override void VisitDeclaratorDecl (DeclaratorDecl decl)
+ {
+ base.VisitDeclaratorDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitDeclaratorDecl (decl);
+ }
+
+ public override void VisitDeclRefExpr (DeclRefExpr stmt)
+ {
+ base.VisitDeclRefExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitDeclRefExpr (stmt);
+ }
+
+ public override void VisitElaboratedType (ElaboratedType type)
+ {
+ base.VisitElaboratedType (type);
+ foreach (var v in Visitors)
+ v.VisitElaboratedType (type);
+ }
+
+ public override void VisitEnumConstantDecl (EnumConstantDecl decl)
+ {
+ base.VisitEnumConstantDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitEnumConstantDecl (decl);
+ }
+
+ public override void VisitEnumDecl (EnumDecl decl)
+ {
+ base.VisitEnumDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitEnumDecl (decl);
+ }
+
+ public override void VisitExplicitCastExpr (ExplicitCastExpr stmt)
+ {
+ base.VisitExplicitCastExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitExplicitCastExpr (stmt);
+ }
+
+ public override void VisitExpr (Expr stmt)
+ {
+ base.VisitExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitExpr (stmt);
+ }
+
+ public override void VisitExtVectorType (ExtVectorType type)
+ {
+ base.VisitExtVectorType (type);
+ foreach (var v in Visitors)
+ v.VisitExtVectorType (type);
+ }
+
+ public override void VisitFieldDecl (FieldDecl decl)
+ {
+ base.VisitFieldDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitFieldDecl (decl);
+ }
+
+ public override void VisitFloatingLiteral (FloatingLiteral stmt)
+ {
+ base.VisitFloatingLiteral (stmt);
+ foreach (var v in Visitors)
+ v.VisitFloatingLiteral (stmt);
+ }
+
+ public override void VisitFullExpr (FullExpr stmt)
+ {
+ base.VisitFullExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitFullExpr (stmt);
+ }
+
+ public override void VisitFunctionDecl (FunctionDecl decl)
+ {
+ base.VisitFunctionDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitFunctionDecl (decl);
+ }
+
+ public override void VisitFunctionNoProtoType (FunctionNoProtoType type)
+ {
+ base.VisitFunctionNoProtoType (type);
+ foreach (var v in Visitors)
+ v.VisitFunctionNoProtoType (type);
+ }
+
+ public override void VisitFunctionProtoType (FunctionProtoType type)
+ {
+ base.VisitFunctionProtoType (type);
+ foreach (var v in Visitors)
+ v.VisitFunctionProtoType (type);
+ }
+
+ public override void VisitImplicitCastExpr (ImplicitCastExpr stmt)
+ {
+ base.VisitImplicitCastExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitImplicitCastExpr (stmt);
+ }
+
+ public override void VisitIncompleteArrayType (IncompleteArrayType type)
+ {
+ base.VisitIncompleteArrayType (type);
+ foreach (var v in Visitors)
+ v.VisitIncompleteArrayType (type);
+ }
+
+ public override void VisitIndirectFieldDecl (IndirectFieldDecl decl)
+ {
+ base.VisitIndirectFieldDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitIndirectFieldDecl (decl);
+ }
+
+ public override void VisitIntegerLiteral (IntegerLiteral stmt)
+ {
+ base.VisitIntegerLiteral (stmt);
+ foreach (var v in Visitors)
+ v.VisitIntegerLiteral (stmt);
+ }
+
+ public override void VisitLinkageSpecDecl (LinkageSpecDecl decl)
+ {
+ base.VisitLinkageSpecDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitLinkageSpecDecl (decl);
+ }
+
+ public override void VisitLValueReferenceType (LValueReferenceType type)
+ {
+ base.VisitLValueReferenceType (type);
+ foreach (var v in Visitors)
+ v.VisitLValueReferenceType (type);
+ }
+
+ public override void VisitMacroQualifiedType (MacroQualifiedType type)
+ {
+ base.VisitMacroQualifiedType (type);
+ foreach (var v in Visitors)
+ v.VisitMacroQualifiedType (type);
+ }
+
+ public override void VisitManagedAssembly (AssemblyDefinition assembly)
+ {
+ base.VisitManagedAssembly (assembly);
+ foreach (var v in Visitors)
+ v.VisitManagedAssembly (assembly);
+ }
+
+ public override void VisitManagedMethod (MethodDefinition method)
+ {
+ base.VisitManagedMethod (method);
+ foreach (var v in Visitors)
+ v.VisitManagedMethod (method);
+ }
+
+ public override void VisitManagedModule (ModuleDefinition module)
+ {
+ base.VisitManagedModule (module);
+ foreach (var v in Visitors)
+ v.VisitManagedModule (module);
+ }
+
+ public override void VisitManagedType (TypeDefinition type)
+ {
+ base.VisitManagedType (type);
+ foreach (var v in Visitors)
+ v.VisitManagedType (type);
+ }
+
+ public override void VisitNamedDecl (NamedDecl decl)
+ {
+ base.VisitNamedDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitNamedDecl (decl);
+ }
+
+ public override void VisitNamespaceDecl (NamespaceDecl decl)
+ {
+ base.VisitNamespaceDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitNamespaceDecl (decl);
+ }
+
+ public override void VisitNode (object node)
+ {
+ base.VisitNode (node);
+ foreach (var v in Visitors)
+ v.VisitNode (node);
+ }
+
+ public override void VisitObjCCategoryDecl (ObjCCategoryDecl decl)
+ {
+ base.VisitObjCCategoryDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCCategoryDecl (decl);
+ }
+
+ public override void VisitObjCContainerDecl (ObjCContainerDecl decl)
+ {
+ base.VisitObjCContainerDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCContainerDecl (decl);
+ }
+
+ public override void VisitObjCInterfaceDecl (ObjCInterfaceDecl decl)
+ {
+ base.VisitObjCInterfaceDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCInterfaceDecl (decl);
+ }
+
+ public override void VisitObjCIvarDecl (ObjCIvarDecl decl)
+ {
+ base.VisitObjCIvarDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCIvarDecl (decl);
+ }
+
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
+ {
+ base.VisitObjCMethodDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCMethodDecl (decl);
+ }
+
+ public override void VisitObjCObjectPointerType (ObjCObjectPointerType type)
+ {
+ base.VisitObjCObjectPointerType (type);
+ foreach (var v in Visitors)
+ v.VisitObjCObjectPointerType (type);
+ }
+
+ public override void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
+ {
+ base.VisitObjCPropertyDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCPropertyDecl (decl);
+ }
+
+ public override void VisitObjCProtocolDecl (ObjCProtocolDecl decl)
+ {
+ base.VisitObjCProtocolDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCProtocolDecl (decl);
+ }
+
+ public override void VisitObjCTypeParamDecl (ObjCTypeParamDecl decl)
+ {
+ base.VisitObjCTypeParamDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitObjCTypeParamDecl (decl);
+ }
+
+ public override void VisitObjCTypeParamType (ObjCTypeParamType type)
+ {
+ base.VisitObjCTypeParamType (type);
+ foreach (var v in Visitors)
+ v.VisitObjCTypeParamType (type);
+ }
+
+ public override void VisitParenExpr (ParenExpr stmt)
+ {
+ base.VisitParenExpr (stmt);
+ foreach (var v in Visitors)
+ v.VisitParenExpr (stmt);
+ }
+
+ public override void VisitParenType (ParenType type)
+ {
+ base.VisitParenType (type);
+ foreach (var v in Visitors)
+ v.VisitParenType (type);
+ }
+
+ public override void VisitRecordDecl (RecordDecl decl)
+ {
+ base.VisitRecordDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitRecordDecl (decl);
+ }
+
+ public override void VisitRef (Ref @ref)
+ {
+ base.VisitRef (@ref);
+ foreach (var v in Visitors)
+ v.VisitRef (@ref);
+ }
+
+ public override void VisitReferenceType (ReferenceType type)
+ {
+ base.VisitReferenceType (type);
+ foreach (var v in Visitors)
+ v.VisitReferenceType (type);
+ }
+
+ public override void VisitStmt (Stmt stmt)
+ {
+ base.VisitStmt (stmt);
+ foreach (var v in Visitors)
+ v.VisitStmt (stmt);
+ }
+
+ public override void VisitTagDecl (TagDecl decl)
+ {
+ base.VisitTagDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitTagDecl (decl);
+ }
+
+ public override void VisitTagType (TagType type)
+ {
+ base.VisitTagType (type);
+ foreach (var v in Visitors)
+ v.VisitTagType (type);
+ }
+
+ public sealed override void VisitTranslationUnitDecl (TranslationUnitDecl translationUnitDecl)
+ {
+ base.VisitTranslationUnitDecl (translationUnitDecl);
+ // If we iterate over all the visitors here, we end up visiting the same nodes multiple times.
+ }
+
+ public override void VisitType (ClangSharp.Type type)
+ {
+ base.VisitType (type);
+ foreach (var v in Visitors)
+ v.VisitType (type);
+ }
+
+ public override void VisitTypeDecl (TypeDecl decl)
+ {
+ base.VisitTypeDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitTypeDecl (decl);
+ }
+
+ public override void VisitTypedefDecl (TypedefDecl decl)
+ {
+ base.VisitTypedefDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitTypedefDecl (decl);
+ }
+
+ public override void VisitTypedefNameDecl (TypedefNameDecl decl)
+ {
+ base.VisitTypedefNameDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitTypedefNameDecl (decl);
+ }
+
+ public override void VisitTypeWithKeyword (TypeWithKeyword type)
+ {
+ base.VisitTypeWithKeyword (type);
+ foreach (var v in Visitors)
+ v.VisitTypeWithKeyword (type);
+ }
+
+ public override void VisitUnaryOperator (UnaryOperator stmt)
+ {
+ base.VisitUnaryOperator (stmt);
+ foreach (var v in Visitors)
+ v.VisitUnaryOperator (stmt);
+ }
+
+ public override void VisitValueDecl (ValueDecl decl)
+ {
+ base.VisitValueDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitValueDecl (decl);
+ }
+
+ public override void VisitValueStmt (ValueStmt stmt)
+ {
+ base.VisitValueStmt (stmt);
+ foreach (var v in Visitors)
+ v.VisitValueStmt (stmt);
+ }
+
+ public override void VisitVarDecl (VarDecl decl)
+ {
+ base.VisitVarDecl (decl);
+ foreach (var v in Visitors)
+ v.VisitVarDecl (decl);
+ }
+
+ public override void VisitVectorType (VectorType type)
+ {
+ base.VisitVectorType (type);
+ foreach (var v in Visitors)
+ v.VisitVectorType (type);
+ }
}
public class BaseVisitor : AstVisitor {
+ public BaseVisitor (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
public virtual void VisitManagedAssembly (AssemblyDefinition assembly)
{
@@ -209,16 +763,14 @@ public virtual void VisitManagedType (TypeDefinition type)
public virtual void VisitManagedMethod (MethodDefinition method)
{
}
-
- // last chance to report errors
- public virtual void End ()
- {
- }
}
-
// debug
class ListNative : BaseVisitor {
+ public ListNative (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
public override void VisitDecl (Decl decl)
{
diff --git a/tests/xtro-sharpie/xtro-sharpie/SelectorCheck.cs b/tests/xtro-sharpie/xtro-sharpie/SelectorCheck.cs
index 6180d0757633..e31701909bb6 100644
--- a/tests/xtro-sharpie/xtro-sharpie/SelectorCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/SelectorCheck.cs
@@ -5,12 +5,8 @@
// if headers defines a selector for which we have no bindings
//
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
+using System.Diagnostics;
+using System.Runtime.Serialization;
namespace Extrospection {
@@ -19,6 +15,11 @@ public class SelectorCheck : BaseVisitor {
HashSet qualified_selectors = new HashSet ();
Dictionary>> qualified_properties = new Dictionary>> ();
+ public SelectorCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
// most selectors will be found in [Export] attribtues
public override void VisitManagedMethod (MethodDefinition method)
{
@@ -65,7 +66,7 @@ public override void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
if (framework is null)
return;
- var nativeArgumentSemantic = decl.Attributes.ToArgumentSemantic ();
+ var nativeArgumentSemantic = decl.GetPropertyAttributes ().ToArgumentSemantic ();
var nativeMethodDefinition = decl.QualifiedName;
if (qualified_properties.TryGetValue (nativeMethodDefinition, out var managedArgumentSemanticList)) {
@@ -84,11 +85,8 @@ public override void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
}
}
- public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
-
// protocol members are checked in ObjCProtocolCheck
if (decl.DeclContext is ObjCProtocolDecl)
return;
diff --git a/tests/xtro-sharpie/xtro-sharpie/SimdCheck.cs b/tests/xtro-sharpie/xtro-sharpie/SimdCheck.cs
index b76c4a74bcc8..b3dd890463d0 100644
--- a/tests/xtro-sharpie/xtro-sharpie/SimdCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/SimdCheck.cs
@@ -1,11 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
class SimdCheck : BaseVisitor {
@@ -98,6 +90,11 @@ class ManagedSimdInfo {
}
Dictionary managed_methods = new Dictionary ();
+ public SimdCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
public override void VisitManagedMethod (MethodDefinition method)
{
var type = method.DeclaringType;
@@ -172,12 +169,12 @@ bool IsSimdType (TypeReference td, ref bool invalid_for_simd)
bool ContainsSimdTypes (ObjCMethodDecl decl, ref string simd_type, ref bool requires_marshal_directive, ref bool only_return_type_is_simd)
{
- if (IsSimdType (decl, decl.ReturnQualType, ref simd_type, ref requires_marshal_directive))
+ if (IsSimdType (decl, decl.ReturnType, ref simd_type, ref requires_marshal_directive))
return true;
var is_simd_type = false;
foreach (var param in decl.Parameters) {
- if (!IsSimdType (decl, param.QualType, ref simd_type, ref requires_marshal_directive))
+ if (!IsSimdType (decl, param.Type, ref simd_type, ref requires_marshal_directive))
continue;
is_simd_type = true;
only_return_type_is_simd = false;
@@ -186,30 +183,30 @@ bool ContainsSimdTypes (ObjCMethodDecl decl, ref string simd_type, ref bool requ
return is_simd_type;
}
- bool IsExtVector (Decl decl, QualType type, ref string simd_type)
+ bool IsExtVector (Decl decl, ClangSharp.Type type, ref string simd_type)
{
var rv = false;
- var t = type.CanonicalQualType.Type;
+ var t = type.CanonicalType;
// Unpoint the type
- var pointerType = t as Clang.Ast.PointerType;
+ var pointerType = t as ClangSharp.PointerType;
if (pointerType is not null)
- t = pointerType.PointeeQualType.Type;
+ t = pointerType.PointeeType;
- if (t.Kind == TypeKind.ExtVector) {
+ if (t.Kind == CXTypeKind.CXType_ExtVector) {
rv = true;
} else {
var r = (t as RecordType)?.Decl;
if (r is not null) {
foreach (var f in r.Fields) {
- var qt = f.QualType.CanonicalQualType.Type;
- if (qt.Kind == TypeKind.ExtVector) {
+ var qt = f.Type.CanonicalType;
+ if (qt.Kind == CXTypeKind.CXType_ExtVector) {
rv = true;
break;
}
var at = qt as ConstantArrayType;
if (at is not null) {
- if (at.ElementType.Type.Kind == TypeKind.ExtVector) {
+ if (at.ElementType.Kind == CXTypeKind.CXType_ExtVector) {
rv = true;
break;
}
@@ -231,7 +228,7 @@ bool IsExtVector (Decl decl, QualType type, ref string simd_type)
return rv;
}
- bool IsSimdType (Decl decl, QualType type, ref string simd_type, ref bool requires_marshal_directive)
+ bool IsSimdType (Decl decl, ClangSharp.Type type, ref string simd_type, ref bool requires_marshal_directive)
{
var str = Undecorate (type.ToString ());
@@ -339,11 +336,8 @@ void CheckMarshalDirective (MethodDefinition method, string simd_type, bool only
Log.On (framework).Add ($"!wrong-simd-missing-marshaldirective! {method}: simd type: {simd_type}");
}
- public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
-
// don't process methods (or types) that are unavailable for the current platform
if (!decl.IsAvailable () || !(decl.DeclContext as Decl).IsAvailable ())
return;
@@ -382,11 +376,8 @@ public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKi
if (parentClass is not null)
attrs.AddRange (parentClass.Attrs);
- foreach (var attr in attrs) {
- var av_attr = attr as AvailabilityAttr;
- if (av_attr is null)
- continue;
- if (av_attr.Platform.Name != "ios")
+ foreach (var av_attr in attrs.GetAvailabilityAttributes ()) {
+ if (av_attr.AvailabilityAttributePlatformIdentifierName.ToLowerInvariant () != "ios")
continue;
if (av_attr.Introduced.Major >= 11) {
is_new = true;
diff --git a/tests/xtro-sharpie/xtro-sharpie/UIAppearanceCheck.cs b/tests/xtro-sharpie/xtro-sharpie/UIAppearanceCheck.cs
index fcac2ebfdb9a..47d3895f77e4 100644
--- a/tests/xtro-sharpie/xtro-sharpie/UIAppearanceCheck.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/UIAppearanceCheck.cs
@@ -8,13 +8,6 @@
// when an API is decorated with [Appearance] attribute but ObjC headers don't have a UI_APPEARANCE_SELECTOR
//
-using System;
-using System.Collections.Generic;
-
-using Mono.Cecil;
-
-using Clang.Ast;
-
namespace Extrospection {
public class UIAppearanceCheck : BaseVisitor {
@@ -23,6 +16,11 @@ public class UIAppearanceCheck : BaseVisitor {
static HashSet appearance_methods = new HashSet ();
static Dictionary methods = new Dictionary ();
+ public UIAppearanceCheck (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
static MethodDefinition GetMethod (ObjCMethodDecl decl)
{
methods.TryGetValue (decl.GetName (), out var md);
@@ -55,34 +53,31 @@ public override void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
return;
// does not look exposed, but part of the dump
- if (decl.DumpToString ().IndexOf ("UI_APPEARANCE_SELECTOR", StringComparison.OrdinalIgnoreCase) < 0)
+ if (!decl.IsUIAppearanceSelector)
return;
- var getter = decl.Getter;
+ var getter = decl.GetterMethodDecl;
if (getter is not null)
- VisitObjCMethodDecl (getter);
- var setter = decl.Setter;
+ VisitObjCMethodDeclImpl (getter);
+ var setter = decl.SetterMethodDecl;
if (setter is not null)
- VisitObjCMethodDecl (setter);
+ VisitObjCMethodDeclImpl (setter);
}
- public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
- if (visitKind != VisitKind.Enter)
- return;
-
// don't process methods (or types) that are unavailable for the current platform
if (!decl.IsAvailable () || !(decl.DeclContext as Decl).IsAvailable ())
return;
// does not look exposed, but part of the dump
- if (decl.DumpToString ().IndexOf ("UI_APPEARANCE_SELECTOR", StringComparison.OrdinalIgnoreCase) < 0)
+ if (!decl.IsUIAppearanceSelector)
return;
- VisitObjCMethodDecl (decl);
+ VisitObjCMethodDeclImpl (decl);
}
- void VisitObjCMethodDecl (ObjCMethodDecl decl)
+ void VisitObjCMethodDeclImpl (ObjCMethodDecl decl)
{
var framework = Helpers.GetFramework (decl);
if (framework is null)
@@ -113,7 +108,7 @@ void VisitObjCMethodDecl (ObjCMethodDecl decl)
Log.On (framework).Add ($"!missing-ui-appearance-support! {method.GetName ()} is missing [Appearance]");
}
- public override void End ()
+ public override void EndVisit ()
{
// looking for extra [Appearance] attributes
foreach (var t in appearance_types) {
diff --git a/tests/xtro-sharpie/xtro-sharpie/VersionHelpers.cs b/tests/xtro-sharpie/xtro-sharpie/VersionHelpers.cs
index 2ebf84d78a2e..8798b2e5f233 100644
--- a/tests/xtro-sharpie/xtro-sharpie/VersionHelpers.cs
+++ b/tests/xtro-sharpie/xtro-sharpie/VersionHelpers.cs
@@ -1,5 +1,3 @@
-using System;
-using Clang;
using static Extrospection.Helpers;
namespace Extrospection {
diff --git a/tests/xtro-sharpie/xtro-sharpie/xtro-sharpie.csproj b/tests/xtro-sharpie/xtro-sharpie/xtro-sharpie.csproj
index f28b4da3c550..6f6eba16dbe4 100644
--- a/tests/xtro-sharpie/xtro-sharpie/xtro-sharpie.csproj
+++ b/tests/xtro-sharpie/xtro-sharpie/xtro-sharpie.csproj
@@ -1,45 +1,19 @@
- net4.7.2
+ net$(BundledNETCoreAppTargetFrameworkVersion)
Exe
false
latest
+
+
+
+ osx-arm64
+ false
-
-
- Project
- ../$(iOS_PCH) --output-directory ../api-annotations-dotnet --lib ../../../packages/microsoft.netcore.app.ref/$(MicrosoftNETCoreAppRefPackageVersion)/ref/$(DOTNET_TFM) $(iOS_DLL)
- .
-
-
- Project
- ../$(tvOS_PCH) --output-directory ../api-annotations-dotnet --lib ../../../packages/microsoft.netcore.app.ref/$(MicrosoftNETCoreAppRefPackageVersion)/ref/$(DOTNET_TFM) $(tvOS_DLL)
- .
-
-
- Project
- ../$(macOS_PCH) --output-directory ../api-annotations-dotnet --lib ../../../packages/microsoft.netcore.app.ref/$(MicrosoftNETCoreAppRefPackageVersion)/ref/$(DOTNET_TFM) $(macOS_DLL)
- .
-
-
- Project
- ../$(MacCatalyst_PCH) --output-directory ../api-annotations-dotnet --lib ../../../packages/microsoft.netcore.app.ref/$(MicrosoftNETCoreAppRefPackageVersion)/ref/$(DOTNET_TFM) $(MacCatalyst_DLL)
- .
-
+
-
- \Library\Frameworks\ObjectiveSharpie.framework\Versions\Current\bin\Clang.dll
-
-
-
+
-
-
- $(SHARPIE)/../bin/x64/Release/libclang-mono.dylib
- /Library/Frameworks/ObjectiveSharpie.framework/Versions/Current/bin/libclang-mono.dylib
-
-
-
diff --git a/tools/Makefile b/tools/Makefile
index fb542bff3f44..ee73e7c5ba3e 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -2,6 +2,10 @@ TOP=..
include $(TOP)/Make.config
+ifndef IS_LINUX
+SUBDIRS += sharpie
+endif
+
SUBDIRS += devops
SUBDIRS += mtouch
@@ -9,3 +13,4 @@ SUBDIRS += mtouch
SUBDIRS+=mlaunch
SUBDIRS += dotnet-linker
+
diff --git a/tools/autoformat.sh b/tools/autoformat.sh
index 0713cdeae03e..78270150c242 100755
--- a/tools/autoformat.sh
+++ b/tools/autoformat.sh
@@ -45,10 +45,16 @@ $DOTNET --info
function af_whitespace ()
{
- echo "Processing $1..."
+ echo "Processing whitespace in $1..."
$DOTNET format whitespace "$1"
}
+function af ()
+{
+ echo "Formatting $i"
+ $DOTNET format "$1"
+}
+
# Start formatting!
af_whitespace "$SRC_DIR/tests/cecil-tests/cecil-tests.csproj"
af_whitespace "$SRC_DIR/tests/dotnet/UnitTests/DotNetUnitTests.csproj"
@@ -90,6 +96,8 @@ af_whitespace "$SRC_DIR/tests/common/Touch.Unit/Touch.Client/dotnet/Touch.Client
af_whitespace "$SRC_DIR/tests/common/Touch.Unit/Touch.Client/dotnet/Touch.Client.macOS.csproj"
af_whitespace "$SRC_DIR/tests/common/Touch.Unit/Touch.Client/dotnet/Touch.Client.tvOS.csproj"
+af "$SRC_DIR/tools/sharpie/sharpie.slnx"
+
echo "Processing $SRC_DIR..."
$DOTNET format whitespace --folder "$SRC_DIR"
diff --git a/tools/common/Make.common b/tools/common/Make.common
index 248e8f480575..a83dd8a8c63b 100644
--- a/tools/common/Make.common
+++ b/tools/common/Make.common
@@ -1,5 +1,8 @@
# We check in SdkVersions.cs so that it's easier to use this file when building tests on Windows.
+LAST_XCODE_BUMP:=$(shell git blame -- $(TOP)/Make.config HEAD | grep " XCODE_VERSION=" | sed 's/ .*//')
+XCODE_BUMP_COMMIT_DISTANCE:=$(shell git log "$(LAST_XCODE_BUMP)..HEAD" --oneline | wc -l | sed -e 's/ //g')
+
$(abspath ../common/SdkVersions.cs): ../common/SdkVersions.in.cs Makefile $(TOP)/Make.config $(TOP)/Make.versions
$(Q_GEN) sed \
-e 's/@IOS_SDK_VERSION@/$(IOS_SDK_VERSION)/g' -e 's/@TVOS_SDK_VERSION@/$(TVOS_SDK_VERSION)/' -e 's/@MACOS_SDK_VERSION@/$(MACOS_SDK_VERSION)/' \
@@ -53,4 +56,7 @@ $(abspath ../common/ProductConstants.cs): ../common/ProductConstants.in.cs Makef
$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),-e "s/@$(platform)_NUGET_REVISION@/$(NUGET_PRERELEASE_IDENTIFIER)$($(platform)_NUGET_COMMIT_DISTANCE)$(NUGET_BUILD_METADATA)/g") \
\
-e "s/@PRODUCT_HASH@/$(CURRENT_HASH_LONG)/g" \
+ \
+ -e "s/@XCODE_VERSION@/$(XCODE_VERSION)/g" \
+ -e "s/@XCODE_BUMP_COMMIT_DISTANCE@/$(XCODE_BUMP_COMMIT_DISTANCE)/g" \
$< > $@
diff --git a/tools/common/ProductConstants.in.cs b/tools/common/ProductConstants.in.cs
index 2e262ce1283e..49b966bb75c0 100644
--- a/tools/common/ProductConstants.in.cs
+++ b/tools/common/ProductConstants.in.cs
@@ -6,11 +6,15 @@
#endif
namespace Xamarin {
- sealed class ProductConstants {
+ public sealed class ProductConstants {
public string Version;
public string Revision;
public const string Hash = "@PRODUCT_HASH@";
+ internal const string XcodeVersion = "@XCODE_VERSION@";
+ internal const string XcodeBumpCommitDistance = "@XCODE_BUMP_COMMIT_DISTANCE@";
+ public const string SharpieVersion = XcodeVersion + ".0." + XcodeBumpCommitDistance;
+
ProductConstants (string version, string revision)
{
Version = version;
diff --git a/tools/common/StringUtils.cs b/tools/common/StringUtils.cs
index 8d57d72876a3..42baad54543a 100644
--- a/tools/common/StringUtils.cs
+++ b/tools/common/StringUtils.cs
@@ -7,7 +7,7 @@
#nullable enable
namespace Xamarin.Utils {
- internal class StringUtils {
+ class StringUtils {
static StringUtils ()
{
PlatformID pid = Environment.OSVersion.Platform;
@@ -236,6 +236,150 @@ public static Version ParseVersion (string v)
return new Version (major, 0);
return Version.Parse (v);
}
+
+ ///
+ /// Format a message according to MSBuild diagnostic format.
+ ///
+ /// The file name in the formatted message (null if no file name is present).
+ /// The line number in the formatted message (null if no line number is present).
+ /// True if the message is an error, false if it is a warning.
+ /// The prefix of the message.
+ /// The code of the message.
+ /// The message text.
+ ///
+ ///
+ public static string FormatMessage (string? fileName, long? lineNumber, bool isError, string prefix, int code, string message)
+ {
+ var sb = new StringBuilder ();
+ if (!string.IsNullOrEmpty (fileName)) {
+ sb.Append (fileName);
+ if (lineNumber is not null && lineNumber.Value > 0)
+ sb.Append ('(').Append (lineNumber.Value).Append (")");
+ sb.Append (": ");
+ }
+ sb.Append (isError ? "error" : "warning").Append (' ');
+ sb.Append (prefix).Append (code.ToString ("0000: "));
+ sb.Append (message);
+ return sb.ToString ();
+ }
+
+ ///
+ /// Parse a formatted message created with .
+ ///
+ /// The formatted message line to parse.
+ /// The file name in the formatted message (null if no file name is present).
+ /// The line number in the formatted message (null if no line number is present).
+ /// True if the message is an error, false if it is a warning, null if neither.
+ /// The prefix of the message.
+ /// The code of the message.
+ /// The message text.
+ ///
+ public static bool TryParseFormattedMessage (string? line, out string? fileName, out int? lineNumber, out bool isError, [NotNullWhen (true)] out string? prefix, out int code, [NotNullWhen (true)] out string? message)
+ {
+ fileName = null;
+ lineNumber = null;
+ isError = false;
+ prefix = null;
+ code = 0;
+ message = null;
+
+#if NET
+ if (string.IsNullOrEmpty (line))
+#else
+ if (string.IsNullOrEmpty (line) || line is null)
+#endif
+ return false;
+
+ var origin = string.Empty;
+
+ if (IndexOfAny (line, out var idxError, out var endError, ": error ", ": error ")) {
+ isError = true;
+ origin = line.Substring (0, idxError);
+ line = line.Substring (endError);
+ line = RemovePathAtEnd (line);
+ } else if (IndexOfAny (line, out var idxWarning, out var endWarning, ": warning ", ": warning ")) {
+ isError = false;
+ origin = line.Substring (0, idxWarning);
+ line = line.Substring (endWarning);
+ line = RemovePathAtEnd (line);
+ } else if (line.StartsWith ("error ", StringComparison.Ordinal)) {
+ isError = true;
+ line = line.Substring (6);
+ } else if (line.StartsWith ("warning ", StringComparison.Ordinal)) {
+ isError = false;
+ line = line.Substring (8);
+ } else {
+ // something else
+ return false;
+ }
+
+ if (line.Length < 7)
+ return false; // something else
+
+ var firstNumber = line.IndexOfAny ("0123456789".ToCharArray ());
+ if (firstNumber == -1)
+ return false; // something else)
+ prefix = line.Substring (0, firstNumber);
+ if (!int.TryParse (line.Substring (firstNumber, 4), out var codeValue))
+ return false; // something else
+ code = codeValue;
+ line = line.Substring (firstNumber + 4);
+
+ if (line.StartsWith (": "))
+ line = line.Substring (2);
+
+ message = line;
+
+ if (!string.IsNullOrEmpty (origin)) {
+ var idx = origin.IndexOf ('(');
+ if (idx > 0) {
+ var closing = origin.IndexOf (')');
+ if (!int.TryParse (origin.Substring (idx + 1, closing - idx - 1), out var number))
+ return false;
+ lineNumber = number;
+ fileName = origin.Substring (0, idx);
+ } else {
+ fileName = origin;
+ }
+ }
+
+ return true;
+ }
+
+ static bool IndexOfAny (string line, out int start, out int end, params string [] values)
+ {
+ foreach (var value in values) {
+ start = line.IndexOf (value, StringComparison.Ordinal);
+ if (start >= 0) {
+ end = start + value.Length;
+ return true;
+ }
+ }
+ start = -1;
+ end = -1;
+ return false;
+ }
+
+ static string RemovePathAtEnd (string line)
+ {
+#if NET
+ if (line.TrimEnd ().EndsWith (']')) {
+#else
+ if (line.TrimEnd ().EndsWith ("]")) {
+#endif
+ var start = line.LastIndexOf ('[');
+ if (start >= 0) {
+ // we want to get the space before `[` too.
+ if (start > 0 && line [start - 1] == ' ')
+ start--;
+
+ line = line.Substring (0, start);
+ return line;
+ }
+ }
+
+ return line;
+ }
}
static class StringExtensions {
diff --git a/tools/devops/LocProject.json.in b/tools/devops/LocProject.json.in
index b93da497f87c..a3ce89fb431c 100644
--- a/tools/devops/LocProject.json.in
+++ b/tools/devops/LocProject.json.in
@@ -62,6 +62,16 @@
"LciFile": "",
"Parser": "",
"LssFiles": []
+ },
+ {
+ "SourceFile": "@WORKING_DIRECTORY@/../../tools/sharpie/Sharpie.Bind/Resources.resx",
+ "Languages": "",
+ "CopyOption": "LangIDOnName",
+ "OutputPath": "@WORKING_DIRECTORY@/../../tools/sharpie/Sharpie.Bind/TranslatedAssemblies",
+ "LclFile": "",
+ "LciFile": "",
+ "Parser": "",
+ "LssFiles": []
}
],
"LssFiles": [],
diff --git a/tools/devops/README.md b/tools/devops/README.md
index 621063388fb8..07f4895e8b88 100644
--- a/tools/devops/README.md
+++ b/tools/devops/README.md
@@ -304,6 +304,7 @@ testConfigurations:
- label: linker # Linker tests
- label: monotouch # MonoTouch tests (split by platform)
- label: msbuild # MSBuild tests
+ - label: sharpie # Sharpie tests
- label: xcframework # XCFramework tests
- label: xtro # Xtro tests
- label: windows # Windows integration tests
diff --git a/tools/devops/automation/templates/common/configure.yml b/tools/devops/automation/templates/common/configure.yml
index 23a590e9e76e..aa3a5006ae02 100644
--- a/tools/devops/automation/templates/common/configure.yml
+++ b/tools/devops/automation/templates/common/configure.yml
@@ -83,6 +83,11 @@ parameters:
splitByPlatforms: false,
testPrefix: 'simulator_tests',
},
+ {
+ label: sharpie,
+ splitByPlatforms: false,
+ testPrefix: 'simulator_tests',
+ },
{
label: xcframework,
splitByPlatforms: false,
diff --git a/tools/devops/automation/templates/tests/stage.yml b/tools/devops/automation/templates/tests/stage.yml
index de2d7424def8..7301307f3f1f 100644
--- a/tools/devops/automation/templates/tests/stage.yml
+++ b/tools/devops/automation/templates/tests/stage.yml
@@ -94,6 +94,7 @@ stages:
demands:
- Agent.OS -equals Darwin
- macOS.Name -equals ${{ parameters.macOSName }}
+ - macOS.Architecture -equals arm64
- XcodeChannel -equals ${{ parameters.XcodeChannel }}
- ${{ each demand in parameters.extraBotDemands }}:
- demand
diff --git a/tools/sharpie/.gitignore b/tools/sharpie/.gitignore
new file mode 100644
index 000000000000..383b1a18ada1
--- /dev/null
+++ b/tools/sharpie/.gitignore
@@ -0,0 +1,2 @@
+*.inc
+
diff --git a/tools/sharpie/Makefile b/tools/sharpie/Makefile
new file mode 100644
index 000000000000..c7978f6ee6a3
--- /dev/null
+++ b/tools/sharpie/Makefile
@@ -0,0 +1,35 @@
+TOP=../..
+include $(TOP)/Make.config
+include $(TOP)/mk/rules.mk
+include ../common/Make.common
+
+SHARPIE_VERSION_BUILD=0
+SHARPIE_VERSION=$(XCODE_VERSION).$(SHARPIE_VERSION_BUILD).$(XCODE_BUMP_COMMIT_DISTANCE)$(NUGET_PRERELEASE_IDENTIFIER)
+
+# Sharpie.Bind.csproj.inc contains the $(Sharpie.Bind_dependencies) variable used to determine if Sharpie.Bind needs to be rebuilt or not.
+Sharpie.Bind/Sharpie.Bind.csproj.inc: export BUILD_VERBOSITY=$(MSBUILD_VERBOSITY)
+Sharpie.Bind/Sharpie.Bind.csproj.inc: export DOTNET:=$(DOTNET)
+-include Sharpie.Bind/Sharpie.Bind.csproj.inc
+
+SHARPIE_BIND_TOOL_DEBUG=Sharpie.Bind.Tool/bin/Debug/osx-arm64/Sharpie.Bind.Tool
+
+all-local:: $(SHARPIE_BIND_TOOL_DEBUG)
+$(SHARPIE_BIND_TOOL_DEBUG): $(Sharpie.Bind_dependencies)
+ $(Q_BUILD) $(DOTNET) build Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj $(DOTNET_BUILD_VERBOSITY) -bl:$@-build.binlog
+
+SHARPIE_BIND_TOOL_NUPKG_NAME=Sharpie.Bind.Tool.$(SHARPIE_VERSION).nupkg
+SHARPIE_BIND_TOOL_NUPKG=Sharpie.Bind.Tool/bin/Release/$(SHARPIE_BIND_TOOL_NUPKG_NAME)
+
+pack: $(SHARPIE_BIND_TOOL_NUPKG)
+$(SHARPIE_BIND_TOOL_NUPKG): $(Sharpie.Bind_dependencies)
+ $(Q_BUILD) $(DOTNET) pack Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj "/p:Version=$(SHARPIE_VERSION)" $(DOTNET_PACK_VERBOSITY) -bl:$@.binlog
+
+all-local:: $(DOTNET_NUPKG_DIR)/$(SHARPIE_BIND_TOOL_NUPKG_NAME)
+$(DOTNET_NUPKG_DIR)/$(SHARPIE_BIND_TOOL_NUPKG_NAME): $(SHARPIE_BIND_TOOL_NUPKG)
+ $(Q) mkdir -p $(dir $@)
+ $(Q) $(CP) $< $@
+
+run-tests: $(Sharpie.Bind_dependencies)
+ $(Q_BUILD) $(DOTNET) test $(TOP)/tests/sharpie/Sharpie.Bind.Tests/Sharpie.Bind.Tests.csproj --logger "console;verbosity=detailed" $(DOTNET_BUILD_VERBOSITY) -bl:$@.binlog
+
+generated-files: $(abspath ../common/SdkVersions.cs) $(abspath ../common/ProductConstants.cs)
diff --git a/tools/sharpie/README.md b/tools/sharpie/README.md
new file mode 100644
index 000000000000..48e9d1185d56
--- /dev/null
+++ b/tools/sharpie/README.md
@@ -0,0 +1,3 @@
+# Objective Sharpie
+
+A clang-based C# binding generator for Objective-C.
diff --git a/tools/sharpie/Sharpie.Bind.Tool/Program.cs b/tools/sharpie/Sharpie.Bind.Tool/Program.cs
new file mode 100644
index 000000000000..59657eeabbf8
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind.Tool/Program.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Sharpie.Bind;
+
+class Program {
+ static void ShowHelp ()
+ {
+ var help =
+"""
+usage: sharpie [OPTIONS] TOOL [TOOL_OPTIONS]
+
+Copyright 2026 Microsoft. All rights reserved.
+
+Documentation:
+ https://aka.ms/sharpie-docs
+
+Options:
+ -h, -help Show detailed help
+ -v, -version Show version information
+
+Available Tools:
+ bind Create a C# binding to Objective-C APIs
+ sdk-db Generate bindings for an entire platform's SDK
+""";
+ Console.WriteLine (help);
+ }
+
+ static int Main (string [] args)
+ {
+ try {
+ if (args.Length == 0) {
+ ShowHelp ();
+ return 0;
+ }
+
+ switch (args [0]) {
+ case "-h":
+ case "--help":
+ case "-help":
+ case "help":
+ case "?":
+ ShowHelp ();
+ return 0;
+ case "-v":
+ case "--version":
+ case "-version":
+ Console.WriteLine ($"dotnet-sharpie {Xamarin.ProductConstants.SharpieVersion}");
+ return 0;
+ case "bind":
+ return Tools.Bind (args.Skip (1).ToArray ());
+ case "sdk-db":
+ return Tools.SdkDb (args.Skip (1).ToArray ());
+ default:
+ Console.Error.WriteLine ($"Unknown option: {args [0]}");
+ return 1;
+ }
+ } catch (Exception e) {
+ Console.Error.WriteLine ("An unexpected exception occurred: " + e);
+ return 2;
+ }
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind.Tool/README.md b/tools/sharpie/Sharpie.Bind.Tool/README.md
new file mode 100644
index 000000000000..b54ebeaae015
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind.Tool/README.md
@@ -0,0 +1,15 @@
+# About
+
+Objective Sharpie is a command line tool to help bootstrap the first pass of a C# binding for an Objective-C framework. It works by parsing the header files of a framework to map the public API into the binding definition.
+
+Objective Sharpie uses Clang to parse header files, so the binding is as exact and thorough as possible.
+
+> [!IMPORTANT]
+> Objective Sharpie is a tool for experienced developers with
+> advanced knowledge of Objective-C (and by extension, C). Before
+> attempting to bind an Objective-C library you should understand
+> of how the native framework works, and how to use it.
+
+# More information
+
+See [Creating Bindings with Objective Sharpie](https://aka.ms/sharpie-docs) for in-depth documentation on how to use Objective Sharpie.
diff --git a/tools/sharpie/Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj b/tools/sharpie/Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj
new file mode 100644
index 000000000000..ce9a63328354
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind.Tool/Sharpie.Bind.Tool.csproj
@@ -0,0 +1,41 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)
+ latest
+ enable
+ enable
+ Exe
+ false
+
+
+
+ osx-arm64
+ true
+ sharpie
+
+
+ $(NETCoreSdkRuntimeIdentifier)
+
+ true
+ major
+
+ README.md
+ LICENSE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/sharpie/Sharpie.Bind/ArgumentSemantic.cs b/tools/sharpie/Sharpie.Bind/ArgumentSemantic.cs
new file mode 100644
index 000000000000..9d2dcbbbf37b
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/ArgumentSemantic.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind;
+
+public enum ArgumentSemantic {
+ None,
+ Assign,
+ Retain,
+ Copy,
+ Weak,
+ Strong,
+ UnsafeUnretained,
+}
diff --git a/tools/sharpie/Sharpie.Bind/AstVisitor.cs b/tools/sharpie/Sharpie.Bind/AstVisitor.cs
new file mode 100644
index 000000000000..73ebbd7446f3
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/AstVisitor.cs
@@ -0,0 +1,532 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using static ClangSharp.Interop.CX_DeclKind;
+
+namespace Sharpie.Bind;
+
+public abstract class AstVisitor {
+ public BindingResult BindingResult { get; set; }
+
+ public AstVisitor (BindingResult bindingResult)
+ {
+ this.BindingResult = bindingResult;
+ }
+
+ public Func? IsIncluded { get; set; }
+
+ public virtual bool IsDeclIncluded (Decl? decl)
+ {
+ if (decl is null)
+ return false;
+ if (IsIncluded is null)
+ return true;
+ return IsIncluded (decl);
+ }
+
+ public virtual void VisitObjCTypeParamDecl (ObjCTypeParamDecl decl)
+ {
+ VisitTypedefNameDecl (decl);
+ }
+
+ public virtual void VisitTypedefNameDecl (TypedefNameDecl decl)
+ {
+ VisitTypeDecl (decl);
+ }
+
+ public virtual void VisitTypeDecl (TypeDecl decl)
+ {
+ VisitNamedDecl (decl);
+ }
+
+ public virtual void VisitNamedDecl (NamedDecl decl)
+ {
+ // VisitDecl (decl);
+ }
+
+ public virtual void VisitTagDecl (TagDecl decl)
+ {
+ VisitTypeDecl (decl);
+ }
+
+ public virtual void VisitConstantExpr (ConstantExpr stmt)
+ {
+ VisitFullExpr (stmt);
+ }
+
+ public virtual void VisitFullExpr (FullExpr stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitExpr (Expr stmt)
+ {
+ VisitValueStmt (stmt);
+ }
+
+ public virtual void VisitValueStmt (ValueStmt stmt)
+ {
+ VisitStmt (stmt);
+ }
+
+ public virtual void VisitUnaryExprOrTypeTraitExpr (UnaryExprOrTypeTraitExpr stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitDeclRefExpr (DeclRefExpr stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitCastExpr (CastExpr stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitExplicitCastExpr (ExplicitCastExpr stmt)
+ {
+ VisitCastExpr (stmt);
+ }
+
+ public virtual void VisitImplicitCastExpr (ImplicitCastExpr stmt)
+ {
+ VisitCastExpr (stmt);
+ }
+
+ public virtual void VisitParenExpr (ParenExpr stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitUnaryOperator (UnaryOperator stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitBinaryOperator (BinaryOperator stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitFloatingLiteral (FloatingLiteral stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitCharacterLiteral (CharacterLiteral stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitIntegerLiteral (IntegerLiteral stmt)
+ {
+ VisitExpr (stmt);
+ }
+
+ public virtual void VisitStmt (Stmt stmt)
+ {
+ VisitNode (stmt);
+ }
+
+ public virtual void VisitNode (object node)
+ {
+ // empty!
+ }
+
+ public virtual void VisitReferenceType (ReferenceType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitLValueReferenceType (LValueReferenceType type)
+ {
+ VisitReferenceType (type);
+ }
+
+ public virtual void VisitFunctionNoProtoType (FunctionNoProtoType type)
+ {
+ VisitFunctionType (type);
+ }
+
+ public virtual void VisitAtomicType (AtomicType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitComplexType (ComplexType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitAdjustedType (AdjustedType type)
+ {
+ VisitType (type);
+
+ }
+
+ public virtual void VisitDecayedType (DecayedType type)
+ {
+ VisitAdjustedType (type);
+ }
+
+ public virtual void VisitArrayType (ArrayType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitMacroQualifiedType (MacroQualifiedType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitFunctionType (FunctionType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitTypeWithKeyword (TypeWithKeyword type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitElaboratedType (ElaboratedType type)
+ {
+ VisitTypeWithKeyword (type);
+ }
+
+ public virtual void VisitTagType (TagType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitRecordType (RecordType type)
+ {
+ VisitTagType (type);
+ }
+
+ public virtual void VisitEnumType (EnumType type)
+ {
+ VisitTagType (type);
+ }
+
+ public virtual void VisitObjCTypeParamType (ObjCTypeParamType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitObjCObjectType (ObjCObjectType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitObjCObjectPointerType (ObjCObjectPointerType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitPointerType (PointerType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitAttributedType (AttributedType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitParenType (ParenType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitType (ClangSharp.Type type)
+ {
+ VisitNode (type);
+ }
+
+ public virtual void VisitBuiltinType (BuiltinType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitTypedefType (TypedefType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitValueDecl (ValueDecl decl)
+ {
+ VisitNamedDecl (decl);
+ }
+
+ public virtual void VisitDeclaratorDecl (DeclaratorDecl decl)
+ {
+ VisitValueDecl (decl);
+ }
+
+ public virtual void VisitVarDecl (VarDecl decl)
+ {
+ VisitDeclaratorDecl (decl);
+ }
+ public virtual void VisitFieldDecl (FieldDecl decl)
+ {
+ VisitDeclaratorDecl (decl);
+ }
+
+ public virtual void VisitRecordDecl (RecordDecl decl)
+ {
+ VisitTagDecl (decl);
+ }
+
+ public virtual void VisitFunctionDecl (FunctionDecl decl)
+ {
+ VisitDeclaratorDecl (decl);
+ }
+
+ public virtual void VisitFunctionProtoType (FunctionProtoType type)
+ {
+ VisitFunctionType (type);
+ }
+
+ public virtual void VisitObjCContainerDecl (ObjCContainerDecl decl)
+ {
+ VisitNamedDecl (decl);
+ Visit (decl.Decls);
+ }
+
+ public virtual void VisitObjCCategoryDecl (ObjCCategoryDecl decl)
+ {
+ VisitObjCContainerDecl (decl);
+ }
+
+ public virtual void VisitObjCMethodDecl (ObjCMethodDecl decl)
+ {
+ VisitNamedDecl (decl);
+ }
+
+ public virtual void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
+ {
+ VisitNamedDecl (decl);
+ }
+
+ public virtual void VisitTypedefDecl (TypedefDecl decl)
+ {
+ VisitTypedefNameDecl (decl);
+ }
+
+ public virtual void VisitBlockPointerType (BlockPointerType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitEnumConstantDecl (EnumConstantDecl decl)
+ {
+ VisitValueDecl (decl);
+ }
+
+ public virtual void VisitIndirectFieldDecl (IndirectFieldDecl decl)
+ {
+ // turns into an infinite loop
+ // VisitValueDecl (decl);
+ }
+ public virtual void VisitObjCIvarDecl (ObjCIvarDecl decl)
+ {
+ VisitFieldDecl (decl);
+ }
+
+ public virtual void VisitConstantArrayType (ConstantArrayType type)
+ {
+ VisitArrayType (type);
+ }
+
+ public virtual void VisitIncompleteArrayType (IncompleteArrayType type)
+ {
+ VisitArrayType (type);
+ }
+
+ public virtual void VisitLinkageSpecDecl (LinkageSpecDecl decl)
+ {
+ // VisitDecl (decl);
+ }
+
+ public virtual void VisitVectorType (VectorType type)
+ {
+ VisitType (type);
+ }
+
+ public virtual void VisitExtVectorType (ExtVectorType type)
+ {
+ // VisitVectorType (type);
+ VisitType (type);
+ }
+
+ public virtual void VisitAttr (Attr attr)
+ {
+ }
+
+ public virtual void VisitRef (Ref @ref)
+ {
+ }
+
+ public virtual void VisitEnumDecl (EnumDecl decl)
+ {
+ VisitTagDecl (decl);
+ }
+
+ public virtual void VisitObjCInterfaceDecl (ObjCInterfaceDecl decl)
+ {
+ VisitObjCContainerDecl (decl);
+ }
+
+ public virtual void VisitObjCProtocolDecl (ObjCProtocolDecl decl)
+ {
+ VisitObjCContainerDecl (decl);
+ }
+
+ public virtual void VisitNamespaceDecl (NamespaceDecl decl)
+ {
+ // VisitNamedDecl (decl);
+ }
+
+ public virtual void VisitTranslationUnitDecl (TranslationUnitDecl translationUnitDecl)
+ {
+ Visit (translationUnitDecl.Decls);
+ Visit (translationUnitDecl.CursorChildren.Except (translationUnitDecl.Decls));
+ }
+
+ public void Visit (Cursor cursor)
+ {
+ if (cursor is Attr attr) {
+ VisitAttr (attr);
+ } else if (cursor is Decl decl) {
+ if (IsDeclIncluded (decl))
+ VisitDecl (decl);
+ } else if (cursor is Ref @ref) {
+ VisitRef (@ref);
+ } else if (cursor is Stmt stmt) {
+ BindingResult.ReportUnsupportedConstruct (cursor.Location, $"Statement visitation. CursorKind: '{cursor.CursorKindSpelling}'");
+ } else if (cursor is MacroDefinitionRecord macroDefinitionRecord) {
+ BindingResult.ReportUnsupportedConstruct (cursor.Location, $"Macro definition visitation. CursorKind: '{cursor.CursorKindSpelling}'");
+ } else if (cursor is MacroExpansion macroExpansion) {
+ BindingResult.ReportUnsupportedConstruct (cursor.Location, $"Macro expansion visitation. CursorKind: '{cursor.CursorKindSpelling}'");
+ } else if (cursor is InclusionDirective inclusionDirective) {
+ BindingResult.ReportUnsupportedConstruct (cursor.Location, $"Inclusion directive visitation. CursorKind: '{cursor.CursorKindSpelling}'");
+ } else {
+ BindingResult.ReportUnsupportedConstruct (cursor.Location, $"Visiting cursor of kind: '{cursor.CursorKindSpelling}'");
+ }
+ }
+
+ protected void Visit (IEnumerable cursors)
+ {
+ foreach (var cursor in cursors) {
+ Visit (cursor);
+ }
+ }
+
+ public virtual void VisitDecl (Decl decl)
+ {
+ switch (decl.Kind) {
+ case CX_DeclKind_AccessSpec:
+ // Access specifications are also exposed as a queryable property
+ // on the declarations they impact, so we don't need to do anything
+ break;
+ case CX_DeclKind_Empty:
+ // Nothing to generate for empty declarations
+ break;
+ case CX_DeclKind_Friend:
+ // Nothing to generate for friend declarations
+ break;
+ case CX_DeclKind_LinkageSpec:
+ var lsd = (LinkageSpecDecl) decl;
+ Visit (lsd.Decls);
+ break;
+ case CX_DeclKind_Namespace:
+ VisitNamespaceDecl ((NamespaceDecl) decl);
+ break;
+ case CX_DeclKind_Enum:
+ VisitEnumDecl ((EnumDecl) decl);
+ break;
+ case CX_DeclKind_Record:
+ case CX_DeclKind_CXXRecord:
+ VisitRecordDecl ((RecordDecl) decl);
+ break;
+ case CX_DeclKind_TypeAlias:
+ // Nothing to generate for type alias declarations
+ break;
+ case CX_DeclKind_Typedef:
+ VisitTypedefDecl ((TypedefDecl) decl);
+ break;
+ case CX_DeclKind_Using:
+ // Using declarations only introduce existing members into
+ // the current scope. There isn't an easy way to translate
+ // this to C#, so we will ignore them for now.
+ break;
+ case CX_DeclKind_Field:
+ VisitFieldDecl ((FieldDecl) decl);
+ break;
+ case CX_DeclKind_Function:
+ case CX_DeclKind_CXXMethod:
+ case CX_DeclKind_CXXConstructor:
+ case CX_DeclKind_CXXDestructor:
+ case CX_DeclKind_CXXConversion:
+ VisitFunctionDecl ((FunctionDecl) decl);
+ break;
+ case CX_DeclKind_Var:
+ VisitVarDecl ((VarDecl) decl);
+ break;
+ case CX_DeclKind_EnumConstant:
+ VisitEnumConstantDecl ((EnumConstantDecl) decl);
+ break;
+ case CX_DeclKind_IndirectField:
+ VisitIndirectFieldDecl ((IndirectFieldDecl) decl);
+ break;
+ case CX_DeclKind_PragmaComment:
+ // Pragma comments can't be easily modeled in C#
+ // We'll ignore them for now.
+ break;
+ case CX_DeclKind_StaticAssert:
+ // Static asserts can't be easily modeled in C#
+ // We'll ignore them for now.
+ break;
+ case CX_DeclKind_TranslationUnit:
+ VisitTranslationUnitDecl ((TranslationUnitDecl) decl);
+ break;
+ case CX_DeclKind_ObjCInterface:
+ VisitObjCInterfaceDecl ((ObjCInterfaceDecl) decl);
+ break;
+ case CX_DeclKind_ObjCProtocol:
+ VisitObjCProtocolDecl ((ObjCProtocolDecl) decl);
+ break;
+ case CX_DeclKind_ObjCMethod:
+ VisitObjCMethodDecl ((ObjCMethodDecl) decl);
+ break;
+ case CX_DeclKind_ObjCProperty:
+ VisitObjCPropertyDecl ((ObjCPropertyDecl) decl);
+ break;
+ case CX_DeclKind_ObjCCategory:
+ VisitObjCCategoryDecl ((ObjCCategoryDecl) decl);
+ break;
+ case CX_DeclKind_ObjCIvar:
+ VisitObjCIvarDecl ((ObjCIvarDecl) decl);
+ break;
+ case CX_DeclKind_Import:
+ // Imports are handled elsewhere; nothing to do here.
+ break;
+ case CX_DeclKind_BuiltinTemplate:
+ break;
+ case CX_DeclKind_ObjCCompatibleAlias:
+ // Example:
+ // @compatibility_alias GCDeviceElement GCControllerElement;
+ // Not sure if we can do something here, but for now we ignore it.
+ break;
+ default:
+ BindingResult.ReportUnsupportedConstruct (decl.Location, $"Unsupported declaration: '{decl.DeclKindName}'.");
+ break;
+ }
+ }
+
+ public virtual void EndVisit ()
+ {
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/AbstractAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/AbstractAttribute.cs
new file mode 100644
index 000000000000..0acd4a4cc744
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/AbstractAttribute.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class AbstractAttribute : GroupedAttribute {
+ public AbstractAttribute () : base (1)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("AbstractAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/AdviceAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/AdviceAttribute.cs
new file mode 100644
index 000000000000..032847a884dd
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/AdviceAttribute.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public class AdviceAttribute : GroupedAttribute {
+ public AdviceAttribute () : base (1) => Type = AstType.Create ("Foundation.AdviceAttribute");
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/AvailabilityBaseAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/AvailabilityBaseAttribute.cs
new file mode 100644
index 000000000000..f4885a96520f
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/AvailabilityBaseAttribute.cs
@@ -0,0 +1,183 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+enum PlatformName : byte {
+ None,
+ MacOSX,
+ MacOSXAppExtension,
+ iOS,
+ iOSAppExtension,
+ WatchOS,
+ WatchOSAppExtension,
+ TvOS,
+ TvOSAppExtension,
+ Swift,
+ BridgeOS,
+ MacCatalyst,
+ DriverKit,
+ VisionOS,
+ MacCatalystAppExtension,
+}
+
+enum AvailabilityKind {
+ Introduced,
+ Deprecated,
+ Obsoleted,
+ Unavailable,
+}
+
+class AvailabilityBaseAttribute : ICSharpCode.NRefactory.CSharp.Attribute {
+ public bool IsShorthand { get; private set; }
+
+ public AvailabilityBaseAttribute (
+ AvailabilityKind availabilityKind,
+ PlatformName platform,
+ VersionTuple version,
+ string? message,
+ bool asShorthand = false)
+ {
+ if (asShorthand &&
+ (availabilityKind == AvailabilityKind.Introduced ||
+ availabilityKind == AvailabilityKind.Unavailable) &&
+ String.IsNullOrWhiteSpace (message)) {
+ string? shorthandName = null;
+ switch (platform) {
+ case PlatformName.iOS:
+ shorthandName = "iOS";
+ break;
+ case PlatformName.MacOSX:
+ shorthandName = "Mac";
+ break;
+ case PlatformName.WatchOS:
+ shorthandName = "Watch";
+ break;
+ case PlatformName.TvOS:
+ shorthandName = "TV";
+ break;
+ case PlatformName.MacCatalyst:
+ shorthandName = "MacCatalyst";
+ break;
+ }
+
+ if (shorthandName is not null) {
+ if (availabilityKind == AvailabilityKind.Unavailable)
+ shorthandName = "No" + shorthandName;
+ Type = AstType.Create (shorthandName);
+ IsShorthand = true;
+ }
+ }
+
+ if (Type.IsNull) {
+ Type = AstType.Create ("ObjCRuntime." + availabilityKind);
+
+ Arguments.Add (new MemberReferenceExpression (
+ new TypeReferenceExpression (AstType.Create ("ObjCRuntime.PlatformName")),
+ platform.ToString ()
+ ));
+ }
+
+ if (!version.IsEmpty) {
+ Arguments.Add (new PrimitiveExpression (version.Major));
+ Arguments.Add (new PrimitiveExpression (version.Minor.GetValueOrDefault ()));
+ if (version.Subminor is not null)
+ Arguments.Add (new PrimitiveExpression (version.Subminor.Value));
+ }
+
+ if (!asShorthand) {
+ if (!String.IsNullOrWhiteSpace (message))
+ Arguments.Add (new NamedArgumentExpression ("message", new PrimitiveExpression (message)));
+ }
+ }
+
+ public static IEnumerable FromClang (Attr attr)
+ {
+ var platform = GetPlatform (attr.AvailabilityAttributePlatformIdentifierName);
+
+ var shorthand = ShorthandFromClang (platform, attr);
+ if (shorthand is not null) {
+ yield return shorthand;
+ yield break;
+ }
+
+ if (attr.AvailabilityAttributeIntroduced.HasValue && !attr.AvailabilityAttributeIntroduced.Value.IsEmpty)
+ yield return new AvailabilityBaseAttribute (
+ AvailabilityKind.Introduced, platform, attr.AvailabilityAttributeIntroduced ?? default, attr.AvailabilityAttributeMessage);
+
+ if (attr.AvailabilityAttributeDeprecated.HasValue && !attr.AvailabilityAttributeDeprecated.Value.IsEmpty)
+ yield return new AvailabilityBaseAttribute (
+ AvailabilityKind.Deprecated, platform, attr.AvailabilityAttributeDeprecated.Value, attr.AvailabilityAttributeMessage);
+
+ if (attr.AvailabilityAttributeObsoleted.HasValue && !attr.AvailabilityAttributeObsoleted.Value.IsEmpty)
+ yield return new AvailabilityBaseAttribute (
+ AvailabilityKind.Obsoleted, platform, attr.AvailabilityAttributeObsoleted.Value, attr.AvailabilityAttributeMessage);
+
+ if (attr.AvailabilityAttributeUnavailable)
+ yield return new AvailabilityBaseAttribute (
+ AvailabilityKind.Unavailable, platform, VersionTuple.Empty, attr.AvailabilityAttributeMessage);
+ }
+
+ static PlatformName GetPlatform (string? name)
+ {
+ switch (name) {
+ case "ios":
+ return PlatformName.iOS;
+ case "ios_app_extension":
+ return PlatformName.iOSAppExtension;
+ case "macosx":
+ case "macos":
+ return PlatformName.MacOSX;
+ case "macosx_app_extension":
+ case "macos_app_extension":
+ return PlatformName.MacOSXAppExtension;
+ case "watchos":
+ return PlatformName.WatchOS;
+ case "watchos_app_extension":
+ return PlatformName.WatchOSAppExtension;
+ case "tvos":
+ return PlatformName.TvOS;
+ case "tvos_app_extension":
+ return PlatformName.TvOSAppExtension;
+ case "swift":
+ return PlatformName.Swift;
+ case "bridgeos":
+ return PlatformName.BridgeOS;
+ case "uikitformac":
+ case "macCatalyst":
+ case "maccatalyst":
+ return PlatformName.MacCatalyst;
+ case "driverkit":
+ return PlatformName.DriverKit;
+ case "xros":
+ case "visionOS":
+ case "visionos":
+ return PlatformName.VisionOS;
+ case "maccatalyst_app_extension":
+ return PlatformName.MacCatalystAppExtension;
+ default:
+ throw new Exception ($"Unsupported clang availability platform: '{name}'");
+ }
+ }
+
+ static AvailabilityBaseAttribute? ShorthandFromClang (PlatformName platform, Attr attr)
+ {
+ // shorthand attributes are only returned iff there
+ // is one attribute of any kind for the platform
+ var hasIntroduced = attr.AvailabilityAttributeIntroduced.HasValue && !attr.AvailabilityAttributeIntroduced.Value.IsEmpty;
+ var hasDeprecated = attr.AvailabilityAttributeDeprecated.HasValue && !attr.AvailabilityAttributeDeprecated.Value.IsEmpty;
+ var hasObsoleted = attr.AvailabilityAttributeObsoleted.HasValue && !attr.AvailabilityAttributeObsoleted.Value.IsEmpty;
+ var hasUnavailable = attr.AvailabilityAttributeUnavailable;
+
+ if (hasIntroduced && !hasDeprecated && !hasObsoleted && !hasUnavailable)
+ return new AvailabilityBaseAttribute (AvailabilityKind.Introduced,
+ platform, attr.AvailabilityAttributeIntroduced ?? default, attr.AvailabilityAttributeMessage, true);
+ else if (hasUnavailable && !hasIntroduced && !hasDeprecated && !hasObsoleted)
+ return new AvailabilityBaseAttribute (AvailabilityKind.Unavailable,
+ platform, VersionTuple.Empty, attr.AvailabilityAttributeMessage, true);
+
+ return null;
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/BaseTypeAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/BaseTypeAttribute.cs
new file mode 100644
index 000000000000..b9bbfd3b5eca
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/BaseTypeAttribute.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class BaseTypeAttribute : GroupedAttribute {
+ public AstType? BaseType {
+ get {
+ var typeofExpr = Arguments.FirstOrNullObject () as TypeOfExpression;
+ if (typeofExpr is not null)
+ return typeofExpr.Type;
+ return null;
+ }
+ }
+
+ public BaseTypeAttribute (string type) : this (AstType.Create (type))
+ {
+ }
+
+ public BaseTypeAttribute (AstType type) : base (2)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("BaseTypeAttribute");
+ Arguments.Add (new TypeOfExpression (type));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/BindAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/BindAttribute.cs
new file mode 100644
index 000000000000..fd1b917d7acf
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/BindAttribute.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class BindAttribute : GroupedAttribute {
+ public BindAttribute (string name) : base (1)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("BindAttribute");
+ Arguments.Add (new PrimitiveExpression (name));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/CategoryAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/CategoryAttribute.cs
new file mode 100644
index 000000000000..bf2c90c0c06b
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/CategoryAttribute.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class CategoryAttribute : GroupedAttribute {
+ public CategoryAttribute () : base (1)
+ {
+ Type = AstType.Create ("Category");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/DesignatedInitializerAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/DesignatedInitializerAttribute.cs
new file mode 100644
index 000000000000..74f5fc865a9a
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/DesignatedInitializerAttribute.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class DesignatedInitializerAttribute : GroupedAttribute {
+ public DesignatedInitializerAttribute () : base (3)
+ {
+ Type = AstType.Create ("Foundation.DesignatedInitializerAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/DisableDefaultCtorAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/DisableDefaultCtorAttribute.cs
new file mode 100644
index 000000000000..bced3ec8e0ba
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/DisableDefaultCtorAttribute.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class DisableDefaultCtorAttribute : GroupedAttribute {
+ public DisableDefaultCtorAttribute () : base (3)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("DisableDefaultCtorAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/DllImportAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/DllImportAttribute.cs
new file mode 100644
index 000000000000..efbffdabc166
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/DllImportAttribute.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class DllImportAttribute : GroupedAttribute {
+ public DllImportAttribute (string libraryName) : base (1)
+ {
+ Type = AstType.Create ("System.Runtime.InteropServices.DllImport");
+ Arguments.Add (new PrimitiveExpression (libraryName));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/ExportAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/ExportAttribute.cs
new file mode 100644
index 000000000000..9509c0dbca2e
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/ExportAttribute.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class ExportAttribute : GroupedAttribute {
+ public string Name { get; private set; }
+ public ArgumentSemantic ArgumentSemantic { get; private set; }
+ public bool IsVariadic { get; private set; }
+
+ public ExportAttribute (string name,
+ ArgumentSemantic argumentSemantic = ArgumentSemantic.None,
+ bool isVariadic = false) : base (2)
+ {
+ Type = AstType.Create ("Foundation.ExportAttribute");
+ Name = name;
+ ArgumentSemantic = argumentSemantic;
+
+ Arguments.Add (new PrimitiveExpression (name));
+
+ if (argumentSemantic != ArgumentSemantic.None)
+ Arguments.Add (new MemberReferenceExpression (
+ new TypeReferenceExpression (AstType.Create ("ObjCRuntime.ArgumentSemantic")),
+ argumentSemantic.ToString ()
+ ));
+
+ if (isVariadic)
+ Arguments.Add (new NamedExpression ("IsVariadic", new PrimitiveExpression (true)));
+ }
+
+ public void RemoveArgumentSemantic ()
+ {
+ if (ArgumentSemantic != ArgumentSemantic.None) {
+ ArgumentSemantic = ArgumentSemantic.None;
+ Arguments.OfType ().FirstOrDefault ()?.Remove ();
+ }
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/FieldAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/FieldAttribute.cs
new file mode 100644
index 000000000000..efb0b4c33e82
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/FieldAttribute.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class FieldAttribute : GroupedAttribute {
+ public string SymbolName { get; private set; }
+ public string? LibraryName { get; private set; }
+
+ public FieldAttribute (string symbolName, string? libraryName = null) : base (1)
+ {
+ SymbolName = symbolName;
+ LibraryName = libraryName;
+
+ Type = AstType.Create ("Foundation.FieldAttribute");
+
+ Arguments.Add (new PrimitiveExpression (SymbolName));
+ if (LibraryName is not null)
+ Arguments.Add (new PrimitiveExpression (LibraryName));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/FieldOffsetAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/FieldOffsetAttribute.cs
new file mode 100644
index 000000000000..238bfaf01b0b
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/FieldOffsetAttribute.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class FieldOffsetAttribute : GroupedAttribute {
+ public int Offset { get; private set; }
+
+ public FieldOffsetAttribute (int offset) : base (1)
+ {
+ Type = typeof (System.Runtime.InteropServices.FieldOffsetAttribute).ToAstType ();
+ Offset = offset;
+ Arguments.Add (new PrimitiveExpression (offset));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/FlagsAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/FlagsAttribute.cs
new file mode 100644
index 000000000000..cdfedcd811f3
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/FlagsAttribute.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class FlagsAttribute : GroupedAttribute {
+ public FlagsAttribute () : base (0)
+ => Type = AstType.Create ("System.FlagsAttribute");
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/GroupedAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/GroupedAttribute.cs
new file mode 100644
index 000000000000..295a58bfd7fb
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/GroupedAttribute.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind.Attributes;
+
+public abstract class GroupedAttribute : ICSharpCode.NRefactory.CSharp.Attribute {
+ public int GroupNumber { get; set; }
+
+ protected GroupedAttribute (int groupNumber)
+ {
+ GroupNumber = groupNumber;
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/InternalAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/InternalAttribute.cs
new file mode 100644
index 000000000000..5433d5ee5e38
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/InternalAttribute.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class InternalAttribute : GroupedAttribute {
+ public InternalAttribute () : base (1)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("InternalAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/ModelAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/ModelAttribute.cs
new file mode 100644
index 000000000000..47225235e18a
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/ModelAttribute.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class ModelAttribute : GroupedAttribute {
+ public static string ModelRemovedComment { get; } = "\n" +
+ " Check whether adding [Model] to this declaration is appropriate.\n" +
+ " [Model] is used to generate a C# class that implements this protocol,\n" +
+ " and might be useful for protocols that consumers are supposed to implement,\n" +
+ " since consumers can subclass the generated class instead of implementing\n" +
+ " the generated interface. If consumers are not supposed to implement this\n" +
+ " protocol, then [Model] is redundant and will generate code that will never\n" +
+ " be used.\n";
+
+ public ModelAttribute () : base (1)
+ {
+ Type = AstType.Create ("Foundation.ModelAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/NativeAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/NativeAttribute.cs
new file mode 100644
index 000000000000..a7f042b02ca5
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/NativeAttribute.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class NativeAttribute : GroupedAttribute {
+ public NativeAttribute () : base (1)
+ {
+ Type = AstType.Create ("ObjCRuntime.NativeAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/NullAllowedAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/NullAllowedAttribute.cs
new file mode 100644
index 000000000000..f1c1ea71e387
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/NullAllowedAttribute.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class NullAllowedAttribute : GroupedAttribute {
+ public NullAllowedAttribute () : base (2)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("NullAllowedAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/ObjectiveSharpieHintAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/ObjectiveSharpieHintAttribute.cs
new file mode 100644
index 000000000000..6f17e92eb233
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/ObjectiveSharpieHintAttribute.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind.Attributes;
+
+public abstract class ObjectiveSharpieHintAttribute : GroupedAttribute {
+ protected ObjectiveSharpieHintAttribute () : base (10)
+ {
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/ProtocolAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/ProtocolAttribute.cs
new file mode 100644
index 000000000000..3b8b6171af30
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/ProtocolAttribute.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class ProtocolAttribute : GroupedAttribute {
+ public ProtocolAttribute () : base (1)
+ {
+ Type = AstType.Create ("Foundation.ProtocolAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/RequiresSuperAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/RequiresSuperAttribute.cs
new file mode 100644
index 000000000000..972ed7db1fbf
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/RequiresSuperAttribute.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class RequiresSuperAttribute : GroupedAttribute {
+ public RequiresSuperAttribute () : base (3)
+ {
+ Type = AstType.Create ("RequiresSuperAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/StaticAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/StaticAttribute.cs
new file mode 100644
index 000000000000..ad52646a51a7
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/StaticAttribute.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class StaticAttribute : GroupedAttribute {
+ public StaticAttribute () : base (1)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("StaticAttribute");
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/StructLayoutAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/StructLayoutAttribute.cs
new file mode 100644
index 000000000000..856064938002
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/StructLayoutAttribute.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class StructLayoutAttribute : GroupedAttribute {
+ public LayoutKind LayoutKind { get; private set; }
+
+ public StructLayoutAttribute (LayoutKind layoutKind) : base (1)
+ {
+ Type = typeof (System.Runtime.InteropServices.StructLayoutAttribute).ToAstType ();
+ LayoutKind = layoutKind;
+ Arguments.Add (typeof (LayoutKind).ToAstType ().Member (layoutKind.ToString ()));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/VerifyAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/VerifyAttribute.cs
new file mode 100644
index 000000000000..32108c0ba11c
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/VerifyAttribute.cs
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public enum VerifyHint {
+ None,
+ InferredFromPreceedingTypedef,
+ InferredFromMemberPrefix,
+ ConstantsInterfaceAssociation,
+ MethodToProperty,
+ StronglyTypedNSArray,
+ PlatformInvoke,
+ GenericTypeParameter,
+}
+
+public static class VerifyHintExtensions {
+ static string? GetHtmlDescription (this VerifyHint hint)
+ {
+ switch (hint) {
+ case VerifyHint.InferredFromPreceedingTypedef:
+ return "The name of this declaration was inferred by common convention from the " +
+ "immediately preceeding typedef in the original native source code. " +
+ "Verify that the inferred name is correct as this convention is ambiguous.";
+ case VerifyHint.InferredFromMemberPrefix:
+ return "The name of this originally anonymous declaration was taken from a " +
+ "common prefix of its members.";
+ case VerifyHint.ConstantsInterfaceAssociation:
+ return "There's no foolproof way to determine with which Objective-C interface " +
+ "an extern variable declaration may be associated. Instances of these are bound " +
+ "as [Field] properties in a partial interface into a nearby concrete " +
+ "interface to produce a more intuitive API, possibly eliminating the 'Constants' " +
+ "interface altogether.";
+ case VerifyHint.MethodToProperty:
+ return "An Objective-C method was bound as a C# property due to convention such as " +
+ "taking no parameters and returning a value (non-void return). Often methods like " +
+ "these should be bound as properties to surface a nicer API, but sometimes false-positives " +
+ "can occur and the binding should actually be a method.";
+ case VerifyHint.StronglyTypedNSArray:
+ return "A native NSArray* was bound as NSObject[]. It might " +
+ "be possible to more strongly type the array in the binding based on expectations set " +
+ "through API documentation (e.g. comments in the header file) or by examining the array " +
+ "contents through testing. For example, an NSArray* containing only NSNumber* instances " +
+ "can be bound as NSNumber[] instead of NSObject[].";
+ case VerifyHint.PlatformInvoke:
+ return "In general P/Invoke bindings are not as correct or complete as Objective-C " +
+ "bindings (at least currently). You may need to fix up the library name (it defaults " +
+ "to '__Internal') and return/parameter types manually to conform to C calling conventions" +
+ "for the target platform. You may find you don't even want to expose the C API in your " +
+ "binding, but if you do, you'll probably also want to relocate the definition to a more " +
+ "appropriate class and expose a stronger type-safe wrapper. For P/Invoke guidance, see " +
+ "http://www.mono-project.com/docs/advanced/pinvoke/.";
+ case VerifyHint.GenericTypeParameter:
+ return "In Objective-C the type was a generic type parameter. It has been bound as " +
+ "as a compatible concrete type, but in the future should become a C# generic type parameter.";
+ case VerifyHint.None:
+ default:
+ return null;
+ }
+ }
+
+ public static string? GetDescription (this VerifyHint hint, bool html = false)
+ {
+ var description = hint.GetHtmlDescription ();
+ if (html)
+ return description;
+
+ return description?.Replace ("", string.Empty)?.Replace ("", string.Empty);
+ }
+}
+
+public sealed class VerifyAttribute : ObjectiveSharpieHintAttribute {
+ public VerifyHint Hint { get; private set; }
+
+ public VerifyAttribute (VerifyHint hint, string? message = null)
+ {
+ Hint = hint;
+ Type = AstType.Create ("VerifyAttribute");
+ Arguments.Add (new IdentifierExpression (hint.ToString ()));
+ if (message is not null)
+ Arguments.Add (new PrimitiveExpression (message));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/Attributes/WrapAttribute.cs b/tools/sharpie/Sharpie.Bind/Attributes/WrapAttribute.cs
new file mode 100644
index 000000000000..fc28b3b204f6
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/Attributes/WrapAttribute.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Sharpie.Bind.Attributes;
+
+public sealed class WrapAttribute : GroupedAttribute {
+ public WrapAttribute (string name) : base (1)
+ {
+ // NOTE: this is in global namespace :-/
+ Type = AstType.Create ("WrapAttribute");
+ Arguments.Add (new PrimitiveExpression (name));
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/BindTool.cs b/tools/sharpie/Sharpie.Bind/BindTool.cs
new file mode 100644
index 000000000000..2f2c5b151c61
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/BindTool.cs
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind;
+
+public class BindTool : ObjectiveCBinder {
+ public override string Tool { get => "bind"; }
+}
diff --git a/tools/sharpie/Sharpie.Bind/BindingException.cs b/tools/sharpie/Sharpie.Bind/BindingException.cs
new file mode 100644
index 000000000000..dede35269c99
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/BindingException.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind;
+
+public class BindingException : Exception {
+ public BindingMessage BindingMessage { get; private set; }
+
+ public BindingException (BindingMessage message)
+ : base (message.ToString ())
+ {
+ BindingMessage = message;
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/BindingGenerator.cs b/tools/sharpie/Sharpie.Bind/BindingGenerator.cs
new file mode 100644
index 000000000000..fca73e3571fc
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/BindingGenerator.cs
@@ -0,0 +1,704 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using ICSharpCode.NRefactory.CSharp;
+
+using Sharpie.Bind.Attributes;
+using Sharpie.Bind.Types;
+
+namespace Sharpie.Bind;
+
+public sealed class BindingGenerator : AstVisitor {
+ readonly DocumentSyntaxTree root = new DocumentSyntaxTree ();
+ readonly Stack entityStack = new Stack ();
+
+ TypeDeclaration? dllImportsType;
+
+ public BindingGenerator (BindingResult bindingResult)
+ : base (bindingResult)
+ {
+ }
+
+ public DocumentSyntaxTree SyntaxTree {
+ get { return root; }
+ }
+
+ EntityDeclaration PushEntity (EntityDeclaration entity)
+ {
+ if (entityStack.Count == 0 || !(entityStack.Peek () is TypeDeclaration))
+ root.Members.Add (entity);
+ else
+ ((TypeDeclaration) entityStack.Peek ()).Members.Add (entity);
+
+ var nativeNode = entity.Annotation ();
+ if (nativeNode is not null) {
+ foreach (var attr in entity.Attributes.SelectMany (s => s.Attributes))
+ attr.AddLinkAnnotation (nativeNode);
+ }
+
+ entityStack.Push (entity);
+ return entity;
+ }
+
+ EntityDeclaration PopEntity ()
+ {
+ var entity = entityStack.Pop ();
+
+ if (String.IsNullOrEmpty (entity.Name)) {
+ var type = entity as TypeDeclaration;
+ if (type is not null && type.Members.Count > 0)
+ return entity;
+
+ entity.Remove ();
+ }
+
+ return entity;
+ }
+
+ EntityDeclaration? CurrentEntity {
+ get { return entityStack.Count > 0 ? entityStack.Peek () : null; }
+ }
+
+ TypeDeclaration CurrentType {
+ get { return (TypeDeclaration) CurrentEntity!; }
+ }
+
+ public override void VisitObjCContainerDecl (ObjCContainerDecl decl)
+ {
+ if (decl.Location.IsInvalid)
+ return;
+ if (!decl.Handle.IsThisDeclarationADefinition && decl is not ObjCCategoryDecl)
+ return;
+
+ PushEntity (Bind (BindingResult, decl));
+ base.VisitObjCContainerDecl (decl);
+ PopEntity ();
+ }
+
+ public override void VisitObjCMethodDecl (ObjCMethodDecl decl)
+ {
+ if (decl.IsPropertyAccessor)
+ return;
+
+ CurrentType.Members.Add (Bind (BindingResult, decl));
+ }
+
+ public override void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
+ {
+ CurrentType.Members.Add (Bind (BindingResult, decl));
+ }
+
+ public override void VisitTypedefDecl (TypedefDecl decl)
+ {
+ var underlyingDesugaredType = decl.UnderlyingType.UnqualifiedDesugaredType;
+ switch (underlyingDesugaredType?.TypeClass) {
+ case CX_TypeClass.CX_TypeClass_Enum:
+ var boundEnum = ((EnumType) underlyingDesugaredType).Decl.Annotation ();
+ if (boundEnum is not null)
+ boundEnum.Name = decl.Name;
+ break;
+ case CX_TypeClass.CX_TypeClass_Record:
+ var boundRecord = ((RecordType) underlyingDesugaredType).Decl.Annotation ();
+ if (boundRecord is not null)
+ boundRecord.Name = decl.Name;
+ break;
+ case CX_TypeClass.CX_TypeClass_BlockPointer:
+ underlyingDesugaredType.AddAnnotation (decl);
+ underlyingDesugaredType.Accept (this);
+ break;
+ }
+ }
+
+ ///
+ /// Translate an anonymous delegate (a System.Action or System.Func) as
+ /// bound by TypeBinder.VisitFunctionType to a strongly named delegate
+ ///
+ public override void VisitBlockPointerType (BlockPointerType type)
+ {
+ var typedef = type.GetAnnotations ().LastOrDefault ();
+ if (typedef is null)
+ return;
+
+ var anonDelegate = type.Bind (BindingResult) as DelegateType;
+ if (anonDelegate is null)
+ throw new InvalidOperationException ("expected DelegateType from " +
+ "BlockPointerType.Bind; should never happen");
+
+ var del = new DelegateDeclaration {
+ Name = typedef.Name
+ };
+
+ del.AddLinkAnnotation (typedef);
+
+ int i = 0;
+ foreach (var typeArg in anonDelegate.TypeArguments) {
+ typeArg.Remove ();
+ del.Parameters.Add (new ParameterDeclaration (typeArg, String.Format ("arg{0}", i++)));
+ }
+
+ var functionProtoType = anonDelegate.Annotation ();
+ if (functionProtoType is not null && functionProtoType.IsVariadic) {
+ var vaParam = del.Parameters.LastOrNullObject ();
+ if (vaParam is not null)
+ vaParam.Name = "varArgs";
+ }
+
+ if (anonDelegate is FuncType) {
+ var returnType = del.Parameters.LastOrNullObject ().Type;
+ returnType.Parent.Remove ();
+ returnType.Remove ();
+ del.ReturnType = returnType;
+ } else {
+ del.ReturnType = new PrimitiveType ("void");
+ }
+
+ PushEntity (del);
+ }
+
+ public override void VisitEnumDecl (EnumDecl decl)
+ {
+ if (decl.Location.IsInvalid || !decl.IsThisDeclarationADefinition)
+ return;
+
+ PushEntity (Bind (BindingResult, decl));
+ Visit (decl.Decls);
+ PopEntity ();
+ }
+
+ public override void VisitEnumConstantDecl (EnumConstantDecl decl)
+ {
+ CurrentType?.Members.Add (Bind (BindingResult, decl));
+ }
+
+ public override void VisitFunctionDecl (FunctionDecl decl)
+ {
+ if (decl is CXXMethodDecl)
+ return;
+
+ if (dllImportsType is null)
+ root.Members.Add (dllImportsType = new TypeDeclaration {
+ ClassType = ClassType.Class,
+ Modifiers = Modifiers.Static,
+ Name = "CFunctions"
+ });
+
+ dllImportsType.Members.Add (Bind (BindingResult, decl));
+ }
+
+ public override void VisitRecordDecl (RecordDecl decl)
+ {
+ if (decl.Location.IsInvalid || !decl.IsThisDeclarationADefinition)
+ return;
+
+ switch (decl.CursorKind) {
+ case CXCursorKind.CXCursor_StructDecl:
+ case CXCursorKind.CXCursor_UnionDecl:
+ break;
+ default:
+ return;
+ }
+
+ var cxxDecl = decl as CXXRecordDecl;
+ if (cxxDecl is not null && !cxxDecl.IsPOD)
+ return;
+
+ PushEntity (Bind (BindingResult, decl));
+ Visit (decl.Decls);
+ PopEntity ();
+ }
+
+ public override void VisitFieldDecl (FieldDecl decl)
+ {
+ if (decl.IsBitField && decl.BitWidthValue == 0)
+ return;
+
+ if (CurrentType is not null && !(decl is ObjCIvarDecl))
+ CurrentType.Members.Add (Bind (decl));
+ }
+
+ class ConstantsInterfaceTypeDeclaration : TypeDeclaration {
+ public ConstantsInterfaceTypeDeclaration ()
+ {
+ Name = "Constants";
+ Modifiers = Modifiers.Partial;
+ ClassType = ClassType.Interface;
+
+ this.AddAttribute (new VerifyAttribute (VerifyHint.ConstantsInterfaceAssociation));
+ this.AddAttribute (new StaticAttribute ());
+ }
+ }
+
+ public override void VisitVarDecl (VarDecl decl)
+ {
+ if (decl.Name is null)
+ return;
+
+ var type = root.Members.LastOrNullObject () as ConstantsInterfaceTypeDeclaration;
+ if (type is null)
+ root.Members.Add (type = new ConstantsInterfaceTypeDeclaration ());
+
+ var property = new PropertyDeclaration {
+ Name = decl.Name,
+ ReturnType = decl.Type.Bind (BindingResult),
+ Getter = new Accessor ()
+ };
+
+ if (string.IsNullOrEmpty (property.Name)) {
+ BindingResult.ReportUnsupportedConstruct (decl.Location, "Variable with no name");
+ return;
+ } else if (property.Name.Contains (' ')) {
+ BindingResult.ReportUnsupportedConstruct (decl.Location, $"Variable with space in its name: {property.Name}");
+ return;
+ }
+
+ property.AddLinkAnnotation (decl);
+
+ property.AddAttribute (new FieldAttribute (decl.Name, "__Internal"));
+
+ type.Members.Add (property);
+ }
+
+ #region Static Binders
+
+ static int anonymousTypeCounter;
+ static TypeDeclaration Bind (BindingResult bindingResult, ObjCContainerDecl decl)
+ {
+ var typeName = decl.GetIsUnnamedOrAnonymous (bindingResult) ? "" : decl.Name;
+
+ if (typeName.Contains (' ')) {
+ bindingResult.ReportUnsupportedConstruct (decl.Location, $"Type with space in its name: {typeName}");
+ }
+
+ var type = new TypeDeclaration {
+ Name = typeName,
+ ClassType = ClassType.Interface
+ };
+
+ type.AddLinkAnnotation (decl);
+
+ // We should check if we are binding a swift bridging header, if so we should use the mangled names.
+ string? swiftName = null;
+ if (decl.Attrs.TryGetObjCRuntimeName (out var name)) {
+ if (IsSwiftName (name))
+ swiftName = name;
+ }
+
+ if (decl is ObjCInterfaceDecl iface && iface.SuperClass is not null) {
+ var bt = new BaseTypeAttribute (iface.SuperClass.Name);
+ if (swiftName is not null)
+ bt.Arguments.Add (new NamedExpression ("Name", new PrimitiveExpression (swiftName)));
+ type.AddAttribute (bt);
+ }
+
+ if (decl is ObjCCategoryDecl category && category.ClassInterface is not null) {
+ type.Name = category.ClassInterface.Name + "_" + type.Name;
+ type.AddAttribute (new CategoryAttribute ());
+ type.AddAttribute (new BaseTypeAttribute (category.ClassInterface.Name));
+ }
+
+ if (decl is ObjCProtocolDecl) {
+ // Just add '[Model]' to Delegates or DataSources we do not need it anywhere else
+ if (NeedsModel (decl.Name)) {
+ type.AddAttribute (new ModelAttribute ());
+ } else {
+ var comment = new Comment (ModelAttribute.ModelRemovedComment, CommentType.MultiLine);
+ type.AddChild (comment, Roles.Comment);
+ }
+
+ var pa = new ProtocolAttribute ();
+ if (swiftName is not null)
+ pa.Arguments.Add (new NamedExpression ("Name", new PrimitiveExpression (swiftName)));
+ type.AddAttribute (pa);
+ }
+
+ foreach (var protocol in decl.Protocols) {
+ AstType protoType;
+ if (protocol.Name == "NSObject") {
+ var bt = new BaseTypeAttribute (protoType = AstType.Create ("Foundation.NSObject"));
+ if (swiftName is not null)
+ bt.Arguments.Add (new NamedExpression ("Name", new PrimitiveExpression (swiftName)));
+ type.AddAttribute (bt);
+ } else
+ type.BaseTypes.Add (protoType = AstType.Create ("I" + protocol.Name));
+ protoType.AddAnnotation (protocol);
+ }
+
+ return type;
+ }
+
+ // Swift symbols begin with either '_T' or '_$'
+ static bool IsSwiftName (string name) => name.StartsWith ("_T", StringComparison.Ordinal) || name.StartsWith ("_$", StringComparison.Ordinal);
+
+ static bool NeedsModel (string name) => name.EndsWith ("Delegate", StringComparison.OrdinalIgnoreCase) || name.EndsWith ("DataSource", StringComparison.OrdinalIgnoreCase);
+
+ public static MethodDeclaration Bind (BindingResult bindingResult, ObjCMethodDecl decl)
+ {
+ MethodDeclaration method;
+
+ if (decl.MethodFamily == ObjCMethodFamily.Init || decl.IsDesignatedInitializer)
+ method = new ObjCConstructorMethodDeclaration {
+ Name = "Constructor",
+ ReturnType = new NativeHandleType ()
+ };
+ else
+ method = new MethodDeclaration {
+ Name = decl.GetSelector ().ToCSharpName (),
+ ReturnType = decl.ReturnType.Bind (bindingResult)
+ };
+
+ if (string.IsNullOrEmpty (method.Name))
+ bindingResult.ReportUnsupportedConstruct (decl.Location, "Method with no name");
+
+ method.AddLinkAnnotation (decl);
+
+ BindParameters (bindingResult, method, decl);
+
+ if (decl.IsClassMethod)
+ method.AddAttribute (new StaticAttribute ());
+
+ if (decl.DeclContext is ObjCProtocolDecl && !decl.Handle.IsObjCOptional)
+ method.AddAttribute (new AbstractAttribute ());
+
+ method.AddAttribute (new ExportAttribute (decl.Name, isVariadic: decl.Handle.IsVariadic));
+
+ if (decl.IsDesignatedInitializer)
+ method.AddAttribute (new DesignatedInitializerAttribute ());
+
+ if (decl.Handle.IsVariadic)
+ method.AddAttribute (new InternalAttribute ());
+
+ if (decl.Attrs.IsObjCRequiresSuperAttr ())
+ method.AddAttribute (new RequiresSuperAttribute ());
+
+ return method;
+ }
+
+ public static ParameterDeclaration Bind (BindingResult bindingResult, ParmVarDecl decl, int index)
+ {
+ ParameterModifier modifier;
+ var param = new ParameterDeclaration (decl.Type.Bind (bindingResult, out modifier), string.IsNullOrEmpty (decl.Name) ? "unnamedParameter" + index : decl.Name);
+ param.ParameterModifier = modifier;
+ param.AddLinkAnnotation (decl);
+ return param;
+ }
+
+ public static PropertyDeclaration Bind (BindingResult bindingResult, ObjCPropertyDecl decl)
+ {
+ var property = new PropertyDeclaration {
+ Name = decl.Name.UCFirst (),
+ ReturnType = decl.Type.Bind (bindingResult)
+ };
+
+ if (string.IsNullOrEmpty (property.Name)) {
+ bindingResult.ReportUnsupportedConstruct (decl.Location, "Property with no name");
+ } else if (property.Name.Contains (' ')) {
+ bindingResult.ReportUnsupportedConstruct (decl.Location, $"Property with space in its name: {property.Name}");
+ }
+
+ property.AddLinkAnnotation (decl);
+
+ if (decl.DeclContext is ObjCProtocolDecl && (
+ !decl.Handle.IsObjCOptional ||
+ decl.GetterMethodDecl?.Handle.IsObjCOptional == false ||
+ decl.SetterMethodDecl?.Handle.IsObjCOptional == false))
+ property.AddAttribute (new AbstractAttribute ());
+
+ if (decl.GetPropertyAttributes ().HasFlag (ObjCPropertyAttributeKind.Class))
+ property.AddAttribute (new StaticAttribute ());
+
+ if (decl.GetPropertyAttributes ().HasFlag (ObjCPropertyAttributeKind.NullResettable))
+ property.AddAttribute (new NullAllowedAttribute ());
+
+ property.AddAttribute (new ExportAttribute (decl.Name, decl.ArgumentSemantic));
+
+ if (decl.GetterMethodDecl is not null) {
+ property.Getter = new Accessor ();
+ if (decl.GetPropertyAttributes ().HasFlag (ObjCPropertyAttributeKind.Getter))
+ property.Getter.AddAttribute (new BindAttribute (decl.GetterMethodDecl.Name));
+ }
+
+ if (decl.SetterMethodDecl is not null) {
+ property.Setter = new Accessor ();
+ if (decl.GetPropertyAttributes ().HasFlag (ObjCPropertyAttributeKind.Setter))
+ property.Setter.AddAttribute (new BindAttribute (decl.SetterMethodDecl.Name));
+ }
+
+ return property;
+ }
+
+ public static TypeDeclaration Bind (BindingResult bindingResult, EnumDecl decl)
+ {
+ var type = new TypeDeclaration {
+ ClassType = ClassType.Enum,
+ Modifiers = Modifiers.Public,
+ Name = decl.GetIsUnnamedOrAnonymous (bindingResult) ? (decl.TypedefNameForAnonDecl?.Name ?? string.Empty) : decl.Name
+ };
+
+ type.AddLinkAnnotation (decl);
+
+ var backingType = decl.IntegerType.Bind (bindingResult);
+ if ((backingType as PrimitiveType)?.Keyword != "int")
+ type.BaseTypes.Add (backingType);
+
+ if (decl.Attrs.IsFlagEnumAttr ())
+ type.AddAttribute (new Attributes.FlagsAttribute ());
+
+ if (backingType is NIntType) {
+ type.AddAttribute (new NativeAttribute ());
+ backingType.ReplaceWith (new PrimitiveType ("long"));
+ } else if (backingType is NUIntType) {
+ type.AddAttribute (new NativeAttribute ());
+ backingType.ReplaceWith (new PrimitiveType ("ulong"));
+ }
+
+ return type;
+ }
+
+ public static EnumMemberDeclaration Bind (BindingResult bindingResult, EnumConstantDecl decl)
+ {
+ try {
+ var member = new EnumMemberDeclaration {
+ Name = decl.Name,
+ Initializer = ExpressionBinder.Bind (bindingResult, decl.InitExpr, n => {
+ var builtinKind = CXTypeKind.CXType_Int;
+ var type = decl.Type;
+
+ // enum constants can take the type of either a builtin,
+ // or a typedef in Objective-C (with 'objc_fixed_enum' support,
+ // or an enum type in C++ (with 'cxx_strong_enums') support.
+ // Resolve typedef types and enum types to builtins. This is
+ // done by hand instead of using a TypeBinder since we _only_
+ // want to allow builtin, typedef, or enum types in the chain.
+ while (true) {
+ var builtinType = type as BuiltinType;
+ if (builtinType is not null) {
+ builtinKind = builtinType.Kind;
+ break;
+ }
+
+ var typedefType = type as TypedefType;
+ if (typedefType is not null) {
+ type = typedefType.Decl.UnderlyingType;
+ continue;
+ }
+
+ var enumType = type as EnumType;
+ if (enumType is not null) {
+ type = enumType.Decl.IntegerType;
+ continue;
+ }
+ var elabType = type as ElaboratedType;
+ if (elabType is not null) {
+ // get the most basic type from the QualType and if we are dealing with a long, set the type accordingly, this
+ // is because we might be dealing with a NSInteger, the issue happens when the enum is exposed to swift
+ var namedType = elabType.Desugar.UnqualifiedDesugaredType as BuiltinType;
+ if (namedType is not null) {
+ // switch on the builtin type and set the type accordingly
+ switch (namedType.Kind) {
+ case CXTypeKind.CXType_UChar:
+ case CXTypeKind.CXType_SChar:
+ case CXTypeKind.CXType_Short:
+ case CXTypeKind.CXType_UShort:
+ case CXTypeKind.CXType_Int:
+ case CXTypeKind.CXType_UInt:
+ case CXTypeKind.CXType_Long:
+ case CXTypeKind.CXType_ULong:
+ case CXTypeKind.CXType_LongLong:
+ case CXTypeKind.CXType_ULongLong:
+ type = namedType;
+ builtinKind = namedType.Kind;
+ // yes! you can use a continue inside a switch
+ continue;
+ default:
+ bindingResult.ReportUnsupportedConstruct (decl.Location, $"Enum constant with unsupported underlying type ({namedType.Kind})");
+ // we do not know how to deal with this
+ break;
+ }
+ }
+ }
+
+ throw new Exception ("Unsupported Clang.Ast.Type for EnumConstantDecl: "
+ + type.Kind + " at " + decl.PresumedLoc);
+ }
+
+ switch (builtinKind) {
+ case CXTypeKind.CXType_Int:
+ return (int) n;
+ case CXTypeKind.CXType_UInt:
+ return (uint) n;
+ case CXTypeKind.CXType_Long:
+ case CXTypeKind.CXType_LongLong:
+ return (long) n;
+ default:
+ return n;
+ }
+ })
+ };
+
+ member.AddLinkAnnotation (decl);
+
+ return member;
+ } catch (Exception e) {
+ string initExpr = "";
+ if (decl.InitExpr is not null) {
+ var expr = decl.InitExpr.ToString ();
+ if (expr is not null)
+ initExpr = expr;
+ }
+ throw new AggregateException ("Unable to bind expression `" + initExpr + "'", e);
+ }
+ }
+
+ public static MethodDeclaration Bind (BindingResult bindingResult, FunctionDecl decl)
+ {
+ var method = new MethodDeclaration {
+ Modifiers = Modifiers.Static | Modifiers.Extern,
+ Name = decl.Name,
+ ReturnType = decl.ReturnType.Bind (bindingResult)
+ };
+
+ if (string.IsNullOrEmpty (method.Name)) {
+ bindingResult.ReportUnsupportedConstruct (decl.Location, "Method with no name");
+ } else if (method.Name.Contains (' ')) {
+ bindingResult.ReportUnsupportedConstruct (decl.Location, $"Method with space in its name: {method.Name}");
+ }
+
+ method.AddLinkAnnotation (decl);
+
+ BindParameters (bindingResult, method, decl);
+
+ method.AddAttribute (new Attributes.DllImportAttribute ("__Internal"));
+ method.AddAttribute (new VerifyAttribute (VerifyHint.PlatformInvoke));
+
+ return method;
+ }
+
+ public static TypeDeclaration Bind (BindingResult bindingResult, RecordDecl decl)
+ {
+ string? typeName;
+
+ if (decl.GetIsUnnamedOrAnonymous (bindingResult)) {
+ if (decl.TypedefNameForAnonDecl is not null) {
+ typeName = decl.TypedefNameForAnonDecl?.Name;
+ } else if (decl.NextDeclInContext is NamedDecl nextNamedDecl && !string.IsNullOrEmpty (nextNamedDecl.Name) && !nextNamedDecl.GetIsUnnamedOrAnonymous (bindingResult)) {
+ typeName = nextNamedDecl.Name;
+ } else {
+ if (decl.CursorKind == CXCursorKind.CXCursor_UnionDecl) {
+ typeName = $"AnonymousUnion{++anonymousTypeCounter}";
+ } else {
+ typeName = $"AnonymousStruct{++anonymousTypeCounter}";
+ }
+ }
+ } else {
+ typeName = decl.Name;
+ }
+
+ if (typeName?.Contains (' ') == true)
+ bindingResult.ReportUnsupportedConstruct (decl.Location, $"Type with space in its name: {typeName}");
+
+ var type = new TypeDeclaration {
+ ClassType = ClassType.Struct,
+ Modifiers = Modifiers.Public,
+ Name = typeName,
+ };
+
+ type.AddLinkAnnotation (decl);
+
+ if (decl.CursorKind != CXCursorKind.CXCursor_UnionDecl)
+ type.AddAttribute (new Attributes.StructLayoutAttribute (LayoutKind.Sequential));
+
+ return type;
+ }
+
+ public FieldDeclaration Bind (FieldDecl decl)
+ {
+ AstType? returnType;
+ var returnDeclType = decl.Type.AsTagDecl;
+ if (returnDeclType is not null && returnDeclType.GetIsUnnamedOrAnonymous (BindingResult)) {
+ var lastType = CurrentType.Members.OfType ().LastOrDefault ();
+ if (lastType is not null)
+ returnType = AstType.Create (lastType.Name);
+ else
+ returnType = AstType.Create (returnDeclType.Name);
+ } else if (decl.Type is ConstantArrayType constantArrayType && constantArrayType.ElementType.AsTagDecl?.GetIsUnnamedOrAnonymous (BindingResult) == true) {
+ var lastType = CurrentType.Members.OfType ().LastOrDefault ();
+ AstType elementType;
+ if (lastType is not null)
+ elementType = AstType.Create (lastType.Name);
+ else
+ elementType = AstType.Create (constantArrayType.ElementType.AsTagDecl.Name);
+ returnType = elementType.MakeArrayType ();
+ } else {
+ returnType = decl.Type.Bind (BindingResult);
+ }
+
+ var returnTypeString = returnType?.ToString () ?? "";
+ if (returnTypeString.Contains ("unnamed"))
+ BindingResult.ReportUnsupportedConstruct (decl.Location, $"Field type with no name or invalid name ({returnTypeString})");
+
+ var field = new FieldDeclaration {
+ Modifiers = Modifiers.Public,
+ ReturnType = returnType,
+ };
+
+ field.AddLinkAnnotation (decl);
+
+ string? name = null;
+ if (decl.GetIsUnnamedOrAnonymous (BindingResult)) {
+ var fieldType = CurrentType.Members.LastOrDefault () as TypeDeclaration;
+ switch (decl.Type.AsTagDecl?.CursorKind) {
+ case CXCursorKind.CXCursor_UnionDecl:
+ if (fieldType is not null) {
+ field.ReturnType = AstType.Create (fieldType.Name);
+ name = "AnonymousUnionField";
+ }
+ break;
+ case CXCursorKind.CXCursor_StructDecl:
+ if (fieldType is not null) {
+ field.ReturnType = AstType.Create (fieldType.Name);
+ name = "AnonymousStructField";
+ }
+ break;
+ }
+ }
+
+ if (string.IsNullOrEmpty (name))
+ name = decl.Name;
+
+ field.Variables.Add (new VariableInitializer (name));
+
+ if (string.IsNullOrEmpty (name))
+ BindingResult.ReportUnsupportedConstruct (decl.Location, "Field with no name");
+ else if (name.Contains (' '))
+ BindingResult.ReportUnsupportedConstruct (decl.Location, $"Field with space in its name: {name}");
+
+ return field;
+ }
+
+ static void BindParameters (BindingResult bindingResult, MethodDeclaration method, object decl)
+ {
+ var parameters = GetParameters (decl, out var isVariadic);
+
+ for (var i = 0; i < parameters.Count; i++)
+ method.Parameters.Add (Bind (bindingResult, parameters [i], i));
+
+ if (isVariadic)
+ method.Parameters.Add (new ParameterDeclaration (new IntPtrType (), "varArgs"));
+ }
+
+ static IReadOnlyList GetParameters (object decl, out bool isVariadic)
+ {
+ isVariadic = false;
+ if (decl is FunctionDecl functionDecl) {
+ isVariadic = functionDecl.IsVariadic;
+ return functionDecl.Parameters;
+ } else if (decl is ObjCMethodDecl methodDecl) {
+ isVariadic = methodDecl.Handle.IsVariadic;
+ return methodDecl.Parameters;
+ } else {
+ throw new NotImplementedException ($"GetParameters: {decl.GetType ().Name}");
+ }
+ }
+
+ #endregion
+}
diff --git a/tools/sharpie/Sharpie.Bind/BindingMassager.cs b/tools/sharpie/Sharpie.Bind/BindingMassager.cs
new file mode 100644
index 000000000000..ef107c47f462
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/BindingMassager.cs
@@ -0,0 +1,176 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Reflection;
+using ICSharpCode.NRefactory.CSharp;
+using Sharpie.Bind.Massagers;
+
+using Type = System.Type;
+
+namespace Sharpie.Bind;
+
+public sealed class BindingMassager {
+ public ObjectiveCBinder Binder { get; }
+
+ public BindingMassager (ObjectiveCBinder binder)
+ {
+ Binder = binder;
+ }
+
+ static readonly List defaultMassagers = new List {
+ typeof (DefaultConstructorMassager),
+ typeof (DelegateMassager),
+ typeof (MethodToPropertyMassager),
+ typeof (ProtocolMethodMassager),
+ typeof (NullabilityMassager),
+ typeof (NSArrayMassager),
+ typeof (ObjCTypeMassager),
+ typeof (NSStringMassager),
+ typeof (ArgumentSemanticMassager),
+ typeof (UnsafeMassager),
+ typeof (AnonymousStructMassager),
+ typeof (UnionStructMassager),
+ typeof (AvailabilityMassager),
+ typeof (EnumNameMassager),
+ typeof (AttributeMassager),
+ typeof (GroupedAttributeMassager),
+ typeof (PlatformTypeMappingMassager),
+ typeof (GenerateUsingStatementsMassager),
+ typeof (SortUsingStatementsMassager)
+ };
+
+ List? _massagers;
+ List massagers {
+ get {
+ if (_massagers is null)
+ _massagers = defaultMassagers.Select (v => CreateMassager (Binder, v)).ToList ();
+ return _massagers;
+ }
+ }
+
+ int FindMassager (Type massagerType)
+ => massagers.FindIndex (m => m.GetType () == massagerType);
+ int FindMassager (string name)
+ => massagers.FindIndex (m => m.GetType () == CreateMassager (Binder, name).GetType ());
+
+ public bool ExcludeMassager (string name)
+ {
+ var index = FindMassager (name);
+ if (index >= 0) {
+ massagers.RemoveAt (index);
+ return true;
+ }
+
+ return false;
+ }
+
+ static MassagerBase CreateMassager (ObjectiveCBinder binder, Type type)
+ {
+ return CreateMassager (binder, type.Name);
+ }
+
+ static MassagerBase CreateMassager (ObjectiveCBinder binder, string name)
+ {
+ const string ns = "Sharpie.Bind.Massagers.";
+
+ if (!name.EndsWith ("Massager", StringComparison.Ordinal))
+ name += "Massager";
+
+ if (name.StartsWith (ns + "."))
+ name = name.Substring (ns.Length + 1);
+
+ switch (name) {
+ case nameof (DefaultConstructorMassager):
+ return new DefaultConstructorMassager (binder);
+ case nameof (DelegateMassager):
+ return new DelegateMassager (binder);
+ case nameof (MethodToPropertyMassager):
+ return new MethodToPropertyMassager (binder);
+ case nameof (ProtocolMethodMassager):
+ return new ProtocolMethodMassager (binder);
+ case nameof (NullabilityMassager):
+ return new NullabilityMassager (binder);
+ case nameof (NSArrayMassager):
+ return new NSArrayMassager (binder);
+ case nameof (ObjCTypeMassager):
+ return new ObjCTypeMassager (binder);
+ case nameof (NSStringMassager):
+ return new NSStringMassager (binder);
+ case nameof (ArgumentSemanticMassager):
+ return new ArgumentSemanticMassager (binder);
+ case nameof (UnsafeMassager):
+ return new UnsafeMassager (binder);
+ case nameof (AnonymousStructMassager):
+ return new AnonymousStructMassager (binder);
+ case nameof (UnionStructMassager):
+ return new UnionStructMassager (binder);
+ case nameof (AvailabilityMassager):
+ return new AvailabilityMassager (binder);
+ case nameof (EnumNameMassager):
+ return new EnumNameMassager (binder);
+ case nameof (AttributeMassager):
+ return new AttributeMassager (binder);
+ case nameof (GroupedAttributeMassager):
+ return new GroupedAttributeMassager (binder);
+ case nameof (PlatformTypeMappingMassager):
+ return new PlatformTypeMappingMassager (binder);
+ case nameof (GenerateUsingStatementsMassager):
+ return new GenerateUsingStatementsMassager (binder);
+ case nameof (SortUsingStatementsMassager):
+ return new SortUsingStatementsMassager (binder);
+ case nameof (ExplicitBaseTypeNameMassager):
+ return new ExplicitBaseTypeNameMassager (binder);
+ default:
+ throw new Exception ($"Unknown massager: {name}");
+ }
+ }
+
+ public bool RegisterMassager (string name)
+ {
+ var massager = CreateMassager (Binder, name);
+ if (FindMassager (massager.GetType ()) < 0)
+ RegisterMassager (massager);
+
+ return true;
+ }
+
+ public void RegisterMassager (MassagerBase massager)
+ {
+ if (massager is null)
+ throw new ArgumentNullException ("massager");
+
+ var registerBefore = massager.GetType ().GetCustomAttribute ();
+ var registerAfter = massager.GetType ().GetCustomAttribute ();
+
+ if (registerBefore is not null && registerAfter is not null)
+ throw new InvalidOperationException ("a massager cannot have both a " +
+ "[RegisterBefore] and [RegisterAfter] attribute");
+
+ for (int i = 0; (registerBefore is not null || registerAfter is not null) && i < massagers.Count; i++) {
+ var type = massagers [i].GetType ();
+
+ if (registerBefore is not null && type == registerBefore.Type) {
+ massagers.Insert (i, massager);
+ return;
+ }
+
+ if (registerAfter is not null && type == registerAfter.Type) {
+ massagers.Insert (i + 1, massager);
+ return;
+ }
+ }
+
+ massagers.Add (massager);
+ }
+
+ public void Massage (AstNode astNode)
+ {
+ if (astNode is null)
+ throw new ArgumentNullException (nameof (astNode));
+
+ foreach (var massager in massagers) {
+ if (massager.Initialize ())
+ astNode.AcceptVisitor (massager);
+ }
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/BindingMessage.cs b/tools/sharpie/Sharpie.Bind/BindingMessage.cs
new file mode 100644
index 000000000000..f4f0ca862db1
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/BindingMessage.cs
@@ -0,0 +1,81 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text;
+using Xamarin.Utils;
+
+namespace Sharpie.Bind;
+
+public class BindingMessage {
+ public int Code;
+ public string Message;
+ public string? FileName;
+ public long LineNumber;
+ public bool IsError;
+
+ static string PREFIX = "SHARPIE";
+
+ BindingMessage (string message)
+ {
+ Message = message;
+ }
+
+ public BindingMessage (int code, params IEnumerable arguments)
+ : this (code, arguments, true)
+ {
+ }
+
+ public BindingMessage (int code, IEnumerable arguments, bool isError, CXSourceLocation? location = null)
+ {
+ Code = code;
+ Message = GetMessage (code);
+ if (arguments.Any ())
+ Message = string.Format (Message, arguments.ToArray ());
+ IsError = isError;
+
+ if (location.HasValue && location.Value.TryGetPresumedLocation (out var presumedLoc)) {
+ var loc = presumedLoc.Value;
+ FileName = loc.FileName;
+ LineNumber = loc.Line;
+ }
+ }
+
+ static string GetMessage (int code)
+ {
+ var property = typeof (Resources).GetProperty ($"SHARPIE{code:D4}");
+ if (property is not null) {
+ var value = property.GetValue (null);
+ if (value is string str && !string.IsNullOrEmpty (str))
+ return str;
+ }
+ return Resources.ErrorMessageNotFound;
+ }
+
+ // http://blogs.msdn.com/b/msbuild/archive/2006/11/03/msbuild-visual-studio-aware-error-messages-and-message-formats.aspx
+ public override string ToString ()
+ {
+ return StringUtils.FormatMessage (FileName, LineNumber, IsError, PREFIX, Code, Message);
+ }
+
+ public static BindingMessage? Parse (string line)
+ {
+ if (!StringUtils.TryParseFormattedMessage (line, out var fileName, out var lineNumber, out var isError, out var _, out var code, out var message))
+ return null;
+
+ return new BindingMessage (message) {
+ Code = code,
+ IsError = isError,
+ FileName = fileName,
+ LineNumber = lineNumber ?? 0,
+ };
+ }
+
+ public void PrintMessage ()
+ {
+ if (IsError) {
+ Console.Error.WriteLine (this);
+ } else {
+ Console.WriteLine (this);
+ }
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/BindingResult.cs b/tools/sharpie/Sharpie.Bind/BindingResult.cs
new file mode 100644
index 000000000000..c4cc7a4153e4
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/BindingResult.cs
@@ -0,0 +1,112 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Mono.CSharp;
+
+namespace Sharpie.Bind;
+
+public class BindingResult {
+ public int Verbosity { get; set; }
+ public int ExitCode { get; set; }
+ public string BindingCode { get; set; } = "";
+ public Dictionary AdditionalFiles { get; set; } = new ();
+ public IList Errors { get => Messages.Where (v => v.IsError).ToList (); }
+ public IList Warnings { get => Messages.Where (v => !v.IsError).ToList (); }
+
+ public List Messages { get; set; } = new ();
+
+ public void ReportError (int code, params IEnumerable arguments)
+ {
+ ReportError (code, (CXSourceLocation?) null, arguments);
+ }
+
+ public void ReportError (int code, CXSourceLocation? location, params IEnumerable arguments)
+ {
+ var message = new BindingMessage (code, arguments, isError: true, location);
+ ReportError (message);
+ }
+
+ public void ReportError (BindingMessage message)
+ {
+ Messages.Add (message);
+ ExitCode = 1;
+ }
+
+ public void ReportWarning (int code, params IEnumerable arguments)
+ {
+ ReportWarning (code, (CXSourceLocation?) null, arguments);
+ }
+
+ public void ReportWarning (int code, CXSourceLocation? location, params IEnumerable args)
+ {
+ var message = new BindingMessage (code, args, isError: false, location);
+ ReportWarning (message);
+ }
+
+ public void ReportWarning (BindingMessage message)
+ {
+ Messages.Add (message);
+ }
+
+ public void Log (int verbosity, string message, params IEnumerable args)
+ {
+ if (verbosity > Verbosity)
+ return;
+
+ var msg = message;
+ if (args.Any ())
+ msg = string.Format (message, args.ToArray ());
+ Console.WriteLine (msg);
+ }
+
+ public void ReportUnsupportedConstruct (CXSourceLocation? location, string message)
+ {
+ ReportWarning (1 /* Unsupported construct: {0}. Generated bindings may be incomplete. Please file an issue at https://github.com/dotnet/macios/issues. */, location, message.TrimEnd ('.'));
+ }
+
+ public void ReportUnexpectedError (Exception exception)
+ {
+ ReportError (0 /* An unexpected error occurred: {0}. Please fill a bug report at https://github.com/dotnet/macios/issues. */, exception.Message.TrimEnd ('.'));
+ }
+
+ public void ReportInternalError (CXSourceLocation? location, string message)
+ {
+ ReportError (99 /* Internal error: {0}. Please file an issue at https://github.com/dotnet/macios/issues. */, location, message);
+ }
+
+ public BindingException CreateInternalError (string message, CXSourceLocation? location = null)
+ {
+ return new BindingException (new BindingMessage (99 /* Internal error: {0}. Please file an issue at https://github.com/dotnet/macios/issues. */, [message], true, location));
+ }
+
+ public void ReportException (Exception exception)
+ {
+ if (exception is BindingException be) {
+ if (be.BindingMessage.IsError) {
+ ReportError (be.BindingMessage);
+ } else {
+ ReportWarning (be.BindingMessage);
+ }
+ } else if (exception is AggregateException ae) {
+ foreach (var inner in ae.InnerExceptions)
+ ReportException (inner);
+ } else {
+ ReportUnexpectedError (exception);
+ }
+ }
+
+ public int PrintMessages ()
+ {
+ Messages.PrintMessages ();
+ return ExitCode;
+ }
+}
+
+public static class BindingResultExtensions {
+ public static void PrintMessages (this IEnumerable messages)
+ {
+ foreach (var msg in messages) {
+ msg.PrintMessage ();
+ }
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/BindingTokenWriter.cs b/tools/sharpie/Sharpie.Bind/BindingTokenWriter.cs
new file mode 100644
index 000000000000..a1e1dfdfda3c
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/BindingTokenWriter.cs
@@ -0,0 +1,282 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Globalization;
+using System.IO;
+
+using Clang;
+
+using ICSharpCode.NRefactory;
+using ICSharpCode.NRefactory.CSharp;
+
+using Sharpie.Bind.Attributes;
+
+namespace Sharpie.Bind;
+
+public class BindingTokenWriter : TokenWriter {
+ readonly Stack nodeStack = new Stack ();
+
+ bool inAttributeSection;
+ bool inPropertyDeclaration;
+ int inComposedType;
+ bool disableNewLine;
+
+ readonly TokenWriter writer;
+ readonly ObjectiveCBinder Binder;
+
+ public BindingTokenWriter (ObjectiveCBinder binder, TokenWriter writer)
+ {
+ if (writer is null)
+ throw new ArgumentNullException (nameof (writer));
+
+ this.Binder = binder;
+ this.writer = writer;
+ }
+
+ public BindingTokenWriter (ObjectiveCBinder binder, TextWriter writer) : this (binder, new TextWriterTokenWriter (writer))
+ {
+ }
+
+ public override void WritePrimitiveType (string type)
+ {
+ writer.WritePrimitiveType (type);
+ }
+
+ public override void Indent ()
+ {
+ writer.Indent ();
+ }
+
+ public override void Unindent ()
+ {
+ writer.Unindent ();
+ }
+
+ public override void WriteComment (CommentType commentType, string content)
+ {
+ writer.WriteComment (commentType, content);
+ if (content == ModelAttribute.ModelRemovedComment)
+ writer.NewLine ();
+ }
+
+ public override void WritePreProcessorDirective (PreProcessorDirectiveType type, string argument)
+ {
+ writer.WritePreProcessorDirective (type, argument);
+ }
+
+ public override void StartNode (AstNode node)
+ {
+ nodeStack.Push (node);
+
+ inPropertyDeclaration |= node is PropertyDeclaration;
+ inAttributeSection |= node is AttributeSection;
+ if (node is ComposedType)
+ inComposedType++;
+
+ if (inPropertyDeclaration && disableNewLine && node is AttributeSection)
+ WriteToken (Roles.Whitespace, " ");
+
+ if (node is TypeDeclaration || node is DelegateDeclaration ||
+ node is PropertyDeclaration || node is MethodDeclaration) {
+ foreach (var nativeNode in node.Annotations.OfType ()) {
+ var comment = GenerateNativeCodeComment (Binder, nativeNode);
+ if (!String.IsNullOrEmpty (comment))
+ WriteComment (CommentType.SingleLine, " " + comment);
+ }
+ }
+
+ writer.StartNode (node);
+ }
+
+ public override void EndNode (AstNode node)
+ {
+ if (node != nodeStack.Pop ())
+ throw new Exception ("node stack is not balanced");
+
+ if (node is PropertyDeclaration) {
+ disableNewLine = false;
+ inPropertyDeclaration = false;
+ NewLine ();
+ } else if ((node is TypeDeclaration || node is DelegateDeclaration) && node.NextSibling is not null) {
+ NewLine ();
+ } else if (node is AttributeSection) {
+ inAttributeSection = false;
+ } else if (node is ComposedType) {
+ inComposedType--;
+ }
+
+ writer.EndNode (node);
+ }
+
+ public override void WriteIdentifier (Identifier identifier)
+ {
+ // write [return: foo] instead of [@return: foo] as NRefactory
+ // always escapes keyword identifiers with '@', which is not ideal
+ // in an attribute section context
+ if (inAttributeSection && identifier.Name == "return") {
+ WriteKeyword (Roles.Identifier, "return");
+ return;
+ }
+
+ writer.WriteIdentifier (identifier);
+ }
+
+ public override void WriteToken (Role role, string token)
+ {
+ if (inPropertyDeclaration) {
+ if (role == Roles.LBrace)
+ disableNewLine = true;
+ else if (role == Roles.RBrace)
+ WriteKeyword (Roles.Whitespace, " ");
+ }
+
+ if (inComposedType > 0 && role == Roles.LBracket)
+ writer.Space ();
+
+ writer.WriteToken (role, token);
+ }
+
+ public override void Space ()
+ {
+ writer.Space ();
+ }
+
+ public override void WritePrimitiveValue (object value, string? literalValue = null)
+ {
+ if (literalValue is not null) {
+ writer.WritePrimitiveValue (value, literalValue);
+ return;
+ }
+
+ var isShiftRhs = false;
+
+ var primitiveExpr = nodeStack.Pop ();
+ try {
+ if (nodeStack.Peek () is BinaryOperatorExpression binopExpr) {
+ // https://github.com/xamarin/ObjectiveSharpie/issues/106
+ // Always write out type suffix for literals on the LHS
+ // of a shift operation. RHS will end up always coercing
+ // into 'int' below, to ensure valid C#.
+ switch (binopExpr.Operator) {
+ case BinaryOperatorType.ShiftLeft:
+ case BinaryOperatorType.ShiftRight:
+ if (binopExpr.Left == primitiveExpr) {
+ writer.WritePrimitiveValue (value);
+ return;
+ } else if (binopExpr.Right == primitiveExpr) {
+ isShiftRhs = true;
+ }
+ break;
+ }
+ }
+ } finally {
+ nodeStack.Push (primitiveExpr);
+ }
+
+ var hexFormat = false;
+
+ if (!isShiftRhs) {
+ var enumDecl = nodeStack
+ .OfType ()
+ .FirstOrDefault (t => t.ClassType == ClassType.Enum);
+
+ hexFormat = enumDecl is not null && enumDecl.HasAttribute ();
+ }
+
+ // The base version will always write the 'u' and 'L'
+ // constant suffixes even if they can fit safely into
+ // an int and would be implicitly convertible. Convert
+ // them to int if possible.
+ // https://bugzilla.xamarin.com/show_bug.cgi?id=28037
+ switch (value) {
+ case ulong ulongValue when ulongValue <= long.MaxValue:
+ if (ulongValue <= int.MaxValue)
+ value = (int) ulongValue;
+ else
+ value = (long) ulongValue;
+ break;
+ case long longValue when longValue <= int.MaxValue:
+ value = (int) longValue;
+ break;
+ case uint uintValue when uintValue <= int.MaxValue:
+ value = (int) uintValue;
+ break;
+ }
+
+ switch (value) {
+ case sbyte _:
+ case byte _:
+ case short _:
+ case ushort _:
+ case int _:
+ case uint _:
+ case long _:
+ case ulong _:
+ string? format = null;
+ if (hexFormat) {
+ format = "x";
+ literalValue = "0x";
+ }
+
+ literalValue += ((IFormattable) value).ToString (format, NumberFormatInfo.InvariantInfo);
+
+ if (value is uint || value is ulong)
+ literalValue += "u";
+
+ if (value is long || value is ulong)
+ literalValue += "L";
+
+ break;
+ }
+
+ writer.WritePrimitiveValue (value, literalValue);
+ }
+
+ public override void WriteKeyword (Role role, string keyword)
+ {
+ if (role == PropertyDeclaration.GetKeywordRole || role == PropertyDeclaration.SetKeywordRole)
+ WriteToken (Roles.Whitespace, " ");
+
+ writer.WriteKeyword (role, keyword);
+
+ if (keyword == TypeOfExpression.TypeofKeywordRole.Token)
+ writer.Space ();
+ else if (keyword == SizeOfExpression.SizeofKeywordRole.Token)
+ writer.Space ();
+ }
+
+ public override void NewLine ()
+ {
+ if (!disableNewLine)
+ writer.NewLine ();
+ }
+
+ static string? GenerateNativeCodeComment (ObjectiveCBinder binder, object nativeNode)
+ {
+ var writer = new StringWriter ();
+ var generator = new NativeCodeGenerator (binder, writer);
+
+ // note that we do not want to call nativeDecl.Accept (generator) since
+ // that will cause the generator to visit DeclContext nodes (e.g. members
+ // of an interface). Calling Visit* methods directly will not traverse
+ // children so we will end up with just the toplevel definition
+ if (nativeNode is ObjCContainerDecl)
+ generator.VisitObjCContainerDecl ((ObjCContainerDecl) nativeNode);
+ else if (nativeNode is ObjCMethodDecl)
+ generator.VisitObjCMethodDecl ((ObjCMethodDecl) nativeNode);
+ else if (nativeNode is ObjCPropertyDecl)
+ generator.VisitObjCPropertyDecl ((ObjCPropertyDecl) nativeNode);
+ else if (nativeNode is FunctionDecl)
+ generator.VisitFunctionDecl ((FunctionDecl) nativeNode);
+ else if (nativeNode is TypedefDecl)
+ generator.VisitTypedefDecl ((TypedefDecl) nativeNode);
+ else if (nativeNode is BlockPointerType)
+ generator.VisitBlockPointerType ((BlockPointerType) nativeNode);
+ else if (nativeNode is VarDecl)
+ generator.VisitVarDecl ((VarDecl) nativeNode);
+ else
+ return null;
+
+ return writer.ToString ().Trim ();
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/ClangExtensions.cs b/tools/sharpie/Sharpie.Bind/ClangExtensions.cs
new file mode 100644
index 000000000000..e7375ff51ab1
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/ClangExtensions.cs
@@ -0,0 +1,447 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Diagnostics;
+using ICSharpCode.NRefactory.CSharp;
+using Mono.CSharp;
+
+namespace Sharpie.Bind;
+
+public static class ClangExtensions {
+ public static bool IsObjCRequiresSuperAttr (this IEnumerable attrs)
+ {
+ return IsAttribute (attrs, CX_AttrKind.CX_AttrKind_ObjCRequiresSuper);
+ }
+
+ public static bool IsDesignatedInitializerAttr (this IEnumerable attrs)
+ {
+ return IsAttribute (attrs, CX_AttrKind.CX_AttrKind_ObjCDesignatedInitializer);
+ }
+
+ public static bool IsFlagEnumAttr (this IEnumerable attrs)
+ {
+ return IsAttribute (attrs, CX_AttrKind.CX_AttrKind_FlagEnum);
+ }
+
+ public static bool IsUnavailableAttr (this IEnumerable attrs)
+ {
+ return IsAttribute (attrs, CX_AttrKind.CX_AttrKind_Unavailable);
+ }
+
+ public static bool IsAnyAvailabilityAttributeUnavailable (this IEnumerable attrs)
+ {
+ return GetAvailabilityAttributes (attrs).Any (v => v.AvailabilityAttributeUnavailable);
+ }
+
+ public static IEnumerable GetAvailabilityAttributes (this IEnumerable attrs)
+ {
+ foreach (var attr in attrs) {
+ if (attr.Kind == CX_AttrKind.CX_AttrKind_Availability)
+ yield return attr;
+ }
+ }
+
+ public static bool TryGetObjCRuntimeName (this IEnumerable attrs, [NotNullWhen (true)] out string? runtimeName)
+ {
+ var attr = attrs.FirstOrDefault (v => v.Kind == CX_AttrKind.CX_AttrKind_ObjCRuntimeName);
+ if (attr is null) {
+ runtimeName = null;
+ return false;
+ }
+ runtimeName = attr.ObjCRuntimeNameMetadataName;
+ return true;
+ }
+
+ public static bool IsAttribute (this IEnumerable attrs, CX_AttrKind kind)
+ {
+ foreach (var a in attrs) {
+ if (a.Kind == kind)
+ return true;
+ }
+ return false;
+ }
+
+ public static IEnumerable GetAttrs (this IEnumerable attrs, CX_AttrKind kind)
+ {
+ foreach (var a in attrs) {
+ if (a.Kind == kind)
+ yield return a;
+ }
+ }
+
+ public static AstType? Bind (this ClangSharp.Type type, BindingResult bindingResult)
+ {
+ ParameterModifier parameterModifier;
+ return type.Bind (bindingResult, false, out parameterModifier);
+ }
+
+ public static AstType? Bind (this ClangSharp.Type type,
+ BindingResult bindingResult,
+ out ParameterModifier parameterModifier)
+ {
+ return type.Bind (bindingResult, true, out parameterModifier);
+ }
+
+ static AstType? Bind (this ClangSharp.Type type,
+ BindingResult bindingResult,
+ bool parameterContext, out ParameterModifier parameterModifier)
+ {
+ if (type is null) {
+ parameterModifier = ParameterModifier.None;
+ return null;
+ }
+
+ var binder = new TypeBinder (bindingResult);
+ type.Accept (binder);
+ binder.Resolve ();
+ parameterModifier = binder.ParameterModifier;
+ return parameterContext ? binder.ParameterType : binder.Type;
+ }
+
+ public static string ToCSharpName (this Selector selector)
+ {
+ return selector.GetNameForSlot (0).UCFirst ();
+ }
+
+ public static ArgumentSemantic ToArgumentSemantic (this ObjCPropertyAttributeKind attr)
+ {
+ if ((attr & ObjCPropertyAttributeKind.Retain) != 0)
+ return ArgumentSemantic.Retain;
+ else if ((attr & ObjCPropertyAttributeKind.Copy) != 0)
+ return ArgumentSemantic.Copy;
+ else if ((attr & ObjCPropertyAttributeKind.Assign) != 0)
+ return ArgumentSemantic.Assign;
+ else if ((attr & ObjCPropertyAttributeKind.Weak) != 0)
+ return ArgumentSemantic.Weak;
+ else if ((attr & ObjCPropertyAttributeKind.Strong) != 0)
+ return ArgumentSemantic.Strong;
+ else if ((attr & ObjCPropertyAttributeKind.UnsafeUnretained) != 0)
+ return ArgumentSemantic.UnsafeUnretained;
+ else
+ return ArgumentSemantic.None;
+ }
+
+ public static BinaryOperatorType ToBinaryOperatorType (this CXBinaryOperatorKind kind)
+ {
+ switch (kind) {
+ case CXBinaryOperatorKind.CXBinaryOperator_Mul:
+ return BinaryOperatorType.Multiply;
+ case CXBinaryOperatorKind.CXBinaryOperator_Div:
+ return BinaryOperatorType.Divide;
+ case CXBinaryOperatorKind.CXBinaryOperator_Rem:
+ return BinaryOperatorType.Modulus;
+ case CXBinaryOperatorKind.CXBinaryOperator_Add:
+ return BinaryOperatorType.Add;
+ case CXBinaryOperatorKind.CXBinaryOperator_Sub:
+ return BinaryOperatorType.Subtract;
+ case CXBinaryOperatorKind.CXBinaryOperator_Shl:
+ return BinaryOperatorType.ShiftLeft;
+ case CXBinaryOperatorKind.CXBinaryOperator_Shr:
+ return BinaryOperatorType.ShiftRight;
+ case CXBinaryOperatorKind.CXBinaryOperator_LT:
+ return BinaryOperatorType.LessThan;
+ case CXBinaryOperatorKind.CXBinaryOperator_GT:
+ return BinaryOperatorType.GreaterThan;
+ case CXBinaryOperatorKind.CXBinaryOperator_LE:
+ return BinaryOperatorType.LessThanOrEqual;
+ case CXBinaryOperatorKind.CXBinaryOperator_GE:
+ return BinaryOperatorType.GreaterThanOrEqual;
+ case CXBinaryOperatorKind.CXBinaryOperator_EQ:
+ return BinaryOperatorType.Equality;
+ case CXBinaryOperatorKind.CXBinaryOperator_NE:
+ return BinaryOperatorType.InEquality;
+ case CXBinaryOperatorKind.CXBinaryOperator_And:
+ return BinaryOperatorType.BitwiseAnd;
+ case CXBinaryOperatorKind.CXBinaryOperator_Xor:
+ return BinaryOperatorType.ExclusiveOr;
+ case CXBinaryOperatorKind.CXBinaryOperator_Or:
+ return BinaryOperatorType.BitwiseOr;
+ case CXBinaryOperatorKind.CXBinaryOperator_LAnd:
+ return BinaryOperatorType.ConditionalAnd;
+ case CXBinaryOperatorKind.CXBinaryOperator_LOr:
+ return BinaryOperatorType.ConditionalOr;
+ case CXBinaryOperatorKind.CXBinaryOperator_PtrMemD:
+ case CXBinaryOperatorKind.CXBinaryOperator_PtrMemI:
+ case CXBinaryOperatorKind.CXBinaryOperator_Assign:
+ case CXBinaryOperatorKind.CXBinaryOperator_MulAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_DivAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_RemAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_AddAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_SubAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_ShlAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_ShrAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_AndAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_XorAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_OrAssign:
+ case CXBinaryOperatorKind.CXBinaryOperator_Comma:
+ default:
+ throw new Exception ("Unsupported BinaryOperatorKind: " + kind);
+ }
+ }
+
+ public static UnaryOperatorType ToUnaryOperatorType (this CXUnaryOperatorKind kind)
+ {
+ switch (kind) {
+ case CXUnaryOperatorKind.CXUnaryOperator_PostInc:
+ return UnaryOperatorType.PostIncrement;
+ case CXUnaryOperatorKind.CXUnaryOperator_PostDec:
+ return UnaryOperatorType.PostDecrement;
+ case CXUnaryOperatorKind.CXUnaryOperator_PreInc:
+ return UnaryOperatorType.Increment;
+ case CXUnaryOperatorKind.CXUnaryOperator_PreDec:
+ return UnaryOperatorType.Decrement;
+ case CXUnaryOperatorKind.CXUnaryOperator_AddrOf:
+ return UnaryOperatorType.AddressOf;
+ case CXUnaryOperatorKind.CXUnaryOperator_Deref:
+ return UnaryOperatorType.Dereference;
+ case CXUnaryOperatorKind.CXUnaryOperator_Plus:
+ return UnaryOperatorType.Plus;
+ case CXUnaryOperatorKind.CXUnaryOperator_Minus:
+ return UnaryOperatorType.Minus;
+ case CXUnaryOperatorKind.CXUnaryOperator_Not:
+ return UnaryOperatorType.BitNot;
+ case CXUnaryOperatorKind.CXUnaryOperator_LNot:
+ return UnaryOperatorType.Not;
+ case CXUnaryOperatorKind.CXUnaryOperator_Real:
+ case CXUnaryOperatorKind.CXUnaryOperator_Imag:
+ case CXUnaryOperatorKind.CXUnaryOperator_Extension:
+ default:
+ throw new ArgumentOutOfRangeException ();
+ }
+ }
+
+ extension(ClangSharp.Type self) {
+ public void Accept (AstVisitor visitor)
+ {
+ if (self is BlockPointerType blockPointerType)
+ visitor.VisitBlockPointerType (blockPointerType);
+ else if (self is FunctionProtoType functionProtoType)
+ visitor.VisitFunctionProtoType (functionProtoType);
+ else if (self is BuiltinType builtinType)
+ visitor.VisitBuiltinType (builtinType);
+ else if (self is AttributedType attributedType)
+ visitor.VisitAttributedType (attributedType);
+ else if (self is ElaboratedType elaboratedType)
+ visitor.VisitElaboratedType (elaboratedType);
+ else if (self is PointerType pointerType)
+ visitor.VisitPointerType (pointerType);
+ else if (self is ObjCObjectPointerType objCObjectPointerType)
+ visitor.VisitObjCObjectPointerType (objCObjectPointerType);
+ else if (self is ObjCObjectType objCObjectType)
+ visitor.VisitObjCObjectType (objCObjectType);
+ else if (self is MacroQualifiedType macroQualifiedType)
+ visitor.VisitMacroQualifiedType (macroQualifiedType);
+ else if (self is ObjCTypeParamType objCTypeParamType)
+ visitor.VisitObjCTypeParamType (objCTypeParamType);
+ else if (self is TagType tagType)
+ visitor.VisitTagType (tagType);
+ else if (self is TypedefType typedefType)
+ visitor.VisitTypedefType (typedefType);
+ else if (self is ConstantArrayType constantArrayType)
+ visitor.VisitConstantArrayType (constantArrayType);
+ else if (self is IncompleteArrayType incompleteArrayType)
+ visitor.VisitIncompleteArrayType (incompleteArrayType);
+ else if (self is VectorType vectorType)
+ visitor.VisitVectorType (vectorType);
+ else if (self is ExtVectorType extVectorType)
+ visitor.VisitExtVectorType (extVectorType);
+ else if (self is ComplexType complexType)
+ visitor.VisitComplexType (complexType);
+ else if (self is LValueReferenceType lValueReferenceType)
+ visitor.VisitLValueReferenceType (lValueReferenceType);
+ else if (self is FunctionNoProtoType functionNoProtoType)
+ visitor.VisitFunctionNoProtoType (functionNoProtoType);
+ else if (self is AtomicType atomicType) {
+ visitor.VisitAtomicType (atomicType);
+ } else
+ visitor.BindingResult.ReportUnsupportedConstruct (self.AsTagDecl?.Location, $"Type kind not supported: {self.GetType ().Name}");
+ }
+ }
+
+ extension(Decl self) {
+ public bool GetIsLastInContext (AstVisitor visitor)
+ {
+ throw visitor.BindingResult.CreateInternalError ("Need a test case for this scenario: is last in context.");
+ }
+
+ public void Accept (AstVisitor visitor)
+ {
+ visitor.BindingResult.ReportUnsupportedConstruct (self.Location, $"Accepting decl of type {self.GetType ().Name}");
+ }
+
+ public bool TryGetPresumedLoc ([NotNullWhen (true)] out Clang.PresumedLoc? presumedLoc)
+ {
+ return self.Location.TryGetPresumedLocation (out presumedLoc);
+ }
+
+ public bool TryGetAttr (CX_AttrKind kind, [NotNullWhen (true)] out Attr? attr)
+ {
+ attr = self.GetAttrs (kind).SingleOrDefault ();
+ return attr is not null;
+ }
+
+ public IEnumerable GetAttrs (CX_AttrKind kind)
+ {
+ foreach (var a in self.Attrs) {
+ if (a.Kind == kind)
+ yield return a;
+ }
+ }
+ }
+
+ extension(CXSourceLocation self) {
+ public bool IsInvalid {
+ get {
+ return self.int_data == 0;
+ }
+ }
+
+ public bool TryGetPresumedLocation ([NotNullWhen (true)] out Clang.PresumedLoc? presumedLoc)
+ {
+ self.GetPresumedLocation (out var fileName, out var line, out var column);
+ presumedLoc = new Clang.PresumedLoc (fileName, line, column);
+ return true;
+ }
+
+ public Clang.PresumedLoc? PresumedLoc {
+ get {
+ self.TryGetPresumedLocation (out var loc);
+ return loc;
+ }
+ }
+ }
+
+ extension(ObjCContainerDecl self) {
+ public IEnumerable Protocols {
+ get {
+ if (self is ObjCInterfaceDecl interfaceDecl)
+ return interfaceDecl.Protocols;
+ if (self is ObjCProtocolDecl protocolDecl)
+ return protocolDecl.Protocols;
+ if (self is ObjCCategoryDecl categoryDecl)
+ return categoryDecl.Protocols;
+
+ throw new NotImplementedException ($"Unknown ObjC container type: {self.GetType ()}");
+ }
+ }
+ }
+
+ extension(ObjCMethodDecl self) {
+ public bool IsDesignatedInitializer {
+ get {
+ if (self.MethodFamily != ObjCMethodFamily.Init)
+ return false;
+
+ return self.Attrs.IsDesignatedInitializerAttr ();
+ }
+ }
+
+ public Selector GetSelector ()
+ {
+ return new Selector (self.Selector);
+ }
+ }
+
+ extension(ObjCPropertyDecl self) {
+ public ArgumentSemantic ArgumentSemantic {
+ get {
+ return self.GetPropertyAttributes ().ToArgumentSemantic ();
+ }
+ }
+ }
+
+ extension(Expr self) {
+ public void Accept (AstVisitor visitor)
+ {
+ if (self is IntegerLiteral integerLiteral)
+ visitor.VisitIntegerLiteral (integerLiteral);
+ else if (self is FloatingLiteral floatingLiteral)
+ visitor.VisitFloatingLiteral (floatingLiteral);
+ else if (self is BinaryOperator binaryOperator)
+ visitor.VisitBinaryOperator (binaryOperator);
+ else if (self is UnaryOperator unaryOperator)
+ visitor.VisitUnaryOperator (unaryOperator);
+ else if (self is ParenExpr parenExpr)
+ visitor.VisitParenExpr (parenExpr);
+ else if (self is ImplicitCastExpr implicitCastExpr)
+ visitor.VisitImplicitCastExpr (implicitCastExpr);
+ else if (self is ExplicitCastExpr explicitCastExpr)
+ visitor.VisitExplicitCastExpr (explicitCastExpr);
+ else if (self is CastExpr castExpr)
+ visitor.VisitCastExpr (castExpr);
+ else if (self is UnaryExprOrTypeTraitExpr unaryExprOrTypeTraitExpr)
+ visitor.VisitUnaryExprOrTypeTraitExpr (unaryExprOrTypeTraitExpr);
+ else if (self is FullExpr fullExpr)
+ visitor.VisitFullExpr (fullExpr);
+ else if (self is DeclRefExpr declRefExpr)
+ visitor.VisitDeclRefExpr (declRefExpr);
+ else if (self is CharacterLiteral characterLiteralExpr)
+ visitor.VisitCharacterLiteral (characterLiteralExpr);
+ else
+ visitor.BindingResult.ReportUnsupportedConstruct (self.Location, $"Expression kind not supported: {self.GetType ().Name}");
+ }
+
+ public bool EvaluateAsInt (out long signedValue, out ulong unsignedValue)
+ {
+ var e = self.Handle.Evaluate;
+ unsignedValue = e.AsUnsigned;
+ signedValue = e.AsLongLong;
+ return true;
+ }
+ }
+
+ extension(Cursor self) {
+ public bool TryGetPresumedLoc (out Clang.PresumedLoc? presumedLoc)
+ {
+ return self.Location.TryGetPresumedLocation (out presumedLoc);
+ }
+
+ public Clang.PresumedLoc? PresumedLoc {
+ get {
+ return self.Location.PresumedLoc;
+ }
+ }
+ }
+
+ extension(NamedDecl self) {
+ public bool GetIsUnnamedOrAnonymous (BindingResult bindingResult)
+ {
+ var name = self.Name;
+
+ if (string.IsNullOrEmpty (name))
+ return true;
+
+ if (name.IndexOf ("(unnamed at ", StringComparison.Ordinal) != -1 ||
+ name.IndexOf ("(unnamed struct at ", StringComparison.Ordinal) != -1 ||
+ name.IndexOf ("(unnamed enum at ", StringComparison.Ordinal) != -1 ||
+ name.IndexOf ("(unnamed union at ", StringComparison.Ordinal) != -1 ||
+ name.IndexOf ("(anonymous at ", StringComparison.Ordinal) != -1)
+ return true;
+
+ if (name.Contains ("unnamed ") || name.Contains ("anonymous "))
+ bindingResult.ReportUnsupportedConstruct (self.Location, $"found 'unnamed' or 'anonymous' in name '{name}'");
+
+ return false;
+ }
+
+ public bool IsUIAppearanceSelector {
+ get {
+ foreach (var attr in self.Attrs) {
+ if (attr.Kind != CX_AttrKind.CX_AttrKind_Annotate)
+ continue;
+
+ return string.Equals (attr.Spelling, "ui_appearance_selector", StringComparison.OrdinalIgnoreCase);
+ }
+
+ return false;
+ }
+ }
+ }
+
+ extension(Attr self) {
+ public VersionTuple Introduced => self.AvailabilityAttributeIntroduced ?? default;
+ public VersionTuple Deprecated => self.AvailabilityAttributeDeprecated ?? default;
+ public VersionTuple Obsoleted => self.AvailabilityAttributeObsoleted ?? default;
+ }
+}
+
diff --git a/tools/sharpie/Sharpie.Bind/CodeWriter.cs b/tools/sharpie/Sharpie.Bind/CodeWriter.cs
new file mode 100644
index 000000000000..25d3514ccb33
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/CodeWriter.cs
@@ -0,0 +1,109 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Text;
+
+namespace Sharpie.Writing;
+
+public class CodeWriter : ICodeWriter {
+ public TextWriter BaseWriter { get; private set; }
+ public string IndentString { get; set; }
+
+ public CodeWriter (TextWriter baseWriter)
+ {
+ if (baseWriter is null)
+ throw new ArgumentNullException (nameof (baseWriter));
+
+ this.BaseWriter = baseWriter;
+
+ IndentString = "\t";
+ }
+
+ public virtual void WriteIndent (int indentLevel)
+ {
+ for (int i = 0; i < indentLevel; i++) {
+ Write (IndentString);
+ }
+ }
+
+ public virtual void WriteLine ()
+ {
+ BaseWriter.WriteLine ();
+ }
+
+ public virtual void Write (Term term, string? str)
+ {
+ BaseWriter.Write (str);
+ }
+
+ public virtual void WriteLine (Term term, string? str)
+ {
+ BaseWriter.WriteLine (str);
+ }
+
+ public void Write (string? str)
+ {
+ Write (Term.None, str);
+ }
+
+ public void WriteLine (string? str)
+ {
+ WriteLine (Term.None, str);
+ }
+
+ public void WriteStringLiteral (string literal, string nullToken)
+ {
+ if (literal is null) {
+ Write (Term.TypeReferenceName, nullToken);
+ return;
+ }
+
+ var builder = new StringBuilder ();
+ builder.Append ("\"");
+ foreach (var c in literal) {
+ switch (c) {
+ case '\\':
+ builder.Append ("\\\\");
+ break;
+ case '\0':
+ builder.Append ("\\0");
+ break;
+ case '\a':
+ builder.Append ("\\a");
+ break;
+ case '\b':
+ builder.Append ("\\b");
+ break;
+ case '\f':
+ builder.Append ("\\f");
+ break;
+ case '\n':
+ builder.Append ("\\n");
+ break;
+ case '\r':
+ builder.Append ("\\r");
+ break;
+ case '\t':
+ builder.Append ("\\t");
+ break;
+ case '\v':
+ builder.Append ("\\v");
+ break;
+ default:
+ builder.Append (c);
+ break;
+ }
+ }
+ builder.Append ("\"");
+ Write (Term.StringLiteral, builder.ToString ());
+ }
+
+ public virtual void PushTag (object tag)
+ {
+ }
+
+ public virtual void PopTag ()
+ {
+ }
+}
diff --git a/tools/sharpie/Sharpie.Bind/CollectionExtensions.cs b/tools/sharpie/Sharpie.Bind/CollectionExtensions.cs
new file mode 100644
index 000000000000..8ab023ea9e1c
--- /dev/null
+++ b/tools/sharpie/Sharpie.Bind/CollectionExtensions.cs
@@ -0,0 +1,86 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Sharpie.Bind;
+
+public static class CollectionExtensions {
+ public static void ForEach (this IEnumerable source, Action action)
+ {
+ if (source is null)
+ throw new ArgumentNullException (nameof (source));
+ if (action is null)
+ throw new ArgumentNullException (nameof (action));
+
+ foreach (var item in source)
+ action (item);
+ }
+
+ public static void AddRange (this System.Collections.ObjectModel.Collection collection, IEnumerable items)
+ {
+ if (collection is null)
+ throw new ArgumentNullException (nameof (collection));
+ if (items is null)
+ throw new ArgumentNullException (nameof (items));
+
+ foreach (var item in items)
+ collection.Add (item);
+ }
+
+ public static T? DequeueOrDefault (this Queue queue)
+ {
+ if (queue is null)
+ throw new ArgumentNullException (nameof (queue));
+
+ return queue.Count == 0 ? default (T) : queue.Dequeue ();
+ }
+
+ public static T? PeekOrDefault