diff --git a/Make.config b/Make.config
index f43673443b79..c01ca83b4a83 100644
--- a/Make.config
+++ b/Make.config
@@ -637,22 +637,7 @@ JENKINS_RESULTS_DIRECTORY ?= $(abspath $(TOP)/jenkins-results)
# Clone files instead of copying them on APFS file systems. Much faster.
CP:=$(shell df -t apfs / >/dev/null 2>&1 && echo "cp -c" || echo "cp")
-# WORKAROUND, Ideally it should be xcode-$(XCODE_PRODUCT_BUILD_VERSION) but mono does not build binaries for each xcode release
-# Xcode 12.4 Build 12D4e
-XCODE_IOS_ARCHIVE_VERSION=xcode-12D4e
-# Xcode 12.4 Build 12D4e
-XCODE_MACOS_ARCHIVE_VERSION=xcode-12D4e
-MONO_IOS_FILENAME:=ios-release-Darwin-$(MONO_HASH).7z
-MONO_IOS_URL:=https://download.mono-project.com/mono-sdks/$(XCODE_IOS_ARCHIVE_VERSION)/$(MONO_IOS_FILENAME)
-
-# Setup various variables depending on whether mono is downloaded or built from source
-ifeq ($(MONO_BUILD_FROM_SOURCE),)
-MONO_IOS_SDK_DESTDIR:=$(abspath $(TOP)/builds/downloads/$(basename $(MONO_IOS_FILENAME)))
-MONO_BUILD_MODE=download-mono
-else
-MONO_IOS_SDK_DESTDIR:=$(abspath $(MONO_PATH)/sdks/out)
-MONO_BUILD_MODE=compile-mono
-endif
+MONO_IOS_SDK_DESTDIR:=$(abspath $(TOP)/builds/downloads/mono-ios-sdk-destdir)
# This variable includes all the platforms we support, even those that might be disabled in this build.
ALL_PLATFORMS=iOS tvOS watchOS macOS
diff --git a/builds/.gitignore b/builds/.gitignore
index dad605eee05e..e258969d6dcd 100644
--- a/builds/.gitignore
+++ b/builds/.gitignore
@@ -3,31 +3,3 @@ dotnet-install.sh
BundledNETCorePlatformsPackageVersion.txt
downloads
.stamp*
-.deps.*.mk
-*.config.cache
-install
-mac32
-mac64
-llvm
-llvm64
-simulator86
-simulator64
-watchsimulator
-tvsimulator
-tools64
-cross
-cross64
-crosstv
-cross-watch
-target7
-target7s
-target64
-targettv
-targetwatch
-watchbcl
-mono-ios-sdk-destdir
-*.dylib
-*.o
-x86-64-slice*
-*.pkg
-
diff --git a/builds/Makefile b/builds/Makefile
index 31d213946add..bfe48c600615 100644
--- a/builds/Makefile
+++ b/builds/Makefile
@@ -12,68 +12,22 @@ else
DOTNET_ARCH=x64
endif
-##
-## Mono download vs. build
-##
-
-download: download-mono
-download-mono: \
- downloads/$(basename $(MONO_IOS_FILENAME)) \
-
-downloads/$(basename $(MONO_IOS_FILENAME)): MONO_URL=$(MONO_IOS_URL)
-
include $(TOP)/mk/colors.mk
-DOWNLOADS = \
- downloads/$(MONO_IOS_FILENAME) \
-
-# This target downloads the mono archives, there's one for Xamarin.iOS and one for Xamarin.Mac.
-# If doing many clean builds, it's possible to copy the downloaded zip file to ~/Library/Caches/xamarin-macios
-# to avoid having to download it every time. The zip files have to be copied manually, otherwise
-# we'd end up filling up a lot of hard drives around the world.
-$(DOWNLOADS):
- $(Q) mkdir -p downloads
- $(Q) echo "Downloading $(MONO_URL)..."
- $(Q) if test -f ~/Library/Caches/xamarin-macios/$(notdir $@); then \
- echo "Found a cached version of $(MONO_URL) in ~/Library/Caches/xamarin-macios/$(notdir $@)."; \
- $(CP) ~/Library/Caches/xamarin-macios/$(notdir $@) $@.tmp; \
- else \
- EC=0; \
- $(CURL_RETRY) $(MONO_URL) --output $@.tmp || EC=$$?; \
- if [[ x$$EC == x22 ]]; then \
- MSG="Could not download the archive %s because the URL doesn't exist. This can happen if bumping mono very soon after the corresponding commit was pushed to mono (i.e. the archive hasn't been built yet). If so, please wait a bit and try again."; \
- printf "$(COLOR_RED)*** $$MSG$(COLOR_CLEAR)\n" "$(notdir $@)"; \
- if test -n "$$FAILURE_REASON_PATH"; then printf "$$MSG\n" "[$(notdir $@)]($(MONO_URL))" >> "$$FAILURE_REASON_PATH"; fi; \
- fi; \
- if [[ x$$EC != x0 ]]; then exit $$EC; fi; \
- if [[ "x$$MACIOS_CACHE_DOWNLOADS" != "x" ]]; then \
- mkdir -p ~/Library/Caches/xamarin-macios/; \
- $(CP) $@.tmp ~/Library/Caches/xamarin-macios/"$(notdir $@)"; \
- echo "Cached the download of $(notdir $@) in ~/Library/Caches/xamarin-macios"; \
- fi; \
- fi
- $(Q) mv $@.tmp $@
- $(Q) echo "Downloaded $(MONO_URL)"
-
-downloads/%: downloads/%.7z
- $(Q) echo "Unzipping $*..."
- $(Q) rm -Rf $@.tmp
- $(Q) 7z x $< -o$@.tmp
- $(Q) find $@.tmp -exec touch {} +
- $(Q) mv $@.tmp $@
- $(Q) echo "Unzipped $*."
-
-downloads/%: downloads/%.nupkg
- $(Q) echo "Unzipping $*..."
- $(Q) rm -Rf $@.tmp
- $(Q) unzip -d $@.tmp $<
- $(Q) find $@.tmp -exec touch {} +
- $(Q) mv $@.tmp $@
- $(Q) echo "Unzipped $*."
+DOTNET_FILENAME=$(DOTNET_VERSION).tar.gz
+DOTNET_CACHE_FILENAME=$(HOME)/Library/Caches/xamarin-macios/$(DOTNET_FILENAME)
downloads/$(DOTNET_INSTALL_NAME): dotnet-install.sh
$(Q) echo "Downloading and installing .NET $(DOTNET_VERSION) ($(DOTNET_ARCH)) into $@..."
- $(Q) ./dotnet-install.sh --install-dir "$@.tmp" --version "$(DOTNET_VERSION)" --architecture $(DOTNET_ARCH) --no-path $$DOTNET_INSTALL_EXTRA_ARGS
+ $(Q) if test -f $(DOTNET_CACHE_FILENAME); then \
+ echo "Found a cached version of .NET $(DOTNET_VERSION) in $(DOTNET_CACHE_FILENAME)."; \
+ mkdir -p "$@.tmp"; \
+ tar -xzf $(DOTNET_CACHE_FILENAME) -C "$@.tmp"; \
+ else \
+ ./dotnet-install.sh --install-dir "$@.tmp" --version "$(DOTNET_VERSION)" --architecture $(DOTNET_ARCH) --no-path --keep-zip --zip-path "downloads/$(DOTNET_FILENAME)" $$DOTNET_INSTALL_EXTRA_ARGS; \
+ cp -c downloads/$(DOTNET_FILENAME) $(DOTNET_CACHE_FILENAME); \
+ echo "Cached the download of $(DOTNET_FILENAME) in ~/Library/Caches/xamarin-macios"; \
+ fi
$(Q) rm -Rf "$@"
$(Q) mv "$@.tmp" "$@"
$(Q) echo "Downloaded and installed .NET $(DOTNET_VERSION) into $@."
@@ -108,10 +62,6 @@ dotnet-install.sh: Makefile
$(Q) chmod +x $@.tmp
$(Q) mv $@.tmp $@
-.stamp-download-mono: $(TOP)/Make.config $(TOP)/mk/mono.mk
- $(MAKE) download-mono
- $(Q) touch $@
-
ifdef CUSTOM_DOTNET
DOWNLOAD_DOTNET_VERSION=$(CUSTOM_DOTNET_VERSION)
else
@@ -170,17 +120,7 @@ dotnet:: $(DOTNET_DOWNLOADS)
all-local:: $(DOTNET_DOWNLOADS)
clean-local::
- $(Q) rm -Rf downloads .stamp-download-mono
-
-all-local:: .stamp-mono-ios-sdk-destdir
-
-.stamp-mono-ios-sdk-destdir: .stamp-$(MONO_BUILD_MODE)
- ln -sf $(MONO_IOS_SDK_DESTDIR) mono-ios-sdk-destdir
- $(Q) touch $@
-
-#
-# .NET
-#
+ $(Q) rm -Rf downloads
DOTNET_COMMON_DIRECTORIES += \
$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),$(DOTNET_DESTDIR)/$($(platform)_NUGET_SDK_NAME)) \
@@ -214,4 +154,3 @@ $(DOTNET_COMMON_DIRECTORIES):
install-dotnet: $(DOTNET_COMMON_TARGETS)
install-local:: install-dotnet
all-local:: install-dotnet
-
diff --git a/builds/Mono.framework-Info.plist b/builds/Mono.framework-Info.plist
deleted file mode 100644
index 216a744ca55b..000000000000
--- a/builds/Mono.framework-Info.plist
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleIdentifier
- xamarin.ios.mono-framework
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- Mono
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
- CFBundleVersion
- 3.12
- NSPrincipalClass
-
- CFBundleExecutable
- Mono
-
- BuildMachineOSBuild
- 13F34
- CFBundleDevelopmentRegion
- en
- CFBundleSupportedPlatforms
-
- iPhoneOS
-
- DTCompiler
- com.apple.compilers.llvm.clang.1_0
- DTPlatformBuild
- 12D508
- DTPlatformName
- iphoneos
- DTPlatformVersion
- 8.2
- DTSDKBuild
- 12D508
- DTSDKName
- iphoneos8.2
- DTXcode
- 0620
- DTXcodeBuild
- 6C131e
- MinimumOSVersion
- 12.2
- UIDeviceFamily
-
- 1
- 2
-
-
-
diff --git a/builds/Mono.framework-tvos.Info.plist b/builds/Mono.framework-tvos.Info.plist
deleted file mode 100644
index c0db855ee5ab..000000000000
--- a/builds/Mono.framework-tvos.Info.plist
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleIdentifier
- xamarin.tvos.mono-framework
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- Mono
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
- CFBundleVersion
- 3.12
- NSPrincipalClass
-
- CFBundleExecutable
- Mono
- BuildMachineOSBuild
- 13F34
- CFBundleDevelopmentRegion
- en
- CFBundleSupportedPlatforms
-
- AppleTVOS
-
- DTCompiler
- com.apple.compilers.llvm.clang.1_0
- DTPlatformBuild
- 12D508
- DTPlatformName
- appletvos
- DTPlatformVersion
- 9.0
- DTSDKBuild
- 12D508
- DTSDKName
- appletvos9.0
- DTXcode
- 0620
- DTXcodeBuild
- 6C131e
- MinimumOSVersion
- 12.2
- UIDeviceFamily
-
- 3
-
-
-
diff --git a/builds/Mono.framework-watchos.Info.plist b/builds/Mono.framework-watchos.Info.plist
deleted file mode 100644
index d49a2c154e7f..000000000000
--- a/builds/Mono.framework-watchos.Info.plist
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleIdentifier
- xamarin.watchos.mono-framework
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- Mono
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
- CFBundleVersion
- 3.12
- NSPrincipalClass
-
- CFBundleExecutable
- Mono
- BuildMachineOSBuild
- 13F34
- CFBundleDevelopmentRegion
- en
- CFBundleSupportedPlatforms
-
- WatchOS
-
- DTCompiler
- com.apple.compilers.llvm.clang.1_0
- DTPlatformBuild
- 12D508
- DTPlatformName
- watchos
- DTPlatformVersion
- 2.0
- DTSDKBuild
- 12D508
- DTSDKName
- watchos2.2
- DTXcode
- 0620
- DTXcodeBuild
- 6C131e
- MinimumOSVersion
- 4.0
- UIDeviceFamily
-
- 4
-
-
-
diff --git a/builds/mac-System.config b/builds/mac-System.config
deleted file mode 100644
index ebb9b2987fd1..000000000000
--- a/builds/mac-System.config
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/BaseStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/BaseStep.cs
new file mode 100644
index 000000000000..39210adc9eeb
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/BaseStep.cs
@@ -0,0 +1,83 @@
+//
+// BaseStep.cs
+//
+// Author:
+// Jb Evain (jbevain@novell.com)
+//
+// (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public abstract class BaseStep : IStep {
+
+ private LinkContext _context;
+
+ public LinkContext Context {
+ get { return _context; }
+ }
+
+ public AnnotationStore Annotations {
+ get { return _context.Annotations; }
+ }
+
+ public Tracer Tracer {
+ get { return _context.Tracer; }
+ }
+
+ public MarkingHelpers MarkingHelpers => _context.MarkingHelpers;
+
+ public void Process (LinkContext context)
+ {
+ _context = context;
+
+ if (!ConditionToProcess ())
+ return;
+
+ Process ();
+
+ foreach (AssemblyDefinition assembly in context.GetAssemblies ())
+ ProcessAssembly (assembly);
+
+ EndProcess ();
+ }
+
+ protected virtual bool ConditionToProcess ()
+ {
+ return true;
+ }
+
+ protected virtual void Process ()
+ {
+ }
+
+ protected virtual void EndProcess ()
+ {
+ }
+
+ protected virtual void ProcessAssembly (AssemblyDefinition assembly)
+ {
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/BlacklistStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/BlacklistStep.cs
new file mode 100644
index 000000000000..6448374c6f06
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/BlacklistStep.cs
@@ -0,0 +1,146 @@
+//
+// Blacklist.cs
+//
+// Author:
+// Jb Evain (jb@nurv.fr)
+//
+// (C) 2007 Novell Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Linq;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+using System.Xml.XPath;
+
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class BlacklistStep : BaseStep {
+
+ protected override void Process ()
+ {
+ foreach (string name in Assembly.GetExecutingAssembly ().GetManifestResourceNames ()) {
+ if (!name.EndsWith (".xml", StringComparison.OrdinalIgnoreCase) || !ShouldProcessAssemblyResource (GetAssemblyName (name)))
+ continue;
+
+ try {
+ Context.LogMessage ($"Processing resource linker descriptor: {name}");
+ AddToPipeline (GetResolveStep (name));
+ } catch (XmlException ex) {
+ /* This could happen if some broken XML file is included. */
+ Context.LogMessage ($"Error processing {name}: {ex}");
+ }
+ }
+
+ foreach (var asm in Context.GetAssemblies ()) {
+ foreach (var rsc in asm.Modules
+ .SelectMany (mod => mod.Resources)
+ .Where (res => res.ResourceType == ResourceType.Embedded)
+ .Where (res => res.Name.EndsWith (".xml", StringComparison.OrdinalIgnoreCase))
+ .Where (res => ShouldProcessAssemblyResource (GetAssemblyName (res.Name)))
+ .Cast ()) {
+ try {
+ Context.LogMessage ($"Processing embedded resource linker descriptor: {rsc.Name}");
+
+ AddToPipeline (GetExternalResolveStep (rsc, asm));
+ } catch (XmlException ex) {
+ /* This could happen if some broken XML file is embedded. */
+ Context.LogMessage ($"Error processing {rsc.Name}: {ex}");
+ }
+ }
+ }
+ }
+
+ static string GetAssemblyName (string descriptor)
+ {
+ int pos = descriptor.LastIndexOf ('.');
+ if (pos == -1)
+ return descriptor;
+
+ return descriptor.Substring (0, pos);
+ }
+
+ bool ShouldProcessAssemblyResource (string name)
+ {
+ AssemblyDefinition assembly = GetAssemblyIfReferenced (name);
+
+ if (assembly is null)
+ return false;
+
+ switch (Annotations.GetAction (assembly)) {
+ case AssemblyAction.Link:
+ case AssemblyAction.AddBypassNGen:
+ case AssemblyAction.AddBypassNGenUsed:
+ case AssemblyAction.Copy:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ AssemblyDefinition GetAssemblyIfReferenced (string name)
+ {
+ foreach (AssemblyDefinition assembly in Context.GetAssemblies ())
+ if (assembly.Name.Name == name)
+ return assembly;
+
+ return null;
+ }
+
+ protected virtual void AddToPipeline (IStep resolveStep)
+ {
+ Context.Pipeline.AddStepAfter (typeof (BlacklistStep), resolveStep);
+ }
+
+ protected virtual IStep GetExternalResolveStep (EmbeddedResource resource, AssemblyDefinition assembly)
+ {
+ return new ResolveFromXmlStep (GetExternalDescriptor (resource), resource.Name, assembly, "resource " + resource.Name + " in " + assembly.FullName);
+ }
+
+ static ResolveFromXmlStep GetResolveStep (string descriptor)
+ {
+ return new ResolveFromXmlStep (GetDescriptor (descriptor), "descriptor " + descriptor + " from " + Assembly.GetExecutingAssembly ().FullName);
+ }
+
+ protected static XPathDocument GetExternalDescriptor (EmbeddedResource resource)
+ {
+ using (var sr = new StreamReader (resource.GetResourceStream ())) {
+ return new XPathDocument (sr);
+ }
+ }
+
+ static XPathDocument GetDescriptor (string descriptor)
+ {
+ using (StreamReader sr = new StreamReader (GetResource (descriptor))) {
+ return new XPathDocument (sr);
+ }
+ }
+
+ static Stream GetResource (string descriptor)
+ {
+ return Assembly.GetExecutingAssembly ().GetManifestResourceStream (descriptor);
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/CleanStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/CleanStep.cs
new file mode 100644
index 000000000000..fd6c1063046d
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/CleanStep.cs
@@ -0,0 +1,106 @@
+//
+// CleanStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class CleanStep : BaseStep {
+
+ protected override void ProcessAssembly (AssemblyDefinition assembly)
+ {
+ if (Annotations.GetAction (assembly) == AssemblyAction.Link)
+ CleanAssembly (assembly);
+ }
+
+ static void CleanAssembly (AssemblyDefinition asm)
+ {
+ foreach (TypeDefinition type in asm.MainModule.Types)
+ CleanType (type);
+ }
+
+ static void CleanType (TypeDefinition type)
+ {
+ if (type.HasProperties)
+ CleanProperties (type);
+ if (type.HasEvents)
+ CleanEvents (type);
+
+ if (type.HasNestedTypes)
+ foreach (var nested in type.NestedTypes)
+ CleanType (nested);
+ }
+
+ static MethodDefinition CheckMethod (TypeDefinition type, MethodDefinition method)
+ {
+ if (method is null)
+ return null;
+
+ return type.Methods.Contains (method) ? method : null;
+ }
+
+ static void CleanEvents (TypeDefinition type)
+ {
+ var events = type.Events;
+
+ for (int i = 0; i < events.Count; i++) {
+ var evt = events [i];
+ evt.AddMethod = CheckMethod (type, evt.AddMethod);
+ evt.InvokeMethod = CheckMethod (type, evt.InvokeMethod);
+ evt.RemoveMethod = CheckMethod (type, evt.RemoveMethod);
+
+ if (!IsEventUsed (evt))
+ events.RemoveAt (i--);
+ }
+ }
+
+ static bool IsEventUsed (EventDefinition evt)
+ {
+ return evt.AddMethod is not null || evt.InvokeMethod is not null || evt.RemoveMethod is not null;
+ }
+
+ static void CleanProperties (TypeDefinition type)
+ {
+ var properties = type.Properties;
+
+ for (int i = 0; i < properties.Count; i++) {
+ var prop = properties [i];
+ prop.GetMethod = CheckMethod (type, prop.GetMethod);
+ prop.SetMethod = CheckMethod (type, prop.SetMethod);
+
+ if (!IsPropertyUsed (prop))
+ properties.RemoveAt (i--);
+ }
+ }
+
+ static bool IsPropertyUsed (PropertyDefinition prop)
+ {
+ return prop.GetMethod is not null || prop.SetMethod is not null;
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/IStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/IStep.cs
new file mode 100644
index 000000000000..c01ef1e6b3fa
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/IStep.cs
@@ -0,0 +1,34 @@
+//
+// IStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Mono.Linker.Steps {
+
+ public interface IStep {
+ void Process (LinkContext context);
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/LoadI18nAssemblies.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/LoadI18nAssemblies.cs
new file mode 100644
index 000000000000..da8bb3921746
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/LoadI18nAssemblies.cs
@@ -0,0 +1,103 @@
+//
+// LoadI18nAssemblies.cs
+//
+// Author:
+// Jb Evain (jbevain@novell.com)
+//
+// (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Linq;
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class LoadI18nAssemblies : BaseStep {
+
+ static readonly byte [] _pktoken = new byte [] { 0x07, 0x38, 0xeb, 0x9f, 0x13, 0x2e, 0xd7, 0x56 };
+
+ I18nAssemblies _assemblies;
+
+ public LoadI18nAssemblies (I18nAssemblies assemblies)
+ {
+ _assemblies = assemblies;
+ }
+
+ protected override bool ConditionToProcess ()
+ {
+ return _assemblies != I18nAssemblies.None &&
+ Context.GetAssemblies ().FirstOrDefault (a => a.Name.Name == "mscorlib")?.MainModule.GetType ("System.MonoType") is not null;
+ }
+
+ protected override void Process ()
+ {
+ LoadAssembly (GetAssemblyName (I18nAssemblies.Base));
+
+ LoadI18nAssembly (I18nAssemblies.CJK);
+ LoadI18nAssembly (I18nAssemblies.MidEast);
+ LoadI18nAssembly (I18nAssemblies.Other);
+ LoadI18nAssembly (I18nAssemblies.Rare);
+ LoadI18nAssembly (I18nAssemblies.West);
+ }
+
+ bool ShouldCopyAssembly (I18nAssemblies current)
+ {
+ return (current & _assemblies) != 0;
+ }
+
+ void LoadI18nAssembly (I18nAssemblies asm)
+ {
+ if (!ShouldCopyAssembly (asm))
+ return;
+
+ AssemblyNameReference name = GetAssemblyName (asm);
+ LoadAssembly (name);
+ }
+
+ void LoadAssembly (AssemblyNameReference name)
+ {
+ AssemblyDefinition assembly = Context.Resolve (name);
+ Context.Annotations.SetAction (assembly, AssemblyAction.Copy);
+ ResolveFromAssemblyStep.ProcessLibrary (Context, assembly, ResolveFromAssemblyStep.RootVisibility.Any);
+ }
+
+ AssemblyNameReference GetAssemblyName (I18nAssemblies assembly)
+ {
+ AssemblyNameReference name = new AssemblyNameReference ("I18N", GetCorlibVersion ());
+ if (assembly != I18nAssemblies.Base)
+ name.Name += "." + assembly;
+
+ name.PublicKeyToken = _pktoken;
+ return name;
+ }
+
+ Version GetCorlibVersion ()
+ {
+ foreach (AssemblyDefinition assembly in Context.GetAssemblies ())
+ if (assembly.Name.Name == "mscorlib")
+ return assembly.Name.Version;
+
+ return new Version ();
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/LoadReferencesStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/LoadReferencesStep.cs
new file mode 100644
index 000000000000..06684edb61cb
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/LoadReferencesStep.cs
@@ -0,0 +1,61 @@
+//
+// LoadReferencesStep.cs
+//
+// Author:
+// Jb Evain (jbevain@novell.com)
+//
+// (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class LoadReferencesStep : BaseStep {
+
+ readonly HashSet references = new HashSet ();
+
+ protected override void ProcessAssembly (AssemblyDefinition assembly)
+ {
+ ProcessReferences (assembly);
+ }
+
+ protected void ProcessReferences (AssemblyDefinition assembly)
+ {
+ if (!references.Add (assembly.Name))
+ return;
+
+ Context.RegisterAssembly (assembly);
+
+ foreach (AssemblyDefinition referenceDefinition in Context.ResolveReferences (assembly)) {
+ try {
+ ProcessReferences (referenceDefinition);
+ } catch (Exception ex) {
+ throw new LoadException (string.Format ("Error while processing references of '{0}'", assembly.FullName), ex);
+ }
+ }
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/MarkStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/MarkStep.cs
new file mode 100644
index 000000000000..ff46157cbaeb
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/MarkStep.cs
@@ -0,0 +1,3350 @@
+//
+// MarkStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+// (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Collections.Generic;
+
+namespace Mono.Linker.Steps {
+
+ public partial class MarkStep : IStep {
+
+ protected LinkContext _context;
+ protected Queue _methods;
+ protected List _virtual_methods;
+ protected Queue _assemblyLevelAttributes;
+ protected Queue _lateMarkedAttributes;
+ protected List _typesWithInterfaces;
+ protected List _unreachableBodies;
+
+ public MarkStep ()
+ {
+ _methods = new Queue ();
+ _virtual_methods = new List ();
+ _assemblyLevelAttributes = new Queue ();
+ _lateMarkedAttributes = new Queue ();
+ _typesWithInterfaces = new List ();
+ _unreachableBodies = new List ();
+ }
+
+ public AnnotationStore Annotations => _context.Annotations;
+ public Tracer Tracer => _context.Tracer;
+
+ public virtual void Process (LinkContext context)
+ {
+ _context = context;
+
+ Initialize ();
+ Process ();
+ Complete ();
+ }
+
+ void Initialize ()
+ {
+ foreach (AssemblyDefinition assembly in _context.GetAssemblies ())
+ InitializeAssembly (assembly);
+ }
+
+ protected virtual void InitializeAssembly (AssemblyDefinition assembly)
+ {
+ Tracer.Push (assembly);
+ try {
+ switch (_context.Annotations.GetAction (assembly)) {
+ case AssemblyAction.Copy:
+ case AssemblyAction.Save:
+ MarkEntireAssembly (assembly);
+ break;
+ case AssemblyAction.Link:
+ case AssemblyAction.AddBypassNGen:
+ case AssemblyAction.AddBypassNGenUsed:
+ MarkAssembly (assembly);
+
+ foreach (TypeDefinition type in assembly.MainModule.Types)
+ InitializeType (type);
+
+ break;
+ }
+ } finally {
+ Tracer.Pop ();
+ }
+ }
+
+ void Complete ()
+ {
+ foreach (var body in _unreachableBodies) {
+ Annotations.SetAction (body.Method, MethodAction.ConvertToThrow);
+ }
+ }
+
+ void InitializeType (TypeDefinition type)
+ {
+ if (type.HasNestedTypes) {
+ foreach (var nested in type.NestedTypes)
+ InitializeType (nested);
+ }
+
+ if (!Annotations.IsMarked (type))
+ return;
+
+ MarkType (type);
+
+ if (type.HasFields)
+ InitializeFields (type);
+ if (type.HasMethods)
+ InitializeMethods (type.Methods);
+ }
+
+ protected bool IsFullyPreserved (TypeDefinition type)
+ {
+ if (Annotations.TryGetPreserve (type, out TypePreserve preserve) && preserve == TypePreserve.All)
+ return true;
+
+ switch (Annotations.GetAction (type.Module.Assembly)) {
+ case AssemblyAction.Save:
+ case AssemblyAction.Copy:
+ case AssemblyAction.CopyUsed:
+ case AssemblyAction.AddBypassNGen:
+ case AssemblyAction.AddBypassNGenUsed:
+ return true;
+ }
+
+ return false;
+ }
+
+ void InitializeFields (TypeDefinition type)
+ {
+ foreach (FieldDefinition field in type.Fields)
+ if (Annotations.IsMarked (field))
+ MarkField (field);
+ }
+
+ void InitializeMethods (Collection methods)
+ {
+ foreach (MethodDefinition method in methods)
+ if (Annotations.IsMarked (method))
+ EnqueueMethod (method);
+ }
+
+ void MarkEntireType (TypeDefinition type)
+ {
+ if (type.HasNestedTypes) {
+ foreach (TypeDefinition nested in type.NestedTypes)
+ MarkEntireType (nested);
+ }
+
+ Annotations.Mark (type);
+ MarkCustomAttributes (type);
+ MarkTypeSpecialCustomAttributes (type);
+
+ if (type.HasInterfaces) {
+ foreach (InterfaceImplementation iface in type.Interfaces) {
+ MarkInterfaceImplementation (iface);
+ }
+ }
+
+ MarkGenericParameterProvider (type);
+
+ if (type.HasFields) {
+ foreach (FieldDefinition field in type.Fields) {
+ MarkField (field);
+ }
+ }
+
+ if (type.HasMethods) {
+ foreach (MethodDefinition method in type.Methods) {
+ Annotations.Mark (method);
+ Annotations.SetAction (method, MethodAction.ForceParse);
+ EnqueueMethod (method);
+ }
+ }
+
+ if (type.HasProperties) {
+ foreach (var property in type.Properties) {
+ MarkProperty (property);
+ }
+ }
+
+ if (type.HasEvents) {
+ foreach (var ev in type.Events) {
+ MarkEvent (ev);
+ }
+ }
+ }
+
+ void Process ()
+ {
+ while (ProcessPrimaryQueue () || ProcessLazyAttributes () || ProcessLateMarkedAttributes ())
+
+ // deal with [TypeForwardedTo] pseudo-attributes
+ foreach (AssemblyDefinition assembly in _context.GetAssemblies ()) {
+ if (!assembly.MainModule.HasExportedTypes)
+ continue;
+
+ foreach (var exported in assembly.MainModule.ExportedTypes) {
+ bool isForwarder = exported.IsForwarder;
+ var declaringType = exported.DeclaringType;
+ while (!isForwarder && (declaringType is not null)) {
+ isForwarder = declaringType.IsForwarder;
+ declaringType = declaringType.DeclaringType;
+ }
+
+ if (!isForwarder)
+ continue;
+ TypeDefinition type = exported.Resolve ();
+ if (type is null)
+ continue;
+ if (!Annotations.IsMarked (type))
+ continue;
+ Tracer.Push (type);
+ try {
+ _context.MarkingHelpers.MarkExportedType (exported, assembly.MainModule);
+ } finally {
+ Tracer.Pop ();
+ }
+ }
+ }
+ }
+
+ bool ProcessPrimaryQueue ()
+ {
+ if (QueueIsEmpty ())
+ return false;
+
+ while (!QueueIsEmpty ()) {
+ ProcessQueue ();
+ ProcessVirtualMethods ();
+ ProcessMarkedTypesWithInterfaces ();
+ ProcessPendingBodies ();
+ DoAdditionalProcessing ();
+ }
+
+ return true;
+ }
+
+ void ProcessQueue ()
+ {
+ while (!QueueIsEmpty ()) {
+ MethodDefinition method = _methods.Dequeue ();
+ Tracer.Push (method);
+ try {
+ ProcessMethod (method);
+ } catch (Exception e) {
+ throw new MarkException (string.Format ("Error processing method: '{0}' in assembly: '{1}'", method.FullName, method.Module.Name), e, method);
+ } finally {
+ Tracer.Pop ();
+ }
+ }
+ }
+
+ bool QueueIsEmpty ()
+ {
+ return _methods.Count == 0;
+ }
+
+ protected virtual void EnqueueMethod (MethodDefinition method)
+ {
+ _methods.Enqueue (method);
+ }
+
+ void ProcessVirtualMethods ()
+ {
+ foreach (MethodDefinition method in _virtual_methods) {
+ Tracer.Push (method);
+ ProcessVirtualMethod (method);
+ Tracer.Pop ();
+ }
+ }
+
+ void ProcessMarkedTypesWithInterfaces ()
+ {
+ // We may mark an interface type later on. Which means we need to reprocess any time with one or more interface implementations that have not been marked
+ // and if an interface type is found to be marked and implementation is not marked, then we need to mark that implementation
+
+ // copy the data to avoid modified while enumerating error potential, which can happen under certain conditions.
+ var typesWithInterfaces = _typesWithInterfaces.ToArray ();
+
+ foreach (var type in typesWithInterfaces) {
+ // Exception, types that have not been flagged as instantiated yet. These types may not need their interfaces even if the
+ // interface type is marked
+ if (!Annotations.IsInstantiated (type))
+ continue;
+
+ MarkInterfaceImplementations (type);
+ }
+ }
+
+ void ProcessPendingBodies ()
+ {
+ for (int i = 0; i < _unreachableBodies.Count; i++) {
+ var body = _unreachableBodies [i];
+ if (Annotations.IsInstantiated (body.Method.DeclaringType)) {
+ MarkMethodBody (body);
+ _unreachableBodies.RemoveAt (i--);
+ }
+ }
+ }
+
+ void ProcessVirtualMethod (MethodDefinition method)
+ {
+ var overrides = Annotations.GetOverrides (method);
+ if (overrides is null)
+ return;
+
+ foreach (OverrideInformation @override in overrides)
+ ProcessOverride (@override);
+ }
+
+ void ProcessOverride (OverrideInformation overrideInformation)
+ {
+ var method = overrideInformation.Override;
+ var @base = overrideInformation.Base;
+ if (!Annotations.IsMarked (method.DeclaringType))
+ return;
+
+ if (Annotations.IsProcessed (method))
+ return;
+
+ if (Annotations.IsMarked (method))
+ return;
+
+ var isInstantiated = Annotations.IsInstantiated (method.DeclaringType);
+
+ // We don't need to mark overrides until it is possible that the type could be instantiated
+ // Note : The base type is interface check should be removed once we have base type sweeping
+ if (IsInterfaceOverrideThatDoesNotNeedMarked (overrideInformation, isInstantiated))
+ return;
+
+ if (!isInstantiated && !@base.IsAbstract && _context.IsOptimizationEnabled (CodeOptimizations.OverrideRemoval))
+ return;
+
+ MarkMethod (method);
+ ProcessVirtualMethod (method);
+ }
+
+ bool IsInterfaceOverrideThatDoesNotNeedMarked (OverrideInformation overrideInformation, bool isInstantiated)
+ {
+ if (!overrideInformation.IsOverrideOfInterfaceMember || isInstantiated)
+ return false;
+
+ if (overrideInformation.MatchingInterfaceImplementation is not null)
+ return !Annotations.IsMarked (overrideInformation.MatchingInterfaceImplementation);
+
+ var interfaceType = overrideInformation.InterfaceType;
+ var overrideDeclaringType = overrideInformation.Override.DeclaringType;
+
+ if (!IsInterfaceImplementationMarked (overrideDeclaringType, interfaceType)) {
+ var derivedInterfaceTypes = Annotations.GetDerivedInterfacesForInterface (interfaceType);
+
+ // There are no derived interface types that could be marked, it's safe to skip marking this override
+ if (derivedInterfaceTypes is null)
+ return true;
+
+ // If none of the other interfaces on the type that implement the interface from the @base type are marked, then it's safe to skip
+ // marking this override
+ if (!derivedInterfaceTypes.Any (d => IsInterfaceImplementationMarked (overrideDeclaringType, d)))
+ return true;
+ }
+
+ return false;
+ }
+
+ bool IsInterfaceImplementationMarked (TypeDefinition type, TypeDefinition interfaceType)
+ {
+ return type.HasInterface (@interfaceType, out InterfaceImplementation implementation) && Annotations.IsMarked (implementation);
+ }
+
+ void MarkMarshalSpec (IMarshalInfoProvider spec)
+ {
+ if (!spec.HasMarshalInfo)
+ return;
+
+ if (spec.MarshalInfo is CustomMarshalInfo marshaler)
+ MarkType (marshaler.ManagedType);
+ }
+
+ void MarkCustomAttributes (ICustomAttributeProvider provider)
+ {
+ if (!provider.HasCustomAttributes)
+ return;
+
+ bool markOnUse = _context.KeepUsedAttributeTypesOnly && Annotations.GetAction (GetAssemblyFromCustomAttributeProvider (provider)) == AssemblyAction.Link;
+
+ Tracer.Push (provider);
+ try {
+ foreach (CustomAttribute ca in provider.CustomAttributes) {
+ if (IsUserDependencyMarker (ca.AttributeType) && provider is MemberReference mr) {
+ MarkUserDependency (mr, ca);
+
+ if (_context.KeepDependencyAttributes) {
+ MarkCustomAttribute (ca);
+ continue;
+ }
+
+ if (Annotations.GetAction (mr.Module.Assembly) == AssemblyAction.Link)
+ continue;
+ }
+
+ if (markOnUse) {
+ _lateMarkedAttributes.Enqueue (new AttributeProviderPair (ca, provider));
+ continue;
+ }
+
+ MarkCustomAttribute (ca);
+ MarkSpecialCustomAttributeDependencies (ca);
+ }
+ } finally {
+ Tracer.Pop ();
+ }
+ }
+
+ static AssemblyDefinition GetAssemblyFromCustomAttributeProvider (ICustomAttributeProvider provider)
+ {
+ return provider switch {
+ MemberReference mr => mr.Module.Assembly,
+ AssemblyDefinition ad => ad,
+ ModuleDefinition md => md.Assembly,
+ InterfaceImplementation ii => ii.InterfaceType.Module.Assembly,
+ GenericParameterConstraint gpc => gpc.ConstraintType.Module.Assembly,
+ ParameterDefinition pd => pd.ParameterType.Module.Assembly,
+ MethodReturnType mrt => mrt.ReturnType.Module.Assembly,
+ _ => throw new NotImplementedException (provider.GetType ().ToString ()),
+ };
+ }
+
+ protected virtual bool IsUserDependencyMarker (TypeReference type)
+ {
+ return PreserveDependencyLookupStep.IsPreserveDependencyAttribute (type);
+ }
+
+ protected virtual void MarkUserDependency (MemberReference context, CustomAttribute ca)
+ {
+ if (ca.HasProperties && ca.Properties [0].Name == "Condition") {
+ var condition = ca.Properties [0].Argument.Value as string;
+ switch (condition) {
+ case "":
+ case null:
+ break;
+ case "DEBUG":
+ if (!_context.KeepMembersForDebugger)
+ return;
+
+ break;
+ default:
+ // Don't have yet a way to match the general condition so everything is excluded
+ return;
+ }
+ }
+
+ AssemblyDefinition assembly;
+ var args = ca.ConstructorArguments;
+ if (args.Count >= 3 && args [2].Value is string assemblyName) {
+ if (!_context.Resolver.AssemblyCache.TryGetValue (assemblyName, out assembly)) {
+ _context.LogMessage (MessageImportance.Low, $"Could not resolve '{assemblyName}' assembly dependency");
+ return;
+ }
+ } else {
+ assembly = null;
+ }
+
+ TypeDefinition td;
+ if (args.Count >= 2 && args [1].Value is string typeName) {
+ td = FindType (assembly ?? context.Module.Assembly, typeName);
+
+ if (td is null) {
+ _context.LogMessage (MessageImportance.Low, $"Could not resolve '{typeName}' type dependency");
+ return;
+ }
+ } else {
+ td = context.DeclaringType.Resolve ();
+ }
+
+ string member = null;
+ string [] signature = null;
+ if (args.Count >= 1 && args [0].Value is string memberSignature) {
+ memberSignature = memberSignature.Replace (" ", "");
+ var sign_start = memberSignature.IndexOf ('(');
+ var sign_end = memberSignature.LastIndexOf (')');
+ if (sign_start > 0 && sign_end > sign_start) {
+ var parameters = memberSignature.Substring (sign_start + 1, sign_end - sign_start - 1);
+ signature = string.IsNullOrEmpty (parameters) ? Array.Empty () : parameters.Split (',');
+ member = memberSignature.Substring (0, sign_start);
+ } else {
+ member = memberSignature;
+ }
+ }
+
+ if (member == "*") {
+ MarkEntireType (td);
+ return;
+ }
+
+ if (MarkDependencyMethod (td, member, signature))
+ return;
+
+ if (MarkDependencyField (td, member))
+ return;
+
+ _context.LogMessage (MessageImportance.High, $"Could not resolve dependency member '{member}' declared in type '{td.FullName}'");
+ }
+
+ static TypeDefinition FindType (AssemblyDefinition assembly, string fullName)
+ {
+ fullName = fullName.ToCecilName ();
+
+ var type = assembly.MainModule.GetType (fullName);
+ return type?.Resolve ();
+ }
+
+ bool MarkDependencyMethod (TypeDefinition type, string name, string [] signature)
+ {
+ bool marked = false;
+
+ int arity_marker = name.IndexOf ('`');
+ if (arity_marker < 1 || !int.TryParse (name.Substring (arity_marker + 1), out int arity)) {
+ arity = 0;
+ } else {
+ name = name.Substring (0, arity_marker);
+ }
+
+ foreach (var m in type.Methods) {
+ if (m.Name != name)
+ continue;
+
+ if (m.GenericParameters.Count != arity)
+ continue;
+
+ if (signature is null) {
+ MarkIndirectlyCalledMethod (m);
+ marked = true;
+ continue;
+ }
+
+ var mp = m.Parameters;
+ if (mp.Count != signature.Length)
+ continue;
+
+ int i = 0;
+ for (; i < signature.Length; ++i) {
+ if (mp [i].ParameterType.FullName != signature [i].Trim ().ToCecilName ()) {
+ i = -1;
+ break;
+ }
+ }
+
+ if (i < 0)
+ continue;
+
+ MarkIndirectlyCalledMethod (m);
+ marked = true;
+ }
+
+ return marked;
+ }
+
+ bool MarkDependencyField (TypeDefinition type, string name)
+ {
+ foreach (var f in type.Fields) {
+ if (f.Name == name) {
+ MarkField (f);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void LazyMarkCustomAttributes (ICustomAttributeProvider provider, AssemblyDefinition assembly)
+ {
+ if (!provider.HasCustomAttributes)
+ return;
+
+ foreach (CustomAttribute ca in provider.CustomAttributes)
+ _assemblyLevelAttributes.Enqueue (new AttributeProviderPair (ca, assembly));
+ }
+
+ protected virtual void MarkCustomAttribute (CustomAttribute ca)
+ {
+ Tracer.Push ((object) ca.AttributeType ?? (object) ca);
+ try {
+ Annotations.Mark (ca);
+ MarkMethod (ca.Constructor);
+
+ MarkCustomAttributeArguments (ca);
+
+ TypeReference constructor_type = ca.Constructor.DeclaringType;
+ TypeDefinition type = constructor_type.Resolve ();
+
+ if (type is null) {
+ HandleUnresolvedType (constructor_type);
+ return;
+ }
+
+ MarkCustomAttributeProperties (ca, type);
+ MarkCustomAttributeFields (ca, type);
+ } finally {
+ Tracer.Pop ();
+ }
+ }
+
+ protected virtual bool ShouldMarkCustomAttribute (CustomAttribute ca, ICustomAttributeProvider provider)
+ {
+ var attr_type = ca.AttributeType;
+
+ if (_context.KeepUsedAttributeTypesOnly) {
+ switch (attr_type.FullName) {
+ // These are required by the runtime
+ case "System.ThreadStaticAttribute":
+ case "System.ContextStaticAttribute":
+ case "System.Runtime.CompilerServices.IsByRefLikeAttribute":
+ return true;
+ // Attributes related to `fixed` keyword used to declare fixed length arrays
+ case "System.Runtime.CompilerServices.FixedBufferAttribute":
+ return true;
+ case "System.Runtime.InteropServices.InterfaceTypeAttribute":
+ case "System.Runtime.InteropServices.GuidAttribute":
+ case "System.Runtime.CompilerServices.InternalsVisibleToAttribute":
+ return true;
+ }
+
+ if (!Annotations.IsMarked (attr_type.Resolve ()))
+ return false;
+ }
+
+ return true;
+ }
+
+ protected virtual bool ShouldMarkTypeStaticConstructor (TypeDefinition type)
+ {
+ if (Annotations.HasPreservedStaticCtor (type))
+ return false;
+
+ if (type.IsBeforeFieldInit && _context.IsOptimizationEnabled (CodeOptimizations.BeforeFieldInit))
+ return false;
+
+ return true;
+ }
+
+ protected void MarkStaticConstructor (TypeDefinition type)
+ {
+ if (MarkMethodIf (type.Methods, IsNonEmptyStaticConstructor) is not null)
+ Annotations.SetPreservedStaticCtor (type);
+ }
+
+ protected virtual bool ShouldMarkTopLevelCustomAttribute (AttributeProviderPair app, MethodDefinition resolvedConstructor)
+ {
+ var ca = app.Attribute;
+
+ if (!ShouldMarkCustomAttribute (app.Attribute, app.Provider))
+ return false;
+
+ // If an attribute's module has not been marked after processing all types in all assemblies and the attribute itself has not been marked,
+ // then surely nothing is using this attribute and there is no need to mark it
+ if (!Annotations.IsMarked (resolvedConstructor.Module) &&
+ !Annotations.IsMarked (ca.AttributeType) &&
+ Annotations.GetAction (resolvedConstructor.Module.Assembly) == AssemblyAction.Link)
+ return false;
+
+ if (ca.Constructor.DeclaringType.Namespace == "System.Diagnostics") {
+ string attributeName = ca.Constructor.DeclaringType.Name;
+ if (attributeName == "DebuggerDisplayAttribute" || attributeName == "DebuggerTypeProxyAttribute") {
+ var displayTargetType = GetDebuggerAttributeTargetType (app.Attribute, (AssemblyDefinition) app.Provider);
+ if (displayTargetType is null || !Annotations.IsMarked (displayTargetType))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected void MarkSecurityDeclarations (ISecurityDeclarationProvider provider)
+ {
+ // most security declarations are removed (if linked) but user code might still have some
+ // and if the attributes references types then they need to be marked too
+ if ((provider is null) || !provider.HasSecurityDeclarations)
+ return;
+
+ foreach (var sd in provider.SecurityDeclarations)
+ MarkSecurityDeclaration (sd);
+ }
+
+ protected virtual void MarkSecurityDeclaration (SecurityDeclaration sd)
+ {
+ if (!sd.HasSecurityAttributes)
+ return;
+
+ foreach (var sa in sd.SecurityAttributes)
+ MarkSecurityAttribute (sa);
+ }
+
+ protected virtual void MarkSecurityAttribute (SecurityAttribute sa)
+ {
+ TypeReference security_type = sa.AttributeType;
+ TypeDefinition type = security_type.Resolve ();
+ if (type is null) {
+ HandleUnresolvedType (security_type);
+ return;
+ }
+
+ MarkType (security_type);
+ MarkSecurityAttributeProperties (sa, type);
+ MarkSecurityAttributeFields (sa, type);
+ }
+
+ protected void MarkSecurityAttributeProperties (SecurityAttribute sa, TypeDefinition attribute)
+ {
+ if (!sa.HasProperties)
+ return;
+
+ foreach (var named_argument in sa.Properties)
+ MarkCustomAttributeProperty (named_argument, attribute);
+ }
+
+ protected void MarkSecurityAttributeFields (SecurityAttribute sa, TypeDefinition attribute)
+ {
+ if (!sa.HasFields)
+ return;
+
+ foreach (var named_argument in sa.Fields)
+ MarkCustomAttributeField (named_argument, attribute);
+ }
+
+ protected void MarkCustomAttributeProperties (CustomAttribute ca, TypeDefinition attribute)
+ {
+ if (!ca.HasProperties)
+ return;
+
+ foreach (var named_argument in ca.Properties)
+ MarkCustomAttributeProperty (named_argument, attribute);
+ }
+
+ protected void MarkCustomAttributeProperty (CustomAttributeNamedArgument namedArgument, TypeDefinition attribute)
+ {
+ PropertyDefinition property = GetProperty (attribute, namedArgument.Name);
+ Tracer.Push (property);
+ if (property is not null)
+ MarkMethod (property.SetMethod);
+
+ MarkCustomAttributeArgument (namedArgument.Argument);
+ Tracer.Pop ();
+ }
+
+ PropertyDefinition GetProperty (TypeDefinition type, string propertyname)
+ {
+ while (type is not null) {
+ PropertyDefinition property = type.Properties.FirstOrDefault (p => p.Name == propertyname);
+ if (property is not null)
+ return property;
+
+ type = type.BaseType?.Resolve ();
+ }
+
+ return null;
+ }
+
+ protected void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute)
+ {
+ if (!ca.HasFields)
+ return;
+
+ foreach (var named_argument in ca.Fields)
+ MarkCustomAttributeField (named_argument, attribute);
+ }
+
+ protected void MarkCustomAttributeField (CustomAttributeNamedArgument namedArgument, TypeDefinition attribute)
+ {
+ FieldDefinition field = GetField (attribute, namedArgument.Name);
+ if (field is not null)
+ MarkField (field);
+
+ MarkCustomAttributeArgument (namedArgument.Argument);
+ }
+
+ FieldDefinition GetField (TypeDefinition type, string fieldname)
+ {
+ while (type is not null) {
+ FieldDefinition field = type.Fields.FirstOrDefault (f => f.Name == fieldname);
+ if (field is not null)
+ return field;
+
+ type = type.BaseType?.Resolve ();
+ }
+
+ return null;
+ }
+
+ MethodDefinition GetMethodWithNoParameters (TypeDefinition type, string methodname)
+ {
+ while (type is not null) {
+ MethodDefinition method = type.Methods.FirstOrDefault (m => m.Name == methodname && !m.HasParameters);
+ if (method is not null)
+ return method;
+
+ type = type.BaseType.Resolve ();
+ }
+
+ return null;
+ }
+
+ void MarkCustomAttributeArguments (CustomAttribute ca)
+ {
+ if (!ca.HasConstructorArguments)
+ return;
+
+ foreach (var argument in ca.ConstructorArguments)
+ MarkCustomAttributeArgument (argument);
+ }
+
+ void MarkCustomAttributeArgument (CustomAttributeArgument argument)
+ {
+ var at = argument.Type;
+
+ if (at.IsArray) {
+ var et = at.GetElementType ();
+
+ MarkType (et);
+ if (argument.Value is null)
+ return;
+
+ foreach (var caa in (CustomAttributeArgument []) argument.Value)
+ MarkCustomAttributeArgument (caa);
+
+ return;
+ }
+
+ if (at.Namespace == "System") {
+ switch (at.Name) {
+ case "Type":
+ MarkType (argument.Type);
+ MarkType ((TypeReference) argument.Value);
+ return;
+
+ case "Object":
+ var boxed_value = (CustomAttributeArgument) argument.Value;
+ MarkType (boxed_value.Type);
+ MarkCustomAttributeArgument (boxed_value);
+ return;
+ }
+ }
+ }
+
+ protected bool CheckProcessed (IMetadataTokenProvider provider)
+ {
+ if (Annotations.IsProcessed (provider))
+ return true;
+
+ Annotations.Processed (provider);
+ return false;
+ }
+
+ protected void MarkAssembly (AssemblyDefinition assembly)
+ {
+ if (CheckProcessed (assembly))
+ return;
+
+ ProcessModule (assembly);
+
+ MarkAssemblyCustomAttributes (assembly);
+
+ MarkSecurityDeclarations (assembly);
+
+ foreach (ModuleDefinition module in assembly.Modules)
+ LazyMarkCustomAttributes (module, assembly);
+ }
+
+ void MarkEntireAssembly (AssemblyDefinition assembly)
+ {
+ MarkCustomAttributes (assembly);
+ MarkCustomAttributes (assembly.MainModule);
+
+ if (assembly.MainModule.HasExportedTypes) {
+ // TODO: This needs more work accross all steps
+ }
+
+ foreach (TypeDefinition type in assembly.MainModule.Types)
+ MarkEntireType (type);
+ }
+
+ void ProcessModule (AssemblyDefinition assembly)
+ {
+ // Pre-mark if there is any methods as they need to be executed
+ // at assembly load time
+ foreach (TypeDefinition type in assembly.MainModule.Types) {
+ if (type.Name == "" && type.HasMethods) {
+ MarkType (type);
+ break;
+ }
+ }
+ }
+
+ bool ProcessLazyAttributes ()
+ {
+ if (Annotations.HasMarkedAnyIndirectlyCalledMethods () && MarkDisablePrivateReflectionAttribute ())
+ return true;
+
+ var startingQueueCount = _assemblyLevelAttributes.Count;
+ if (startingQueueCount == 0)
+ return false;
+
+ var skippedItems = new List ();
+ var markOccurred = false;
+
+ while (_assemblyLevelAttributes.Count != 0) {
+ var assemblyLevelAttribute = _assemblyLevelAttributes.Dequeue ();
+ var customAttribute = assemblyLevelAttribute.Attribute;
+
+ var resolved = customAttribute.Constructor.Resolve ();
+ if (resolved is null) {
+ HandleUnresolvedMethod (customAttribute.Constructor);
+ continue;
+ }
+
+ if (!ShouldMarkTopLevelCustomAttribute (assemblyLevelAttribute, resolved)) {
+ skippedItems.Add (assemblyLevelAttribute);
+ continue;
+ }
+
+ string attributeFullName = customAttribute.Constructor.DeclaringType.FullName;
+ switch (attributeFullName) {
+ case "System.Diagnostics.DebuggerDisplayAttribute":
+ MarkTypeWithDebuggerDisplayAttribute (GetDebuggerAttributeTargetType (assemblyLevelAttribute.Attribute, (AssemblyDefinition) assemblyLevelAttribute.Provider), customAttribute);
+ break;
+ case "System.Diagnostics.DebuggerTypeProxyAttribute":
+ MarkTypeWithDebuggerTypeProxyAttribute (GetDebuggerAttributeTargetType (assemblyLevelAttribute.Attribute, (AssemblyDefinition) assemblyLevelAttribute.Provider), customAttribute);
+ break;
+ }
+
+ markOccurred = true;
+ MarkCustomAttribute (customAttribute);
+ }
+
+ // requeue the items we skipped in case we need to make another pass
+ foreach (var item in skippedItems)
+ _assemblyLevelAttributes.Enqueue (item);
+
+ return markOccurred;
+ }
+
+ bool ProcessLateMarkedAttributes ()
+ {
+ var startingQueueCount = _lateMarkedAttributes.Count;
+ if (startingQueueCount == 0)
+ return false;
+
+ var skippedItems = new List ();
+ var markOccurred = false;
+
+ while (_lateMarkedAttributes.Count != 0) {
+ var attributeProviderPair = _lateMarkedAttributes.Dequeue ();
+ var customAttribute = attributeProviderPair.Attribute;
+
+ var resolved = customAttribute.Constructor.Resolve ();
+ if (resolved is null) {
+ HandleUnresolvedMethod (customAttribute.Constructor);
+ continue;
+ }
+
+ if (!ShouldMarkCustomAttribute (customAttribute, attributeProviderPair.Provider)) {
+ skippedItems.Add (attributeProviderPair);
+ continue;
+ }
+
+ markOccurred = true;
+ MarkCustomAttribute (customAttribute);
+ MarkSpecialCustomAttributeDependencies (customAttribute);
+ }
+
+ // requeue the items we skipped in case we need to make another pass
+ foreach (var item in skippedItems)
+ _lateMarkedAttributes.Enqueue (item);
+
+ return markOccurred;
+ }
+
+ protected void MarkField (FieldReference reference)
+ {
+ if (reference.DeclaringType is GenericInstanceType)
+ MarkType (reference.DeclaringType);
+
+ FieldDefinition field = reference.Resolve ();
+
+ if (field is null) {
+ HandleUnresolvedField (reference);
+ return;
+ }
+
+ MarkField (field);
+ }
+
+ void MarkField (FieldDefinition field)
+ {
+ if (CheckProcessed (field))
+ return;
+
+ MarkType (field.DeclaringType);
+ MarkType (field.FieldType);
+ MarkCustomAttributes (field);
+ MarkMarshalSpec (field);
+ DoAdditionalFieldProcessing (field);
+
+ var parent = field.DeclaringType;
+ if (!Annotations.HasPreservedStaticCtor (parent))
+ MarkStaticConstructor (parent);
+
+ if (Annotations.HasSubstitutedInit (field)) {
+ Annotations.SetPreservedStaticCtor (parent);
+ Annotations.SetSubstitutedInit (parent);
+ }
+
+ Annotations.Mark (field);
+ }
+
+ protected virtual bool IgnoreScope (IMetadataScope scope)
+ {
+ AssemblyDefinition assembly = ResolveAssembly (scope);
+ return Annotations.GetAction (assembly) != AssemblyAction.Link;
+ }
+
+ void MarkScope (IMetadataScope scope)
+ {
+ if (scope is IMetadataTokenProvider provider)
+ Annotations.Mark (provider);
+ }
+
+ protected virtual void MarkSerializable (TypeDefinition type)
+ {
+ MarkDefaultConstructor (type);
+ MarkMethodsIf (type.Methods, IsSpecialSerializationConstructor);
+ }
+
+ protected virtual TypeDefinition MarkType (TypeReference reference)
+ {
+ if (reference is null)
+ return null;
+
+ reference = GetOriginalType (reference);
+
+ if (reference is FunctionPointerType)
+ return null;
+
+ if (reference is GenericParameter)
+ return null;
+
+ // if (IgnoreScope (reference.Scope))
+ // return null;
+
+ TypeDefinition type = reference.Resolve ();
+
+ if (type is null) {
+ HandleUnresolvedType (reference);
+ return null;
+ }
+
+ if (CheckProcessed (type))
+ return null;
+
+ Tracer.Push (type);
+
+ MarkScope (type.Scope);
+ MarkType (type.BaseType);
+ MarkType (type.DeclaringType);
+ MarkCustomAttributes (type);
+ MarkSecurityDeclarations (type);
+
+ if (type.IsMulticastDelegate ()) {
+ MarkMulticastDelegate (type);
+ }
+
+ if (type.IsSerializable ())
+ MarkSerializable (type);
+
+ if (!_context.IsFeatureExcluded ("etw") && BCL.EventTracingForWindows.IsEventSourceImplementation (type, _context)) {
+ MarkEventSourceProviders (type);
+ }
+
+ MarkTypeSpecialCustomAttributes (type);
+
+ MarkGenericParameterProvider (type);
+
+ // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
+ if (type.IsValueType || !type.IsAutoLayout)
+ MarkFields (type, type.IsEnum);
+
+ // There are a number of markings we can defer until later when we know it's possible a reference type could be instantiated
+ // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type
+ // However, for some other types there is no benefit to deferring
+ if (type.IsInterface) {
+ // There's no benefit to deferring processing of an interface type until we know a type implementing that interface is marked
+ MarkRequirementsForInstantiatedTypes (type);
+ } else if (type.IsValueType) {
+ // Note : Technically interfaces could be removed from value types in some of the same cases as reference types, however, it's harder to know when
+ // a value type instance could exist. You'd have to track initobj and maybe locals types. Going to punt for now.
+ MarkRequirementsForInstantiatedTypes (type);
+ } else if (IsFullyPreserved (type)) {
+ // Here for a couple reasons:
+ // * Edge case to cover a scenario where a type has preserve all, implements interfaces, but does not have any instance ctors.
+ // Normally TypePreserve.All would cause an instance ctor to be marked and that would in turn lead to MarkInterfaceImplementations being called
+ // Without an instance ctor, MarkInterfaceImplementations is not called and then TypePreserve.All isn't truly respected.
+ // * If an assembly has the action Copy and had ResolveFromAssemblyStep ran for the assembly, then InitializeType will have led us here
+ // When the entire assembly is preserved, then all interfaces, base, etc will be preserved on the type, so we need to make sure
+ // all of these types are marked. For example, if an interface implementation is of a type in another assembly that is linked,
+ // and there are no other usages of that interface type, then we need to make sure the interface type is still marked because
+ // this type is going to retain the interface implementation
+ MarkRequirementsForInstantiatedTypes (type);
+ } else if (AlwaysMarkTypeAsInstantiated (type)) {
+ MarkRequirementsForInstantiatedTypes (type);
+ }
+
+ if (type.HasInterfaces)
+ _typesWithInterfaces.Add (type);
+
+ if (type.HasMethods) {
+ MarkMethodsIf (type.Methods, IsVirtualNeededByTypeDueToPreservedScope);
+ if (ShouldMarkTypeStaticConstructor (type))
+ MarkStaticConstructor (type);
+
+ MarkMethodsIf (type.Methods, HasSerializationAttribute);
+ }
+
+ DoAdditionalTypeProcessing (type);
+
+ Tracer.Pop ();
+
+ Annotations.Mark (type);
+
+ ApplyPreserveInfo (type);
+
+ return type;
+ }
+
+ // Allow subclassers to mark additional things in the main processing loop
+ protected virtual void DoAdditionalProcessing ()
+ {
+ }
+
+ // Allow subclassers to mark additional things
+ protected virtual void DoAdditionalTypeProcessing (TypeDefinition type)
+ {
+ }
+
+ // Allow subclassers to mark additional things
+ protected virtual void DoAdditionalFieldProcessing (FieldDefinition field)
+ {
+ }
+
+ // Allow subclassers to mark additional things
+ protected virtual void DoAdditionalPropertyProcessing (PropertyDefinition property)
+ {
+ }
+
+ // Allow subclassers to mark additional things
+ protected virtual void DoAdditionalEventProcessing (EventDefinition evt)
+ {
+ }
+
+ // Allow subclassers to mark additional things
+ protected virtual void DoAdditionalInstantiatedTypeProcessing (TypeDefinition type)
+ {
+ }
+
+ void MarkAssemblyCustomAttributes (AssemblyDefinition assembly)
+ {
+ if (!assembly.HasCustomAttributes)
+ return;
+
+ foreach (CustomAttribute attribute in assembly.CustomAttributes)
+ _assemblyLevelAttributes.Enqueue (new AttributeProviderPair (attribute, assembly));
+ }
+
+ TypeDefinition GetDebuggerAttributeTargetType (CustomAttribute ca, AssemblyDefinition asm)
+ {
+ TypeReference targetTypeReference = null;
+ foreach (var property in ca.Properties) {
+ if (property.Name == "Target") {
+ targetTypeReference = (TypeReference) property.Argument.Value;
+ break;
+ }
+
+ if (property.Name == "TargetTypeName") {
+ if (TypeNameParser.TryParseTypeAssemblyQualifiedName ((string) property.Argument.Value, out string typeName, out string assemblyName)) {
+ if (string.IsNullOrEmpty (assemblyName))
+ targetTypeReference = asm.MainModule.GetType (typeName);
+ else
+ targetTypeReference = _context.GetAssemblies ().FirstOrDefault (a => a.Name.Name == assemblyName)?.MainModule.GetType (typeName);
+ }
+ break;
+ }
+ }
+
+ return targetTypeReference?.Resolve ();
+ }
+
+ void MarkTypeSpecialCustomAttributes (TypeDefinition type)
+ {
+ if (!type.HasCustomAttributes)
+ return;
+
+ foreach (CustomAttribute attribute in type.CustomAttributes) {
+ var attrType = attribute.Constructor.DeclaringType;
+ switch (attrType.Name) {
+ case "XmlSchemaProviderAttribute" when attrType.Namespace == "System.Xml.Serialization":
+ MarkXmlSchemaProvider (type, attribute);
+ break;
+ case "DebuggerDisplayAttribute" when attrType.Namespace == "System.Diagnostics":
+ MarkTypeWithDebuggerDisplayAttribute (type, attribute);
+ break;
+ case "DebuggerTypeProxyAttribute" when attrType.Namespace == "System.Diagnostics":
+ MarkTypeWithDebuggerTypeProxyAttribute (type, attribute);
+ break;
+ case "EventDataAttribute" when attrType.Namespace == "System.Diagnostics.Tracing":
+ MarkMethodsIf (type.Methods, MethodDefinitionExtensions.IsPublicInstancePropertyMethod);
+ break;
+ case "TypeDescriptionProviderAttribute" when attrType.Namespace == "System.ComponentModel":
+ MarkTypeConverterLikeDependency (attribute, l => l.IsDefaultConstructor ());
+ break;
+ }
+ }
+ }
+
+ //
+ // Used for known framework attributes which can be applied to any element
+ //
+ bool MarkSpecialCustomAttributeDependencies (CustomAttribute ca)
+ {
+ var dt = ca.Constructor.DeclaringType;
+ if (dt.Name == "TypeConverterAttribute" && dt.Namespace == "System.ComponentModel") {
+ MarkTypeConverterLikeDependency (ca, l =>
+ l.IsDefaultConstructor () ||
+ l.Parameters.Count == 1 && l.Parameters [0].ParameterType.IsTypeOf ("System", "Type"));
+ return true;
+ }
+
+ return false;
+ }
+
+ void MarkMethodSpecialCustomAttributes (MethodDefinition method)
+ {
+ if (!method.HasCustomAttributes)
+ return;
+
+ foreach (CustomAttribute attribute in method.CustomAttributes) {
+ switch (attribute.Constructor.DeclaringType.FullName) {
+ case "System.Web.Services.Protocols.SoapHeaderAttribute":
+ MarkSoapHeader (method, attribute);
+ break;
+ }
+ }
+ }
+
+ void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
+ {
+ if (TryGetStringArgument (attribute, out string name))
+ MarkNamedMethod (type, name);
+ }
+
+ protected virtual void MarkTypeConverterLikeDependency (CustomAttribute attribute, Func predicate)
+ {
+ var args = attribute.ConstructorArguments;
+ if (args.Count < 1)
+ return;
+
+ TypeDefinition tdef = null;
+ switch (attribute.ConstructorArguments [0].Value) {
+ case string s:
+ tdef = ResolveFullyQualifiedTypeName (s);
+ break;
+ case TypeReference type:
+ tdef = type.Resolve ();
+ break;
+ }
+
+ if (tdef is null)
+ return;
+
+ MarkMethodsIf (tdef.Methods, predicate);
+ }
+
+ void MarkTypeWithDebuggerDisplayAttribute (TypeDefinition type, CustomAttribute attribute)
+ {
+ if (_context.KeepMembersForDebugger) {
+
+ string displayString = (string) attribute.ConstructorArguments [0].Value;
+
+ Regex regex = new Regex ("{[^{}]+}", RegexOptions.Compiled);
+
+ foreach (Match match in regex.Matches (displayString)) {
+ // Remove '{' and '}'
+ string realMatch = match.Value.Substring (1, match.Value.Length - 2);
+
+ // Remove ",nq" suffix if present
+ // (it asks the expression evaluator to remove the quotes when displaying the final value)
+ if (Regex.IsMatch (realMatch, @".+,\s*nq")) {
+ realMatch = realMatch.Substring (0, realMatch.LastIndexOf (','));
+ }
+
+ if (realMatch.EndsWith ("()")) {
+ string methodName = realMatch.Substring (0, realMatch.Length - 2);
+ MethodDefinition method = GetMethodWithNoParameters (type, methodName);
+ if (method is not null) {
+ MarkMethod (method);
+ continue;
+ }
+ } else {
+ FieldDefinition field = GetField (type, realMatch);
+ if (field is not null) {
+ MarkField (field);
+ continue;
+ }
+
+ PropertyDefinition property = GetProperty (type, realMatch);
+ if (property is not null) {
+ if (property.GetMethod is not null) {
+ MarkMethod (property.GetMethod);
+ }
+ if (property.SetMethod is not null) {
+ MarkMethod (property.SetMethod);
+ }
+ continue;
+ }
+ }
+
+ while (type is not null) {
+ MarkMethods (type);
+ MarkFields (type, includeStatic: true);
+ type = type.BaseType?.Resolve ();
+ }
+ return;
+ }
+ }
+ }
+
+ void MarkTypeWithDebuggerTypeProxyAttribute (TypeDefinition type, CustomAttribute attribute)
+ {
+ if (_context.KeepMembersForDebugger) {
+ object constructorArgument = attribute.ConstructorArguments [0].Value;
+ TypeReference proxyTypeReference = constructorArgument as TypeReference;
+ if (proxyTypeReference is null) {
+ if (constructorArgument is string proxyTypeReferenceString) {
+ proxyTypeReference = type.Module.GetType (proxyTypeReferenceString, runtimeName: true);
+ }
+ }
+
+ if (proxyTypeReference is null) {
+ return;
+ }
+
+ MarkType (proxyTypeReference);
+
+ TypeDefinition proxyType = proxyTypeReference.Resolve ();
+ if (proxyType is not null) {
+ MarkMethods (proxyType);
+ MarkFields (proxyType, includeStatic: true);
+ }
+ }
+ }
+
+ static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
+ {
+ argument = null;
+
+ if (attribute.ConstructorArguments.Count < 1)
+ return false;
+
+ argument = attribute.ConstructorArguments [0].Value as string;
+
+ return argument is not null;
+ }
+
+ protected int MarkNamedMethod (TypeDefinition type, string method_name)
+ {
+ if (!type.HasMethods)
+ return 0;
+
+ int count = 0;
+ foreach (MethodDefinition method in type.Methods) {
+ if (method.Name != method_name)
+ continue;
+
+ MarkMethod (method);
+ count++;
+ }
+
+ return count;
+ }
+
+ void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
+ {
+ if (!TryGetStringArgument (attribute, out string member_name))
+ return;
+
+ MarkNamedField (method.DeclaringType, member_name);
+ MarkNamedProperty (method.DeclaringType, member_name);
+ }
+
+ void MarkNamedField (TypeDefinition type, string field_name)
+ {
+ if (!type.HasFields)
+ return;
+
+ foreach (FieldDefinition field in type.Fields) {
+ if (field.Name != field_name)
+ continue;
+
+ MarkField (field);
+ }
+ }
+
+ void MarkNamedProperty (TypeDefinition type, string property_name)
+ {
+ if (!type.HasProperties)
+ return;
+
+ foreach (PropertyDefinition property in type.Properties) {
+ if (property.Name != property_name)
+ continue;
+
+ Tracer.Push (property);
+ MarkMethod (property.GetMethod);
+ MarkMethod (property.SetMethod);
+ Tracer.Pop ();
+ }
+ }
+
+ void MarkInterfaceImplementations (TypeDefinition type)
+ {
+ if (!type.HasInterfaces)
+ return;
+
+ foreach (var iface in type.Interfaces) {
+ // Only mark interface implementations of interface types that have been marked.
+ // This enables stripping of interfaces that are never used
+ var resolvedInterfaceType = iface.InterfaceType.Resolve ();
+ if (resolvedInterfaceType is null) {
+ HandleUnresolvedType (iface.InterfaceType);
+ continue;
+ }
+
+ if (ShouldMarkInterfaceImplementation (type, iface, resolvedInterfaceType))
+ MarkInterfaceImplementation (iface);
+ }
+ }
+
+ void MarkGenericParameterProvider (IGenericParameterProvider provider)
+ {
+ if (!provider.HasGenericParameters)
+ return;
+
+ foreach (GenericParameter parameter in provider.GenericParameters)
+ MarkGenericParameter (parameter);
+ }
+
+ void MarkGenericParameter (GenericParameter parameter)
+ {
+ MarkCustomAttributes (parameter);
+ if (!parameter.HasConstraints)
+ return;
+
+ foreach (var constraint in parameter.Constraints) {
+ MarkCustomAttributes (constraint);
+ MarkType (constraint.ConstraintType);
+ }
+ }
+
+ bool IsVirtualNeededByTypeDueToPreservedScope (MethodDefinition method)
+ {
+ if (!method.IsVirtual)
+ return false;
+
+ var base_list = Annotations.GetBaseMethods (method);
+ if (base_list is null)
+ return false;
+
+ foreach (MethodDefinition @base in base_list) {
+ // Just because the type is marked does not mean we need interface methods.
+ // if the type is never instantiated, interfaces will be removed
+ if (@base.DeclaringType.IsInterface)
+ continue;
+
+ // If the type is marked, we need to keep overrides of abstract members defined in assemblies
+ // that are copied. However, if the base method is virtual, then we don't need to keep the override
+ // until the type could be instantiated
+ if (!@base.IsAbstract)
+ continue;
+
+ if (IgnoreScope (@base.DeclaringType.Scope))
+ return true;
+
+ if (IsVirtualNeededByTypeDueToPreservedScope (@base))
+ return true;
+ }
+
+ return false;
+ }
+
+ bool IsVirtualNeededByInstantiatedTypeDueToPreservedScope (MethodDefinition method)
+ {
+ if (!method.IsVirtual)
+ return false;
+
+ var base_list = Annotations.GetBaseMethods (method);
+ if (base_list is null)
+ return false;
+
+ foreach (MethodDefinition @base in base_list) {
+ if (IgnoreScope (@base.DeclaringType.Scope))
+ return true;
+
+ if (IsVirtualNeededByTypeDueToPreservedScope (@base))
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool IsSpecialSerializationConstructor (MethodDefinition method)
+ {
+ if (!method.IsInstanceConstructor ())
+ return false;
+
+ var parameters = method.Parameters;
+ if (parameters.Count != 2)
+ return false;
+
+ return parameters [0].ParameterType.Name == "SerializationInfo" &&
+ parameters [1].ParameterType.Name == "StreamingContext";
+ }
+
+ protected void MarkMethodsIf (Collection methods, Func predicate)
+ {
+ foreach (MethodDefinition method in methods)
+ if (predicate (method))
+ MarkMethod (method);
+ }
+
+ protected MethodDefinition MarkMethodIf (Collection methods, Func predicate)
+ {
+ foreach (MethodDefinition method in methods) {
+ if (predicate (method)) {
+ return MarkMethod (method);
+ }
+ }
+
+ return null;
+ }
+
+ protected bool MarkDefaultConstructor (TypeDefinition type)
+ {
+ if (type?.HasMethods != true)
+ return false;
+
+ return MarkMethodIf (type.Methods, MethodDefinitionExtensions.IsDefaultConstructor) is not null;
+ }
+
+ static bool IsNonEmptyStaticConstructor (MethodDefinition method)
+ {
+ if (!method.IsStaticConstructor ())
+ return false;
+
+ if (!method.HasBody || !method.IsIL)
+ return true;
+
+ if (method.Body.CodeSize != 1)
+ return true;
+
+ return method.Body.Instructions [0].OpCode.Code != Code.Ret;
+ }
+
+ static bool HasSerializationAttribute (MethodDefinition method)
+ {
+ if (!method.HasCustomAttributes)
+ return false;
+ foreach (var ca in method.CustomAttributes) {
+ var cat = ca.AttributeType;
+ if (cat.Namespace != "System.Runtime.Serialization")
+ continue;
+ switch (cat.Name) {
+ case "OnDeserializedAttribute":
+ case "OnDeserializingAttribute":
+ case "OnSerializedAttribute":
+ case "OnSerializingAttribute":
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected virtual bool AlwaysMarkTypeAsInstantiated (TypeDefinition td)
+ {
+ switch (td.Name) {
+ // These types are created from native code which means we are unable to track when they are instantiated
+ // Since these are such foundational types, let's take the easy route and just always assume an instance of one of these
+ // could exist
+ case "Delegate":
+ case "MulticastDelegate":
+ case "ValueType":
+ case "Enum":
+ return td.Namespace == "System";
+ }
+
+ return false;
+ }
+
+ void MarkEventSourceProviders (TypeDefinition td)
+ {
+ foreach (var nestedType in td.NestedTypes) {
+ if (BCL.EventTracingForWindows.IsProviderName (nestedType.Name))
+ MarkStaticFields (nestedType);
+ }
+ }
+
+ protected virtual void MarkMulticastDelegate (TypeDefinition type)
+ {
+ MarkMethodCollection (type.Methods);
+ }
+
+ TypeDefinition ResolveFullyQualifiedTypeName (string name)
+ {
+ if (!TypeNameParser.TryParseTypeAssemblyQualifiedName (name, out string typeName, out string assemblyName))
+ return null;
+
+ foreach (var assemblyDefinition in _context.GetAssemblies ()) {
+ if (assemblyName is not null && assemblyDefinition.Name.Name != assemblyName)
+ continue;
+
+ var foundType = assemblyDefinition.MainModule.GetType (typeName);
+ if (foundType is null)
+ continue;
+
+ return foundType;
+ }
+
+ return null;
+ }
+
+ protected TypeReference GetOriginalType (TypeReference type)
+ {
+ while (type is TypeSpecification) {
+ if (type is GenericInstanceType git)
+ MarkGenericArguments (git);
+
+ if (type is IModifierType mod)
+ MarkModifierType (mod);
+
+ if (type is FunctionPointerType fnptr) {
+ MarkParameters (fnptr);
+ MarkType (fnptr.ReturnType);
+ break; // FunctionPointerType is the original type
+ }
+
+ type = ((TypeSpecification) type).ElementType;
+ }
+
+ return type;
+ }
+
+ void MarkParameters (FunctionPointerType fnptr)
+ {
+ if (!fnptr.HasParameters)
+ return;
+
+ for (int i = 0; i < fnptr.Parameters.Count; i++) {
+ MarkType (fnptr.Parameters [i].ParameterType);
+ }
+ }
+
+ void MarkModifierType (IModifierType mod)
+ {
+ MarkType (mod.ModifierType);
+ }
+
+ void MarkGenericArguments (IGenericInstance instance)
+ {
+ foreach (TypeReference argument in instance.GenericArguments)
+ MarkType (argument);
+
+ MarkGenericArgumentConstructors (instance);
+ }
+
+ void MarkGenericArgumentConstructors (IGenericInstance instance)
+ {
+ var arguments = instance.GenericArguments;
+
+ var generic_element = GetGenericProviderFromInstance (instance);
+ if (generic_element is null)
+ return;
+
+ var parameters = generic_element.GenericParameters;
+
+ if (arguments.Count != parameters.Count)
+ return;
+
+ for (int i = 0; i < arguments.Count; i++) {
+ var argument = arguments [i];
+ var parameter = parameters [i];
+
+ if (!parameter.HasDefaultConstructorConstraint)
+ continue;
+
+ var argument_definition = argument.Resolve ();
+ MarkDefaultConstructor (argument_definition);
+ }
+ }
+
+ static IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
+ {
+ if (instance is GenericInstanceMethod method)
+ return method.ElementMethod.Resolve ();
+
+ if (instance is GenericInstanceType type)
+ return type.ElementType.Resolve ();
+
+ return null;
+ }
+
+ void ApplyPreserveInfo (TypeDefinition type)
+ {
+ ApplyPreserveMethods (type);
+
+ if (!Annotations.TryGetPreserve (type, out TypePreserve preserve))
+ return;
+
+ switch (preserve) {
+ case TypePreserve.All:
+ MarkFields (type, true);
+ MarkMethods (type);
+ break;
+ case TypePreserve.Fields:
+ if (!MarkFields (type, true, true))
+ _context.LogMessage ($"Type {type.FullName} has no fields to preserve");
+ break;
+ case TypePreserve.Methods:
+ if (!MarkMethods (type))
+ _context.LogMessage ($"Type {type.FullName} has no methods to preserve");
+ break;
+ }
+ }
+
+ void ApplyPreserveMethods (TypeDefinition type)
+ {
+ var list = Annotations.GetPreservedMethods (type);
+ if (list is null)
+ return;
+
+ MarkMethodCollection (list);
+ }
+
+ void ApplyPreserveMethods (MethodDefinition method)
+ {
+ var list = Annotations.GetPreservedMethods (method);
+ if (list is null)
+ return;
+
+ MarkMethodCollection (list);
+ }
+
+ protected bool MarkFields (TypeDefinition type, bool includeStatic, bool markBackingFieldsOnlyIfPropertyMarked = false)
+ {
+ if (!type.HasFields)
+ return false;
+
+ foreach (FieldDefinition field in type.Fields) {
+ if (!includeStatic && field.IsStatic)
+ continue;
+
+ if (markBackingFieldsOnlyIfPropertyMarked && field.Name.EndsWith (">k__BackingField", StringComparison.Ordinal)) {
+ // We can't reliably construct the expected property name from the backing field name for all compilers
+ // because csc shortens the name of the backing field in some cases
+ // For example:
+ // Field Name = .Bar>k__BackingField
+ // Property Name = IFoo.Bar
+ //
+ // instead we will search the properties and find the one that makes use of the current backing field
+ var propertyDefinition = SearchPropertiesForMatchingFieldDefinition (field);
+ if (propertyDefinition is not null && !Annotations.IsMarked (propertyDefinition))
+ continue;
+ }
+ MarkField (field);
+ }
+
+ return true;
+ }
+
+ static PropertyDefinition SearchPropertiesForMatchingFieldDefinition (FieldDefinition field)
+ {
+ foreach (var property in field.DeclaringType.Properties) {
+ var instr = property.GetMethod?.Body?.Instructions;
+ if (instr is null)
+ continue;
+
+ foreach (var ins in instr) {
+ if (ins?.Operand == field)
+ return property;
+ }
+ }
+
+ return null;
+ }
+
+ protected void MarkStaticFields (TypeDefinition type)
+ {
+ if (!type.HasFields)
+ return;
+
+ foreach (FieldDefinition field in type.Fields) {
+ if (field.IsStatic)
+ MarkField (field);
+ }
+ }
+
+ protected virtual bool MarkMethods (TypeDefinition type)
+ {
+ if (!type.HasMethods)
+ return false;
+
+ MarkMethodCollection (type.Methods);
+ return true;
+ }
+
+ void MarkMethodCollection (IList methods)
+ {
+ foreach (MethodDefinition method in methods)
+ MarkMethod (method);
+ }
+
+ protected void MarkIndirectlyCalledMethod (MethodDefinition method)
+ {
+ MarkMethod (method);
+ Annotations.MarkIndirectlyCalledMethod (method);
+ }
+
+ protected virtual MethodDefinition MarkMethod (MethodReference reference)
+ {
+ reference = GetOriginalMethod (reference);
+
+ if (reference.DeclaringType is ArrayType)
+ return null;
+
+ Tracer.Push (reference);
+ if (reference.DeclaringType is GenericInstanceType)
+ MarkType (reference.DeclaringType);
+
+ // if (IgnoreScope (reference.DeclaringType.Scope))
+ // return;
+
+ MethodDefinition method = reference.Resolve ();
+
+ try {
+ if (method is null) {
+ HandleUnresolvedMethod (reference);
+ return null;
+ }
+
+ if (Annotations.GetAction (method) == MethodAction.Nothing)
+ Annotations.SetAction (method, MethodAction.Parse);
+
+ EnqueueMethod (method);
+ } finally {
+ Tracer.Pop ();
+ }
+ Tracer.AddDependency (method);
+
+ return method;
+ }
+
+ AssemblyDefinition ResolveAssembly (IMetadataScope scope)
+ {
+ AssemblyDefinition assembly = _context.Resolve (scope);
+ MarkAssembly (assembly);
+ return assembly;
+ }
+
+ protected MethodReference GetOriginalMethod (MethodReference method)
+ {
+ while (method is MethodSpecification) {
+ if (method is GenericInstanceMethod gim)
+ MarkGenericArguments (gim);
+
+ method = ((MethodSpecification) method).ElementMethod;
+ }
+
+ return method;
+ }
+
+ protected virtual void ProcessMethod (MethodDefinition method)
+ {
+ if (CheckProcessed (method))
+ return;
+
+ Tracer.Push (method);
+ MarkType (method.DeclaringType);
+ MarkCustomAttributes (method);
+ MarkSecurityDeclarations (method);
+
+ MarkGenericParameterProvider (method);
+
+ if (ShouldMarkAsInstancePossible (method))
+ MarkRequirementsForInstantiatedTypes (method.DeclaringType);
+
+ if (method.IsConstructor) {
+ if (!Annotations.ProcessSatelliteAssemblies && KnownMembers.IsSatelliteAssemblyMarker (method))
+ Annotations.ProcessSatelliteAssemblies = true;
+ } else if (method.IsPropertyMethod ())
+ MarkProperty (method.GetProperty ());
+ else if (method.IsEventMethod ())
+ MarkEvent (method.GetEvent ());
+
+ if (method.HasParameters) {
+ foreach (ParameterDefinition pd in method.Parameters) {
+ MarkType (pd.ParameterType);
+ MarkCustomAttributes (pd);
+ MarkMarshalSpec (pd);
+ }
+ }
+
+ if (method.HasOverrides) {
+ foreach (MethodReference ov in method.Overrides) {
+ MarkMethod (ov);
+ MarkExplicitInterfaceImplementation (method, ov);
+ }
+ }
+
+ MarkMethodSpecialCustomAttributes (method);
+
+ if (method.IsVirtual)
+ _virtual_methods.Add (method);
+
+ MarkNewCodeDependencies (method);
+
+ MarkBaseMethods (method);
+
+ MarkType (method.ReturnType);
+ MarkCustomAttributes (method.MethodReturnType);
+ MarkMarshalSpec (method.MethodReturnType);
+
+ if (method.IsPInvokeImpl || method.IsInternalCall) {
+ ProcessInteropMethod (method);
+ }
+
+ if (ShouldParseMethodBody (method))
+ MarkMethodBody (method.Body);
+
+ DoAdditionalMethodProcessing (method);
+
+ Annotations.Mark (method);
+
+ ApplyPreserveMethods (method);
+ Tracer.Pop ();
+ }
+
+ // Allow subclassers to mark additional things when marking a method
+ protected virtual void DoAdditionalMethodProcessing (MethodDefinition method)
+ {
+ }
+
+ protected virtual bool ShouldMarkAsInstancePossible (MethodDefinition method)
+ {
+ // We don't need to mark it multiple times
+ if (Annotations.IsInstantiated (method.DeclaringType))
+ return false;
+
+ if (method.IsInstanceConstructor ())
+ return true;
+
+ if (method.DeclaringType.IsInterface)
+ return true;
+
+ return false;
+ }
+
+ protected virtual void MarkRequirementsForInstantiatedTypes (TypeDefinition type)
+ {
+ if (Annotations.IsInstantiated (type))
+ return;
+
+ Annotations.MarkInstantiated (type);
+
+ MarkInterfaceImplementations (type);
+
+ foreach (var method in GetRequiredMethodsForInstantiatedType (type))
+ MarkMethod (method);
+
+ DoAdditionalInstantiatedTypeProcessing (type);
+ }
+
+ ///
+ /// Collect methods that must be marked once a type is determined to be instantiated.
+ ///
+ /// This method is virtual in order to give derived mark steps an opportunity to modify the collection of methods that are needed
+ ///
+ ///
+ ///
+ protected virtual IEnumerable GetRequiredMethodsForInstantiatedType (TypeDefinition type)
+ {
+ foreach (var method in type.Methods) {
+ if (method.IsFinalizer () || IsVirtualNeededByInstantiatedTypeDueToPreservedScope (method))
+ yield return method;
+ }
+ }
+
+ void MarkExplicitInterfaceImplementation (MethodDefinition method, MethodReference ov)
+ {
+ var resolvedOverride = ov.Resolve ();
+
+ if (resolvedOverride is null) {
+ HandleUnresolvedMethod (ov);
+ return;
+ }
+
+ if (resolvedOverride.DeclaringType.IsInterface) {
+ foreach (var ifaceImpl in method.DeclaringType.Interfaces) {
+ var resolvedInterfaceType = ifaceImpl.InterfaceType.Resolve ();
+ if (resolvedInterfaceType is null) {
+ HandleUnresolvedType (ifaceImpl.InterfaceType);
+ continue;
+ }
+
+ if (resolvedInterfaceType == resolvedOverride.DeclaringType) {
+ MarkInterfaceImplementation (ifaceImpl);
+ return;
+ }
+ }
+ }
+ }
+
+ void MarkNewCodeDependencies (MethodDefinition method)
+ {
+ switch (Annotations.GetAction (method)) {
+ case MethodAction.ConvertToStub:
+ if (!method.IsInstanceConstructor ())
+ return;
+
+ var baseType = method.DeclaringType.BaseType.Resolve ();
+ if (!MarkDefaultConstructor (baseType))
+ throw new NotSupportedException ($"Cannot stub constructor on '{method.DeclaringType}' when base type does not have default constructor");
+
+ break;
+
+ case MethodAction.ConvertToThrow:
+ MarkAndCacheConvertToThrowExceptionCtor ();
+ break;
+ }
+ }
+
+ protected virtual void MarkAndCacheConvertToThrowExceptionCtor ()
+ {
+ if (_context.MarkedKnownMembers.NotSupportedExceptionCtorString is not null)
+ return;
+
+ var nse = BCL.FindPredefinedType ("System", "NotSupportedException", _context);
+ if (nse is null)
+ throw new NotSupportedException ("Missing predefined 'System.NotSupportedException' type");
+
+ MarkType (nse);
+
+ var nseCtor = MarkMethodIf (nse.Methods, KnownMembers.IsNotSupportedExceptionCtorString);
+ if (nseCtor is null)
+ throw new MarkException ($"Could not find constructor on '{nse.FullName}'");
+
+ _context.MarkedKnownMembers.NotSupportedExceptionCtorString = nseCtor;
+
+ var objectType = BCL.FindPredefinedType ("System", "Object", _context);
+ if (objectType is null)
+ throw new NotSupportedException ("Missing predefined 'System.Object' type");
+
+ MarkType (objectType);
+
+ var objectCtor = MarkMethodIf (objectType.Methods, MethodDefinitionExtensions.IsDefaultConstructor);
+ if (objectCtor is null)
+ throw new MarkException ($"Could not find constructor on '{objectType.FullName}'");
+
+ _context.MarkedKnownMembers.ObjectCtor = objectCtor;
+ }
+
+ bool MarkDisablePrivateReflectionAttribute ()
+ {
+ if (_context.MarkedKnownMembers.DisablePrivateReflectionAttributeCtor is not null)
+ return false;
+
+ var nse = BCL.FindPredefinedType ("System.Runtime.CompilerServices", "DisablePrivateReflectionAttribute", _context);
+ if (nse is null)
+ throw new NotSupportedException ("Missing predefined 'System.Runtime.CompilerServices.DisablePrivateReflectionAttribute' type");
+
+ MarkType (nse);
+
+ var ctor = MarkMethodIf (nse.Methods, MethodDefinitionExtensions.IsDefaultConstructor);
+ if (ctor is null)
+ throw new MarkException ($"Could not find constructor on '{nse.FullName}'");
+
+ _context.MarkedKnownMembers.DisablePrivateReflectionAttributeCtor = ctor;
+ return true;
+ }
+
+ void MarkBaseMethods (MethodDefinition method)
+ {
+ var base_methods = Annotations.GetBaseMethods (method);
+ if (base_methods is null)
+ return;
+
+ foreach (MethodDefinition base_method in base_methods) {
+ if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
+ continue;
+
+ MarkMethod (base_method);
+ MarkBaseMethods (base_method);
+ }
+ }
+
+ void ProcessInteropMethod (MethodDefinition method)
+ {
+ TypeDefinition returnTypeDefinition = method.ReturnType.Resolve ();
+
+ const bool includeStaticFields = false;
+ if (returnTypeDefinition is not null && !returnTypeDefinition.IsImport) {
+ MarkDefaultConstructor (returnTypeDefinition);
+ MarkFields (returnTypeDefinition, includeStaticFields);
+ }
+
+ if (method.HasThis && !method.DeclaringType.IsImport) {
+ MarkFields (method.DeclaringType, includeStaticFields);
+ }
+
+ foreach (ParameterDefinition pd in method.Parameters) {
+ TypeReference paramTypeReference = pd.ParameterType;
+ if (paramTypeReference is TypeSpecification) {
+ paramTypeReference = (paramTypeReference as TypeSpecification).ElementType;
+ }
+ TypeDefinition paramTypeDefinition = paramTypeReference.Resolve ();
+ if (paramTypeDefinition is not null && !paramTypeDefinition.IsImport) {
+ MarkFields (paramTypeDefinition, includeStaticFields);
+ if (pd.ParameterType.IsByReference) {
+ MarkDefaultConstructor (paramTypeDefinition);
+ }
+ }
+ }
+ }
+
+ protected virtual bool ShouldParseMethodBody (MethodDefinition method)
+ {
+ if (!method.HasBody)
+ return false;
+
+ switch (Annotations.GetAction (method)) {
+ case MethodAction.ForceParse:
+ return true;
+ case MethodAction.Parse:
+ AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
+ switch (Annotations.GetAction (assembly)) {
+ case AssemblyAction.Link:
+ case AssemblyAction.Copy:
+ case AssemblyAction.CopyUsed:
+ case AssemblyAction.AddBypassNGen:
+ case AssemblyAction.AddBypassNGenUsed:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+
+ protected void MarkProperty (PropertyDefinition prop)
+ {
+ MarkCustomAttributes (prop);
+ DoAdditionalPropertyProcessing (prop);
+ }
+
+ protected virtual void MarkEvent (EventDefinition evt)
+ {
+ MarkCustomAttributes (evt);
+ MarkMethodIfNotNull (evt.AddMethod);
+ MarkMethodIfNotNull (evt.InvokeMethod);
+ MarkMethodIfNotNull (evt.RemoveMethod);
+ DoAdditionalEventProcessing (evt);
+ }
+
+ void MarkMethodIfNotNull (MethodReference method)
+ {
+ if (method is null)
+ return;
+
+ MarkMethod (method);
+ }
+
+ protected virtual void MarkMethodBody (MethodBody body)
+ {
+ if (_context.IsOptimizationEnabled (CodeOptimizations.UnreachableBodies) && IsUnreachableBody (body)) {
+ MarkAndCacheConvertToThrowExceptionCtor ();
+ _unreachableBodies.Add (body);
+ return;
+ }
+
+ foreach (VariableDefinition var in body.Variables)
+ MarkType (var.VariableType);
+
+ foreach (ExceptionHandler eh in body.ExceptionHandlers)
+ if (eh.HandlerType == ExceptionHandlerType.Catch)
+ MarkType (eh.CatchType);
+
+ foreach (Instruction instruction in body.Instructions)
+ MarkInstruction (instruction);
+
+ MarkInterfacesNeededByBodyStack (body);
+
+ MarkReflectionLikeDependencies (body);
+
+ PostMarkMethodBody (body);
+ }
+
+ bool IsUnreachableBody (MethodBody body)
+ {
+ return !body.Method.IsStatic
+ && !Annotations.IsInstantiated (body.Method.DeclaringType)
+ && MethodBodyScanner.IsWorthConvertingToThrow (body);
+ }
+
+
+ partial void PostMarkMethodBody (MethodBody body);
+
+ void MarkInterfacesNeededByBodyStack (MethodBody body)
+ {
+ // If a type could be on the stack in the body and an interface it implements could be on the stack on the body
+ // then we need to mark that interface implementation. When this occurs it is not safe to remove the interface implementation from the type
+ // even if the type is never instantiated
+ var implementations = MethodBodyScanner.GetReferencedInterfaces (_context.Annotations, body);
+ if (implementations is null)
+ return;
+
+ foreach (var implementation in implementations)
+ MarkInterfaceImplementation (implementation);
+ }
+
+ protected virtual void MarkInstruction (Instruction instruction)
+ {
+ switch (instruction.OpCode.OperandType) {
+ case OperandType.InlineField:
+ MarkField ((FieldReference) instruction.Operand);
+ break;
+ case OperandType.InlineMethod:
+ MarkMethod ((MethodReference) instruction.Operand);
+ break;
+ case OperandType.InlineTok:
+ object token = instruction.Operand;
+ if (token is TypeReference)
+ MarkType ((TypeReference) token);
+ else if (token is MethodReference)
+ MarkMethod ((MethodReference) token);
+ else
+ MarkField ((FieldReference) token);
+ break;
+ case OperandType.InlineType:
+ MarkType ((TypeReference) instruction.Operand);
+ break;
+ default:
+ break;
+ }
+ }
+
+ protected virtual void HandleUnresolvedType (TypeReference reference)
+ {
+ if (!_context.IgnoreUnresolved) {
+ throw new ResolutionException (reference);
+ }
+ }
+
+ protected virtual void HandleUnresolvedMethod (MethodReference reference)
+ {
+ if (!_context.IgnoreUnresolved) {
+ throw new ResolutionException (reference);
+ }
+ }
+
+ protected virtual void HandleUnresolvedField (FieldReference reference)
+ {
+ if (!_context.IgnoreUnresolved) {
+ throw new ResolutionException (reference);
+ }
+ }
+
+ protected virtual bool ShouldMarkInterfaceImplementation (TypeDefinition type, InterfaceImplementation iface, TypeDefinition resolvedInterfaceType)
+ {
+ if (Annotations.IsMarked (iface))
+ return false;
+
+ if (Annotations.IsMarked (resolvedInterfaceType))
+ return true;
+
+ if (!_context.IsOptimizationEnabled (CodeOptimizations.UnusedInterfaces))
+ return true;
+
+ // It's hard to know if a com or windows runtime interface will be needed from managed code alone,
+ // so as a precaution we will mark these interfaces once the type is instantiated
+ if (resolvedInterfaceType.IsImport || resolvedInterfaceType.IsWindowsRuntime)
+ return true;
+
+ return IsFullyPreserved (type);
+ }
+
+ protected virtual void MarkInterfaceImplementation (InterfaceImplementation iface)
+ {
+ MarkCustomAttributes (iface);
+ MarkType (iface.InterfaceType);
+ Annotations.Mark (iface);
+ }
+
+ bool HasManuallyTrackedDependency (MethodBody methodBody)
+ {
+ return PreserveDependencyLookupStep.HasPreserveDependencyAttribute (methodBody.Method);
+ }
+
+ //
+ // Extension point for reflection logic handling customization
+ //
+ protected virtual bool ProcessReflectionDependency (MethodBody body, Instruction instruction)
+ {
+ return false;
+ }
+
+ //
+ // Tries to mark additional dependencies used in reflection like calls (e.g. typeof (MyClass).GetField ("fname"))
+ //
+ protected virtual void MarkReflectionLikeDependencies (MethodBody body)
+ {
+ if (HasManuallyTrackedDependency (body))
+ return;
+
+ var instructions = body.Instructions;
+ ReflectionPatternDetector detector = new ReflectionPatternDetector (this, body.Method);
+
+ //
+ // Starting at 1 because all patterns require at least 1 instruction backward lookup
+ //
+ for (var i = 1; i < instructions.Count; i++) {
+ var instruction = instructions [i];
+
+ if (instruction.OpCode != OpCodes.Call && instruction.OpCode != OpCodes.Callvirt)
+ continue;
+
+ if (ProcessReflectionDependency (body, instruction))
+ continue;
+
+ if (!(instruction.Operand is MethodReference methodCalled))
+ continue;
+
+ var methodCalledDefinition = methodCalled.Resolve ();
+ if (methodCalledDefinition is null)
+ continue;
+
+ ReflectionPatternContext reflectionContext = new ReflectionPatternContext (_context, body.Method, methodCalledDefinition, i);
+ try {
+ detector.Process (ref reflectionContext);
+ } finally {
+ reflectionContext.Dispose ();
+ }
+ }
+ }
+
+ ///
+ /// Helper struct to pass around context information about reflection pattern
+ /// as a single parameter (and have a way to extend this in the future if we need to easily).
+ /// Also implements a simple validation mechanism to check that the code does report patter recognition
+ /// results for all methods it works on.
+ /// The promise of the pattern recorder is that for a given reflection method, it will either not talk
+ /// about it ever, or it will always report recognized/unrecognized.
+ ///
+ struct ReflectionPatternContext : IDisposable {
+ readonly LinkContext _context;
+#if DEBUG
+ bool _patternAnalysisAttempted;
+ bool _patternReported;
+#endif
+
+ public MethodDefinition MethodCalling { get; private set; }
+ public MethodDefinition MethodCalled { get; private set; }
+ public int InstructionIndex { get; private set; }
+
+ public ReflectionPatternContext (LinkContext context, MethodDefinition methodCalling, MethodDefinition methodCalled, int instructionIndex)
+ {
+ _context = context;
+ MethodCalling = methodCalling;
+ MethodCalled = methodCalled;
+ InstructionIndex = instructionIndex;
+
+#if DEBUG
+ _patternAnalysisAttempted = false;
+ _patternReported = false;
+#endif
+ }
+
+ [Conditional ("DEBUG")]
+ public void AnalyzingPattern ()
+ {
+#if DEBUG
+ _patternAnalysisAttempted = true;
+#endif
+ }
+
+ public void RecordRecognizedPattern (T accessedItem, Action mark)
+ where T : IMemberDefinition
+ {
+#if DEBUG
+ Debug.Assert (_patternAnalysisAttempted, "To correctly report all patterns, when starting to analyze a pattern the AnalyzingPattern must be called first.");
+ _patternReported = true;
+#endif
+
+ _context.Tracer.Push ($"Reflection-{accessedItem}");
+ try {
+ mark ();
+ _context.ReflectionPatternRecorder.RecognizedReflectionAccessPattern (MethodCalling, MethodCalled, accessedItem);
+ } finally {
+ _context.Tracer.Pop ();
+ }
+ }
+
+ public void RecordUnrecognizedPattern (string message)
+ {
+#if DEBUG
+ Debug.Assert (_patternAnalysisAttempted, "To correctly report all patterns, when starting to analyze a pattern the AnalyzingPattern must be called first.");
+ _patternReported = true;
+#endif
+
+ _context.ReflectionPatternRecorder.UnrecognizedReflectionAccessPattern (MethodCalling, MethodCalled, message);
+ }
+
+ public void Dispose ()
+ {
+#if DEBUG
+ Debug.Assert (!_patternAnalysisAttempted || _patternReported, "A reflection pattern was analyzed, but no result was reported.");
+#endif
+ }
+ }
+
+ class ReflectionPatternDetector {
+ readonly MarkStep _markStep;
+ readonly MethodDefinition _methodCalling;
+ readonly Collection _instructions;
+
+ public ReflectionPatternDetector (MarkStep markStep, MethodDefinition callingMethod)
+ {
+ _markStep = markStep;
+ _methodCalling = callingMethod;
+ _instructions = _methodCalling.Body.Instructions;
+ }
+
+ public void Process (ref ReflectionPatternContext reflectionContext)
+ {
+ var methodCalled = reflectionContext.MethodCalled;
+ var instructionIndex = reflectionContext.InstructionIndex;
+ var methodCalledType = methodCalled.DeclaringType;
+
+ switch (methodCalledType.Name) {
+ //
+ // System.Type
+ //
+ case "Type" when methodCalledType.Namespace == "System":
+
+ // Some of the overloads are implemented by calling another overload of the same name.
+ // These "internal" calls are not interesting to analyze, the outermost call is the one
+ // which needs to be analyzed. The assumption is that all overloads have the same semantics.
+ // (for example that all overload of GetConstructor if used require the specified type to have a .ctor).
+ if (_methodCalling.DeclaringType == methodCalled.DeclaringType && _methodCalling.Name == methodCalled.Name)
+ break;
+
+ switch (methodCalled.Name) {
+ //
+ // GetConstructor (Type [])
+ // GetConstructor (BindingFlags, Binder, Type [], ParameterModifier [])
+ // GetConstructor (BindingFlags, Binder, CallingConventions, Type [], ParameterModifier [])
+ //
+ case "GetConstructor":
+ if (!methodCalled.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Constructor, instructionIndex - 1);
+
+ break;
+
+ //
+ // GetMethod (string)
+ // GetMethod (string, BindingFlags)
+ // GetMethod (string, Type[])
+ // GetMethod (string, Type[], ParameterModifier[])
+ // GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
+ // GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
+ //
+ // TODO: .NET Core extensions
+ // GetMethod (string, int, Type[])
+ // GetMethod (string, int, Type[], ParameterModifier[]?)
+ // GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
+ // GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
+ //
+ case "GetMethod":
+ if (!methodCalled.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Method, instructionIndex - 1);
+
+ break;
+
+ //
+ // GetField (string)
+ // GetField (string, BindingFlags)
+ //
+ case "GetField":
+ if (!methodCalled.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Field, instructionIndex - 1);
+
+ break;
+
+ //
+ // GetEvent (string)
+ // GetEvent (string, BindingFlags)
+ //
+ case "GetEvent":
+ if (!methodCalled.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Event, instructionIndex - 1);
+
+ break;
+
+ //
+ // GetProperty (string)
+ // GetProperty (string, BindingFlags)
+ // GetProperty (string, Type)
+ // GetProperty (string, Type[])
+ // GetProperty (string, Type, Type[])
+ // GetProperty (string, Type, Type[], ParameterModifier[])
+ // GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
+ //
+ case "GetProperty":
+ if (!methodCalled.IsStatic)
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Property, instructionIndex - 1);
+
+ break;
+
+ //
+ // GetType (string)
+ // GetType (string, Boolean)
+ // GetType (string, Boolean, Boolean)
+ // GetType (string, Func, Func)
+ // GetType (string, Func, Func, Boolean)
+ // GetType (string, Func, Func, Boolean, Boolean)
+ //
+ case "GetType":
+ if (!methodCalled.IsStatic) {
+ break;
+ } else {
+ reflectionContext.AnalyzingPattern ();
+
+ var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, methodCalled.Parameters.Count);
+ if (first_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ break;
+ }
+
+ //
+ // The next value must be string constant (we don't handle anything else)
+ //
+ var first_arg = _instructions [first_arg_instr];
+ if (first_arg.OpCode != OpCodes.Ldstr) {
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with argument which cannot be analyzed");
+ break;
+ }
+
+ string typeName = (string) first_arg.Operand;
+ TypeDefinition foundType = _markStep.ResolveFullyQualifiedTypeName (typeName);
+ if (foundType is null) {
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with type name `{typeName}` which can't be resolved.");
+ break;
+ }
+
+ reflectionContext.RecordRecognizedPattern (foundType, () => _markStep.MarkType (foundType));
+ }
+ break;
+ }
+
+ break;
+
+ //
+ // System.Linq.Expressions.Expression
+ //
+ case "Expression" when methodCalledType.Namespace == "System.Linq.Expressions":
+ Instruction second_argument;
+ TypeDefinition declaringType;
+
+ if (!methodCalled.IsStatic)
+ break;
+
+ switch (methodCalled.Name) {
+
+ //
+ // static Call (Type, String, Type[], Expression[])
+ //
+ case "Call": {
+ reflectionContext.AnalyzingPattern ();
+
+ var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 4);
+ if (first_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ break;
+ }
+
+ var first_arg = _instructions [first_arg_instr];
+ if (first_arg.OpCode == OpCodes.Ldtoken)
+ first_arg_instr++;
+
+ declaringType = FindReflectionTypeForLookup (_instructions, first_arg_instr);
+ if (declaringType is null) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 1st argument which cannot be analyzed");
+ break;
+ }
+
+ var second_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 3);
+ second_argument = _instructions [second_arg_instr];
+ if (second_argument.OpCode != OpCodes.Ldstr) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 2nd argument which cannot be analyzed");
+ break;
+ }
+
+ var name = (string) second_argument.Operand;
+
+ MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, name, null, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
+ }
+
+ break;
+
+ //
+ // static Property(Expression, Type, String)
+ // static Field (Expression, Type, String)
+ //
+ case "Property":
+ case "Field": {
+ reflectionContext.AnalyzingPattern ();
+
+ var second_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 2);
+ if (second_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ break;
+ }
+
+ var second_arg = _instructions [second_arg_instr];
+ if (second_arg.OpCode == OpCodes.Ldtoken)
+ second_arg_instr++;
+
+ declaringType = FindReflectionTypeForLookup (_instructions, second_arg_instr);
+ if (declaringType is null) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 2nd argument which cannot be analyzed");
+ break;
+ }
+
+ var third_arg_inst = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 1);
+ var third_argument = _instructions [third_arg_inst];
+ if (third_argument.OpCode != OpCodes.Ldstr) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with the 3rd argument which cannot be analyzed");
+ break;
+ }
+
+ var name = (string) third_argument.Operand;
+
+ //
+ // The first argument can be any expression but we are looking only for simple null
+ // which we can convert to static only field lookup
+ //
+ var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 3);
+ bool staticOnly = false;
+
+ if (first_arg_instr >= 0) {
+ var first_arg = _instructions [first_arg_instr];
+ if (first_arg.OpCode == OpCodes.Ldnull)
+ staticOnly = true;
+ }
+
+ if (methodCalled.Name [0] == 'P')
+ MarkPropertiesFromReflectionCall (ref reflectionContext, declaringType, name, staticOnly);
+ else
+ MarkFieldsFromReflectionCall (ref reflectionContext, declaringType, name, staticOnly);
+ }
+
+ break;
+
+ //
+ // static New (Type)
+ //
+ case "New": {
+ reflectionContext.AnalyzingPattern ();
+
+ var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 1);
+ if (first_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ break;
+ }
+
+ var first_arg = _instructions [first_arg_instr];
+ if (first_arg.OpCode == OpCodes.Ldtoken)
+ first_arg_instr++;
+
+ declaringType = FindReflectionTypeForLookup (_instructions, first_arg_instr);
+ if (declaringType is null) {
+ reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 1st argument which cannot be analyzed");
+ break;
+ }
+
+ MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, ".ctor", 0, BindingFlags.Instance, parametersCount: 0);
+ }
+ break;
+ }
+
+ break;
+
+ //
+ // System.Reflection.RuntimeReflectionExtensions
+ //
+ case "RuntimeReflectionExtensions" when methodCalledType.Namespace == "System.Reflection":
+ switch (methodCalled.Name) {
+ //
+ // static GetRuntimeField (this Type type, string name)
+ //
+ case "GetRuntimeField":
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Field, instructionIndex - 1, thisExtension: true);
+ break;
+
+ //
+ // static GetRuntimeMethod (this Type type, string name, Type[] parameters)
+ //
+ case "GetRuntimeMethod":
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Method, instructionIndex - 1, thisExtension: true);
+ break;
+
+ //
+ // static GetRuntimeProperty (this Type type, string name)
+ //
+ case "GetRuntimeProperty":
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Property, instructionIndex - 1, thisExtension: true);
+ break;
+
+ //
+ // static GetRuntimeEvent (this Type type, string name)
+ //
+ case "GetRuntimeEvent":
+ ProcessSystemTypeGetMemberLikeCall (ref reflectionContext, System.Reflection.MemberTypes.Event, instructionIndex - 1, thisExtension: true);
+ break;
+ }
+
+ break;
+
+ //
+ // System.AppDomain
+ //
+ case "AppDomain" when methodCalledType.Namespace == "System":
+ //
+ // CreateInstance (string assemblyName, string typeName)
+ // CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
+ //
+ // CreateInstanceAndUnwrap (string assemblyName, string typeName)
+ // CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
+ //
+ // CreateInstanceFrom (string assemblyFile, string typeName)
+ // CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
+ //
+ // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
+ // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
+ //
+ switch (methodCalled.Name) {
+ case "CreateInstance":
+ case "CreateInstanceAndUnwrap":
+ case "CreateInstanceFrom":
+ case "CreateInstanceFromAndUnwrap":
+ ProcessActivatorCallWithStrings (ref reflectionContext, instructionIndex - 1, methodCalled.Parameters.Count < 4);
+ break;
+ }
+
+ break;
+
+ //
+ // System.Reflection.Assembly
+ //
+ case "Assembly" when methodCalledType.Namespace == "System.Reflection":
+ //
+ // CreateInstance (string typeName)
+ // CreateInstance (string typeName, bool ignoreCase)
+ // CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
+ //
+ if (methodCalled.Name == "CreateInstance") {
+ //
+ // TODO: This could be supported for `this` only calls
+ //
+ reflectionContext.AnalyzingPattern ();
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' is not yet supported");
+ break;
+ }
+
+ break;
+
+ //
+ // System.Activator
+ //
+ case "Activator" when methodCalledType.Namespace == "System":
+ if (!methodCalled.IsStatic)
+ break;
+
+ switch (methodCalled.Name) {
+ //
+ // static T CreateInstance ()
+ //
+ case "CreateInstance" when methodCalled.ContainsGenericParameter:
+ // Not sure it's worth implementing as we cannot expant T and simple cases can be rewritten
+ reflectionContext.AnalyzingPattern ();
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' is not supported");
+ break;
+
+ //
+ // static CreateInstance (string assemblyName, string typeName)
+ // static CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
+ // static CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
+ //
+ // static CreateInstance (System.Type type)
+ // static CreateInstance (System.Type type, bool nonPublic)
+ // static CreateInstance (System.Type type, params object?[]? args)
+ // static CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
+ // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
+ // static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
+ //
+ case "CreateInstance": {
+ reflectionContext.AnalyzingPattern ();
+
+ var parameters = methodCalled.Parameters;
+ if (parameters.Count < 1)
+ break;
+
+ if (parameters [0].ParameterType.MetadataType == MetadataType.String) {
+ ProcessActivatorCallWithStrings (ref reflectionContext, instructionIndex - 1, parameters.Count < 4);
+ break;
+ }
+
+ var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, methodCalled.Parameters.Count);
+ if (first_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ break;
+ }
+
+ if (parameters [0].ParameterType.IsTypeOf ("System", "Type")) {
+ declaringType = FindReflectionTypeForLookup (_instructions, first_arg_instr + 1);
+ if (declaringType is null) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 1st argument expression which cannot be analyzed");
+ break;
+ }
+
+ BindingFlags bindingFlags = BindingFlags.Instance;
+ int? parametersCount = null;
+
+ if (methodCalled.Parameters.Count == 1) {
+ parametersCount = 0;
+ } else {
+ var second_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, methodCalled.Parameters.Count - 1);
+ second_argument = _instructions [second_arg_instr];
+ switch (second_argument.OpCode.Code) {
+ case Code.Ldc_I4_0 when parameters [1].ParameterType.MetadataType == MetadataType.Boolean:
+ parametersCount = 0;
+ bindingFlags |= BindingFlags.Public;
+ break;
+ case Code.Ldc_I4_1 when parameters [1].ParameterType.MetadataType == MetadataType.Boolean:
+ parametersCount = 0;
+ break;
+ case Code.Ldc_I4_S when parameters [1].ParameterType.IsTypeOf ("System.Reflection", "BindingFlags"):
+ bindingFlags = (BindingFlags) (sbyte) second_argument.Operand;
+ break;
+ }
+ }
+
+ MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, ".ctor", 0, bindingFlags, parametersCount);
+ break;
+ }
+ }
+
+ break;
+
+ //
+ // static CreateInstanceFrom (string assemblyFile, string typeName)
+ // static CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
+ // static CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
+ //
+ case "CreateInstanceFrom":
+ ProcessActivatorCallWithStrings (ref reflectionContext, instructionIndex - 1, methodCalled.Parameters.Count < 4);
+ break;
+ }
+
+ break;
+ }
+
+ }
+
+ //
+ // Handles static method calls in form of Create (string assemblyFile, string typeName, ......)
+ //
+ void ProcessActivatorCallWithStrings (ref ReflectionPatternContext reflectionContext, int startIndex, bool defaultCtorOnly)
+ {
+ reflectionContext.AnalyzingPattern ();
+
+ var parameters = reflectionContext.MethodCalled.Parameters;
+ if (parameters.Count < 2) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' is not supported");
+ return;
+ }
+
+ if (parameters [0].ParameterType.MetadataType != MetadataType.String && parameters [1].ParameterType.MetadataType != MetadataType.String) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' is not supported");
+ return;
+ }
+
+ var first_arg_instr = GetInstructionAtStackDepth (_instructions, startIndex, reflectionContext.MethodCalled.Parameters.Count);
+ if (first_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ return;
+ }
+
+ var first_arg = _instructions [first_arg_instr];
+ if (first_arg.OpCode != OpCodes.Ldstr) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with the 1st argument which cannot be analyzed");
+ return;
+ }
+
+ var second_arg_instr = GetInstructionAtStackDepth (_instructions, startIndex, reflectionContext.MethodCalled.Parameters.Count - 1);
+ if (second_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ return;
+ }
+
+ var second_arg = _instructions [second_arg_instr];
+ if (second_arg.OpCode != OpCodes.Ldstr) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with the 2nd argument which cannot be analyzed");
+ return;
+ }
+
+ string assembly_name = (string) first_arg.Operand;
+ if (!_markStep._context.Resolver.AssemblyCache.TryGetValue (assembly_name, out var assembly)) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' references assembly '{assembly_name}' which could not be found");
+ return;
+ }
+
+ string type_name = (string) second_arg.Operand;
+ var declaringType = FindType (assembly, type_name);
+
+ if (declaringType is null) {
+ reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' references type '{type_name}' which could not be found");
+ return;
+ }
+
+ MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, ".ctor", 0, null, defaultCtorOnly ? 0 : (int?) null);
+ }
+
+ //
+ // Handles instance methods called over typeof (Foo) with string name as the first argument
+ //
+ void ProcessSystemTypeGetMemberLikeCall (ref ReflectionPatternContext reflectionContext, System.Reflection.MemberTypes memberTypes, int startIndex, bool thisExtension = false)
+ {
+ reflectionContext.AnalyzingPattern ();
+
+ int first_instance_arg = reflectionContext.MethodCalled.Parameters.Count;
+ if (thisExtension)
+ --first_instance_arg;
+
+ var first_arg_instr = GetInstructionAtStackDepth (_instructions, startIndex, first_instance_arg);
+ if (first_arg_instr < 0) {
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed");
+ return;
+ }
+
+ var first_arg = _instructions [first_arg_instr];
+ BindingFlags? bindingFlags = default;
+ string name = default;
+
+ if (memberTypes == System.Reflection.MemberTypes.Constructor) {
+ if (first_arg.OpCode == OpCodes.Ldc_I4_S && reflectionContext.MethodCalled.Parameters.Count > 0 && reflectionContext.MethodCalled.Parameters [0].ParameterType.IsTypeOf ("System.Reflection", "BindingFlags")) {
+ bindingFlags = (BindingFlags) (sbyte) first_arg.Operand;
+ }
+ } else {
+ //
+ // The next value must be string constant (we don't handle anything else)
+ //
+ if (first_arg.OpCode != OpCodes.Ldstr) {
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with argument which cannot be analyzed");
+ return;
+ }
+
+ name = (string) first_arg.Operand;
+
+ var pos_arg = _instructions [first_arg_instr + 1];
+ if (pos_arg.OpCode == OpCodes.Ldc_I4_S && reflectionContext.MethodCalled.Parameters.Count > 1 && reflectionContext.MethodCalled.Parameters [1].ParameterType.IsTypeOf ("System.Reflection", "BindingFlags")) {
+ bindingFlags = (BindingFlags) (sbyte) pos_arg.Operand;
+ }
+ }
+
+ var declaringType = FindReflectionTypeForLookup (_instructions, first_arg_instr - 1);
+ if (declaringType is null) {
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' does not use detectable instance type extraction");
+ return;
+ }
+
+ switch (memberTypes) {
+ case System.Reflection.MemberTypes.Constructor:
+ MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, ".ctor", 0, bindingFlags);
+ break;
+ case System.Reflection.MemberTypes.Method:
+ MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, name, 0, bindingFlags);
+ break;
+ case System.Reflection.MemberTypes.Field:
+ MarkFieldsFromReflectionCall (ref reflectionContext, declaringType, name);
+ break;
+ case System.Reflection.MemberTypes.Property:
+ MarkPropertiesFromReflectionCall (ref reflectionContext, declaringType, name);
+ break;
+ case System.Reflection.MemberTypes.Event:
+ MarkEventsFromReflectionCall (ref reflectionContext, declaringType, name);
+ break;
+ default:
+ Debug.Fail ("Unsupported member type");
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{_methodCalling.FullName}' is of unexpected member type.");
+ break;
+ }
+ }
+
+ //
+ // arity is null for name match regardless of arity
+ //
+ void MarkMethodsFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, int? arity, BindingFlags? bindingFlags, int? parametersCount = null)
+ {
+ bool foundMatch = false;
+ foreach (var method in declaringType.Methods) {
+ var mname = method.Name;
+
+ // Either exact match or generic method with any arity when unspecified
+ if (mname != name && !(arity is null && mname.StartsWith (name, StringComparison.Ordinal) && mname.Length > name.Length + 2 && mname [name.Length + 1] == '`')) {
+ continue;
+ }
+
+ if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static && !method.IsStatic)
+ continue;
+
+ if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance && method.IsStatic)
+ continue;
+
+ if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public && !method.IsPublic)
+ continue;
+
+ if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic && method.IsPublic)
+ continue;
+
+ if (parametersCount is not null && parametersCount != method.Parameters.Count)
+ continue;
+
+ foundMatch = true;
+ reflectionContext.RecordRecognizedPattern (method, () => _markStep.MarkIndirectlyCalledMethod (method));
+ }
+
+ if (!foundMatch)
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve method `{name}` on type `{declaringType.FullName}`.");
+ }
+
+ void MarkPropertiesFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false)
+ {
+ bool foundMatch = false;
+ foreach (var property in declaringType.Properties) {
+ if (property.Name != name)
+ continue;
+
+ bool markedAny = false;
+
+ // It is not easy to reliably detect in the IL code whether the getter or setter (or both) are used.
+ // Be conservative and mark everything for the property.
+ var getter = property.GetMethod;
+ if (getter is not null && (!staticOnly || staticOnly && getter.IsStatic)) {
+ reflectionContext.RecordRecognizedPattern (getter, () => _markStep.MarkIndirectlyCalledMethod (getter));
+ markedAny = true;
+ }
+
+ var setter = property.SetMethod;
+ if (setter is not null && (!staticOnly || staticOnly && setter.IsStatic)) {
+ reflectionContext.RecordRecognizedPattern (setter, () => _markStep.MarkIndirectlyCalledMethod (setter));
+ markedAny = true;
+ }
+
+ if (markedAny) {
+ foundMatch = true;
+ reflectionContext.RecordRecognizedPattern (property, () => _markStep.MarkProperty (property));
+ }
+ }
+
+ if (!foundMatch)
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve property `{name}` on type `{declaringType.FullName}`.");
+ }
+
+ void MarkFieldsFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false)
+ {
+ bool foundMatch = false;
+ foreach (var field in declaringType.Fields) {
+ if (field.Name != name)
+ continue;
+
+ if (staticOnly && !field.IsStatic)
+ continue;
+
+ foundMatch = true;
+ reflectionContext.RecordRecognizedPattern (field, () => _markStep.MarkField (field));
+ break;
+ }
+
+ if (!foundMatch)
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve field `{name}` on type `{declaringType.FullName}`.");
+ }
+
+ void MarkEventsFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name)
+ {
+ bool foundMatch = false;
+ foreach (var eventInfo in declaringType.Events) {
+ if (eventInfo.Name != name)
+ continue;
+
+ foundMatch = true;
+ reflectionContext.RecordRecognizedPattern (eventInfo, () => _markStep.MarkEvent (eventInfo));
+ }
+
+ if (!foundMatch)
+ reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve event `{name}` on type `{declaringType.FullName}`.");
+ }
+ }
+
+ static int GetInstructionAtStackDepth (Collection instructions, int startIndex, int stackSizeToBacktrace)
+ {
+ for (int i = startIndex; i >= 0; --i) {
+ var instruction = instructions [i];
+
+ switch (instruction.OpCode.StackBehaviourPop) {
+ case StackBehaviour.Pop0:
+ break;
+ case StackBehaviour.Pop1:
+ case StackBehaviour.Popi:
+ case StackBehaviour.Popref:
+ stackSizeToBacktrace++;
+ break;
+ case StackBehaviour.Pop1_pop1:
+ case StackBehaviour.Popi_pop1:
+ case StackBehaviour.Popi_popi:
+ case StackBehaviour.Popi_popi8:
+ case StackBehaviour.Popi_popr4:
+ case StackBehaviour.Popi_popr8:
+ case StackBehaviour.Popref_pop1:
+ case StackBehaviour.Popref_popi:
+ stackSizeToBacktrace += 2;
+ break;
+ case StackBehaviour.Popref_popi_popi:
+ case StackBehaviour.Popref_popi_popi8:
+ case StackBehaviour.Popref_popi_popr4:
+ case StackBehaviour.Popref_popi_popr8:
+ case StackBehaviour.Popref_popi_popref:
+ stackSizeToBacktrace += 3;
+ break;
+ case StackBehaviour.Varpop:
+ switch (instruction.OpCode.Code) {
+ case Code.Call:
+ case Code.Calli:
+ case Code.Callvirt:
+ if (instruction.Operand is MethodReference mr) {
+ stackSizeToBacktrace += mr.Parameters.Count;
+ if (mr.Resolve ()?.IsStatic == false)
+ stackSizeToBacktrace++;
+ }
+
+ break;
+ case Code.Newobj:
+ if (instruction.Operand is MethodReference ctor) {
+ stackSizeToBacktrace += ctor.Parameters.Count;
+ }
+ break;
+ case Code.Ret:
+ // TODO: Need method return type for correct stack size but this path should not be hit yet
+ break;
+ default:
+ return -3;
+ }
+ break;
+ }
+
+ switch (instruction.OpCode.StackBehaviourPush) {
+ case StackBehaviour.Push0:
+ break;
+ case StackBehaviour.Push1:
+ case StackBehaviour.Pushi:
+ case StackBehaviour.Pushi8:
+ case StackBehaviour.Pushr4:
+ case StackBehaviour.Pushr8:
+ case StackBehaviour.Pushref:
+ stackSizeToBacktrace--;
+ break;
+ case StackBehaviour.Push1_push1:
+ stackSizeToBacktrace -= 2;
+ break;
+ case StackBehaviour.Varpush:
+ //
+ // Only call, calli, callvirt will hit this
+ //
+ if (instruction.Operand is MethodReference mr && mr.ReturnType.MetadataType != MetadataType.Void) {
+ stackSizeToBacktrace--;
+ }
+ break;
+ }
+
+ if (stackSizeToBacktrace == 0)
+ return i;
+
+ if (stackSizeToBacktrace < 0)
+ return -1;
+ }
+
+ return -2;
+ }
+
+ static TypeDefinition FindReflectionTypeForLookup (Collection instructions, int startIndex)
+ {
+ while (startIndex >= 1) {
+ int storeIndex = -1;
+ var instruction = instructions [startIndex];
+ switch (instruction.OpCode.Code) {
+ //
+ // Pattern #1
+ //
+ // typeof (Foo).ReflectionCall ()
+ //
+ case Code.Call:
+ if (!(instruction.Operand is MethodReference mr) || mr.Name != "GetTypeFromHandle")
+ return null;
+
+ var ldtoken = instructions [startIndex - 1];
+
+ if (ldtoken.OpCode != OpCodes.Ldtoken)
+ return null;
+
+ return (ldtoken.Operand as TypeReference).Resolve ();
+
+ //
+ // Patern #2
+ //
+ // var temp = typeof (Foo);
+ // temp.ReflectionCall ()
+ //
+ case Code.Ldloc_0:
+ storeIndex = GetIndexOfInstruction (instructions, OpCodes.Stloc_0, startIndex - 1);
+ startIndex = storeIndex - 1;
+ break;
+ case Code.Ldloc_1:
+ storeIndex = GetIndexOfInstruction (instructions, OpCodes.Stloc_1, startIndex - 1);
+ startIndex = storeIndex - 1;
+ break;
+ case Code.Ldloc_2:
+ storeIndex = GetIndexOfInstruction (instructions, OpCodes.Stloc_2, startIndex - 1);
+ startIndex = storeIndex - 1;
+ break;
+ case Code.Ldloc_3:
+ storeIndex = GetIndexOfInstruction (instructions, OpCodes.Stloc_3, startIndex - 1);
+ startIndex = storeIndex - 1;
+ break;
+ case Code.Ldloc_S:
+ storeIndex = GetIndexOfInstruction (instructions, OpCodes.Stloc_S, startIndex - 1, l => (VariableReference) l.Operand == (VariableReference) instruction.Operand);
+ startIndex = storeIndex - 1;
+ break;
+ case Code.Ldloc:
+ storeIndex = GetIndexOfInstruction (instructions, OpCodes.Stloc, startIndex - 1, l => (VariableReference) l.Operand == (VariableReference) instruction.Operand);
+ startIndex = storeIndex - 1;
+ break;
+
+ case Code.Nop:
+ startIndex--;
+ break;
+
+ default:
+ return null;
+ }
+ }
+
+ return null;
+ }
+
+ static int GetIndexOfInstruction (Collection instructions, OpCode opcode, int startIndex, Predicate comparer = null)
+ {
+ while (startIndex >= 0) {
+ var instr = instructions [startIndex];
+ if (instr.OpCode == opcode && (comparer is null || comparer (instr)))
+ return startIndex;
+
+ startIndex--;
+ }
+
+ return -1;
+ }
+
+ protected class AttributeProviderPair {
+ public AttributeProviderPair (CustomAttribute attribute, ICustomAttributeProvider provider)
+ {
+ Attribute = attribute;
+ Provider = provider;
+ }
+
+ public CustomAttribute Attribute { get; private set; }
+ public ICustomAttributeProvider Provider { get; private set; }
+ }
+ }
+
+ // Make our own copy of the BindingFlags enum, so that we don't depend on System.Reflection.
+ [Flags]
+ enum BindingFlags {
+ Default = 0,
+ IgnoreCase = 1,
+ DeclaredOnly = 2,
+ Instance = 4,
+ Static = 8,
+ Public = 16,
+ NonPublic = 32,
+ FlattenHierarchy = 64,
+ InvokeMethod = 256,
+ CreateInstance = 512,
+ GetField = 1024,
+ SetField = 2048,
+ GetProperty = 4096,
+ SetProperty = 8192,
+ PutDispProperty = 16384,
+ PutRefDispProperty = 32768,
+ ExactBinding = 65536,
+ SuppressChangeType = 131072,
+ OptionalParamBinding = 262144,
+ IgnoreReturn = 16777216
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/OutputStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/OutputStep.cs
new file mode 100644
index 000000000000..d4e52806c53d
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/OutputStep.cs
@@ -0,0 +1,301 @@
+//
+// OutputStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Cecil.PE;
+
+namespace Mono.Linker.Steps {
+
+ public class OutputStep : BaseStep {
+ private static Dictionary architectureMap;
+
+ private enum NativeOSOverride {
+ Apple = 0x4644,
+ FreeBSD = 0xadc4,
+ Linux = 0x7b79,
+ NetBSD = 0x1993,
+ Default = 0
+ }
+
+ List assembliesWritten;
+
+ public OutputStep ()
+ {
+ assembliesWritten = new List ();
+ }
+
+ static TargetArchitecture CalculateArchitecture (TargetArchitecture readyToRunArch)
+ {
+ if (architectureMap is null) {
+ architectureMap = new Dictionary ();
+ foreach (var os in Enum.GetValues (typeof (NativeOSOverride))) {
+ ushort osVal = (ushort) (NativeOSOverride) os;
+ foreach (var arch in Enum.GetValues (typeof (TargetArchitecture))) {
+ ushort archVal = (ushort) (TargetArchitecture) arch;
+ architectureMap.Add ((ushort) (archVal ^ osVal), (TargetArchitecture) arch);
+ }
+ }
+ }
+
+ TargetArchitecture pureILArch;
+ if (architectureMap.TryGetValue ((ushort) readyToRunArch, out pureILArch)) {
+ return pureILArch;
+ }
+ throw new BadImageFormatException ("unrecognized module attributes");
+ }
+
+ protected override void Process ()
+ {
+ CheckOutputDirectory ();
+ Tracer.Finish ();
+ }
+
+ protected override void EndProcess ()
+ {
+ if (Context.AssemblyListFile is not null) {
+ using (var w = File.CreateText (Context.AssemblyListFile)) {
+ w.WriteLine ("[" + String.Join (", ", assembliesWritten.Select (a => "\"" + a + "\"").ToArray ()) + "]");
+ }
+ }
+ }
+
+ void CheckOutputDirectory ()
+ {
+ if (Directory.Exists (Context.OutputDirectory))
+ return;
+
+ Directory.CreateDirectory (Context.OutputDirectory);
+ }
+
+ protected override void ProcessAssembly (AssemblyDefinition assembly)
+ {
+ OutputAssembly (assembly);
+ }
+
+ protected void WriteAssembly (AssemblyDefinition assembly, string directory)
+ {
+ WriteAssembly (assembly, directory, SaveSymbols (assembly));
+ }
+
+ protected virtual void WriteAssembly (AssemblyDefinition assembly, string directory, WriterParameters writerParameters)
+ {
+ foreach (var module in assembly.Modules) {
+ // Write back pure IL even for crossgen-ed assemblies
+ if (module.IsCrossgened ()) {
+ module.Attributes |= ModuleAttributes.ILOnly;
+ module.Attributes ^= ModuleAttributes.ILLibrary;
+ module.Architecture = CalculateArchitecture (module.Architecture);
+ }
+ }
+
+ string outputName = GetAssemblyFileName (assembly, directory);
+ try {
+ assembly.Write (outputName, writerParameters);
+ } catch (Exception e) {
+ throw new OutputException ($"Failed to write '{outputName}", e);
+ }
+ }
+
+ void OutputAssembly (AssemblyDefinition assembly)
+ {
+ string directory = Context.OutputDirectory;
+
+ CopyConfigFileIfNeeded (assembly, directory);
+
+ var action = Annotations.GetAction (assembly);
+ Context.LogMessage (MessageImportance.Low, $"Output action: {action,8} assembly: {assembly}");
+
+ switch (action) {
+ case AssemblyAction.Save:
+ case AssemblyAction.Link:
+ case AssemblyAction.AddBypassNGen:
+ Context.Tracer.AddDependency (assembly);
+ WriteAssembly (assembly, directory);
+ CopySatelliteAssembliesIfNeeded (assembly, directory);
+ assembliesWritten.Add (GetOriginalAssemblyFileInfo (assembly).Name);
+ break;
+ case AssemblyAction.Copy:
+ Context.Tracer.AddDependency (assembly);
+ CloseSymbols (assembly);
+ CopyAssembly (assembly, directory);
+ CopySatelliteAssembliesIfNeeded (assembly, directory);
+ assembliesWritten.Add (GetOriginalAssemblyFileInfo (assembly).Name);
+ break;
+ case AssemblyAction.Delete:
+ CloseSymbols (assembly);
+ DeleteAssembly (assembly, directory);
+ break;
+ default:
+ CloseSymbols (assembly);
+ break;
+ }
+ }
+
+ protected virtual void DeleteAssembly (AssemblyDefinition assembly, string directory)
+ {
+ var target = GetAssemblyFileName (assembly, directory);
+ if (File.Exists (target)) {
+ File.Delete (target);
+ File.Delete (target + ".mdb");
+ File.Delete (Path.ChangeExtension (target, "pdb"));
+ File.Delete (GetConfigFile (target));
+ }
+ }
+
+ void CloseSymbols (AssemblyDefinition assembly)
+ {
+ Annotations.CloseSymbolReader (assembly);
+ }
+
+ WriterParameters SaveSymbols (AssemblyDefinition assembly)
+ {
+ var parameters = new WriterParameters {
+ DeterministicMvid = Context.DeterministicOutput
+ };
+
+ if (!Context.LinkSymbols)
+ return parameters;
+
+ if (!assembly.MainModule.HasSymbols)
+ return parameters;
+
+ // Use a string check to avoid a hard dependency on Mono.Cecil.Pdb
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT && assembly.MainModule.SymbolReader.GetType ().FullName == "Mono.Cecil.Pdb.NativePdbReader")
+ return parameters;
+
+ if (Context.SymbolWriterProvider is not null)
+ parameters.SymbolWriterProvider = Context.SymbolWriterProvider;
+ else
+ parameters.WriteSymbols = true;
+ return parameters;
+ }
+
+
+ void CopySatelliteAssembliesIfNeeded (AssemblyDefinition assembly, string directory)
+ {
+ if (!Annotations.ProcessSatelliteAssemblies)
+ return;
+
+ FileInfo original = GetOriginalAssemblyFileInfo (assembly);
+ string resourceFile = GetAssemblyResourceFileName (original.FullName);
+
+ foreach (var subDirectory in Directory.EnumerateDirectories (original.DirectoryName)) {
+ var satelliteAssembly = Path.Combine (subDirectory, resourceFile);
+ if (!File.Exists (satelliteAssembly))
+ continue;
+
+ string cultureName = subDirectory.Substring (subDirectory.LastIndexOf (Path.DirectorySeparatorChar) + 1);
+ string culturePath = Path.Combine (directory, cultureName);
+
+ Directory.CreateDirectory (culturePath);
+ File.Copy (satelliteAssembly, Path.Combine (culturePath, resourceFile), true);
+ }
+ }
+
+ void CopyConfigFileIfNeeded (AssemblyDefinition assembly, string directory)
+ {
+ string config = GetConfigFile (GetOriginalAssemblyFileInfo (assembly).FullName);
+ if (!File.Exists (config))
+ return;
+
+ string target = Path.GetFullPath (GetConfigFile (GetAssemblyFileName (assembly, directory)));
+
+ if (config == target)
+ return;
+
+ File.Copy (config, GetConfigFile (GetAssemblyFileName (assembly, directory)), true);
+ }
+
+ static string GetAssemblyResourceFileName (string assembly)
+ {
+ return Path.GetFileNameWithoutExtension (assembly) + ".resources.dll";
+ }
+
+ static string GetConfigFile (string assembly)
+ {
+ return assembly + ".config";
+ }
+
+ static FileInfo GetOriginalAssemblyFileInfo (AssemblyDefinition assembly)
+ {
+ return new FileInfo (assembly.MainModule.FileName);
+ }
+
+ protected virtual void CopyAssembly (AssemblyDefinition assembly, string directory)
+ {
+ // Special case. When an assembly has embedded pdbs, link symbols is not enabled, and the assembly's action is copy,
+ // we want to match the behavior of assemblies with the other symbol types and end up with an assembly that does not have symbols.
+ // In order to do that, we can't simply copy files. We need to write the assembly without symbols
+ if (assembly.MainModule.HasSymbols && !Context.LinkSymbols && assembly.MainModule.SymbolReader is EmbeddedPortablePdbReader) {
+ WriteAssembly (assembly, directory, new WriterParameters ());
+ return;
+ }
+
+ FileInfo fi = GetOriginalAssemblyFileInfo (assembly);
+ string target = Path.GetFullPath (Path.Combine (directory, fi.Name));
+ string source = fi.FullName;
+ if (source == target)
+ return;
+
+ CopyFileAndRemoveReadOnly (source, target);
+
+ if (!Context.LinkSymbols)
+ return;
+
+ var mdb = source + ".mdb";
+ if (File.Exists (mdb))
+ CopyFileAndRemoveReadOnly (mdb, target + ".mdb");
+
+ var pdb = Path.ChangeExtension (source, "pdb");
+ if (File.Exists (pdb))
+ CopyFileAndRemoveReadOnly (pdb, Path.ChangeExtension (target, "pdb"));
+ }
+
+ static void CopyFileAndRemoveReadOnly (string src, string dest)
+ {
+ File.Copy (src, dest, true);
+
+ System.IO.FileAttributes attrs = File.GetAttributes (dest);
+
+ if ((attrs & System.IO.FileAttributes.ReadOnly) == System.IO.FileAttributes.ReadOnly)
+ File.SetAttributes (dest, attrs & ~System.IO.FileAttributes.ReadOnly);
+ }
+
+ protected virtual string GetAssemblyFileName (AssemblyDefinition assembly, string directory)
+ {
+ string file = GetOriginalAssemblyFileInfo (assembly).Name;
+ return Path.Combine (directory, file);
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/PreserveDependencyLookupStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/PreserveDependencyLookupStep.cs
new file mode 100644
index 000000000000..0ff917d71666
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/PreserveDependencyLookupStep.cs
@@ -0,0 +1,99 @@
+//
+// PreserveDependencyLookupStep.cs
+//
+// Author:
+// Marek Safar (marek.safar@gmail.com)
+//
+// Copyright (C) 2018 Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Mono.Cecil;
+using Mono.Collections.Generic;
+
+namespace Mono.Linker.Steps {
+ public class PreserveDependencyLookupStep : LoadReferencesStep {
+ protected override void ProcessAssembly (AssemblyDefinition assembly)
+ {
+ var module = assembly.MainModule;
+
+ foreach (var type in module.Types) {
+ if (type.HasMethods) {
+ foreach (var method in type.GetMethods ()) {
+ var md = method.Resolve ();
+ if (md?.HasCustomAttributes != true)
+ continue;
+
+ ProcessPreserveDependencyAttribute (md.CustomAttributes);
+ }
+ }
+
+ if (type.HasFields) {
+ foreach (var field in type.Fields) {
+ var md = field.Resolve ();
+ if (md?.HasCustomAttributes != true)
+ continue;
+
+ ProcessPreserveDependencyAttribute (md.CustomAttributes);
+ }
+ }
+ }
+ }
+
+ public static bool IsPreserveDependencyAttribute (TypeReference tr)
+ {
+ return tr.Name == "PreserveDependencyAttribute" && tr.Namespace == "System.Runtime.CompilerServices";
+ }
+
+ public static bool HasPreserveDependencyAttribute (MethodDefinition method)
+ {
+ if (!method.HasCustomAttributes)
+ return false;
+
+ foreach (var ca in method.CustomAttributes) {
+ if (IsPreserveDependencyAttribute (ca.AttributeType))
+ return true;
+ }
+
+ return false;
+ }
+
+ void ProcessPreserveDependencyAttribute (Collection attributes)
+ {
+ foreach (var ca in attributes) {
+ if (!IsPreserveDependencyAttribute (ca.AttributeType))
+ continue;
+
+ if (ca.ConstructorArguments.Count != 3)
+ continue;
+
+ var assemblyName = ca.ConstructorArguments [2].Value as string;
+ if (assemblyName is null)
+ continue;
+
+ var newDependency = Context.Resolve (new AssemblyNameReference (assemblyName, new Version ()));
+ if (newDependency is not null)
+ ProcessReferences (newDependency);
+ }
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/RegenerateGuidStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/RegenerateGuidStep.cs
new file mode 100644
index 000000000000..6b2558e8352d
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/RegenerateGuidStep.cs
@@ -0,0 +1,48 @@
+//
+// CleanStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2008 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class RegenerateGuidStep : BaseStep {
+
+ protected override void ProcessAssembly (AssemblyDefinition assembly)
+ {
+ if (Annotations.GetAction (assembly) == AssemblyAction.Link)
+ RegenerateGuid (assembly);
+ }
+
+ static void RegenerateGuid (AssemblyDefinition asm)
+ {
+ asm.MainModule.Mvid = Guid.NewGuid ();
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromAssemblyStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromAssemblyStep.cs
new file mode 100644
index 000000000000..94d317e9f153
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromAssemblyStep.cs
@@ -0,0 +1,249 @@
+//
+// ResolveFromAssemblyStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Mono.Cecil;
+using Mono.Collections.Generic;
+
+namespace Mono.Linker.Steps {
+
+ public class ResolveFromAssemblyStep : ResolveStep {
+
+ AssemblyDefinition _assembly;
+ string _file;
+ RootVisibility _rootVisibility;
+
+ public enum RootVisibility {
+ Any = 0,
+ PublicAndFamily = 1,
+ PublicAndFamilyAndAssembly = 2
+ }
+
+
+ public ResolveFromAssemblyStep (string assembly, RootVisibility rootVisibility = RootVisibility.Any)
+ {
+ _file = assembly;
+ _rootVisibility = rootVisibility;
+ }
+
+ public ResolveFromAssemblyStep (AssemblyDefinition assembly)
+ {
+ _assembly = assembly;
+ }
+
+ protected override void Process ()
+ {
+ if (_assembly is not null)
+ Context.Resolver.CacheAssembly (_assembly);
+
+ var ignoreUnresolved = Context.Resolver.IgnoreUnresolved;
+ if (_rootVisibility == RootVisibility.PublicAndFamily) {
+ Context.Resolver.IgnoreUnresolved = false;
+ }
+
+ AssemblyDefinition assembly = _assembly ?? Context.Resolve (_file);
+ Context.Resolver.IgnoreUnresolved = ignoreUnresolved;
+ if (_rootVisibility != RootVisibility.Any && HasInternalsVisibleTo (assembly)) {
+ _rootVisibility = RootVisibility.PublicAndFamilyAndAssembly;
+ }
+
+ switch (assembly.MainModule.Kind) {
+ case ModuleKind.Dll:
+ ProcessLibrary (assembly);
+ break;
+ default:
+ ProcessExecutable (assembly);
+ break;
+ }
+ }
+
+ protected virtual void ProcessLibrary (AssemblyDefinition assembly)
+ {
+ ProcessLibrary (Context, assembly, _rootVisibility);
+ }
+
+ public static void ProcessLibrary (LinkContext context, AssemblyDefinition assembly, RootVisibility rootVisibility = RootVisibility.Any)
+ {
+ var action = rootVisibility == RootVisibility.Any ? AssemblyAction.Copy : AssemblyAction.Link;
+ context.SetAction (assembly, action);
+
+ context.Tracer.Push (assembly);
+
+ foreach (TypeDefinition type in assembly.MainModule.Types)
+ MarkType (context, type, rootVisibility);
+
+ if (assembly.MainModule.HasExportedTypes) {
+ foreach (var exported in assembly.MainModule.ExportedTypes) {
+ bool isForwarder = exported.IsForwarder;
+ var declaringType = exported.DeclaringType;
+ while (!isForwarder && (declaringType is not null)) {
+ isForwarder = declaringType.IsForwarder;
+ declaringType = declaringType.DeclaringType;
+ }
+
+ if (!isForwarder)
+ continue;
+ TypeDefinition resolvedExportedType = exported.Resolve ();
+
+ if (resolvedExportedType is null) {
+ //
+ // It's quite common for assemblies to have broken exported types
+ //
+ // One source of them is from native csc which added all nested types of
+ // type-forwarded types automatically including private ones.
+ //
+ // Next source of broken type-forwarders is from custom metadata writers which
+ // simply write bogus information.
+ //
+ // Both cases are bugs not on our end but we still want to link all assemblies
+ // especially when such types cannot be used anyway
+ //
+ context.LogMessage ($"Cannot find declaration of exported type '{exported}' from the assembly '{assembly}'");
+
+ continue;
+ }
+
+ context.Resolve (resolvedExportedType.Scope);
+ MarkType (context, resolvedExportedType, rootVisibility);
+ context.MarkingHelpers.MarkExportedType (exported, assembly.MainModule);
+ }
+ }
+
+ context.Tracer.Pop ();
+ }
+
+ static void MarkType (LinkContext context, TypeDefinition type, RootVisibility rootVisibility)
+ {
+ bool markType;
+ switch (rootVisibility) {
+ default:
+ markType = true;
+ break;
+
+ case RootVisibility.PublicAndFamilyAndAssembly:
+ markType = !type.IsNestedPrivate;
+ break;
+
+ case RootVisibility.PublicAndFamily:
+ markType = type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly;
+ break;
+ }
+
+ if (!markType) {
+ return;
+ }
+
+ context.Annotations.MarkAndPush (type);
+
+ if (type.HasFields)
+ MarkFields (context, type.Fields, rootVisibility);
+ if (type.HasMethods)
+ MarkMethods (context, type.Methods, rootVisibility);
+ if (type.HasNestedTypes)
+ foreach (var nested in type.NestedTypes)
+ MarkType (context, nested, rootVisibility);
+
+ context.Tracer.Pop ();
+ }
+
+ void ProcessExecutable (AssemblyDefinition assembly)
+ {
+ Context.SetAction (assembly, AssemblyAction.Link);
+
+ Tracer.Push (assembly);
+
+ Annotations.Mark (assembly.EntryPoint.DeclaringType);
+
+ MarkMethod (Context, assembly.EntryPoint, MethodAction.Parse, RootVisibility.Any);
+
+ Tracer.Pop ();
+ }
+
+ static void MarkFields (LinkContext context, Collection fields, RootVisibility rootVisibility)
+ {
+ foreach (FieldDefinition field in fields) {
+ bool markField;
+ switch (rootVisibility) {
+ default:
+ markField = true;
+ break;
+
+ case RootVisibility.PublicAndFamily:
+ markField = field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly;
+ break;
+
+ case RootVisibility.PublicAndFamilyAndAssembly:
+ markField = field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly || field.IsAssembly || field.IsFamilyAndAssembly;
+ break;
+ }
+ if (markField) {
+ context.Annotations.Mark (field);
+ }
+ }
+ }
+
+ static void MarkMethods (LinkContext context, Collection methods, RootVisibility rootVisibility)
+ {
+ foreach (MethodDefinition method in methods)
+ MarkMethod (context, method, MethodAction.ForceParse, rootVisibility);
+ }
+
+ static void MarkMethod (LinkContext context, MethodDefinition method, MethodAction action, RootVisibility rootVisibility)
+ {
+ bool markMethod;
+ switch (rootVisibility) {
+ default:
+ markMethod = true;
+ break;
+
+ case RootVisibility.PublicAndFamily:
+ markMethod = method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly;
+ break;
+
+ case RootVisibility.PublicAndFamilyAndAssembly:
+ markMethod = method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly || method.IsAssembly || method.IsFamilyAndAssembly;
+ break;
+ }
+
+ if (markMethod) {
+ context.Annotations.Mark (method);
+ context.Annotations.SetAction (method, action);
+ }
+ }
+
+ static bool HasInternalsVisibleTo (AssemblyDefinition assembly)
+ {
+ foreach (CustomAttribute attribute in assembly.CustomAttributes) {
+ if (attribute.Constructor.DeclaringType.FullName ==
+ "System.Runtime.CompilerServices.InternalsVisibleToAttribute")
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromXApiStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromXApiStep.cs
new file mode 100644
index 000000000000..3d4f7099cea1
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromXApiStep.cs
@@ -0,0 +1,138 @@
+//
+// ResolveFromXApiStep.cs
+//
+// Author:
+// Jb Evain (jbevain@novell.com)
+//
+// (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Xml.XPath;
+
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class ResolveFromXApiStep : ResolveStep, IXApiVisitor {
+
+ static readonly string _name = "name";
+ static readonly string _ns = string.Empty;
+
+ XPathDocument _document;
+
+ public ResolveFromXApiStep (XPathDocument document)
+ {
+ _document = document;
+ }
+
+ protected override void Process ()
+ {
+ XApiReader reader = new XApiReader (_document, this);
+ reader.Process (Context);
+ }
+
+ public void OnAssembly (XPathNavigator nav, AssemblyDefinition assembly)
+ {
+ }
+
+ public void OnAttribute (XPathNavigator nav)
+ {
+ string name = GetName (nav);
+
+ TypeDefinition type = Context.GetType (name);
+ if (type is not null)
+ MarkType (type);
+ }
+
+ public void OnClass (XPathNavigator nav, TypeDefinition type)
+ {
+ MarkType (type);
+ }
+
+ public void OnInterface (XPathNavigator nav, TypeDefinition type)
+ {
+ MarkType (type);
+ }
+
+ public void OnField (XPathNavigator nav, FieldDefinition field)
+ {
+ MarkField (field);
+ }
+
+ public void OnMethod (XPathNavigator nav, MethodDefinition method)
+ {
+ MarkMethod (method);
+ }
+
+ public void OnConstructor (XPathNavigator nav, MethodDefinition method)
+ {
+ MarkMethod (method);
+ }
+
+ public void OnProperty (XPathNavigator nav, PropertyDefinition property)
+ {
+ }
+
+ public void OnEvent (XPathNavigator nav, EventDefinition evt)
+ {
+ if (evt.AddMethod is not null)
+ MarkMethod (evt.AddMethod);
+ if (evt.InvokeMethod is not null)
+ MarkMethod (evt.InvokeMethod);
+ if (evt.RemoveMethod is not null)
+ MarkMethod (evt.RemoveMethod);
+ }
+
+ static string GetName (XPathNavigator nav)
+ {
+ return GetAttribute (nav, _name);
+ }
+
+ static string GetAttribute (XPathNavigator nav, string attribute)
+ {
+ return nav.GetAttribute (attribute, _ns);
+ }
+
+ void MarkType (TypeDefinition type)
+ {
+ InternalMark (type);
+ }
+
+ void MarkField (FieldDefinition field)
+ {
+ InternalMark (field);
+ }
+
+ void InternalMark (IMetadataTokenProvider provider)
+ {
+ Annotations.Mark (provider);
+ Annotations.SetPublic (provider);
+ }
+
+ void MarkMethod (MethodDefinition method)
+ {
+ InternalMark (method);
+ Annotations.MarkIndirectlyCalledMethod (method);
+ Annotations.SetAction (method, MethodAction.Parse);
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromXmlStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromXmlStep.cs
new file mode 100644
index 000000000000..8f794173b839
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveFromXmlStep.cs
@@ -0,0 +1,727 @@
+//
+// ResolveFromXmlStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+// (C) 2007 Novell, Inc.
+// Copyright 2013 Xamarin Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml.XPath;
+
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class XmlResolutionException : Exception {
+ public XmlResolutionException (string message, Exception innerException)
+ : base (message, innerException)
+ {
+ }
+ }
+
+ public class ResolveFromXmlStep : ResolveStep {
+
+ static readonly string _signature = "signature";
+ static readonly string _fullname = "fullname";
+ static readonly string _required = "required";
+ static readonly string _preserve = "preserve";
+ static readonly string _accessors = "accessors";
+ static readonly string _ns = string.Empty;
+
+ static readonly string [] _accessorsAll = new string [] { "all" };
+ static readonly char [] _accessorsSep = new char [] { ';' };
+
+ XPathDocument _document;
+ string _xmlDocumentLocation;
+ string _resourceName;
+ AssemblyDefinition _resourceAssembly;
+
+ public ResolveFromXmlStep (XPathDocument document, string xmlDocumentLocation = "")
+ {
+ _document = document;
+ _xmlDocumentLocation = xmlDocumentLocation;
+ }
+
+ public ResolveFromXmlStep (XPathDocument document, string resourceName, AssemblyDefinition resourceAssembly, string xmlDocumentLocation = "")
+ : this (document, xmlDocumentLocation)
+ {
+ if (string.IsNullOrEmpty (resourceName))
+ throw new ArgumentNullException (nameof (resourceName));
+
+ if (resourceAssembly is null)
+ throw new ArgumentNullException (nameof (resourceAssembly));
+
+ _resourceName = resourceName;
+ _resourceAssembly = resourceAssembly;
+ }
+
+ protected override void Process ()
+ {
+ XPathNavigator nav = _document.CreateNavigator ();
+
+ // This step can be created with XML files that aren't necessarily
+ // linker descriptor files. So bail if we don't have a element.
+ if (!nav.MoveToChild ("linker", _ns))
+ return;
+
+ try {
+ ProcessAssemblies (Context, nav.SelectChildren ("assembly", _ns));
+
+ if (!string.IsNullOrEmpty (_resourceName) && Context.StripResources)
+ Context.Annotations.AddResourceToRemove (_resourceAssembly, _resourceName);
+ } catch (Exception ex) when (!(ex is XmlResolutionException)) {
+ throw new XmlResolutionException (string.Format ("Failed to process XML description: {0}", _xmlDocumentLocation), ex);
+ }
+ }
+
+ protected virtual void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ()) {
+ AssemblyDefinition assembly = GetAssembly (context, GetAssemblyName (iterator.Current));
+ if (assembly is not null)
+ ProcessAssembly (assembly, iterator);
+ }
+ }
+
+ protected virtual void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator)
+ {
+ if (IsExcluded (iterator.Current))
+ return;
+
+ Tracer.Push (assembly);
+ if (GetTypePreserve (iterator.Current) == TypePreserve.All) {
+ foreach (var type in assembly.MainModule.Types)
+ MarkAndPreserveAll (type);
+ } else {
+ ProcessTypes (assembly, iterator.Current.SelectChildren ("type", _ns));
+ ProcessNamespaces (assembly, iterator.Current.SelectChildren ("namespace", _ns));
+ }
+ Tracer.Pop ();
+ }
+
+ void ProcessNamespaces (AssemblyDefinition assembly, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ()) {
+ string fullname = GetFullName (iterator.Current);
+ foreach (TypeDefinition type in assembly.MainModule.Types) {
+ if (type.Namespace != fullname)
+ continue;
+
+ MarkAndPreserveAll (type);
+ }
+ }
+ }
+
+ void MarkAndPreserveAll (TypeDefinition type)
+ {
+ Annotations.MarkAndPush (type);
+ Annotations.SetPreserve (type, TypePreserve.All);
+
+ if (!type.HasNestedTypes) {
+ Tracer.Pop ();
+ return;
+ }
+
+ foreach (TypeDefinition nested in type.NestedTypes)
+ MarkAndPreserveAll (nested);
+
+ Tracer.Pop ();
+ }
+
+ void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ()) {
+ XPathNavigator nav = iterator.Current;
+
+ string fullname = GetFullName (nav);
+
+ if (IsTypePattern (fullname)) {
+ ProcessTypePattern (fullname, assembly, nav);
+ continue;
+ }
+
+ TypeDefinition type = assembly.MainModule.GetType (fullname);
+
+ if (type is null) {
+ if (assembly.MainModule.HasExportedTypes) {
+ foreach (var exported in assembly.MainModule.ExportedTypes) {
+ if (fullname == exported.FullName) {
+ Tracer.Push (exported);
+ MarkingHelpers.MarkExportedType (exported, assembly.MainModule);
+ var resolvedExternal = exported.Resolve ();
+ Tracer.Pop ();
+ if (resolvedExternal is not null) {
+ type = resolvedExternal;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (type is null)
+ continue;
+
+ ProcessType (type, nav);
+ }
+ }
+
+ static bool IsTypePattern (string fullname)
+ {
+ return fullname.IndexOf ("*") != -1;
+ }
+
+ static Regex CreateRegexFromPattern (string pattern)
+ {
+ return new Regex (pattern.Replace (".", @"\.").Replace ("*", "(.*)"));
+ }
+
+ void MatchType (TypeDefinition type, Regex regex, XPathNavigator nav)
+ {
+ if (regex.Match (type.FullName).Success)
+ ProcessType (type, nav);
+
+ if (!type.HasNestedTypes)
+ return;
+
+ foreach (var nt in type.NestedTypes)
+ MatchType (nt, regex, nav);
+ }
+
+ void MatchExportedType (ExportedType exportedType, ModuleDefinition module, Regex regex, XPathNavigator nav)
+ {
+ if (regex.Match (exportedType.FullName).Success) {
+ MarkingHelpers.MarkExportedType (exportedType, module);
+ TypeDefinition type = exportedType.Resolve ();
+ if (type is not null) {
+ ProcessType (type, nav);
+ }
+ }
+ }
+
+
+ void ProcessTypePattern (string fullname, AssemblyDefinition assembly, XPathNavigator nav)
+ {
+ Regex regex = CreateRegexFromPattern (fullname);
+
+ foreach (TypeDefinition type in assembly.MainModule.Types) {
+ MatchType (type, regex, nav);
+ }
+
+ if (assembly.MainModule.HasExportedTypes) {
+ foreach (var exported in assembly.MainModule.ExportedTypes) {
+ MatchExportedType (exported, assembly.MainModule, regex, nav);
+ }
+ }
+ }
+
+ protected virtual void ProcessType (TypeDefinition type, XPathNavigator nav)
+ {
+ if (IsExcluded (nav))
+ return;
+
+ TypePreserve preserve = GetTypePreserve (nav);
+
+ if (!IsRequired (nav)) {
+ Annotations.SetPreserve (type, preserve);
+ return;
+ }
+
+ if (Annotations.IsMarked (type)) {
+ var existingLevel = Annotations.TryGetPreserve (type, out TypePreserve existingPreserve) ? existingPreserve : TypePreserve.Nothing;
+ var duplicateLevel = preserve != TypePreserve.Nothing ? preserve : nav.HasChildren ? TypePreserve.Nothing : TypePreserve.All;
+ Context.LogMessage ($"Duplicate preserve in {_xmlDocumentLocation} of {type.FullName} ({existingLevel}). Duplicate uses ({duplicateLevel})");
+ }
+
+ Annotations.MarkAndPush (type);
+ Tracer.AddDirectDependency (this, type);
+
+ if (type.IsNested) {
+ var parent = type;
+ while (parent.IsNested) {
+ parent = parent.DeclaringType;
+ Annotations.Mark (parent);
+ }
+ }
+
+ if (preserve != TypePreserve.Nothing)
+ Annotations.SetPreserve (type, preserve);
+
+ if (nav.HasChildren) {
+ MarkSelectedFields (nav, type);
+ MarkSelectedMethods (nav, type);
+ MarkSelectedEvents (nav, type);
+ MarkSelectedProperties (nav, type);
+ }
+ Tracer.Pop ();
+ }
+
+ void MarkSelectedFields (XPathNavigator nav, TypeDefinition type)
+ {
+ XPathNodeIterator fields = nav.SelectChildren ("field", _ns);
+ if (fields.Count == 0)
+ return;
+
+ ProcessFields (type, fields);
+ }
+
+ void MarkSelectedMethods (XPathNavigator nav, TypeDefinition type)
+ {
+ XPathNodeIterator methods = nav.SelectChildren ("method", _ns);
+ if (methods.Count == 0)
+ return;
+
+ ProcessMethods (type, methods);
+ }
+
+ void MarkSelectedEvents (XPathNavigator nav, TypeDefinition type)
+ {
+ XPathNodeIterator events = nav.SelectChildren ("event", _ns);
+ if (events.Count == 0)
+ return;
+
+ ProcessEvents (type, events);
+ }
+
+ void MarkSelectedProperties (XPathNavigator nav, TypeDefinition type)
+ {
+ XPathNodeIterator properties = nav.SelectChildren ("property", _ns);
+ if (properties.Count == 0)
+ return;
+
+ ProcessProperties (type, properties);
+ }
+
+ static TypePreserve GetTypePreserve (XPathNavigator nav)
+ {
+ string attribute = GetAttribute (nav, _preserve);
+ if (string.IsNullOrEmpty (attribute))
+ return nav.HasChildren ? TypePreserve.Nothing : TypePreserve.All;
+
+ TypePreserve result;
+ if (Enum.TryParse (attribute, true, out result))
+ return result;
+ return TypePreserve.Nothing;
+ }
+
+ void ProcessFields (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ())
+ ProcessField (type, iterator);
+ }
+
+ protected virtual void ProcessField (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ if (IsExcluded (iterator.Current))
+ return;
+
+ string value = GetSignature (iterator.Current);
+ if (!String.IsNullOrEmpty (value))
+ ProcessFieldSignature (type, value);
+
+ value = GetAttribute (iterator.Current, "name");
+ if (!String.IsNullOrEmpty (value))
+ ProcessFieldName (type, value);
+ }
+
+ void ProcessFieldSignature (TypeDefinition type, string signature)
+ {
+ FieldDefinition field = GetField (type, signature);
+ MarkField (type, field, signature);
+ }
+
+ void MarkField (TypeDefinition type, FieldDefinition field, string signature)
+ {
+ if (field is not null) {
+ if (Annotations.IsMarked (field))
+ Context.LogMessage ($"Duplicate preserve in {_xmlDocumentLocation} of {field.FullName}");
+
+ Annotations.Mark (field);
+ } else {
+ AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type, signature));
+ }
+ }
+
+ void ProcessFieldName (TypeDefinition type, string name)
+ {
+ if (!type.HasFields)
+ return;
+
+ foreach (FieldDefinition field in type.Fields)
+ if (field.Name == name)
+ MarkField (type, field, name);
+ }
+
+ protected static FieldDefinition GetField (TypeDefinition type, string signature)
+ {
+ if (!type.HasFields)
+ return null;
+
+ foreach (FieldDefinition field in type.Fields)
+ if (signature == GetFieldSignature (field))
+ return field;
+
+ return null;
+ }
+
+ static string GetFieldSignature (FieldDefinition field)
+ {
+ return field.FieldType.FullName + " " + field.Name;
+ }
+
+ void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ())
+ ProcessMethod (type, iterator);
+ }
+
+ protected virtual void ProcessMethod (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ if (IsExcluded (iterator.Current))
+ return;
+
+ string value = GetSignature (iterator.Current);
+ if (!String.IsNullOrEmpty (value))
+ ProcessMethodSignature (type, value);
+
+ value = GetAttribute (iterator.Current, "name");
+ if (!String.IsNullOrEmpty (value))
+ ProcessMethodName (type, value);
+ }
+
+ void ProcessMethodSignature (TypeDefinition type, string signature)
+ {
+ MethodDefinition meth = GetMethod (type, signature);
+ MarkMethod (type, meth, signature);
+ }
+
+ void MarkMethod (TypeDefinition type, MethodDefinition method, string signature)
+ {
+ if (method is not null) {
+ MarkMethod (method);
+ } else
+ AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
+ }
+
+ void MarkMethod (MethodDefinition method)
+ {
+ if (Annotations.IsMarked (method))
+ Context.LogMessage ($"Duplicate preserve in {_xmlDocumentLocation} of {method.FullName}");
+
+ Annotations.Mark (method);
+ Annotations.MarkIndirectlyCalledMethod (method);
+ Tracer.AddDirectDependency (this, method);
+ Annotations.SetAction (method, MethodAction.Parse);
+ }
+
+ void MarkMethodIfNotNull (MethodDefinition method)
+ {
+ if (method is null)
+ return;
+
+ MarkMethod (method);
+ }
+
+ void ProcessMethodName (TypeDefinition type, string name)
+ {
+ if (!type.HasMethods)
+ return;
+
+ foreach (MethodDefinition method in type.Methods)
+ if (name == method.Name)
+ MarkMethod (type, method, name);
+ }
+
+ protected static MethodDefinition GetMethod (TypeDefinition type, string signature)
+ {
+ if (type.HasMethods)
+ foreach (MethodDefinition meth in type.Methods)
+ if (signature == GetMethodSignature (meth, false))
+ return meth;
+
+ return null;
+ }
+
+ public static string GetMethodSignature (MethodDefinition meth, bool includeGenericParameters)
+ {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (meth.ReturnType.FullName);
+ sb.Append (" ");
+ sb.Append (meth.Name);
+ if (includeGenericParameters && meth.HasGenericParameters) {
+ sb.Append ("`");
+ sb.Append (meth.GenericParameters.Count);
+ }
+
+ sb.Append ("(");
+ if (meth.HasParameters) {
+ for (int i = 0; i < meth.Parameters.Count; i++) {
+ if (i > 0)
+ sb.Append (",");
+
+ sb.Append (meth.Parameters [i].ParameterType.FullName);
+ }
+ }
+ sb.Append (")");
+ return sb.ToString ();
+ }
+
+ void ProcessEvents (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ())
+ ProcessEvent (type, iterator);
+ }
+
+ protected virtual void ProcessEvent (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ if (IsExcluded (iterator.Current))
+ return;
+
+ string value = GetSignature (iterator.Current);
+ if (!String.IsNullOrEmpty (value))
+ ProcessEventSignature (type, value);
+
+ value = GetAttribute (iterator.Current, "name");
+ if (!String.IsNullOrEmpty (value))
+ ProcessEventName (type, value);
+ }
+
+ void ProcessEventSignature (TypeDefinition type, string signature)
+ {
+ EventDefinition @event = GetEvent (type, signature);
+ MarkEvent (type, @event, signature);
+ }
+
+ void MarkEvent (TypeDefinition type, EventDefinition @event, string signature)
+ {
+ if (@event is not null) {
+ if (Annotations.IsMarked (@event))
+ Context.LogMessage ($"Duplicate preserve in {_xmlDocumentLocation} of {@event.FullName}");
+
+ Annotations.Mark (@event);
+
+ MarkMethod (@event.AddMethod);
+ MarkMethod (@event.RemoveMethod);
+ MarkMethodIfNotNull (@event.InvokeMethod);
+ } else
+ AddUnresolveMarker (string.Format ("T: {0}; E: {1}", type, signature));
+ }
+
+ void ProcessEventName (TypeDefinition type, string name)
+ {
+ if (!type.HasEvents)
+ return;
+
+ foreach (EventDefinition @event in type.Events)
+ if (@event.Name == name)
+ MarkEvent (type, @event, name);
+ }
+
+ protected static EventDefinition GetEvent (TypeDefinition type, string signature)
+ {
+ if (!type.HasEvents)
+ return null;
+
+ foreach (EventDefinition @event in type.Events)
+ if (signature == GetEventSignature (@event))
+ return @event;
+
+ return null;
+ }
+
+ static string GetEventSignature (EventDefinition @event)
+ {
+ return @event.EventType.FullName + " " + @event.Name;
+ }
+
+ void ProcessProperties (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ while (iterator.MoveNext ())
+ ProcessProperty (type, iterator);
+ }
+
+ protected virtual void ProcessProperty (TypeDefinition type, XPathNodeIterator iterator)
+ {
+ if (IsExcluded (iterator.Current))
+ return;
+
+ string value = GetSignature (iterator.Current);
+ if (!String.IsNullOrEmpty (value))
+ ProcessPropertySignature (type, value, GetAccessors (iterator.Current));
+
+ value = GetAttribute (iterator.Current, "name");
+ if (!String.IsNullOrEmpty (value))
+ ProcessPropertyName (type, value, _accessorsAll);
+ }
+
+ void ProcessPropertySignature (TypeDefinition type, string signature, string [] accessors)
+ {
+ PropertyDefinition property = GetProperty (type, signature);
+ MarkProperty (type, property, signature, accessors);
+ }
+
+ void MarkProperty (TypeDefinition type, PropertyDefinition property, string signature, string [] accessors)
+ {
+ if (property is not null) {
+ if (Annotations.IsMarked (property))
+ Context.LogMessage ($"Duplicate preserve in {_xmlDocumentLocation} of {property.FullName}");
+
+ Annotations.Mark (property);
+
+ MarkPropertyAccessors (type, property, accessors);
+ } else
+ AddUnresolveMarker (string.Format ("T: {0}; P: {1}", type, signature));
+ }
+
+ void MarkPropertyAccessors (TypeDefinition type, PropertyDefinition property, string [] accessors)
+ {
+ if (Array.IndexOf (accessors, "all") >= 0) {
+ MarkMethodIfNotNull (property.GetMethod);
+ MarkMethodIfNotNull (property.SetMethod);
+
+ return;
+ }
+ if (property.GetMethod is not null
+ && Array.IndexOf (accessors, "get") >= 0)
+ MarkMethod (property.GetMethod);
+ else if (property.GetMethod is null)
+ AddUnresolveMarker (string.Format ("T: {0}' M: {1} get_{2}", type, property.PropertyType, property.Name));
+
+ if (property.SetMethod is not null
+ && Array.IndexOf (accessors, "set") >= 0)
+ MarkMethod (property.SetMethod);
+ else if (property.SetMethod is null)
+ AddUnresolveMarker (string.Format ("T: {0}' M: System.Void set_{2} ({1})", type, property.PropertyType, property.Name));
+ }
+
+ void ProcessPropertyName (TypeDefinition type, string name, string [] accessors)
+ {
+ if (!type.HasProperties)
+ return;
+
+ foreach (PropertyDefinition property in type.Properties)
+ if (property.Name == name)
+ MarkProperty (type, property, name, accessors);
+ }
+
+ protected static PropertyDefinition GetProperty (TypeDefinition type, string signature)
+ {
+ if (!type.HasProperties)
+ return null;
+
+ foreach (PropertyDefinition property in type.Properties)
+ if (signature == GetPropertySignature (property))
+ return property;
+
+ return null;
+ }
+
+ static string GetPropertySignature (PropertyDefinition property)
+ {
+ return property.PropertyType.FullName + " " + property.Name;
+ }
+
+ protected AssemblyDefinition GetAssembly (LinkContext context, AssemblyNameReference assemblyName)
+ {
+ var assembly = context.Resolve (assemblyName);
+ ProcessReferences (assembly, context);
+ return assembly;
+ }
+
+ protected virtual AssemblyNameReference GetAssemblyName (XPathNavigator nav)
+ {
+ return AssemblyNameReference.Parse (GetFullName (nav));
+ }
+
+ static void ProcessReferences (AssemblyDefinition assembly, LinkContext context)
+ {
+ context.ResolveReferences (assembly);
+ }
+
+ static bool IsRequired (XPathNavigator nav)
+ {
+ string attribute = GetAttribute (nav, _required);
+ if (attribute is null || attribute.Length == 0)
+ return true;
+
+ bool result;
+ if (bool.TryParse (attribute, out result))
+ return result;
+ return false;
+ }
+
+ protected static string GetSignature (XPathNavigator nav)
+ {
+ return GetAttribute (nav, _signature);
+ }
+
+ static string GetFullName (XPathNavigator nav)
+ {
+ return GetAttribute (nav, _fullname);
+ }
+
+ protected static string [] GetAccessors (XPathNavigator nav)
+ {
+ string accessorsValue = GetAttribute (nav, _accessors);
+
+ if (accessorsValue is not null) {
+ string [] accessors = accessorsValue.Split (
+ _accessorsSep, StringSplitOptions.RemoveEmptyEntries);
+
+ if (accessors.Length > 0) {
+ for (int i = 0; i < accessors.Length; ++i)
+ accessors [i] = accessors [i].ToLower ();
+
+ return accessors;
+ }
+ }
+ return _accessorsAll;
+ }
+
+ protected static string GetAttribute (XPathNavigator nav, string attribute)
+ {
+ return nav.GetAttribute (attribute, _ns);
+ }
+
+ protected virtual bool IsExcluded (XPathNavigator nav)
+ {
+ var value = GetAttribute (nav, "feature");
+ if (string.IsNullOrEmpty (value))
+ return false;
+
+ return Context.IsFeatureExcluded (value);
+ }
+
+
+ public override string ToString ()
+ {
+ return "ResolveFromXmlStep: " + _xmlDocumentLocation;
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveStep.cs
new file mode 100644
index 000000000000..604728bef247
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/ResolveStep.cs
@@ -0,0 +1,56 @@
+//
+// ResolveStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+
+namespace Mono.Linker.Steps {
+
+ public abstract class ResolveStep : BaseStep {
+
+ readonly List _unResolved;
+
+ protected ResolveStep ()
+ {
+ _unResolved = new List ();
+ }
+
+ public bool AllMarkerResolved {
+ get { return _unResolved.Count == 0; }
+ }
+
+ public string [] GetUnresolvedMarkers ()
+ {
+ return _unResolved.ToArray ();
+ }
+
+ protected void AddUnresolveMarker (string signature)
+ {
+ _unResolved.Add (signature);
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/SweepStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/SweepStep.cs
new file mode 100644
index 000000000000..dd1e411be8c1
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/SweepStep.cs
@@ -0,0 +1,714 @@
+//
+// SweepStep.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// (C) 2006 Jb Evain
+// (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Collections.Generic;
+using Mono.Cecil.Cil;
+
+namespace Mono.Linker.Steps {
+
+ public class SweepStep : BaseStep {
+ AssemblyDefinition [] assemblies;
+ readonly bool sweepSymbols;
+ readonly HashSet BypassNGenToSave = new HashSet ();
+
+ public SweepStep (bool sweepSymbols = true)
+ {
+ this.sweepSymbols = sweepSymbols;
+ }
+
+ protected override void Process ()
+ {
+ assemblies = Context.Annotations.GetAssemblies ().ToArray ();
+
+ foreach (var assembly in assemblies) {
+ RemoveUnusedAssembly (assembly);
+ }
+
+ foreach (var assembly in assemblies) {
+ ProcessAssemblyAction (assembly);
+ }
+ }
+
+ void RemoveUnusedAssembly (AssemblyDefinition assembly)
+ {
+ switch (Annotations.GetAction (assembly)) {
+ case AssemblyAction.AddBypassNGenUsed:
+ case AssemblyAction.CopyUsed:
+ case AssemblyAction.Link:
+ if (!IsUsedAssembly (assembly))
+ RemoveAssembly (assembly);
+
+ break;
+ }
+ }
+
+ protected void ProcessAssemblyAction (AssemblyDefinition assembly)
+ {
+ switch (Annotations.GetAction (assembly)) {
+ case AssemblyAction.AddBypassNGenUsed:
+ Annotations.SetAction (assembly, AssemblyAction.AddBypassNGen);
+ goto case AssemblyAction.AddBypassNGen;
+
+ case AssemblyAction.AddBypassNGen:
+ // FIXME: AddBypassNGen is just wrong, it should not be action as we need to
+ // turn it to Action.Save here to e.g. correctly update debug symbols
+ if (!Context.KeepTypeForwarderOnlyAssemblies || BypassNGenToSave.Contains (assembly)) {
+ goto case AssemblyAction.Save;
+ }
+
+ break;
+
+ case AssemblyAction.CopyUsed:
+ Annotations.SetAction (assembly, AssemblyAction.Copy);
+ goto case AssemblyAction.Copy;
+
+ case AssemblyAction.Copy:
+ //
+ // Facade assemblies can have unused forwarders pointing to
+ // removed type (when facades are kept)
+ //
+ // main.exe -> facade.dll -> lib.dll
+ // link | copy | link
+ //
+ // when main.exe has unused reference to type in lib.dll
+ //
+ if (SweepTypeForwarders (assembly))
+ Annotations.SetAction (assembly, AssemblyAction.Save);
+
+ break;
+
+ case AssemblyAction.Link:
+ SweepAssembly (assembly);
+ break;
+
+ case AssemblyAction.Save:
+ //
+ // Save means we need to rewrite the assembly due to removed assembly
+ // reference. We do any additional removed assembly reference clean up here
+ //
+ UpdateForwardedTypesScope (assembly);
+ UpdateCustomAttributesTypesScopes (assembly);
+ SweepTypeForwarders (assembly);
+ break;
+ }
+ }
+
+ protected virtual void SweepAssembly (AssemblyDefinition assembly)
+ {
+ var types = new List ();
+
+ foreach (TypeDefinition type in assembly.MainModule.Types) {
+ if (Annotations.IsMarked (type)) {
+ SweepType (type);
+ types.Add (type);
+ continue;
+ }
+
+ if (type.Name == "")
+ types.Add (type);
+ else
+ ElementRemoved (type);
+ }
+
+ assembly.MainModule.Types.Clear ();
+ foreach (TypeDefinition type in types)
+ assembly.MainModule.Types.Add (type);
+
+ SweepResources (assembly);
+ SweepCustomAttributes (assembly);
+
+ foreach (var module in assembly.Modules)
+ SweepCustomAttributes (module);
+
+ SweepTypeForwarders (assembly);
+
+ UpdateForwardedTypesScope (assembly);
+ }
+
+ bool IsUsedAssembly (AssemblyDefinition assembly)
+ {
+ if (IsMarkedAssembly (assembly))
+ return true;
+
+ if (assembly.MainModule.HasExportedTypes && Context.KeepTypeForwarderOnlyAssemblies)
+ return true;
+
+ return false;
+ }
+
+ bool IsMarkedAssembly (AssemblyDefinition assembly)
+ {
+ return Annotations.IsMarked (assembly.MainModule);
+ }
+
+ protected virtual void RemoveAssembly (AssemblyDefinition assembly)
+ {
+ Annotations.SetAction (assembly, AssemblyAction.Delete);
+
+ foreach (var a in assemblies) {
+ switch (Annotations.GetAction (a)) {
+ case AssemblyAction.Skip:
+ case AssemblyAction.Delete:
+ continue;
+ }
+
+ SweepReferences (a, assembly);
+ }
+ }
+
+ void SweepResources (AssemblyDefinition assembly)
+ {
+ var resourcesToRemove = Annotations.GetResourcesToRemove (assembly);
+ if (resourcesToRemove is not null) {
+ var resources = assembly.MainModule.Resources;
+
+ for (int i = 0; i < resources.Count; i++) {
+ var resource = resources [i] as EmbeddedResource;
+ if (resource is null)
+ continue;
+
+ if (resourcesToRemove.Contains (resource.Name))
+ resources.RemoveAt (i--);
+ }
+ }
+ }
+
+ void SweepReferences (AssemblyDefinition assembly, AssemblyDefinition referenceToRemove)
+ {
+ if (assembly == referenceToRemove)
+ return;
+
+ bool reference_removed = false;
+
+ var references = assembly.MainModule.AssemblyReferences;
+ for (int i = 0; i < references.Count; i++) {
+ var reference = references [i];
+
+ AssemblyDefinition ad = Context.Resolver.Resolve (reference);
+ if (ad is null || !AreSameReference (ad.Name, referenceToRemove.Name))
+ continue;
+
+ ReferenceRemoved (assembly, reference);
+ references.RemoveAt (i--);
+ reference_removed = true;
+ }
+
+ if (reference_removed) {
+ switch (Annotations.GetAction (assembly)) {
+ case AssemblyAction.CopyUsed:
+ if (IsUsedAssembly (assembly)) {
+ goto case AssemblyAction.Copy;
+ }
+ break;
+
+ case AssemblyAction.Copy:
+ //
+ // Assembly has a reference to another assembly which has been fully removed. This can
+ // happen when for example the reference assembly is 'copy-used' and it's not needed.
+ //
+ // or
+ //
+ // Assembly can contain type references with
+ // type forwarders to deleted assembly (facade) when
+ // facade assemblies are not kept. For that reason we need to
+ // rewrite the copy to save to update the scopes not to point
+ // forwarding assembly (facade).
+ //
+ // foo.dll -> facade.dll -> lib.dll
+ // copy | copy (delete) | link
+ //
+ Annotations.SetAction (assembly, AssemblyAction.Save);
+ break;
+
+ case AssemblyAction.AddBypassNGenUsed:
+ if (IsUsedAssembly (assembly)) {
+ Annotations.SetAction (assembly, AssemblyAction.AddBypassNGen);
+ goto case AssemblyAction.AddBypassNGen;
+ }
+ break;
+
+ case AssemblyAction.AddBypassNGen:
+ BypassNGenToSave.Add (assembly);
+ break;
+ }
+ }
+ }
+
+ bool SweepTypeForwarders (AssemblyDefinition assembly)
+ {
+ if (assembly.MainModule.HasExportedTypes) {
+ return SweepCollectionMetadata (assembly.MainModule.ExportedTypes);
+ }
+
+ return false;
+ }
+
+ void UpdateForwardedTypesScope (AssemblyDefinition assembly)
+ {
+ var changed_types = new Dictionary ();
+
+ foreach (TypeReference tr in assembly.MainModule.GetTypeReferences ()) {
+ if (tr.IsWindowsRuntimeProjection)
+ continue;
+
+ TypeDefinition td;
+ try {
+ td = tr.Resolve ();
+ } catch (AssemblyResolutionException) {
+ // Don't crash on unresolved assembly
+ continue;
+ }
+
+ // at this stage reference might include things that can't be resolved
+ // and if it is (resolved) it needs to be kept only if marked (#16213)
+ if (td is null || !Annotations.IsMarked (td))
+ continue;
+
+ IMetadataScope scope = assembly.MainModule.ImportReference (td).Scope;
+ if (tr.Scope != scope)
+ changed_types.Add (tr, scope);
+ }
+
+ //
+ // Resolved everything first before updating scopes.
+ // If we set the scope to null, then calling Resolve() on any of its
+ // nested types would crash.
+ //
+ foreach (var e in changed_types) {
+ e.Key.Scope = e.Value;
+ }
+
+ if (assembly.MainModule.HasExportedTypes) {
+ foreach (var et in assembly.MainModule.ExportedTypes) {
+ var td = et.Resolve ();
+ if (td is null)
+ continue;
+
+ et.Scope = assembly.MainModule.ImportReference (td).Scope;
+ }
+ }
+ }
+
+ static void UpdateCustomAttributesTypesScopes (AssemblyDefinition assembly)
+ {
+ UpdateCustomAttributesTypesScopes ((ICustomAttributeProvider) assembly);
+
+ foreach (var module in assembly.Modules)
+ UpdateCustomAttributesTypesScopes (module);
+
+ foreach (var type in assembly.MainModule.Types)
+ UpdateCustomAttributesTypesScopes (type);
+ }
+
+ static void UpdateCustomAttributesTypesScopes (TypeDefinition typeDefinition)
+ {
+ UpdateCustomAttributesTypesScopes ((ICustomAttributeProvider) typeDefinition);
+
+ if (typeDefinition.HasEvents)
+ UpdateCustomAttributesTypesScopes (typeDefinition.Events);
+
+ if (typeDefinition.HasFields)
+ UpdateCustomAttributesTypesScopes (typeDefinition.Fields);
+
+ if (typeDefinition.HasMethods)
+ UpdateCustomAttributesTypesScopes (typeDefinition.Methods);
+
+ if (typeDefinition.HasProperties)
+ UpdateCustomAttributesTypesScopes (typeDefinition.Properties);
+
+ if (typeDefinition.HasGenericParameters)
+ UpdateCustomAttributesTypesScopes (typeDefinition.GenericParameters);
+
+ if (typeDefinition.HasNestedTypes) {
+ foreach (var nestedType in typeDefinition.NestedTypes) {
+ UpdateCustomAttributesTypesScopes (nestedType);
+ }
+ }
+ }
+
+ static void UpdateCustomAttributesTypesScopes (Collection providers) where T : ICustomAttributeProvider
+ {
+ foreach (var provider in providers)
+ UpdateCustomAttributesTypesScopes (provider);
+ }
+
+ static void UpdateCustomAttributesTypesScopes (Collection genericParameters)
+ {
+ foreach (var gp in genericParameters) {
+ UpdateCustomAttributesTypesScopes (gp);
+
+ if (gp.HasConstraints)
+ UpdateCustomAttributesTypesScopes (gp.Constraints);
+ }
+ }
+
+ static void UpdateCustomAttributesTypesScopes (ICustomAttributeProvider customAttributeProvider)
+ {
+ if (!customAttributeProvider.HasCustomAttributes)
+ return;
+
+ foreach (var ca in customAttributeProvider.CustomAttributes)
+ UpdateForwardedTypesScope (ca);
+ }
+
+ static void UpdateForwardedTypesScope (CustomAttribute attribute)
+ {
+ AssemblyDefinition assembly = attribute.Constructor.Module.Assembly;
+
+ if (attribute.HasConstructorArguments) {
+ foreach (var ca in attribute.ConstructorArguments)
+ UpdateForwardedTypesScope (ca, assembly);
+ }
+
+ if (attribute.HasFields) {
+ foreach (var field in attribute.Fields)
+ UpdateForwardedTypesScope (field.Argument, assembly);
+ }
+
+ if (attribute.HasProperties) {
+ foreach (var property in attribute.Properties)
+ UpdateForwardedTypesScope (property.Argument, assembly);
+ }
+ }
+
+ static void UpdateForwardedTypesScope (CustomAttributeArgument attributeArgument, AssemblyDefinition assembly)
+ {
+ UpdateTypeScope (attributeArgument.Type, assembly);
+
+ switch (attributeArgument.Value) {
+ case TypeReference tr:
+ UpdateTypeScope (tr, assembly);
+ break;
+ case CustomAttributeArgument caa:
+ UpdateForwardedTypesScope (caa, assembly);
+ break;
+ case CustomAttributeArgument [] array:
+ foreach (var item in array)
+ UpdateForwardedTypesScope (item, assembly);
+ break;
+ }
+ }
+
+ static void UpdateTypeScope (TypeReference type, AssemblyDefinition assembly)
+ {
+ // Can't update the scope of windows runtime projections
+ if (type.IsWindowsRuntimeProjection)
+ return;
+
+ if (type is GenericInstanceType git && git.HasGenericArguments) {
+ UpdateTypeScope (git.ElementType, assembly);
+ foreach (var ga in git.GenericArguments)
+ UpdateTypeScope (ga, assembly);
+ return;
+ }
+
+ if (type is ArrayType at) {
+ UpdateTypeScope (at.ElementType, assembly);
+ return;
+ }
+
+ TypeDefinition td = type.Resolve ();
+ if (td is null)
+ return;
+
+ IMetadataScope scope = assembly.MainModule.ImportReference (td).Scope;
+ if (type.Scope != scope)
+ type.Scope = td.Scope;
+ }
+
+ protected virtual void SweepType (TypeDefinition type)
+ {
+ if (type.HasFields)
+ SweepCollectionWithCustomAttributes (type.Fields);
+
+ if (type.HasMethods)
+ SweepMethods (type.Methods);
+
+ if (type.HasNestedTypes)
+ SweepNestedTypes (type);
+
+ if (type.HasInterfaces)
+ SweepInterfaces (type);
+
+ if (type.HasCustomAttributes)
+ SweepCustomAttributes (type);
+
+ if (type.HasGenericParameters)
+ SweepGenericParameters (type.GenericParameters);
+
+ if (type.HasProperties)
+ SweepCustomAttributeCollection (type.Properties);
+
+ if (type.HasEvents)
+ SweepCustomAttributeCollection (type.Events);
+
+ if (type.HasFields && !type.IsBeforeFieldInit && !Annotations.HasPreservedStaticCtor (type) && !type.IsEnum)
+ type.IsBeforeFieldInit = true;
+ }
+
+ protected void SweepNestedTypes (TypeDefinition type)
+ {
+ for (int i = 0; i < type.NestedTypes.Count; i++) {
+ var nested = type.NestedTypes [i];
+ if (Annotations.IsMarked (nested)) {
+ SweepType (nested);
+ } else {
+ ElementRemoved (type.NestedTypes [i]);
+ type.NestedTypes.RemoveAt (i--);
+ }
+ }
+ }
+
+ protected void SweepInterfaces (TypeDefinition type)
+ {
+ for (int i = type.Interfaces.Count - 1; i >= 0; i--) {
+ var iface = type.Interfaces [i];
+ if (Annotations.IsMarked (iface)) {
+ SweepCustomAttributes (iface);
+ continue;
+ }
+ InterfaceRemoved (type, iface);
+ type.Interfaces.RemoveAt (i);
+ }
+ }
+
+ protected void SweepGenericParameters (Collection genericParameters)
+ {
+ foreach (var gp in genericParameters) {
+ SweepCustomAttributes (gp);
+
+ if (gp.HasConstraints)
+ SweepCustomAttributeCollection (gp.Constraints);
+ }
+ }
+
+ protected void SweepCustomAttributes (TypeDefinition type)
+ {
+ var removed = SweepCustomAttributes (type as ICustomAttributeProvider);
+
+ if (ShouldSetHasSecurityToFalse (type, type, type.HasSecurity, removed))
+ type.HasSecurity = false;
+ }
+
+ protected void SweepCustomAttributes (MethodDefinition method)
+ {
+ var removed = SweepCustomAttributes (method as ICustomAttributeProvider);
+
+ if (ShouldSetHasSecurityToFalse (method, method, method.HasSecurity, removed))
+ method.HasSecurity = false;
+ }
+
+ bool ShouldSetHasSecurityToFalse (ISecurityDeclarationProvider providerAsSecurity, ICustomAttributeProvider provider, bool existingHasSecurity, IList removedAttributes)
+ {
+ if (existingHasSecurity && removedAttributes.Count > 0 && !providerAsSecurity.HasSecurityDeclarations) {
+ // If the method or type had security before and all attributes were removed, or no remaining attributes are security attributes,
+ // then we need to set HasSecurity to false
+ if (provider.CustomAttributes.Count == 0 || provider.CustomAttributes.All (attr => !IsSecurityAttributeType (attr.AttributeType.Resolve ())))
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool IsSecurityAttributeType (TypeDefinition definition)
+ {
+ if (definition is null)
+ return false;
+
+ if (definition.Namespace == "System.Security") {
+ switch (definition.FullName) {
+ // This seems to be one attribute in the System.Security namespace that doesn't count
+ // as an attribute that requires HasSecurity to be true
+ case "System.Security.SecurityCriticalAttribute":
+ return false;
+ }
+
+ return true;
+ }
+
+ if (definition.BaseType is null)
+ return false;
+
+ return IsSecurityAttributeType (definition.BaseType.Resolve ());
+ }
+
+ protected IList SweepCustomAttributes (ICustomAttributeProvider provider)
+ {
+ var removed = new List ();
+
+ for (int i = provider.CustomAttributes.Count - 1; i >= 0; i--) {
+ var attribute = provider.CustomAttributes [i];
+ if (Annotations.IsMarked (attribute)) {
+ UpdateForwardedTypesScope (attribute);
+ } else {
+ CustomAttributeUsageRemoved (provider, attribute);
+ removed.Add (provider.CustomAttributes [i]);
+ provider.CustomAttributes.RemoveAt (i);
+ }
+ }
+
+ return removed;
+ }
+
+ protected void SweepCustomAttributeCollection (Collection providers) where T : ICustomAttributeProvider
+ {
+ foreach (var provider in providers)
+ SweepCustomAttributes (provider);
+ }
+
+ protected virtual void SweepMethods (Collection methods)
+ {
+ SweepCollectionWithCustomAttributes (methods);
+ if (sweepSymbols)
+ SweepDebugInfo (methods);
+
+ foreach (var method in methods) {
+ if (method.HasGenericParameters)
+ SweepGenericParameters (method.GenericParameters);
+
+ SweepCustomAttributes (method.MethodReturnType);
+
+ if (!method.HasParameters)
+ continue;
+
+ foreach (var parameter in method.Parameters)
+ SweepCustomAttributes (parameter);
+ }
+ }
+
+ void SweepDebugInfo (Collection methods)
+ {
+ List sweptScopes = null;
+ foreach (var m in methods) {
+ if (m.DebugInformation is null)
+ continue;
+
+ var scope = m.DebugInformation.Scope;
+ if (scope is null)
+ continue;
+
+ if (sweptScopes is null) {
+ sweptScopes = new List ();
+ } else if (sweptScopes.Contains (scope)) {
+ continue;
+ }
+
+ sweptScopes.Add (scope);
+
+ if (scope.HasConstants) {
+ var constants = scope.Constants;
+ for (int i = 0; i < constants.Count; ++i) {
+ if (!Annotations.IsMarked (constants [i].ConstantType))
+ constants.RemoveAt (i--);
+ }
+ }
+
+ var import = scope.Import;
+ while (import is not null) {
+ if (import.HasTargets) {
+ var targets = import.Targets;
+ for (int i = 0; i < targets.Count; ++i) {
+ var ttype = targets [i].Type;
+ if (ttype is not null && !Annotations.IsMarked (ttype))
+ targets.RemoveAt (i--);
+
+ // TODO: Clear also AssemblyReference and Namespace when not marked
+ }
+ }
+
+ import = import.Parent;
+ }
+ }
+ }
+
+ protected void SweepCollectionWithCustomAttributes (IList list) where T : ICustomAttributeProvider
+ {
+ for (int i = 0; i < list.Count; i++)
+ if (ShouldRemove (list [i])) {
+ ElementRemoved (list [i]);
+ list.RemoveAt (i--);
+ } else {
+ SweepCustomAttributes (list [i]);
+ }
+ }
+
+ protected bool SweepCollectionMetadata (IList list) where T : IMetadataTokenProvider
+ {
+ bool removed = false;
+
+ for (int i = 0; i < list.Count; i++) {
+ if (ShouldRemove (list [i])) {
+ ElementRemoved (list [i]);
+ list.RemoveAt (i--);
+ removed = true;
+ }
+ }
+
+ return removed;
+ }
+
+ protected virtual bool ShouldRemove (T element) where T : IMetadataTokenProvider
+ {
+ return !Annotations.IsMarked (element);
+ }
+
+ static bool AreSameReference (AssemblyNameReference a, AssemblyNameReference b)
+ {
+ if (a == b)
+ return true;
+
+ if (a.Name != b.Name)
+ return false;
+
+ if (a.Version > b.Version)
+ return false;
+
+ return true;
+ }
+
+ protected virtual void ElementRemoved (IMetadataTokenProvider element)
+ {
+ }
+
+ protected virtual void ReferenceRemoved (AssemblyDefinition assembly, AssemblyNameReference reference)
+ {
+ }
+
+ protected virtual void InterfaceRemoved (TypeDefinition type, InterfaceImplementation iface)
+ {
+ }
+
+ protected virtual void CustomAttributeUsageRemoved (ICustomAttributeProvider provider, CustomAttribute attribute)
+ {
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/TypeMapStep.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/TypeMapStep.cs
new file mode 100644
index 000000000000..053ad77373d9
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker.Steps/TypeMapStep.cs
@@ -0,0 +1,371 @@
+//
+// TypeMapStep.cs
+//
+// Author:
+// Jb Evain (jbevain@novell.com)
+//
+// (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+using Mono.Cecil;
+
+namespace Mono.Linker.Steps {
+
+ public class TypeMapStep : BaseStep {
+
+ protected override void ProcessAssembly (AssemblyDefinition assembly)
+ {
+ foreach (TypeDefinition type in assembly.MainModule.Types)
+ MapType (type);
+ }
+
+ protected virtual void MapType (TypeDefinition type)
+ {
+ MapVirtualMethods (type);
+ MapInterfaceMethodsInTypeHierarchy (type);
+ MapInterfaceHierarchy (type);
+ MapBaseTypeHierarchy (type);
+
+ if (!type.HasNestedTypes)
+ return;
+
+ foreach (var nested in type.NestedTypes)
+ MapType (nested);
+ }
+
+ void MapInterfaceHierarchy (TypeDefinition type)
+ {
+ if (!type.IsInterface || !type.HasInterfaces)
+ return;
+
+ foreach (var iface in type.Interfaces) {
+ var resolved = iface.InterfaceType.Resolve ();
+ if (resolved is null)
+ continue;
+
+ Annotations.AddDerivedInterfaceForInterface (resolved, type);
+ }
+ }
+
+ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
+ {
+ if (!type.HasInterfaces)
+ return;
+
+ foreach (var @interface in type.Interfaces) {
+ var interfaceType = @interface.InterfaceType;
+ var iface = interfaceType.Resolve ();
+ if (iface is null || !iface.HasMethods)
+ continue;
+
+ foreach (MethodDefinition interfaceMethod in iface.Methods) {
+ if (TryMatchMethod (type, interfaceMethod) is not null)
+ continue;
+
+ var @base = GetBaseMethodInTypeHierarchy (type, interfaceMethod);
+ if (@base is not null)
+ AnnotateMethods (interfaceMethod, @base, @interface);
+
+ if (interfaceType is GenericInstanceType genericInterfaceInstance) {
+ var genericContext = new Inflater.GenericContext (genericInterfaceInstance, null);
+ var baseInflated = GetBaseInflatedInterfaceMethodInTypeHierarchy (genericContext, type, interfaceMethod);
+ if (baseInflated is not null)
+ Annotations.AddOverride (interfaceMethod, baseInflated, @interface);
+ }
+ }
+ }
+ }
+
+ static MethodReference CreateGenericInstanceCandidate (Inflater.GenericContext context, TypeDefinition candidateType, MethodDefinition interfaceMethod)
+ {
+ var methodReference = new MethodReference (interfaceMethod.Name, interfaceMethod.ReturnType, candidateType) { HasThis = interfaceMethod.HasThis };
+
+ foreach (var genericMethodParameter in interfaceMethod.GenericParameters)
+ methodReference.GenericParameters.Add (new GenericParameter (genericMethodParameter.Name, methodReference));
+
+ if (interfaceMethod.ReturnType.IsGenericParameter || interfaceMethod.ReturnType.IsGenericInstance)
+ methodReference.ReturnType = Inflater.InflateType (context, interfaceMethod.ReturnType);
+
+ foreach (var p in interfaceMethod.Parameters) {
+ var parameterType = p.ParameterType;
+ if (parameterType.IsGenericParameter || parameterType.IsGenericInstance)
+ parameterType = Inflater.InflateType (context, parameterType);
+
+ methodReference.Parameters.Add (new ParameterDefinition (p.Name, p.Attributes, parameterType));
+ }
+
+ return methodReference;
+ }
+
+ void MapVirtualMethods (TypeDefinition type)
+ {
+ if (!type.HasMethods)
+ return;
+
+ foreach (MethodDefinition method in type.Methods) {
+ if (!method.IsVirtual)
+ continue;
+
+ MapVirtualMethod (method);
+
+ if (method.HasOverrides)
+ MapOverrides (method);
+ }
+ }
+
+ void MapVirtualMethod (MethodDefinition method)
+ {
+ MapVirtualBaseMethod (method);
+ MapVirtualInterfaceMethod (method);
+ }
+
+ void MapVirtualBaseMethod (MethodDefinition method)
+ {
+ MethodDefinition @base = GetBaseMethodInTypeHierarchy (method);
+ if (@base is null)
+ return;
+
+ AnnotateMethods (@base, method);
+ }
+
+ void MapVirtualInterfaceMethod (MethodDefinition method)
+ {
+ foreach (MethodDefinition @base in GetBaseMethodsInInterfaceHierarchy (method))
+ AnnotateMethods (@base, method);
+ }
+
+ void MapOverrides (MethodDefinition method)
+ {
+ foreach (MethodReference override_ref in method.Overrides) {
+ MethodDefinition @override = override_ref.Resolve ();
+ if (@override is null)
+ continue;
+
+ AnnotateMethods (@override, method);
+ }
+ }
+
+ void MapBaseTypeHierarchy (TypeDefinition type)
+ {
+ if (!type.IsClass)
+ return;
+
+ var bases = new List ();
+ var current = type.BaseType;
+
+ while (current is not null) {
+ var resolved = current.Resolve ();
+ if (resolved is null)
+ break;
+
+ // Exclude Object. That's implied and adding it to the list will just lead to lots of extra unnecessary processing
+ if (resolved.BaseType is null)
+ break;
+
+ bases.Add (resolved);
+ current = resolved.BaseType;
+ }
+
+ Annotations.SetClassHierarchy (type, bases);
+ }
+
+ void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, InterfaceImplementation matchingInterfaceImplementation = null)
+ {
+ Annotations.AddBaseMethod (@override, @base);
+ Annotations.AddOverride (@base, @override, matchingInterfaceImplementation);
+ }
+
+ static MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method)
+ {
+ return GetBaseMethodInTypeHierarchy (method.DeclaringType, method);
+ }
+
+ static MethodDefinition GetBaseMethodInTypeHierarchy (TypeDefinition type, MethodDefinition method)
+ {
+ TypeReference @base = type.GetInflatedBaseType ();
+ while (@base is not null) {
+ MethodDefinition base_method = TryMatchMethod (@base, method);
+ if (base_method is not null)
+ return base_method;
+
+ @base = @base.GetInflatedBaseType ();
+ }
+
+ return null;
+ }
+
+ static MethodDefinition GetBaseInflatedInterfaceMethodInTypeHierarchy (Inflater.GenericContext context, TypeDefinition type, MethodDefinition interfaceMethod)
+ {
+ TypeReference @base = type.GetInflatedBaseType ();
+ while (@base is not null) {
+ var candidate = CreateGenericInstanceCandidate (context, @base.Resolve (), interfaceMethod);
+
+ MethodDefinition base_method = TryMatchMethod (@base, candidate);
+ if (base_method is not null)
+ return base_method;
+
+ @base = @base.GetInflatedBaseType ();
+ }
+
+ return null;
+ }
+
+ static IEnumerable GetBaseMethodsInInterfaceHierarchy (MethodDefinition method)
+ {
+ return GetBaseMethodsInInterfaceHierarchy (method.DeclaringType, method);
+ }
+
+ static IEnumerable GetBaseMethodsInInterfaceHierarchy (TypeReference type, MethodDefinition method)
+ {
+ foreach (TypeReference @interface in type.GetInflatedInterfaces ()) {
+ MethodDefinition base_method = TryMatchMethod (@interface, method);
+ if (base_method is not null)
+ yield return base_method;
+
+ foreach (MethodDefinition @base in GetBaseMethodsInInterfaceHierarchy (@interface, method))
+ yield return @base;
+ }
+ }
+
+ static MethodDefinition TryMatchMethod (TypeReference type, MethodReference method)
+ {
+ foreach (var candidate in type.GetMethods ()) {
+ if (MethodMatch (candidate, method))
+ return candidate.Resolve ();
+ }
+
+ return null;
+ }
+
+ static bool MethodMatch (MethodReference candidate, MethodReference method)
+ {
+ var candidateDef = candidate.Resolve ();
+
+ if (!candidateDef.IsVirtual)
+ return false;
+
+ if (candidate.HasParameters != method.HasParameters)
+ return false;
+
+ if (candidate.Name != method.Name)
+ return false;
+
+ if (candidate.HasGenericParameters != method.HasGenericParameters)
+ return false;
+
+ // we need to track what the generic parameter represent - as we cannot allow it to
+ // differ between the return type or any parameter
+ if (!TypeMatch (candidate.GetReturnType (), method.GetReturnType ()))
+ return false;
+
+ if (!candidate.HasParameters)
+ return true;
+
+ var cp = candidate.Parameters;
+ var mp = method.Parameters;
+ if (cp.Count != mp.Count)
+ return false;
+
+ if (candidate.GenericParameters.Count != method.GenericParameters.Count)
+ return false;
+
+ for (int i = 0; i < cp.Count; i++) {
+ if (!TypeMatch (candidate.GetParameterType (i), method.GetParameterType (i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool TypeMatch (IModifierType a, IModifierType b)
+ {
+ if (!TypeMatch (a.ModifierType, b.ModifierType))
+ return false;
+
+ return TypeMatch (a.ElementType, b.ElementType);
+ }
+
+ static bool TypeMatch (TypeSpecification a, TypeSpecification b)
+ {
+ var gita = a as GenericInstanceType;
+ if (gita is not null)
+ return TypeMatch (gita, (GenericInstanceType) b);
+
+ var mta = a as IModifierType;
+ if (mta is not null)
+ return TypeMatch (mta, (IModifierType) b);
+
+ return TypeMatch (a.ElementType, b.ElementType);
+ }
+
+ static bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
+ {
+ if (!TypeMatch (a.ElementType, b.ElementType))
+ return false;
+
+ if (a.HasGenericArguments != b.HasGenericArguments)
+ return false;
+
+ if (!a.HasGenericArguments)
+ return true;
+
+ var gaa = a.GenericArguments;
+ var gab = b.GenericArguments;
+ if (gaa.Count != gab.Count)
+ return false;
+
+ for (int i = 0; i < gaa.Count; i++) {
+ if (!TypeMatch (gaa [i], gab [i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool TypeMatch (GenericParameter a, GenericParameter b)
+ {
+ if (a.Position != b.Position)
+ return false;
+
+ if (a.Type != b.Type)
+ return false;
+
+ return true;
+ }
+
+ static bool TypeMatch (TypeReference a, TypeReference b)
+ {
+ if (a is TypeSpecification || b is TypeSpecification) {
+ if (a.GetType () != b.GetType ())
+ return false;
+
+ return TypeMatch ((TypeSpecification) a, (TypeSpecification) b);
+ }
+
+ if (a is GenericParameter && b is GenericParameter)
+ return TypeMatch ((GenericParameter) a, (GenericParameter) b);
+
+ return a.FullName == b.FullName;
+ }
+ }
+}
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/Annotations.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/Annotations.cs
new file mode 100644
index 000000000000..c060892ba545
--- /dev/null
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/Annotations.cs
@@ -0,0 +1,464 @@
+//
+// Annotations.cs
+//
+// Author:
+// Jb Evain (jbevain@novell.com)
+//
+// (C) 2007 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Mono.Linker {
+
+ public partial class AnnotationStore {
+
+ protected readonly LinkContext context;
+
+ protected readonly Dictionary assembly_actions = new Dictionary ();
+ protected readonly Dictionary method_actions = new Dictionary ();
+ protected readonly Dictionary method_stub_values = new Dictionary ();
+ protected readonly Dictionary field_values = new Dictionary ();
+ protected readonly HashSet field_init = new HashSet ();
+ protected readonly HashSet fieldType_init = new HashSet ();
+ protected readonly HashSet marked = new HashSet ();
+ protected readonly HashSet processed = new HashSet ();
+ protected readonly Dictionary preserved_types = new Dictionary ();
+ protected readonly Dictionary> preserved_methods = new Dictionary> ();
+ protected readonly HashSet public_api = new HashSet ();
+ protected readonly Dictionary> override_methods = new Dictionary> ();
+ protected readonly Dictionary> base_methods = new Dictionary> ();
+ protected readonly Dictionary symbol_readers = new Dictionary ();
+ protected readonly Dictionary> class_type_base_hierarchy = new Dictionary> ();
+ protected readonly Dictionary> derived_interfaces = new Dictionary> ();
+
+ protected readonly Dictionary