|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Help;
using System.CommandLine.Parsing;
using System.Linq;
using Internal.TypeSystem;
namespace ILCompiler
{
internal sealed class ILCompilerRootCommand : RootCommand
{
public Argument<Dictionary<string, string>> InputFilePaths { get; } =
new("input-file-path") { CustomParser = result => Helpers.BuildPathDictionary(result.Tokens, true), Description = "Input file(s)", Arity = ArgumentArity.OneOrMore };
public Option<Dictionary<string, string>> ReferenceFiles { get; } =
new("--reference", "-r") { CustomParser = result => Helpers.BuildPathDictionary(result.Tokens, false), DefaultValueFactory = result => Helpers.BuildPathDictionary(result.Tokens, false), Description = "Reference file(s) for compilation" };
public Option<string> OutputFilePath { get; } =
new("--out", "-o") { Description = "Output file path" };
public Option<bool> Optimize { get; } =
new("--optimize", "-O") { Description = "Enable optimizations" };
public Option<bool> OptimizeSpace { get; } =
new("--optimize-space", "--Os") { Description = "Enable optimizations, favor code space" };
public Option<bool> OptimizeTime { get; } =
new("--optimize-time", "--Ot") { Description = "Enable optimizations, favor code speed" };
public Option<string[]> MibcFilePaths { get; } =
new("--mibc", "-m") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Mibc file(s) for profile guided optimization" };
public Option<MethodLayoutAlgorithm> MethodLayout { get; } =
new("--method-layout") { CustomParser = MakeMethodLayoutAlgorithm, DefaultValueFactory = MakeMethodLayoutAlgorithm, Description = "Layout algorithm used by profile-driven optimization for arranging methods in a file.", HelpName = "arg" };
public Option<FileLayoutAlgorithm> FileLayout { get; } =
new("--file-layout") { CustomParser = MakeFileLayoutAlgorithm, DefaultValueFactory = MakeFileLayoutAlgorithm, Description = "Layout algorithm used by profile-driven optimization for arranging non-method contents in a file.", HelpName = "arg" };
public Option<string> OrderFile { get; } =
new("--order") { Description = "File that specifies order of symbols within the generated object file" };
public Option<string[]> SatelliteFilePaths { get; } =
new("--satellite") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Satellite assemblies associated with inputs/references" };
public Option<bool> EnableDebugInfo { get; } =
new("--debug", "-g") { Description = "Emit debugging information" };
public Option<bool> UseDwarf5 { get; } =
new("--gdwarf-5") { Description = "Generate source-level debug information with dwarf version 5" };
public Option<bool> NativeLib { get; } =
new("--nativelib") { Description = "Compile as static or shared library" };
public Option<bool> SplitExeInitialization { get; } =
new("--splitinit") { Description = "Split initialization of an executable between the library entrypoint and a main entrypoint" };
public Option<string> ExportsFile { get; } =
new("--exportsfile") { Description = "File to write exported symbol and method definitions" };
public Option<bool> ExportUnmanagedEntryPoints { get; } =
new("--export-unmanaged-entrypoints") { Description = "Controls whether the named UnmanagedCallersOnly methods are exported" };
public Option<string[]> ExportDynamicSymbols { get; } =
new("--export-dynamic-symbol") { Description = "Add dynamic export symbol to exports file" };
public Option<string> DgmlLogFileName { get; } =
new("--dgmllog") { Description = "Save result of dependency analysis as DGML" };
public Option<bool> GenerateFullDgmlLog { get; } =
new("--fulllog") { Description = "Save detailed log of dependency analysis" };
public Option<string> ScanDgmlLogFileName { get; } =
new("--scandgmllog") { Description = "Save result of scanner dependency analysis as DGML" };
public Option<bool> GenerateFullScanDgmlLog { get; } =
new("--scanfulllog") { Description = "Save detailed log of scanner dependency analysis" };
public Option<bool> IsVerbose { get; } =
new("--verbose") { Description = "Enable verbose logging" };
public Option<string> SystemModuleName { get; } =
new("--systemmodule") { DefaultValueFactory = _ => Helpers.DefaultSystemModule, Description = "System module name (default: System.Private.CoreLib)" };
public Option<string> Win32ResourceModuleName { get; } =
new("--win32resourcemodule") { Description = "Name of the module from which to copy Win32 resources (Windows target only)" };
public Option<bool> MultiFile { get; } =
new("--multifile") { Description = "Compile only input files (do not compile referenced assemblies)" };
public Option<bool> WaitForDebugger { get; } =
new("--waitfordebugger") { Description = "Pause to give opportunity to attach debugger" };
public Option<bool> Resilient { get; } =
new("--resilient") { Description = "Ignore unresolved types, methods, and assemblies. Defaults to false" };
public Option<string[]> CodegenOptions { get; } =
new("--codegenopt") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Define a codegen option" };
public Option<string[]> RdXmlFilePaths { get; } =
new("--rdxml") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "RD.XML file(s) for compilation" };
public Option<string[]> LinkTrimFilePaths { get; } =
new("--descriptor") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "ILLink.Descriptor file(s) for compilation" };
public Option<string[]> SubstitutionFilePaths { get; } =
new("--substitution") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "ILLink.Substitution file(s) for compilation" };
public Option<string> MapFileName { get; } =
new("--map") { Description = "Generate a map file" };
public Option<string> MstatFileName { get; } =
new("--mstat") { Description = "Generate an mstat file" };
public Option<string> SourceLinkFileName { get; } =
new("--sourcelink") { Description = "Generate a SourceLink file" };
public Option<string> MetadataLogFileName { get; } =
new("--metadatalog") { Description = "Generate a metadata log file" };
public Option<bool> CompleteTypesMetadata { get; } =
new("--completetypemetadata") { Description = "Generate complete metadata for types" };
public Option<string> ReflectionData { get; } =
new("--reflectiondata") { Description = "Reflection data to generate (one of: all, none)" };
public Option<bool> ScanReflection { get; } =
new("--scanreflection") { Description = "Scan IL for reflection patterns" };
public Option<bool> UseScanner { get; } =
new("--scan") { Description = "Use IL scanner to generate optimized code (implied by -O)" };
public Option<bool> NoScanner { get; } =
new("--noscan") { Description = "Do not use IL scanner to generate optimized code" };
public Option<string> IlDump { get; } =
new("--ildump") { Description = "Dump IL assembly listing for compiler-generated IL" };
public Option<bool> NoInlineTls { get; } =
new("--noinlinetls") { Description = "Do not generate inline thread local statics" };
public Option<string> StackTraceData { get; } =
new("--stacktracedata") { Description = "Stack trace data to generate (one of: frames, lines, none)" };
public Option<string> MethodBodyFolding { get; } =
new("--methodbodyfolding") { Description = "Fold identical method bodies (one of: none, generic, all" };
public Option<string[]> InitAssemblies { get; } =
new("--initassembly") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Assembly(ies) with a library initializer" };
public Option<string[]> FeatureSwitches { get; } =
new("--feature") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Feature switches to apply (format: 'Namespace.Name=[true|false]'" };
public Option<string[]> RuntimeOptions { get; } =
new("--runtimeopt") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Runtime options to set" };
public Option<string[]> RuntimeKnobs { get; } =
new("--runtimeknob") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Runtime knobs to set" };
public Option<int> Parallelism { get; } =
new("--parallelism") { CustomParser = MakeParallelism, DefaultValueFactory = MakeParallelism, Description = "Maximum number of threads to use during compilation" };
public Option<string> InstructionSet { get; } =
new("--instruction-set") { Description = "Instruction set to allow or disallow" };
public Option<int> MaxVectorTBitWidth { get; } =
new("--max-vectort-bitwidth") { Description = "Maximum width, in bits, that Vector<T> is allowed to be" };
public Option<string> Guard { get; } =
new("--guard") { Description = "Enable mitigations. Options: 'cf': CFG (Control Flow Guard, Windows only)" };
public Option<bool> Dehydrate { get; } =
new("--dehydrate") { Description = "Dehydrate runtime data structures" };
public Option<bool> PreinitStatics { get; } =
new("--preinitstatics") { Description = "Interpret static constructors at compile time if possible (implied by -O)" };
public Option<bool> NoPreinitStatics { get; } =
new("--nopreinitstatics") { Description = "Do not interpret static constructors at compile time" };
public Option<bool> InstrumentReachability { get; } =
new("--reachabilityinstrument") { Description = "Instrument code for dynamic reachability" };
public Option<string> UseReachability { get; } =
new("--reachabilityuse") { Description = "Use dynamic reachability instrumentation data to produce minimal output" };
public Option<string[]> SuppressedWarnings { get; } =
new("--nowarn") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Disable specific warning messages" };
public Option<bool> SingleWarn { get; } =
new("--singlewarn") { Description = "Generate single AOT/trimming warning per assembly" };
public Option<bool> NoTrimWarn { get; } =
new("--notrimwarn") { Description = "Disable warnings related to trimming" };
public Option<bool> NoAotWarn { get; } =
new("--noaotwarn") { Description = "Disable warnings related to AOT" };
public Option<string[]> SingleWarnEnabledAssemblies { get; } =
new("--singlewarnassembly") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Generate single AOT/trimming warning for given assembly" };
public Option<string[]> SingleWarnDisabledAssemblies { get; } =
new("--nosinglewarnassembly") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Expand AOT/trimming warnings for given assembly" };
public Option<bool> TreatWarningsAsErrors { get; } =
new("--warnaserror") { Description = "Treat warnings as errors" };
public Option<string[]> WarningsAsErrorsEnable { get; } =
new("--warnaserr") { Description = "Enable treating specific warnings as errors" };
public Option<string[]> WarningsAsErrorsDisable { get; } =
new("--nowarnaserr") { Description = "Disable treating specific warnings as errors" };
public Option<string[]> DirectPInvokes { get; } =
new("--directpinvoke") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "PInvoke to call directly" };
public Option<string[]> DirectPInvokeLists { get; } =
new("--directpinvokelist") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "File with list of PInvokes to call directly" };
public Option<string[]> RootedAssemblies { get; } =
new("--root") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Fully generate given assembly" };
public Option<string[]> ConditionallyRootedAssemblies { get; } =
new("--conditionalroot") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Fully generate given assembly if it's used" };
public Option<string[]> TrimmedAssemblies { get; } =
new("--trim") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Trim the specified assembly" };
public Option<bool> RootDefaultAssemblies { get; } =
new("--defaultrooting") { Description = "Root assemblies that are not marked [IsTrimmable]" };
public Option<TargetArchitecture> TargetArchitecture { get; } =
new("--targetarch") { CustomParser = MakeTargetArchitecture, DefaultValueFactory = MakeTargetArchitecture, Description = "Target architecture for cross compilation", HelpName = "arg" };
public Option<TargetOS> TargetOS { get; } =
new("--targetos") { CustomParser = result => Helpers.GetTargetOS(result.Tokens.Count > 0 ? result.Tokens[0].Value : null), DefaultValueFactory = result => Helpers.GetTargetOS(result.Tokens.Count > 0 ? result.Tokens[0].Value : null), Description = "Target OS for cross compilation", HelpName = "arg" };
public Option<string> JitPath { get; } =
new("--jitpath") { Description = "Path to JIT compiler library" };
public Option<string> SingleMethodTypeName { get; } =
new("--singlemethodtypename") { Description = "Single method compilation: assembly-qualified name of the owning type" };
public Option<string> SingleMethodName { get; } =
new("--singlemethodname") { Description = "Single method compilation: name of the method" };
public Option<int> MaxGenericCycleDepth { get; } =
new("--maxgenericcycle") { DefaultValueFactory = _ => CompilerTypeSystemContext.DefaultGenericCycleDepthCutoff, Description = "Max depth of generic cycle" };
public Option<int> MaxGenericCycleBreadth { get; } =
new("--maxgenericcyclebreadth") { DefaultValueFactory = _ => CompilerTypeSystemContext.DefaultGenericCycleBreadthCutoff, Description = "Max breadth of generic cycle expansion" };
public Option<string[]> SingleMethodGenericArgs { get; } =
new("--singlemethodgenericarg") { Description = "Single method compilation: generic arguments to the method" };
public Option<string> MakeReproPath { get; } =
new("--make-repro-path") { Description = "Path where to place a repro package" };
public Option<string[]> UnmanagedEntryPointsAssemblies { get; } =
new("--generateunmanagedentrypoints") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Generate unmanaged entrypoints for a given assembly" };
public Option<bool> DisableGeneratedCodeHeuristics { get; } =
new("--disable-generated-code-heuristics") { Description = "Disable heuristics for detecting compiler-generated code" };
public Option<string> TypeMapEntryAssembly { get; } =
new("--typemap-entry-assembly") { Description = "Assembly name to use as entry point for TypeMap generation" };
public OptimizationMode OptimizationMode { get; private set; }
public ParseResult Result;
public static bool IsArmel { get; private set; }
public ILCompilerRootCommand(string[] args) : base(".NET Native IL Compiler")
{
Arguments.Add(InputFilePaths);
Options.Add(ReferenceFiles);
Options.Add(OutputFilePath);
Options.Add(Optimize);
Options.Add(OptimizeSpace);
Options.Add(OptimizeTime);
Options.Add(MibcFilePaths);
Options.Add(MethodLayout);
Options.Add(FileLayout);
Options.Add(OrderFile);
Options.Add(SatelliteFilePaths);
Options.Add(EnableDebugInfo);
Options.Add(UseDwarf5);
Options.Add(NativeLib);
Options.Add(SplitExeInitialization);
Options.Add(ExportsFile);
Options.Add(ExportDynamicSymbols);
Options.Add(ExportUnmanagedEntryPoints);
Options.Add(DgmlLogFileName);
Options.Add(GenerateFullDgmlLog);
Options.Add(ScanDgmlLogFileName);
Options.Add(GenerateFullScanDgmlLog);
Options.Add(IsVerbose);
Options.Add(SystemModuleName);
Options.Add(Win32ResourceModuleName);
Options.Add(MultiFile);
Options.Add(WaitForDebugger);
Options.Add(Resilient);
Options.Add(CodegenOptions);
Options.Add(RdXmlFilePaths);
Options.Add(LinkTrimFilePaths);
Options.Add(SubstitutionFilePaths);
Options.Add(MapFileName);
Options.Add(MstatFileName);
Options.Add(SourceLinkFileName);
Options.Add(MetadataLogFileName);
Options.Add(CompleteTypesMetadata);
Options.Add(ReflectionData);
Options.Add(ScanReflection);
Options.Add(UseScanner);
Options.Add(NoScanner);
Options.Add(NoInlineTls);
Options.Add(IlDump);
Options.Add(StackTraceData);
Options.Add(MethodBodyFolding);
Options.Add(InitAssemblies);
Options.Add(FeatureSwitches);
Options.Add(RuntimeOptions);
Options.Add(RuntimeKnobs);
Options.Add(Parallelism);
Options.Add(InstructionSet);
Options.Add(MaxVectorTBitWidth);
Options.Add(Guard);
Options.Add(Dehydrate);
Options.Add(PreinitStatics);
Options.Add(NoPreinitStatics);
Options.Add(InstrumentReachability);
Options.Add(UseReachability);
Options.Add(SuppressedWarnings);
Options.Add(SingleWarn);
Options.Add(NoTrimWarn);
Options.Add(NoAotWarn);
Options.Add(SingleWarnEnabledAssemblies);
Options.Add(SingleWarnDisabledAssemblies);
Options.Add(TreatWarningsAsErrors);
Options.Add(WarningsAsErrorsEnable);
Options.Add(WarningsAsErrorsDisable);
Options.Add(DirectPInvokes);
Options.Add(DirectPInvokeLists);
Options.Add(MaxGenericCycleDepth);
Options.Add(MaxGenericCycleBreadth);
Options.Add(RootedAssemblies);
Options.Add(ConditionallyRootedAssemblies);
Options.Add(TrimmedAssemblies);
Options.Add(RootDefaultAssemblies);
Options.Add(TargetArchitecture);
Options.Add(TargetOS);
Options.Add(JitPath);
Options.Add(SingleMethodTypeName);
Options.Add(SingleMethodName);
Options.Add(SingleMethodGenericArgs);
Options.Add(MakeReproPath);
Options.Add(UnmanagedEntryPointsAssemblies);
Options.Add(DisableGeneratedCodeHeuristics);
Options.Add(TypeMapEntryAssembly);
this.SetAction(result =>
{
Result = result;
if (result.GetValue(OptimizeSpace))
{
OptimizationMode = OptimizationMode.PreferSize;
}
else if (result.GetValue(OptimizeTime))
{
OptimizationMode = OptimizationMode.PreferSpeed;
}
else if (result.GetValue(Optimize))
{
OptimizationMode = OptimizationMode.Blended;
}
else
{
OptimizationMode = OptimizationMode.None;
}
try
{
string makeReproPath = result.GetValue(MakeReproPath);
if (makeReproPath != null)
{
// Create a repro package in the specified path
// This package will have the set of input files needed for compilation
// + the original command line arguments
// + a rsp file that should work to directly run out of the zip file
#pragma warning disable CA1861 // Avoid constant arrays as arguments. Only executed once during the execution of the program.
Helpers.MakeReproPackage(makeReproPath, result.GetValue(OutputFilePath), args, result,
inputOptions : new[] { "-r", "--reference", "-m", "--mibc", "--rdxml", "--directpinvokelist", "--descriptor", "--satellite", "--order" },
outputOptions : new[] { "-o", "--out", "--exportsfile", "--dgmllog", "--scandgmllog", "--mstat", "--sourcelink" });
#pragma warning restore CA1861 // Avoid constant arrays as arguments
}
return new Program(this).Run();
}
#if DEBUG
catch (CodeGenerationFailedException ex) when (DumpReproArguments(ex))
{
throw new NotSupportedException(); // Unreachable
}
#else
catch (Exception e)
{
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("Error: " + e.Message);
Console.Error.WriteLine(e.ToString());
Console.ResetColor();
}
return 1;
#endif
});
}
public static void PrintExtendedHelp(ParseResult _)
{
Console.WriteLine("Options may be passed on the command line, or via response file. On the command line switch values may be specified by passing " +
"the option followed by a space followed by the value of the option, or by specifying a : between option and switch value. A response file " +
"is specified by passing the @ symbol before the response file name. In a response file all options must be specified on their own lines, and " +
"only the : syntax for switches is supported.\n");
Console.WriteLine("Use the '--' option to disambiguate between input files that have begin with -- and options. After a '--' option, all arguments are " +
"considered to be input files. If no input files begin with '--' then this option is not necessary.\n");
string[] ValidArchitectures = new string[] { "arm", "arm64", "x86", "x64", "riscv64", "loongarch64" };
string[] ValidOS = new string[] { "windows", "linux", "freebsd", "osx", "maccatalyst", "ios", "iossimulator", "tvos", "tvossimulator" };
Console.WriteLine("Valid switches for {0} are: '{1}'. The default value is '{2}'\n", "--targetos", string.Join("', '", ValidOS), Helpers.GetTargetOS(null).ToString().ToLowerInvariant());
Console.WriteLine(string.Format("Valid switches for {0} are: '{1}'. The default value is '{2}'\n", "--targetarch", string.Join("', '", ValidArchitectures), Helpers.GetTargetArchitecture(null).ToString().ToLowerInvariant()));
Console.WriteLine("The allowable values for the --instruction-set option are described in the table below. Each architecture has a different set of valid " +
"instruction sets, and multiple instruction sets may be specified by separating the instructions sets by a ','. By default other instruction sets not " +
"specified may light-up optimistically via dynamic checks. Individual instruction sets can be disallowed from such light-up by prefixing them with '-'. " +
"All such light-up can be disallowed by specifying '-optimistic'. The instruction sets supported by the machine invoking the tool can be targeted by " +
"specifying 'native'. For example 'native', 'avx,aes', 'avx,aes,-avx2', or 'avx,aes,-optimistic'");
foreach (string arch in ValidArchitectures)
{
TargetArchitecture targetArch = Helpers.GetTargetArchitecture(arch);
bool first = true;
foreach (var instructionSet in Internal.JitInterface.InstructionSetFlags.ArchitectureToValidInstructionSets(targetArch).DistinctBy((instructionSet) => instructionSet.Name, StringComparer.OrdinalIgnoreCase))
{
// Only instruction sets with are specifiable should be printed to the help text
if (instructionSet.Specifiable)
{
if (first)
{
Console.Write(arch);
Console.Write(": ");
first = false;
}
else
{
Console.Write(", ");
}
Console.Write(instructionSet.Name);
}
}
if (first) continue; // no instruction-set found for this architecture
Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("The following CPU names are predefined groups of instruction sets and can be used in --instruction-set too:");
Console.WriteLine(string.Join(", ", Internal.JitInterface.InstructionSetFlags.AllCpuNames));
}
private static TargetArchitecture MakeTargetArchitecture(ArgumentResult result)
{
string firstToken = result.Tokens.Count > 0 ? result.Tokens[0].Value : null;
if (firstToken != null && firstToken.Equals("armel", StringComparison.OrdinalIgnoreCase))
{
IsArmel = true;
return Internal.TypeSystem.TargetArchitecture.ARM;
}
return Helpers.GetTargetArchitecture(firstToken);
}
private static int MakeParallelism(ArgumentResult result)
{
if (result.Tokens.Count > 0)
return int.Parse(result.Tokens[0].Value);
// Limit parallelism to 24 wide at most by default, more parallelism is unlikely to improve compilation speed
// as many portions of the process are single threaded, and is known to use excessive memory.
var parallelism = Math.Min(24, Environment.ProcessorCount);
// On 32bit platforms restrict it more, as virtual address space is quite limited
if (!Environment.Is64BitProcess)
parallelism = Math.Min(4, parallelism);
return parallelism;
}
private static MethodLayoutAlgorithm MakeMethodLayoutAlgorithm(ArgumentResult result)
{
if (result.Tokens.Count == 0)
return MethodLayoutAlgorithm.DefaultSort;
return result.Tokens[0].Value.ToLowerInvariant() switch
{
"defaultsort" => MethodLayoutAlgorithm.DefaultSort,
"exclusiveweight" => MethodLayoutAlgorithm.ExclusiveWeight,
"hotcold" => MethodLayoutAlgorithm.HotCold,
"instrumentedhotcold" => MethodLayoutAlgorithm.InstrumentedHotCold,
"hotwarmcold" => MethodLayoutAlgorithm.HotWarmCold,
"pettishansen" => MethodLayoutAlgorithm.PettisHansen,
"random" => MethodLayoutAlgorithm.Random,
"explicit" => MethodLayoutAlgorithm.Explicit,
_ => throw new CommandLineException(result.Tokens[0].Value)
};
}
private static FileLayoutAlgorithm MakeFileLayoutAlgorithm(ArgumentResult result)
{
if (result.Tokens.Count == 0)
return FileLayoutAlgorithm.DefaultSort;
return result.Tokens[0].Value.ToLowerInvariant() switch
{
"defaultsort" => FileLayoutAlgorithm.DefaultSort,
"methodorder" => FileLayoutAlgorithm.MethodOrder,
_ => throw new CommandLineException(result.Tokens[0].Value)
};
}
#if DEBUG
private static bool DumpReproArguments(CodeGenerationFailedException ex)
{
Console.WriteLine("To repro, add following arguments to the command line:");
MethodDesc failingMethod = ex.Method;
var formatter = new CustomAttributeTypeNameFormatter((IAssemblyDesc)failingMethod.Context.SystemModule);
Console.Write($"--singlemethodtypename \"{formatter.FormatName(failingMethod.OwningType, true)}\"");
Console.Write($" --singlemethodname {failingMethod.GetName()}");
for (int i = 0; i < failingMethod.Instantiation.Length; i++)
Console.Write($" --singlemethodgenericarg \"{formatter.FormatName(failingMethod.Instantiation[i], true)}\"");
return false;
}
#endif
}
}
|