Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy into metadata-explorer

pull/1716/head
Siegfried Pammer 6 years ago
parent
commit
475312d5cf
  1. 1
      .gitmodules
  2. 2
      BuildTools/appveyor-install.ps1
  3. 2
      BuildTools/pipelines-install.ps1
  4. 16
      BuildTools/update-assemblyinfo.ps1
  5. 6
      Frontends.sln
  6. 15
      ICSharpCode.Decompiler.Console/ICSharpCode.Decompiler.Console.csproj
  7. BIN
      ICSharpCode.Decompiler.Console/ILSpyCmdNuGetPackageIcon.png
  8. 80
      ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs
  9. 22
      ICSharpCode.Decompiler.Console/README.md
  10. 15
      ICSharpCode.Decompiler.PowerShell/GetDecompilerCmdlet.cs
  11. 16
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  12. 2
      ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
  13. 50
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  14. 13
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  15. 6
      ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
  16. 20
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  17. 9
      ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs
  18. 77
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/FloatingPointArithmetic.cs
  19. 32
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullableTests.cs
  20. 32
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
  21. 117
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/StringConcat.cs
  22. 9
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs
  23. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.cs
  24. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.cs
  25. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs
  26. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs
  27. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Debug.cs
  28. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Release.cs
  29. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1325.cs
  30. 19
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/WeirdEnums.cs
  31. 36
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/WeirdEnums.il
  32. 31
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Async.cs
  33. 65
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs
  34. 60
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncUsing.cs
  35. 586
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
  36. 16
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs
  37. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes2.cs
  38. 80
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomTaskType.cs
  39. 82
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  40. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs
  41. 7
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs
  42. 77
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InterfaceTests.cs
  43. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  44. 3
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  45. 15
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs
  46. 53
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QualifierTests.cs
  47. 53
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs
  48. 82
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
  49. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Using.cs
  50. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs
  51. 33
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.Expected.cs
  52. 27
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.cs
  53. 93
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.opt.roslyn.il
  54. 117
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.roslyn.il
  55. 43
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.Expected.cs
  56. 23
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.cs
  57. 156
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.il
  58. 128
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.opt.il
  59. 126
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.opt.roslyn.il
  60. 145
      ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.roslyn.il
  61. 20
      ICSharpCode.Decompiler.Tests/UglyTestRunner.cs
  62. 10
      ICSharpCode.Decompiler/CSharp/Annotations.cs
  63. 11
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  64. 73
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  65. 54
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  66. 56
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
  67. 398
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  68. 60
      ICSharpCode.Decompiler/CSharp/OutputVisitor/ITokenWriter.cs
  69. 135
      ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs
  70. 40
      ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs
  71. 11
      ICSharpCode.Decompiler/CSharp/Resolver/AwaitResolveResult.cs
  72. 190
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  73. 2
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
  74. 32
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
  75. 5
      ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs
  76. 20
      ICSharpCode.Decompiler/CSharp/Resolver/MemberLookup.cs
  77. 2
      ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs
  78. 186
      ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
  79. 60
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
  80. 2
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  81. 53
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  82. 450
      ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs
  83. 6
      ICSharpCode.Decompiler/CSharp/Syntax/AstNodeCollection.cs
  84. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/Expression.cs
  85. 2
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/NamespaceDeclaration.cs
  86. 96
      ICSharpCode.Decompiler/CSharp/Syntax/IAnnotatable.cs
  87. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Identifier.cs
  88. 2
      ICSharpCode.Decompiler/CSharp/Syntax/IdentifierExpressionBackreference.cs
  89. 2
      ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/Backreference.cs
  90. 4
      ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/Choice.cs
  91. 4
      ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/INode.cs
  92. 2
      ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/NamedNode.cs
  93. 2
      ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/OptionalNode.cs
  94. 2
      ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/Repeat.cs
  95. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Role.cs
  96. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/Statement.cs
  97. 60
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/UsingStatement.cs
  98. 81
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  99. 71
      ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs
  100. 3
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitmodules vendored

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
[submodule "ILSpy-tests"]
path = ILSpy-tests
url = https://github.com/icsharpcode/ILSpy-tests

2
BuildTools/appveyor-install.ps1

@ -4,7 +4,7 @@ $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463"; @@ -4,7 +4,7 @@ $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463";
$baseCommitRev = 1;
# make sure this list matches artifacts-only branches list in appveyor.yml!
$masterBranches = @("master", "3.2.x");
$masterBranches = @("master", "5.0.x");
$globalAssemblyInfoTemplateFile = "ILSpy/Properties/AssemblyInfo.template.cs";

2
BuildTools/pipelines-install.ps1

@ -4,7 +4,7 @@ $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463"; @@ -4,7 +4,7 @@ $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463";
$baseCommitRev = 1;
# make sure this list matches artifacts-only branches list in azure-pipelines.yml!
$masterBranches = @("master", "3.2.x");
$masterBranches = @("master", "5.0.x");
$globalAssemblyInfoTemplateFile = "ILSpy/Properties/AssemblyInfo.template.cs";

16
BuildTools/update-assemblyinfo.ps1

@ -4,16 +4,16 @@ $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463"; @@ -4,16 +4,16 @@ $baseCommit = "d779383cb85003d6dabeb976f0845631e07bf463";
$baseCommitRev = 1;
# make sure this list matches artifacts-only branches list in appveyor.yml!
$masterBranches = @("master", "3.2.x");
$masterBranches = @("master", "5.0.x");
$globalAssemblyInfoTemplateFile = "ILSpy/Properties/AssemblyInfo.template.cs";
function Test-File([string]$filename) {
return [System.IO.File]::Exists( (Join-Path (Get-Location) $filename) );
return [System.IO.File]::Exists((Join-Path (Get-Location) $filename));
}
function Test-Dir([string]$name) {
return [System.IO.Directory]::Exists( (Join-Path (Get-Location) $name) );
return [System.IO.Directory]::Exists((Join-Path (Get-Location) $name));
}
function Find-Git() {
@ -38,22 +38,26 @@ function Find-Git() { @@ -38,22 +38,26 @@ function Find-Git() {
return $false;
}
function No-Git() {
return -not (((Test-Dir ".git") -or (Test-File ".git")) -and (Find-Git));
}
function gitVersion() {
if (-not ((Test-Dir ".git") -and (Find-Git))) {
if (No-Git) {
return 0;
}
return [Int32]::Parse((git rev-list --count "$baseCommit..HEAD")) + $baseCommitRev;
}
function gitCommitHash() {
if (-not ((Test-Dir ".git") -and (Find-Git))) {
if (No-Git) {
return "0000000000000000000000000000000000000000";
}
return (git rev-list "$baseCommit..HEAD") | Select -First 1;
}
function gitBranch() {
if (-not ((Test-Dir ".git") -and (Find-Git))) {
if (No-Git) {
return "no-branch";
}

6
Frontends.sln

@ -14,6 +14,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.Cons @@ -14,6 +14,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.Cons
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.PowerShell", "ICSharpCode.Decompiler.PowerShell\ICSharpCode.Decompiler.PowerShell.csproj", "{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{526B267D-1904-4E9E-80DB-BB2259ADCF6C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -28,6 +30,10 @@ Global @@ -28,6 +30,10 @@ Global
{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}.Release|Any CPU.Build.0 = Release|Any CPU
{526B267D-1904-4E9E-80DB-BB2259ADCF6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{526B267D-1904-4E9E-80DB-BB2259ADCF6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{526B267D-1904-4E9E-80DB-BB2259ADCF6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{526B267D-1904-4E9E-80DB-BB2259ADCF6C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

15
ICSharpCode.Decompiler.Console/ICSharpCode.Decompiler.Console.csproj

@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
<Copyright>Copyright 2011-2019 AlphaSierraPapa</Copyright>
<PackageProjectUrl>https://github.com/icsharpcode/ILSpy/</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIconUrl>https://ilspy.net/images/icon32.png</PackageIconUrl>
<PackageIcon>ILSpyCmdNuGetPackageIcon.png</PackageIcon>
<RepositoryUrl>https://github.com/icsharpcode/ILSpy/</RepositoryUrl>
<Company />
<AssemblyVersion>5.0.0.0</AssemblyVersion>
@ -27,8 +27,19 @@ @@ -27,8 +27,19 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.2" />
<None Include="ILSpyCmdNuGetPackageIcon.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.5124" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.2" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />

BIN
ICSharpCode.Decompiler.Console/ILSpyCmdNuGetPackageIcon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

80
ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs

@ -22,7 +22,7 @@ Remarks: @@ -22,7 +22,7 @@ Remarks:
-o is valid with every option and required when using -p.
")]
[HelpOption("-h|--help")]
[ProjectOptionRequiresOutputDirectoryValidationAttribute]
[ProjectOptionRequiresOutputDirectoryValidation]
class ILSpyCmdProgram
{
public static int Main(string[] args) => CommandLineApplication.Execute<ILSpyCmdProgram>(args);
@ -54,18 +54,27 @@ Remarks: @@ -54,18 +54,27 @@ Remarks:
[Option("-v|--version", "Show version of ICSharpCode.Decompiler used.", CommandOptionType.NoValue)]
public bool ShowVersion { get; }
[Option("-lv|--languageversion", "C# Language version: CSharp1, CSharp2, CSharp3, CSharp4, CSharp5, CSharp6, CSharp7_0, CSharp7_1, CSharp7_2, CSharp7_3, CSharp8_0 or Latest", CommandOptionType.SingleValue)]
public LanguageVersion LanguageVersion { get; } = LanguageVersion.Latest;
[DirectoryExists]
[Option("-r|--referencepath <path>", "Path to a directory containing dependencies of the assembly that is being decompiled.", CommandOptionType.MultipleValue)]
public string[] ReferencePaths { get; } = new string[0];
[Option("--no-dead-code", "Remove dead code.", CommandOptionType.NoValue)]
public bool RemoveDeadCode { get; }
[Option("--no-dead-stores", "Remove dead stores.", CommandOptionType.NoValue)]
public bool RemoveDeadStores { get; }
private int OnExecute(CommandLineApplication app)
{
TextWriter output = System.Console.Out;
bool outputDirectorySpecified = !String.IsNullOrEmpty(OutputDirectory);
bool outputDirectorySpecified = !string.IsNullOrEmpty(OutputDirectory);
try {
if (CreateCompilableProjectFlag) {
DecompileAsProject(InputAssemblyName, OutputDirectory, ReferencePaths);
return DecompileAsProject(InputAssemblyName, OutputDirectory);
} else if (EntityTypes.Any()) {
var values = EntityTypes.SelectMany(v => v.Split(',', ';')).ToArray();
HashSet<TypeKind> kinds = TypesParser.ParseSelection(values);
@ -74,14 +83,14 @@ Remarks: @@ -74,14 +83,14 @@ Remarks:
output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".list.txt");
}
ListContent(InputAssemblyName, output, kinds, ReferencePaths);
return ListContent(InputAssemblyName, output, kinds);
} else if (ShowILCodeFlag) {
if (outputDirectorySpecified) {
string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName);
output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".il");
}
ShowIL(InputAssemblyName, output, ReferencePaths);
return ShowIL(InputAssemblyName, output);
} else if (CreateDebugInfoFlag) {
string pdbFileName = null;
if (outputDirectorySpecified) {
@ -91,7 +100,7 @@ Remarks: @@ -91,7 +100,7 @@ Remarks:
pdbFileName = Path.ChangeExtension(InputAssemblyName, ".pdb");
}
return GeneratePdbForAssembly(InputAssemblyName, pdbFileName, ReferencePaths, app);
return GeneratePdbForAssembly(InputAssemblyName, pdbFileName, app);
} else if (ShowVersion) {
string vInfo = "ilspycmd: " + typeof(ILSpyCmdProgram).Assembly.GetName().Version.ToString() +
Environment.NewLine
@ -102,10 +111,10 @@ Remarks: @@ -102,10 +111,10 @@ Remarks:
if (outputDirectorySpecified) {
string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName);
output = File.CreateText(Path.Combine(OutputDirectory,
(String.IsNullOrEmpty(TypeName) ? outputName : TypeName) + ".decompiled.cs"));
(string.IsNullOrEmpty(TypeName) ? outputName : TypeName) + ".decompiled.cs"));
}
Decompile(InputAssemblyName, output, ReferencePaths, TypeName);
return Decompile(InputAssemblyName, output, TypeName);
}
} catch (Exception ex) {
app.Error.WriteLine(ex.ToString());
@ -117,56 +126,62 @@ Remarks: @@ -117,56 +126,62 @@ Remarks:
return 0;
}
static CSharpDecompiler GetDecompiler(string assemblyFileName, string[] referencePaths)
DecompilerSettings GetSettings()
{
return new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores
};
}
CSharpDecompiler GetDecompiler(string assemblyFileName)
{
var module = new PEFile(assemblyFileName);
var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
foreach (var path in referencePaths) {
foreach (var path in ReferencePaths) {
resolver.AddSearchDirectory(path);
}
return new CSharpDecompiler(assemblyFileName, resolver, new DecompilerSettings());
return new CSharpDecompiler(assemblyFileName, resolver, GetSettings());
}
static void ListContent(string assemblyFileName, TextWriter output, ISet<TypeKind> kinds, string[] referencePaths)
int ListContent(string assemblyFileName, TextWriter output, ISet<TypeKind> kinds)
{
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName, referencePaths);
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
foreach (var type in decompiler.TypeSystem.MainModule.TypeDefinitions) {
if (!kinds.Contains(type.Kind))
continue;
output.WriteLine($"{type.Kind} {type.FullName}");
}
return 0;
}
static void ShowIL(string assemblyFileName, TextWriter output, string[] referencePaths)
int ShowIL(string assemblyFileName, TextWriter output)
{
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName, referencePaths);
ITextOutput textOutput = new PlainTextOutput();
ReflectionDisassembler disassembler = new ReflectionDisassembler(textOutput, CancellationToken.None);
disassembler.DisassembleNamespace(decompiler.TypeSystem.MainModule.RootNamespace.Name,
decompiler.TypeSystem.MainModule.PEFile,
decompiler.TypeSystem.MainModule.TypeDefinitions.Select(x => (TypeDefinitionHandle)x.MetadataToken));
output.WriteLine($"// IL code: {decompiler.TypeSystem.MainModule.AssemblyName}");
output.WriteLine(textOutput.ToString());
var module = new PEFile(assemblyFileName);
output.WriteLine($"// IL code: {module.Name}");
var disassembler = new ReflectionDisassembler(new PlainTextOutput(output), CancellationToken.None);
disassembler.WriteModuleContents(module);
return 0;
}
static void DecompileAsProject(string assemblyFileName, string outputDirectory, string[] referencePaths)
int DecompileAsProject(string assemblyFileName, string outputDirectory)
{
var decompiler = new WholeProjectDecompiler();
var decompiler = new WholeProjectDecompiler() { Settings = GetSettings() };
var module = new PEFile(assemblyFileName);
var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
foreach (var path in referencePaths) {
foreach (var path in ReferencePaths) {
resolver.AddSearchDirectory(path);
}
decompiler.AssemblyResolver = resolver;
decompiler.DecompileProject(module, outputDirectory);
return 0;
}
static void Decompile(string assemblyFileName, TextWriter output, string[] referencePaths, string typeName = null)
int Decompile(string assemblyFileName, TextWriter output, string typeName = null)
{
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName, referencePaths);
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
if (typeName == null) {
output.Write(decompiler.DecompileWholeModuleAsString());
@ -174,9 +189,10 @@ Remarks: @@ -174,9 +189,10 @@ Remarks:
var name = new FullTypeName(typeName);
output.Write(decompiler.DecompileTypeAsString(name));
}
return 0;
}
static int GeneratePdbForAssembly(string assemblyFileName, string pdbFileName, string[] referencePaths, CommandLineApplication app)
int GeneratePdbForAssembly(string assemblyFileName, string pdbFileName, CommandLineApplication app)
{
var module = new PEFile(assemblyFileName,
new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read),
@ -189,8 +205,8 @@ Remarks: @@ -189,8 +205,8 @@ Remarks:
}
using (FileStream stream = new FileStream(pdbFileName, FileMode.OpenOrCreate, FileAccess.Write)) {
var decompiler = GetDecompiler(assemblyFileName, referencePaths);
PortablePdbWriter.WritePdb(module, decompiler, new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }, stream);
var decompiler = GetDecompiler(assemblyFileName);
PortablePdbWriter.WritePdb(module, decompiler, GetSettings(), stream);
}
return 0;

22
ICSharpCode.Decompiler.Console/README.md

@ -14,17 +14,21 @@ dotnet tool for decompiling .NET assemblies and generating portable PDBs @@ -14,17 +14,21 @@ dotnet tool for decompiling .NET assemblies and generating portable PDBs
Usage: ilspycmd [arguments] [options]
Arguments:
Assembly file name The assembly that is being decompiled. This argument is mandatory.
Assembly file name The assembly that is being decompiled. This argument is mandatory.
Options:
-h|--help Show help information
-o|--outputdir <directory> The output directory, if omitted decompiler output is written to standard out.
-p|--project Decompile assembly as compilable project. This requires the output directory option.
-t|--type <type-name> The fully qualified name of the type to decompile.
-il|--ilcode Show IL code.
-d|--debuginfo Generate PDB.
-l|--list <entity-type(s)> Lists all entities of the specified type(s). Valid types: c(lass), i(interface), s(truct), d(elegate), e(num)
-v|--version Show version of ICSharpCode.Decompiler used.
-h|--help Show help information
-o|--outputdir <directory> The output directory, if omitted decompiler output is written to standard out.
-p|--project Decompile assembly as compilable project. This requires the output directory option.
-t|--type <type-name> The fully qualified name of the type to decompile.
-il|--ilcode Show IL code.
-d|--debuginfo Generate PDB.
-l|--list <entity-type(s)> Lists all entities of the specified type(s). Valid types: c(lass), i(interface), s(truct), d(elegate), e(num)
-v|--version Show version of ICSharpCode.Decompiler used.
-lv|--languageversion <version> C# Language version: CSharp1, CSharp2, CSharp3, CSharp4, CSharp5, CSharp6, CSharp7_0, CSharp7_1, CSharp7_2, CSharp7_3, CSharp8_0 or Latest
-r|--referencepath <path> Path to a directory containing dependencies of the assembly that is being decompiled.
--no-dead-code Remove dead code.
--no-dead-stores Remove dead stores.
Remarks:
-o is valid with every option and required when using -p.

15
ICSharpCode.Decompiler.PowerShell/GetDecompilerCmdlet.cs

@ -15,13 +15,24 @@ namespace ICSharpCode.Decompiler.PowerShell @@ -15,13 +15,24 @@ namespace ICSharpCode.Decompiler.PowerShell
[ValidateNotNullOrEmpty]
public string LiteralPath { get; set; }
[Parameter(HelpMessage = "C# Language version to be used by the decompiler")]
public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Latest;
[Parameter(HelpMessage = "Remove dead stores")]
public bool RemoveDeadStores { get; set; }
[Parameter(HelpMessage = "Remove dead code")]
public bool RemoveDeadCode { get; set; }
protected override void ProcessRecord()
{
string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);
try {
var decompiler = new CSharpDecompiler(path, new DecompilerSettings() {
ThrowOnAssemblyResolveErrors = false
var decompiler = new CSharpDecompiler(path, new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores
});
WriteObject(decompiler);

16
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -83,8 +83,14 @@ namespace ICSharpCode.Decompiler.Tests @@ -83,8 +83,14 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public void FloatingPointArithmetic([ValueSource("defaultOptions")] CompilerOptions options)
{
public void FloatingPointArithmetic([ValueSource("noMonoOptions")] CompilerOptions options, [Values(32, 64)] int bits)
{
// The behavior of the #1794 incorrect `(float)(double)val` cast only causes test failures
// for some runtime+compiler combinations.
if (bits == 32)
options |= CompilerOptions.Force32Bit;
// Mono is excluded because we never use it for the second pass, so the test ends up failing
// due to some Mono vs. Roslyn compiler differences.
RunCS(options: options);
}
@ -280,6 +286,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -280,6 +286,12 @@ namespace ICSharpCode.Decompiler.Tests
RunCS(options: options);
}
[Test]
public void StringConcat([ValueSource("defaultOptions")] CompilerOptions options)
{
RunCS(options: options);
}
[Test]
public void MiniJSON([ValueSource("defaultOptions")] CompilerOptions options)
{

2
ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs

@ -13,7 +13,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -13,7 +13,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var section = (AttributeSection)attribute.Parent;
SimpleType type = attribute.Type as SimpleType;
if (section.AttributeTarget == "assembly" &&
(type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "PermissionSet" || type.Identifier == "AssemblyVersion" || type.Identifier == "Debuggable"))
(type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "PermissionSet" || type.Identifier == "AssemblyVersion" || type.Identifier == "Debuggable" || type.Identifier == "TargetFramework"))
{
attribute.Remove();
if (section.Attributes.Count == 0)

50
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -55,6 +55,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
UseRoslyn = 0x10,
UseMcs = 0x20,
ReferenceVisualBasic = 0x40,
ReferenceCore = 0x80,
}
[Flags]
@ -89,12 +90,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -89,12 +90,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
outputFile += ".exe";
otherOptions += "/exe ";
}
if (options.HasFlag(AssemblerOptions.UseDebug)) {
otherOptions += "/debug ";
}
ProcessStartInfo info = new ProcessStartInfo(ilasmPath);
info.Arguments = $"/nologo {otherOptions}/output=\"{outputFile}\" \"{sourceFileName}\"";
info.RedirectStandardError = true;
@ -115,7 +116,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -115,7 +116,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return outputFile;
}
public static string Disassemble(string sourceFileName, string outputFile, AssemblerOptions asmOptions)
{
if (asmOptions.HasFlag(AssemblerOptions.UseOwnDisassembler)) {
@ -141,7 +142,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -141,7 +142,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
string ildasmPath = SdkUtility.GetSdkPath("ildasm.exe");
ProcessStartInfo info = new ProcessStartInfo(ildasmPath);
info.Arguments = $"/nobar /utf8 /out=\"{outputFile}\" \"{sourceFileName}\"";
info.RedirectStandardError = true;
@ -182,8 +183,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -182,8 +183,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return Regex.Replace(il, @"'<PrivateImplementationDetails>\{[0-9A-F-]+\}'", "'<PrivateImplementationDetails>'");
}
static readonly string coreRefAsmPath = new DotNetCorePathFinder(new Version(3, 0)).GetReferenceAssemblyPath(".NETCoreApp, Version = v3.0");
static readonly string refAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2");
@"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2");
static readonly string thisAsmPath = Path.GetDirectoryName(typeof(Tester).Assembly.Location);
static readonly Lazy<IEnumerable<MetadataReference>> defaultReferences = new Lazy<IEnumerable<MetadataReference>>(delegate {
@ -202,6 +205,21 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -202,6 +205,21 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
};
});
static readonly Lazy<IEnumerable<MetadataReference>> coreDefaultReferences = new Lazy<IEnumerable<MetadataReference>>(GetDefaultReferences);
const string targetFrameworkAttributeSnippet = @"
[assembly: System.Runtime.Versioning.TargetFramework("".NETCoreApp, Version = v3.0"", FrameworkDisplayName = """")]
";
static IEnumerable<MetadataReference> GetDefaultReferences()
{
foreach (var reference in Directory.EnumerateFiles(coreRefAsmPath, "*.dll")) {
yield return MetadataReference.CreateFromFile(reference);
}
}
static readonly Lazy<IEnumerable<MetadataReference>> visualBasic = new Lazy<IEnumerable<MetadataReference>>(delegate {
return new[] {
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "Microsoft.VisualBasic.dll"))
@ -217,6 +235,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -217,6 +235,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
if (flags.HasFlag(CompilerOptions.Optimize)) {
preprocessorSymbols.Add("OPT");
}
if (flags.HasFlag(CompilerOptions.ReferenceCore)) {
preprocessorSymbols.Add("NETCORE");
}
if (flags.HasFlag(CompilerOptions.UseRoslyn)) {
preprocessorSymbols.Add("ROSLYN");
preprocessorSymbols.Add("CS60");
@ -224,6 +245,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -224,6 +245,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
preprocessorSymbols.Add("CS71");
preprocessorSymbols.Add("CS72");
preprocessorSymbols.Add("CS73");
preprocessorSymbols.Add("CS80");
preprocessorSymbols.Add("VB11");
preprocessorSymbols.Add("VB14");
preprocessorSymbols.Add("VB15");
@ -251,7 +273,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -251,7 +273,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8
);
var syntaxTrees = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f));
var references = defaultReferences.Value;
if (flags.HasFlag(CompilerOptions.ReferenceCore)) {
syntaxTrees = syntaxTrees.Concat(new[] { SyntaxFactory.ParseSyntaxTree(targetFrameworkAttributeSnippet) });
}
IEnumerable<MetadataReference> references;
if (flags.HasFlag(CompilerOptions.ReferenceCore)) {
references = coreDefaultReferences.Value;
} else {
references = defaultReferences.Value;
}
if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) {
references = references.Concat(visualBasic.Value);
}
@ -465,16 +495,16 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -465,16 +495,16 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return fileName;
}
}
public static void RunAndCompareOutput(string testFileName, string outputFile, string decompiledOutputFile, string decompiledCodeFile = null)
{
string output1, output2, error1, error2;
int result1 = Tester.Run(outputFile, out output1, out error1);
int result2 = Tester.Run(decompiledOutputFile, out output2, out error2);
Assert.AreEqual(0, result1, "Exit code != 0; did the test case crash?" + Environment.NewLine + error1);
Assert.AreEqual(0, result2, "Exit code != 0; did the decompiled code crash?" + Environment.NewLine + error2);
if (output1 != output2 || error1 != error2) {
StringBuilder b = new StringBuilder();
b.AppendLine($"Test {testFileName} failed: output does not match.");

13
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -42,8 +42,8 @@ @@ -42,8 +42,8 @@
<ItemGroup>
<PackageReference Include="DiffLib" Version="2017.7.26.1241" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.3.0-beta1-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.3.0-beta1-final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.4.0-beta3-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.4.0-beta3-final" />
<PackageReference Include="Microsoft.DiaSymReader.Converter.Xml" Version="1.1.0-beta1-63314-01" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
@ -60,6 +60,7 @@ @@ -60,6 +60,7 @@
<None Include="TestCases\Correctness\StackTests.il" />
<None Include="TestCases\Correctness\StackTypes.il" />
<None Include="TestCases\Correctness\Uninit.vb" />
<None Include="TestCases\ILPretty\WeirdEnums.il" />
<None Include="TestCases\ILPretty\ConstantBlobs.il" />
<None Include="TestCases\ILPretty\CS1xSwitch_Debug.il" />
<None Include="TestCases\ILPretty\CS1xSwitch_Release.il" />
@ -79,9 +80,17 @@ @@ -79,9 +80,17 @@
<ItemGroup>
<Compile Include="DisassemblerPrettyTestRunner.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" />
<None Include="TestCases\ILPretty\WeirdEnums.cs" />
<Compile Include="TestCases\ILPretty\ConstantBlobs.cs" />
<None Include="TestCases\Pretty\AsyncStreams.cs" />
<None Include="TestCases\Pretty\AsyncUsing.cs" />
<Compile Include="TestCases\Pretty\OutVariables.cs" />
<Compile Include="TestCases\Pretty\CustomTaskType.cs" />
<None Include="TestCases\Ugly\NoForEachStatement.Expected.cs" />
<Compile Include="TestCases\Ugly\NoForEachStatement.cs" />
<None Include="TestCases\Ugly\NoExtensionMethods.Expected.cs" />
<Compile Include="TestCases\Ugly\NoExtensionMethods.cs" />
<None Include="TestCases\VBPretty\VBCompoundAssign.cs" />
<Compile Include="TestCases\Pretty\ThrowExpressions.cs" />
<None Include="TestCases\ILPretty\Issue1145.cs" />

6
ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

@ -198,6 +198,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -198,6 +198,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(settings: new DecompilerSettings { RemoveDeadStores = true });
}
[Test]
public void WeirdEnums()
{
Run();
}
void Run([CallerMemberName] string testName = null, DecompilerSettings settings = null)
{
var ilFile = Path.Combine(TestCasePath, testName + ".il");

20
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -59,6 +59,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -59,6 +59,12 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn
};
static readonly CompilerOptions[] dotnetCoreOnlyOptions =
{
CompilerOptions.UseRoslyn | CompilerOptions.ReferenceCore,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn | CompilerOptions.ReferenceCore
};
static readonly CompilerOptions[] defaultOptions =
{
CompilerOptions.None,
@ -301,6 +307,18 @@ namespace ICSharpCode.Decompiler.Tests @@ -301,6 +307,18 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions);
}
[Test]
public void AsyncStreams([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void AsyncUsing([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void CustomTaskType([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{
@ -436,7 +454,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -436,7 +454,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void InterfaceTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
RunForLibrary(cscOptions: cscOptions | CompilerOptions.ReferenceCore);
}
[Test]

9
ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs

@ -69,7 +69,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -69,7 +69,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void ICSharpCode_Decompiler()
{
RunWithTest("ICSharpCode.Decompiler", "ICSharpCode.Decompiler.dll", "ICSharpCode.Decompiler.Tests.exe");
RunOnly("ICSharpCode.Decompiler", "ICSharpCode.Decompiler.dll");
}
[Test]
@ -113,7 +113,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -113,7 +113,12 @@ namespace ICSharpCode.Decompiler.Tests
RunInternal(dir, fileToRoundtrip,
outputDir => Tester.RunAndCompareOutput(fileToRoundtrip, Path.Combine(inputDir, fileToRoundtrip), Path.Combine(outputDir, fileToRoundtrip)));
}
void RunOnly(string dir, string fileToRoundtrip)
{
RunInternal(dir, fileToRoundtrip, outputDir => { });
}
void RunInternal(string dir, string fileToRoundtrip, Action<string> testAction, string snkFilePath = null)
{
if (!Directory.Exists(TestDir)) {

77
ICSharpCode.Decompiler.Tests/TestCases/Correctness/FloatingPointArithmetic.cs

@ -7,12 +7,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -7,12 +7,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
public static int Main(string[] args)
{
Issue999();
Issue1656();
Issue1794();
return 0;
}
static void Issue999()
{
for (float i = -10f; i <= 10f; i += 0.01f)
for (float i = -10f; i <= 10f; i += 0.01f)
Console.WriteLine("{1:R}: {0:R}", M(i), i);
}
@ -20,5 +22,78 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -20,5 +22,78 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
return 0.99f * v + 0.01f;
}
static void Issue1656()
{
double primary = 'B';
CxAssert((++primary) == 'C');
CxAssert((--primary) == 'B');
CxAssert((primary++) == 'B');
CxAssert((primary--) == 'C');
}
static void Issue1794()
{
Console.WriteLine("CastUnsignedToFloat:");
Console.WriteLine(CastUnsignedToFloat(9007199791611905).ToString("r"));
Console.WriteLine("CastUnsignedToDouble:");
Console.WriteLine(CastUnsignedToDouble(9007199791611905).ToString("r"));
Console.WriteLine("CastUnsignedToFloatViaDouble:");
Console.WriteLine(CastUnsignedToFloatViaDouble(9007199791611905).ToString("r"));
Console.WriteLine("CastSignedToFloat:");
Console.WriteLine(CastSignedToFloat(9007199791611905).ToString("r"));
Console.WriteLine("ImplicitCastSignedToFloat:");
Console.WriteLine(ImplicitCastSignedToFloat(9007199791611905).ToString("r"));
Console.WriteLine("CastSignedToDouble:");
Console.WriteLine(CastSignedToDouble(9007199791611905).ToString("r"));
Console.WriteLine("CastSignedToFloatViaDouble:");
Console.WriteLine(CastSignedToFloatViaDouble(9007199791611905).ToString("r"));
}
static float CastUnsignedToFloat(ulong val)
{
return (float)val;
}
static double CastUnsignedToDouble(ulong val)
{
return (double)val;
}
static float CastUnsignedToFloatViaDouble(ulong val)
{
// The double-rounding can increase the rounding error
return (float)(double)val;
}
static float CastSignedToFloat(long val)
{
return (float)val;
}
static double CastSignedToDouble(long val)
{
return (double)val;
}
static float CastSignedToFloatViaDouble(long val)
{
// The double-rounding can increase the rounding error
return (float)(double)val;
}
static float ImplicitCastSignedToFloat(long val)
{
return val;
}
static void CxAssert(bool v)
{
if (!v) {
throw new InvalidOperationException();
}
}
}
}

32
ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullableTests.cs

@ -23,6 +23,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -23,6 +23,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
class NullableTests
{
static void Main()
{
AvoidLifting();
BitNot();
}
static void AvoidLifting()
{
Console.WriteLine("MayThrow:");
Console.WriteLine(MayThrow(10, 2, 3));
@ -33,8 +39,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -33,8 +39,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine(NotUsingAllInputs(5, null));
Console.WriteLine("UsingUntestedValue:");
Console.WriteLine(NotUsingAllInputs(5, 3));
Console.WriteLine(NotUsingAllInputs(5, null));
Console.WriteLine(UsingUntestedValue(5, 3));
Console.WriteLine(UsingUntestedValue(5, null));
}
static int? MayThrow(int? a, int? b, int? c)
@ -54,5 +60,27 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -54,5 +60,27 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
// cannot be lifted because the value differs if b == null
return a.HasValue ? a.GetValueOrDefault() + b.GetValueOrDefault() : default(int?);
}
static void BitNot()
{
UInt32? value = 0;
Assert(~value == UInt32.MaxValue);
UInt64? value2 = 0;
Assert(~value2 == UInt64.MaxValue);
UInt16? value3 = 0;
Assert((UInt16)~value3 == (UInt16)UInt16.MaxValue);
UInt32 value4 = 0;
Assert(~value4 == UInt32.MaxValue);
UInt64 value5 = 0;
Assert(~value5 == UInt64.MaxValue);
UInt16 value6 = 0;
Assert((UInt16)~value6 == UInt16.MaxValue);
}
static void Assert(bool b)
{
if (!b)
throw new InvalidOperationException();
}
}
}

32
ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs

@ -33,6 +33,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -33,6 +33,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
ConstructorTest();
TestIndexer();
Issue1281();
Issue1747();
}
#region ConstructorTest
@ -203,6 +204,37 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -203,6 +204,37 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
}
#endregion
#region NullableValueTypes
private static void Issue1747()
{
Console.WriteLine("Issue1747:");
M1747(null);
M1747(true);
M1747(false);
M1747((bool?)true);
M1747((bool?)false);
Console.WriteLine("Issue1747, non-constant:");
bool b = Get<bool>();
M1747(b);
M1747((bool?)b);
}
private static void M1747(bool b)
{
Console.WriteLine("bool=" + b);
}
private static void M1747(bool? b)
{
Console.WriteLine("bool?=" + b);
}
static T Get<T>()
{
return default(T);
}
#endregion
#region IndexerTests
static void TestIndexer()
{

117
ICSharpCode.Decompiler.Tests/TestCases/Correctness/StringConcat.cs

@ -0,0 +1,117 @@ @@ -0,0 +1,117 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
class StringConcat
{
private class C
{
int i;
public C(int i)
{
Console.WriteLine(" new C(" + i + ")");
this.i = i;
}
public override string ToString()
{
Console.WriteLine(" C(" + i + ").ToString()");
return (i++).ToString();
}
}
private struct S
{
int i;
public S(int i)
{
Console.WriteLine(" new C(" + i + ")");
this.i = i;
}
public override string ToString()
{
Console.WriteLine(" S(" + i + ").ToString()");
return (i++).ToString();
}
}
static string Space()
{
Console.WriteLine(" Space()");
return " ";
}
static void TestClass()
{
Console.WriteLine("string + C:");
Console.WriteLine(Space() + new C(1));
Console.WriteLine("C + string:");
Console.WriteLine(new C(2) + Space());
Console.WriteLine("C + string + C:");
Console.WriteLine(new C(3) + Space() + new C(4));
Console.WriteLine("string + C + C:");
Console.WriteLine(Space() + new C(5) + new C(6));
Console.WriteLine("string.Concat(C, string, C):");
Console.WriteLine(string.Concat(new C(10), Space(), new C(11)));
Console.WriteLine("string.Concat(string.Concat(C, string), C):");
Console.WriteLine(string.Concat(string.Concat(new C(15), Space()), new C(16)));
Console.WriteLine("string.Concat(C, string.Concat(string, C)):");
Console.WriteLine(string.Concat(new C(20), string.Concat(Space(), new C(21))));
Console.WriteLine("string.Concat(C, string) + C:");
Console.WriteLine(string.Concat(new C(30), Space()) + new C(31));
}
static void TestStruct()
{
Console.WriteLine("string + S:");
Console.WriteLine(Space() + new S(1));
Console.WriteLine("S + string:");
Console.WriteLine(new S(2) + Space());
Console.WriteLine("S + string + S:");
Console.WriteLine(new S(3) + Space() + new S(4));
Console.WriteLine("string + S + S:");
Console.WriteLine(Space() + new S(5) + new S(6));
Console.WriteLine("string.Concat(S, string, S):");
Console.WriteLine(string.Concat(new S(10), Space(), new S(11)));
Console.WriteLine("string.Concat(string.Concat(S, string), S):");
Console.WriteLine(string.Concat(string.Concat(new S(15), Space()), new S(16)));
Console.WriteLine("string.Concat(S, string.Concat(string, S)):");
Console.WriteLine(string.Concat(new S(20), string.Concat(Space(), new S(21))));
Console.WriteLine("string.Concat(S, string) + S:");
Console.WriteLine(string.Concat(new S(30), Space()) + new S(31));
}
static void TestStructMutation()
{
Console.WriteLine("TestStructMutation:");
S s = new S(0);
Console.WriteLine(Space() + s);
Console.WriteLine(Space() + s.ToString());
Console.WriteLine(s);
}
static void Main()
{
TestClass();
TestStruct();
TestStructMutation();
}
}
}

9
ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
@ -27,6 +28,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -27,6 +28,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
InterestingConstants();
TruncatedComp();
StringConcat();
LinqNullableMin();
LinqNullableMin(1, 2, 3);
}
static void Print<T>(T val)
@ -101,5 +104,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -101,5 +104,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Print(string.Concat(1, 2));
Print(string.Concat(1, 2, "str"));
}
static void LinqNullableMin(params int[] arr)
{
Print(string.Format("LinqNullableMin {0}:", arr.Length));
Print(arr.Min(v => (int?)v));
}
}
}

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.cs

@ -270,7 +270,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -270,7 +270,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static string SwitchOverBool(bool b)
{
Console.WriteLine("SwitchOverBool: " + b.ToString());
Console.WriteLine("SwitchOverBool: " + b);
switch (b) {
case true:
return bool.TrueString;

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.cs

@ -270,7 +270,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -270,7 +270,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static string SwitchOverBool(bool b)
{
Console.WriteLine("SwitchOverBool: " + b.ToString());
Console.WriteLine("SwitchOverBool: " + b);
switch (b) {
case true:
return bool.TrueString;

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs

@ -14,14 +14,12 @@ using System.Diagnostics; @@ -14,14 +14,12 @@ using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
[assembly: FSharpInterfaceDataVersion(2, 0, 0)]
[assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCopyright("Copyright © 2017")]

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs

@ -15,14 +15,12 @@ using System.Diagnostics; @@ -15,14 +15,12 @@ using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
[assembly: FSharpInterfaceDataVersion(2, 0, 0)]
[assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCopyright("Copyright © 2017")]

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Debug.cs

@ -36,7 +36,7 @@ public static class FSharpUsingPatterns @@ -36,7 +36,7 @@ public static class FSharpUsingPatterns
num = fileStream.ReadByte();
}
int num2 = num;
Console.WriteLine("read:" + num2.ToString());
Console.WriteLine("read:" + num2);
}
public static void sample5()

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Release.cs

@ -36,7 +36,7 @@ public static class FSharpUsingPatterns @@ -36,7 +36,7 @@ public static class FSharpUsingPatterns
num = fileStream.ReadByte();
}
int num2 = num;
Console.WriteLine("read:" + num2.ToString());
Console.WriteLine("read:" + num2);
}
public static void sample5()

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1325.cs

@ -6,10 +6,8 @@ using System.Diagnostics; @@ -6,10 +6,8 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
[assembly: Embedded]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]

19
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/WeirdEnums.cs

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
using System;
namespace TestEnum
{
public enum BooleanEnum : bool
{
Min = false,
Zero = false,
One = true,
Max = byte.MaxValue
}
public enum NativeIntEnum : IntPtr
{
Zero = 0L,
One = 1L,
FortyTwo = 42L
}
}

36
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/WeirdEnums.il

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly BoolEnum
{
.ver 1:0:0:0
}
.module BoolEnum.exe
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00020003 // ILONLY 32BITPREFERRED
// Image base: 0x000001C4B6C90000
.class public auto ansi sealed TestEnum.BooleanEnum
extends [mscorlib]System.Enum
{
.field public specialname rtspecialname bool value__
.field public static literal valuetype TestEnum.BooleanEnum Min = bool(false)
.field public static literal valuetype TestEnum.BooleanEnum Zero = bool(false)
.field public static literal valuetype TestEnum.BooleanEnum One = bool(true)
.field public static literal valuetype TestEnum.BooleanEnum Max = uint8(255)
}
.class public auto ansi sealed TestEnum.NativeIntEnum
extends [mscorlib]System.Enum
{
.field public specialname rtspecialname native int value__
.field public static literal valuetype TestEnum.NativeIntEnum Zero = int64(0)
.field public static literal valuetype TestEnum.NativeIntEnum One = int64(1)
.field public static literal valuetype TestEnum.NativeIntEnum FortyTwo = int64(42)
}

31
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Async.cs

@ -167,6 +167,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -167,6 +167,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
};
}
public static async Task AlwaysThrow()
{
throw null;
}
public static async Task InfiniteLoop()
{
while (true) {
}
}
public static async Task InfiniteLoopWithAwait()
{
while (true) {
await Task.Delay(10);
}
}
#if CS70
public static async Task<int> AsyncLocalFunctions()
{
@ -181,6 +199,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -181,6 +199,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
#endif
}
public struct AsyncInStruct
{
private int i;
public async Task<int> Test(AsyncInStruct xx)
{
xx.i++;
i++;
await Task.Yield();
return i + xx.i;
}
}
public struct HopToThreadPoolAwaitable : INotifyCompletion
{
public bool IsCompleted {

65
ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class AsyncStreams
{
public static async IAsyncEnumerable<int> CountTo(int until)
{
for (int i = 0; i < until; i++) {
yield return i;
await Task.Delay(10);
}
}
public static async IAsyncEnumerable<int> AlwaysThrow()
{
throw null;
yield break;
}
public static async IAsyncEnumerator<int> InfiniteLoop()
{
while (true) {
}
yield break;
}
public static async IAsyncEnumerable<int> InfiniteLoopWithAwait()
{
while (true) {
await Task.Delay(10);
}
yield break;
}
public async IAsyncEnumerable<int> AwaitInFinally()
{
try {
Console.WriteLine("try");
yield return 1;
Console.WriteLine("end try");
} finally {
Console.WriteLine("finally");
await Task.Yield();
Console.WriteLine("end finally");
}
}
}
public struct TestStruct
{
private int i;
public async IAsyncEnumerable<int> AwaitInStruct(TestStruct xx)
{
xx.i++;
i++;
await Task.Yield();
yield return i;
yield return xx.i;
}
}
}

60
ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncUsing.cs

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class AsyncUsing
{
internal class AsyncDisposableClass : IAsyncDisposable
{
public ValueTask DisposeAsync()
{
throw new NotImplementedException();
}
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
internal struct AsyncDisposableStruct : IAsyncDisposable
{
public ValueTask DisposeAsync()
{
throw new NotImplementedException();
}
}
public static async void TestAsyncUsing(IAsyncDisposable disposable)
{
await using (disposable) {
Console.WriteLine("Hello");
}
}
public static async void TestAsyncUsingClass()
{
await using (AsyncDisposableClass test = new AsyncDisposableClass()) {
Use(test);
}
}
public static async void TestAsyncUsingStruct()
{
await using (AsyncDisposableStruct asyncDisposableStruct = default(AsyncDisposableStruct)) {
Use(asyncDisposableStruct);
}
}
public static async void TestAsyncUsingNullableStruct()
{
await using (AsyncDisposableStruct? asyncDisposableStruct = new AsyncDisposableStruct?(default(AsyncDisposableStruct))) {
Use(asyncDisposableStruct);
}
}
private static void Use(IAsyncDisposable test)
{
throw new NotImplementedException();
}
}
}

586
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs

File diff suppressed because it is too large Load Diff

16
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs

@ -20,6 +20,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -20,6 +20,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class ConstructorInitializers
{
public struct Issue1743
{
public int Leet;
public Issue1743(int dummy)
: this(dummy, dummy)
{
Leet += dummy;
}
public Issue1743(int dummy1, int dummy2)
{
Leet = dummy1 + dummy2;
}
}
public struct SimpleStruct
{
public int Field1;

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes2.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
using System;
namespace CustomAttributes2
{
public static class CustomAtributes
public static class CustomAttributes
{
[Flags]
public enum EnumWithFlag

80
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomTaskType.cs

@ -1,10 +1,13 @@ @@ -1,10 +1,13 @@
using System;
#pragma warning disable 1998
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class CustomTaskType
public class ValueTaskType
{
private int memberField;
@ -123,3 +126,76 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -123,3 +126,76 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
}
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.Issue1788
{
[AsyncMethodBuilder(typeof(builder))]
internal class async
{
public awaiter GetAwaiter()
{
throw null;
}
}
internal class await
{
public awaiter GetAwaiter()
{
throw null;
}
}
internal class awaiter : INotifyCompletion
{
public bool IsCompleted => true;
public void GetResult()
{
}
public void OnCompleted(Action continuation)
{
}
}
internal class builder
{
public async Task {
get {
throw null;
}
}
public static builder Create()
{
throw null;
}
public void SetResult()
{
}
public void SetException(Exception e)
{
}
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
throw null;
}
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
{
throw null;
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
{
throw null;
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
throw null;
}
}
public class C
{
internal async async @await(@await async)
{
await async;
}
}
}

82
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs

@ -151,6 +151,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -151,6 +151,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
void M3();
}
public class BaseClass : IM3
{
protected virtual void M1()
@ -163,6 +164,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -163,6 +164,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
}
}
public class SubClass : BaseClass
{
protected override void M2()
@ -193,6 +195,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -193,6 +195,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Noop("M3", M3);
#endif
}
public void Test2()
{
Noop("M3.new", new BaseClass().M3);
@ -204,6 +207,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -204,6 +207,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
public class GenericTest<TNonCaptured, TCaptured>
{
public Func<TCaptured> GetFunc(Func<TNonCaptured, TCaptured> f)
{
TCaptured captured = f(default(TNonCaptured));
return delegate {
Console.WriteLine(captured.GetType().FullName);
return captured;
};
}
public Func<TNonCaptured, TNonCapturedMP, TCaptured> GetFunc<TNonCapturedMP>(Func<TCaptured> f)
{
TCaptured captured = f();
return delegate(TNonCaptured a, TNonCapturedMP d) {
Console.WriteLine(a.GetHashCode());
Console.WriteLine(captured.GetType().FullName);
return captured;
};
}
}
public static Func<string, string, bool> test0 = (string a, string b) => string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b);
public static Func<string, string, bool> test1 = (string a, string b) => string.IsNullOrEmpty(a) || !string.IsNullOrEmpty(b);
public static Func<string, string, bool> test2 = (string a, string b) => !string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b);
@ -342,5 +367,62 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -342,5 +367,62 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return (int b) => (int c) => (int d) => a + b + c + d;
}
public static Func<TCaptured> CapturedTypeParameter1<TNonCaptured, TCaptured>(TNonCaptured a, Func<TNonCaptured, TCaptured> f)
{
TCaptured captured = f(a);
return delegate {
Console.WriteLine(captured.GetType().FullName);
return captured;
};
}
public static Func<TCaptured> CapturedTypeParameter2<TNonCaptured, TCaptured>(TNonCaptured a, Func<TNonCaptured, List<TCaptured>> f)
{
List<TCaptured> captured = f(a);
return delegate {
Console.WriteLine(captured.GetType().FullName);
return captured.FirstOrDefault();
};
}
public static Func<int> Issue1773(short data)
{
int integerData = data;
return () => integerData;
}
#if !MCS
// does not compile with mcs...
public static Func<int> Issue1773b(object data)
{
#if ROSLYN
dynamic dynamicData = data;
return () => dynamicData.DynamicCall();
#else
// This is a bug in the old csc: captured dynamic local variables did not have the [DynamicAttribute]
// on the display-class field.
return () => ((dynamic)data).DynamicCall();
#endif
}
public static Func<int> Issue1773c(object data)
{
#if ROSLYN
dynamic dynamicData = data;
return () => dynamicData;
#else
return () => (dynamic)data;
#endif
}
#endif
#if ROSLYN
public static Func<string> Issue1773d((int Integer, string String) data)
{
(int Integer, string RenamedString) valueTuple = data;
return () => valueTuple.RenamedString;
}
#endif
}
}

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs

@ -1026,6 +1026,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1026,6 +1026,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
});
}
public static void StringConcat()
{
Test<Func<string, object, string>>(null, (string a, object b) => a + b);
Test<Func<string, object, string>>(null, (string a, object b) => a + b.ToString());
Test<Func<string, int, string>>(null, (string a, int b) => a + b);
Test<Func<string, int, string>>(null, (string a, int b) => a + b.ToString());
}
public async Task Issue1524(string str)
{
await Task.Delay(100);

7
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs

@ -24,10 +24,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -24,10 +24,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
private class GenericClass<T>
{
private readonly T issue1760;
public void M(out GenericClass<T> self)
{
self = this;
}
public void Issue1760()
{
Console.WriteLine(", " + issue1760);
}
}
public class BaseClass

77
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InterfaceTests.cs

@ -16,21 +16,98 @@ @@ -16,21 +16,98 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class InterfaceTests
{
public interface IA
{
int Property1 {
get;
}
int Property2 {
set;
}
int Property3 {
get;
set;
}
event EventHandler MyEvent;
void Method();
#if CS80
void DefaultMethod()
{
Method();
PrivateMethod();
}
private void PrivateMethod()
{
Method();
}
internal void InternalMethod()
{
Method();
}
sealed void SealedMethod()
{
Method();
}
static void StaticMethod()
{
}
#endif
}
public interface IA2 : IA
{
#if CS80
void IA.InternalMethod()
{
}
#endif
}
public interface IB
{
}
public class C : IA2, IA, IB
{
int IA.Property1 {
get {
throw new NotImplementedException();
}
}
int IA.Property2 {
set {
throw new NotImplementedException();
}
}
int IA.Property3 {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
event EventHandler IA.MyEvent {
add {
}
remove {
}
}
void IA.Method()
{
throw new NotImplementedException();
}
}
}
}

11
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -310,6 +310,17 @@ namespace LocalFunctions @@ -310,6 +310,17 @@ namespace LocalFunctions
}
}
public void WriteCapturedParameter(int i)
{
ParamWrite();
Console.WriteLine(i);
void ParamWrite()
{
i++;
}
}
//public static void LocalFunctionInUsing()
//{
// using (MemoryStream memoryStream = new MemoryStream()) {

3
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -401,7 +401,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -401,7 +401,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine("MoveNext");
if (enumerator.MoveNext()) {
object current = enumerator.Current;
Console.WriteLine("current: " + current);
Console.WriteLine("please don't inline 'current'");
Console.WriteLine(current);
}
} finally {
IDisposable disposable = enumerator as IDisposable;

15
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
@ -182,7 +184,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -182,7 +184,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
Use(GetMyClass()?.Text ?? "Hello");
}
public void CallOnValueTypeField()
{
Use(GetMyClass()?.IntVal.ToString());
@ -258,6 +260,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -258,6 +260,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return t?.Int();
}
public int? Issue1709(object obj)
{
return (obj as ICollection)?.Count + (obj as ICollection<int>)?.Count;
}
private static void Issue1689(List<byte[]> setsOfNumbers)
{
Console.WriteLine(setsOfNumbers?[0]?[1].ToString() == "2");
Console.WriteLine(setsOfNumbers?[1]?[1].ToString() == null);
}
private static dynamic DynamicNullProp(dynamic a)
{
return a?.b.c(1)?.d[10];

53
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QualifierTests.cs

@ -128,9 +128,45 @@ namespace ICSharpCode.Decompiler.Tests.Pretty @@ -128,9 +128,45 @@ namespace ICSharpCode.Decompiler.Tests.Pretty
}
}
private class i
{
public static void Test()
{
}
}
private class value
{
public static int item;
public static void Test()
{
}
}
private int fieldConflict;
private int innerConflict;
private static int PropertyValueParameterConflictsWithTypeName {
get {
return value.item;
}
set {
QualifierTests.value.item = value;
}
}
private int this[string[] Array] {
get {
System.Array.Sort(Array);
return 0;
}
set {
System.Array.Sort(Array);
QualifierTests.value.item = value;
}
}
private void NoParameters()
{
Delegate(Parameter);
@ -209,6 +245,23 @@ namespace ICSharpCode.Decompiler.Tests.Pretty @@ -209,6 +245,23 @@ namespace ICSharpCode.Decompiler.Tests.Pretty
{
}
private void ParameterConflictsWithTypeName(string[] Array)
{
System.Array.Sort(Array);
}
private void LocalConflictsWithTypeName()
{
for (int i = 0; i < 10; i++) {
QualifierTests.i.Test();
}
}
public QualifierTests(string[] Array)
{
System.Array.Sort(Array);
}
}
internal static class ZExt

53
ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs

@ -63,17 +63,68 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -63,17 +63,68 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
private readonly int dummy;
public int Property {
get {
return 1;
}
set {
}
}
#if CS80
public readonly int ReadOnlyProperty {
get {
return 1;
}
set {
}
}
public int PropertyWithReadOnlyGetter {
readonly get {
return 1;
}
set {
}
}
public int PropertyWithReadOnlySetter {
get {
return 1;
}
readonly set {
}
}
public event EventHandler NormalEvent;
public readonly event EventHandler ReadOnlyEvent {
add {
}
remove {
}
}
#endif
public void Method()
{
}
#if CS80
public readonly void ReadOnlyMethod()
{
}
#endif
}
public readonly struct ReadOnlyStruct
{
private readonly int dummy;
private readonly int Field;
public void Method()
{
ref readonly int field = ref Field;
Console.WriteLine("No inlining");
Console.WriteLine(field.GetHashCode());
}
}

82
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs

@ -47,6 +47,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -47,6 +47,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Null
}
private static char ch1767;
#if !ROSLYN
public static State SwitchOverNullableBool(bool? value)
{
@ -366,7 +368,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -366,7 +368,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
#if !ROSLYN
public static string SwitchOverBool(bool b)
{
Console.WriteLine("SwitchOverBool: " + b.ToString());
Console.WriteLine("SwitchOverBool: " + b);
switch (b) {
case true:
return bool.TrueString;
@ -465,7 +467,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -465,7 +467,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine("End of method");
}
public static void SwitchWithGotoComplex(string s)
{
Console.WriteLine("SwitchWithGotoComplex: " + s);
@ -640,7 +642,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -640,7 +642,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine();
}
}
// while condition, return and break cases
public static void SwitchWithContinue2(int i, bool b)
{
@ -681,7 +683,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -681,7 +683,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
i++;
}
}
// for loop version
public static void SwitchWithContinue3(bool b)
{
@ -721,7 +723,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -721,7 +723,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine("loop-tail");
}
}
// foreach version
public static void SwitchWithContinue4(bool b)
{
@ -843,7 +845,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -843,7 +845,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
continue;
}
Console.WriteLine("loop-tail");
} while (++i < 10);
} while (++i < 10);
}
// double break from switch to loop exit requires additional pattern matching in HighLevelLoopTransform
@ -918,7 +920,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -918,7 +920,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
// These decompile poorly into switch statements and should be left as is
#region Overagressive Switch Use
#region Overagressive Switch Use
#if ROSLYN || OPT
public static void SingleIf1(int i, bool a)
@ -929,7 +931,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -929,7 +931,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine(2);
}
#endif
public static void SingleIf2(int i, bool a, bool b)
{
if (i == 1 || (i == 2 && a) || (i == 3 && b)) {
@ -937,7 +939,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -937,7 +939,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine(2);
}
public static void SingleIf3(int i, bool a, bool b)
{
if (a || i == 1 || (i == 2 && b)) {
@ -945,7 +947,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -945,7 +947,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine(2);
}
public static void SingleIf4(int i, bool a)
{
if (i == 1 || i == 2 || (i != 3 && a) || i != 4) {
@ -964,7 +966,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -964,7 +966,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine();
}
public static void IfChainWithCondition(int i)
{
if (i == 0) {
@ -985,7 +987,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -985,7 +987,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine();
}
public static bool SwitchlikeIf(int i, int j)
{
if (i != 0 && j != 0) {
@ -1023,7 +1025,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1023,7 +1025,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
return false;
}
return true;
}
@ -1052,7 +1054,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1052,7 +1054,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine("end");
}
public static bool Loop8(char c, bool b, Func<char> getChar)
{
if (b) {
@ -1071,8 +1073,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1071,8 +1073,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
c = getChar();
} while (c != -1 && c != '\n' && c != '\u2028' && c != '\u2029');
}
#endregion
#endregion
// Ensure correctness of SwitchDetection.UseCSharpSwitch control flow heuristics
public static void SwitchWithBreakCase(int i, bool b)
{
@ -1108,7 +1110,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1108,7 +1110,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine();
}
public static int SwitchWithReturnAndBreak2(int i, bool b)
{
switch (i) {
@ -1130,7 +1132,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1130,7 +1132,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine();
return 0;
}
public static void SwitchWithReturnAndBreak3(int i)
{
switch (i) {
@ -1193,6 +1195,26 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1193,6 +1195,26 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
public static void Issue1745(string aaa)
{
switch (aaa) {
case "a":
case "b":
case "c":
case "d":
case "e":
case "f":
Console.WriteLine(aaa);
break;
case null:
Console.WriteLine("<null>");
break;
case "":
Console.WriteLine("<empty>");
break;
}
}
public static bool DoNotRemoveAssignmentBeforeSwitch(string x, out ConsoleKey key)
{
key = (ConsoleKey)0;
@ -1209,5 +1231,29 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1209,5 +1231,29 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
return key != (ConsoleKey)0;
}
public static void Issue1767(string s)
{
switch (s) {
case "a":
ch1767 = s[0];
break;
case "b":
ch1767 = s[0];
break;
case "c":
ch1767 = s[0];
break;
case "d":
ch1767 = s[0];
break;
case "e":
ch1767 = s[0];
break;
case "f":
ch1767 = s[0];
break;
}
}
}
}

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Using.cs

@ -90,7 +90,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -90,7 +90,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
private void UsingStatementOnNullableStruct(UsingStruct? us)
{
using (us) {
Console.WriteLine("using-body: " + us);
Console.WriteLine("using-body: " + us.ToString());
}
}

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs

@ -184,7 +184,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -184,7 +184,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static void Issue56(int i, out string str)
{
str = "qq";
str += i.ToString();
str += i;
}
public static void CopyAroundAndModifyField(S s)

33
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.Expected.cs

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
using System;
using System.Runtime.CompilerServices;
[assembly: Extension]
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
[Extension]
internal static class NoExtensionMethods
{
[Extension]
internal static Func<T> AsFunc<T>(T value) where T : class
{
return new Func<T>(value, __ldftn(Return));
}
[Extension]
private static T Return<T>(T value)
{
return value;
}
internal static Func<int, int> ExtensionMethodAsStaticFunc()
{
return Return;
}
internal static Func<object> ExtensionMethodBoundToNull()
{
return new Func<object>(null, __ldftn(Return));
}
}
}

27
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
internal static class NoExtensionMethods
{
internal static Func<T> AsFunc<T>(this T value) where T : class
{
return new Func<T>(value.Return);
}
private static T Return<T>(this T value)
{
return value;
}
internal static Func<int, int> ExtensionMethodAsStaticFunc()
{
return Return;
}
internal static Func<object> ExtensionMethodBoundToNull()
{
return ((object)null).Return;
}
}
}

93
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.opt.roslyn.il

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NoExtensionMethods
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NoExtensionMethods.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private abstract auto ansi sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.method assembly hidebysig static class [mscorlib]System.Func`1<!!T>
AsFunc<class T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<!!0>(!!0)
IL_000c: newobj instance void class [mscorlib]System.Func`1<!!T>::.ctor(object,
native int)
IL_0011: ret
} // end of method NoExtensionMethods::AsFunc
.method private hidebysig static !!T Return<T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ret
} // end of method NoExtensionMethods::Return
.method assembly hidebysig static class [mscorlib]System.Func`2<int32,int32>
ExtensionMethodAsStaticFunc() cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldnull
IL_0001: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<int32>(!!0)
IL_0007: newobj instance void class [mscorlib]System.Func`2<int32,int32>::.ctor(object,
native int)
IL_000c: ret
} // end of method NoExtensionMethods::ExtensionMethodAsStaticFunc
.method assembly hidebysig static class [mscorlib]System.Func`1<object>
ExtensionMethodBoundToNull() cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldnull
IL_0001: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<object>(!!0)
IL_0007: newobj instance void class [mscorlib]System.Func`1<object>::.ctor(object,
native int)
IL_000c: ret
} // end of method NoExtensionMethods::ExtensionMethodBoundToNull
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

117
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoExtensionMethods.roslyn.il

@ -0,0 +1,117 @@ @@ -0,0 +1,117 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NoExtensionMethods
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NoExtensionMethods.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private abstract auto ansi sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.method assembly hidebysig static class [mscorlib]System.Func`1<!!T>
AsFunc<class T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 23 (0x17)
.maxstack 2
.locals init (class [mscorlib]System.Func`1<!!T> V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: box !!T
IL_0007: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<!!0>(!!0)
IL_000d: newobj instance void class [mscorlib]System.Func`1<!!T>::.ctor(object,
native int)
IL_0012: stloc.0
IL_0013: br.s IL_0015
IL_0015: ldloc.0
IL_0016: ret
} // end of method NoExtensionMethods::AsFunc
.method private hidebysig static !!T Return<T>(!!T 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 1
.locals init (!!T V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
} // end of method NoExtensionMethods::Return
.method assembly hidebysig static class [mscorlib]System.Func`2<int32,int32>
ExtensionMethodAsStaticFunc() cil managed
{
// Code size 18 (0x12)
.maxstack 2
.locals init (class [mscorlib]System.Func`2<int32,int32> V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<int32>(!!0)
IL_0008: newobj instance void class [mscorlib]System.Func`2<int32,int32>::.ctor(object,
native int)
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
} // end of method NoExtensionMethods::ExtensionMethodAsStaticFunc
.method assembly hidebysig static class [mscorlib]System.Func`1<object>
ExtensionMethodBoundToNull() cil managed
{
// Code size 18 (0x12)
.maxstack 2
.locals init (class [mscorlib]System.Func`1<object> V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: ldftn !!0 ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods::Return<object>(!!0)
IL_0008: newobj instance void class [mscorlib]System.Func`1<object>::.ctor(object,
native int)
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
} // end of method NoExtensionMethods::ExtensionMethodBoundToNull
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoExtensionMethods
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

43
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.Expected.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
internal class NoForEachStatement
{
public static void SimpleNonGenericForeach(IEnumerable enumerable)
{
IEnumerator enumerator = enumerable.GetEnumerator();
try {
while (enumerator.MoveNext()) {
#if ROSLYN && OPT
Console.WriteLine(enumerator.Current);
#else
object current = enumerator.Current;
Console.WriteLine(current);
#endif
}
} finally {
IDisposable disposable = enumerator as IDisposable;
if (disposable != null) {
disposable.Dispose();
}
}
}
public static void SimpleForeachOverInts(IEnumerable<int> enumerable)
{
using (IEnumerator<int> enumerator = enumerable.GetEnumerator()) {
while (enumerator.MoveNext()) {
#if ROSLYN && OPT
Console.WriteLine(enumerator.Current);
#else
int current = enumerator.Current;
Console.WriteLine(current);
#endif
}
}
}
}
}

23
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.cs

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
{
internal class NoForEachStatement
{
public static void SimpleNonGenericForeach(IEnumerable enumerable)
{
foreach (object item in enumerable) {
Console.WriteLine(item);
}
}
public static void SimpleForeachOverInts(IEnumerable<int> enumerable)
{
foreach (int item in enumerable) {
Console.WriteLine(item);
}
}
}
}

156
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.il

@ -0,0 +1,156 @@ @@ -0,0 +1,156 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly rerff2f0
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module rerff2f0.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
extends [mscorlib]System.Object
{
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed
{
// Code size 64 (0x40)
.maxstack 2
.locals init (object V_0,
class [mscorlib]System.Collections.IEnumerator V_1,
bool V_2,
class [mscorlib]System.IDisposable V_3)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.0
IL_0003: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0008: stloc.1
.try
{
IL_0009: br.s IL_001b
IL_000b: ldloc.1
IL_000c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0011: stloc.0
IL_0012: nop
IL_0013: ldloc.0
IL_0014: call void [mscorlib]System.Console::WriteLine(object)
IL_0019: nop
IL_001a: nop
IL_001b: ldloc.1
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0021: stloc.2
IL_0022: ldloc.2
IL_0023: brtrue.s IL_000b
IL_0025: leave.s IL_003e
} // end .try
finally
{
IL_0027: ldloc.1
IL_0028: isinst [mscorlib]System.IDisposable
IL_002d: stloc.3
IL_002e: ldloc.3
IL_002f: ldnull
IL_0030: ceq
IL_0032: stloc.2
IL_0033: ldloc.2
IL_0034: brtrue.s IL_003d
IL_0036: ldloc.3
IL_0037: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003c: nop
IL_003d: endfinally
} // end handler
IL_003e: nop
IL_003f: ret
} // end of method NoForEachStatement::SimpleNonGenericForeach
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed
{
// Code size 57 (0x39)
.maxstack 2
.locals init (int32 V_0,
class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_1,
bool V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.0
IL_0003: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
IL_0008: stloc.1
.try
{
IL_0009: br.s IL_001b
IL_000b: ldloc.1
IL_000c: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
IL_0011: stloc.0
IL_0012: nop
IL_0013: ldloc.0
IL_0014: call void [mscorlib]System.Console::WriteLine(int32)
IL_0019: nop
IL_001a: nop
IL_001b: ldloc.1
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0021: stloc.2
IL_0022: ldloc.2
IL_0023: brtrue.s IL_000b
IL_0025: leave.s IL_0037
} // end .try
finally
{
IL_0027: ldloc.1
IL_0028: ldnull
IL_0029: ceq
IL_002b: stloc.2
IL_002c: ldloc.2
IL_002d: brtrue.s IL_0036
IL_002f: ldloc.1
IL_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0035: nop
IL_0036: endfinally
} // end handler
IL_0037: nop
IL_0038: ret
} // end of method NoForEachStatement::SimpleForeachOverInts
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method NoForEachStatement::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

128
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.opt.il

@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly prqfqkbt
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module prqfqkbt.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
extends [mscorlib]System.Object
{
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed
{
// Code size 50 (0x32)
.maxstack 1
.locals init (object V_0,
class [mscorlib]System.Collections.IEnumerator V_1,
class [mscorlib]System.IDisposable V_2)
IL_0000: ldarg.0
IL_0001: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0006: stloc.1
.try
{
IL_0007: br.s IL_0016
IL_0009: ldloc.1
IL_000a: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: call void [mscorlib]System.Console::WriteLine(object)
IL_0016: ldloc.1
IL_0017: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_001c: brtrue.s IL_0009
IL_001e: leave.s IL_0031
} // end .try
finally
{
IL_0020: ldloc.1
IL_0021: isinst [mscorlib]System.IDisposable
IL_0026: stloc.2
IL_0027: ldloc.2
IL_0028: brfalse.s IL_0030
IL_002a: ldloc.2
IL_002b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0030: endfinally
} // end handler
IL_0031: ret
} // end of method NoForEachStatement::SimpleNonGenericForeach
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed
{
// Code size 43 (0x2b)
.maxstack 1
.locals init (int32 V_0,
class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_1)
IL_0000: ldarg.0
IL_0001: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
IL_0006: stloc.1
.try
{
IL_0007: br.s IL_0016
IL_0009: ldloc.1
IL_000a: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: call void [mscorlib]System.Console::WriteLine(int32)
IL_0016: ldloc.1
IL_0017: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_001c: brtrue.s IL_0009
IL_001e: leave.s IL_002a
} // end .try
finally
{
IL_0020: ldloc.1
IL_0021: brfalse.s IL_0029
IL_0023: ldloc.1
IL_0024: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0029: endfinally
} // end handler
IL_002a: ret
} // end of method NoForEachStatement::SimpleForeachOverInts
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method NoForEachStatement::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

126
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.opt.roslyn.il

@ -0,0 +1,126 @@ @@ -0,0 +1,126 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NoForEachStatement
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NoForEachStatement.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
extends [mscorlib]System.Object
{
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed
{
// Code size 48 (0x30)
.maxstack 1
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
class [mscorlib]System.IDisposable V_1)
IL_0000: ldarg.0
IL_0001: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0006: stloc.0
.try
{
IL_0007: br.s IL_0014
IL_0009: ldloc.0
IL_000a: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_000f: call void [mscorlib]System.Console::WriteLine(object)
IL_0014: ldloc.0
IL_0015: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_001a: brtrue.s IL_0009
IL_001c: leave.s IL_002f
} // end .try
finally
{
IL_001e: ldloc.0
IL_001f: isinst [mscorlib]System.IDisposable
IL_0024: stloc.1
IL_0025: ldloc.1
IL_0026: brfalse.s IL_002e
IL_0028: ldloc.1
IL_0029: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_002e: endfinally
} // end handler
IL_002f: ret
} // end of method NoForEachStatement::SimpleNonGenericForeach
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed
{
// Code size 41 (0x29)
.maxstack 1
.locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_0)
IL_0000: ldarg.0
IL_0001: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
IL_0006: stloc.0
.try
{
IL_0007: br.s IL_0014
IL_0009: ldloc.0
IL_000a: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
IL_000f: call void [mscorlib]System.Console::WriteLine(int32)
IL_0014: ldloc.0
IL_0015: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_001a: brtrue.s IL_0009
IL_001c: leave.s IL_0028
} // end .try
finally
{
IL_001e: ldloc.0
IL_001f: brfalse.s IL_0027
IL_0021: ldloc.0
IL_0022: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0027: endfinally
} // end handler
IL_0028: ret
} // end of method NoForEachStatement::SimpleForeachOverInts
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method NoForEachStatement::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

145
ICSharpCode.Decompiler.Tests/TestCases/Ugly/NoForEachStatement.roslyn.il

@ -0,0 +1,145 @@ @@ -0,0 +1,145 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NoForEachStatement
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NoForEachStatement.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
extends [mscorlib]System.Object
{
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed
{
// Code size 56 (0x38)
.maxstack 1
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
object V_1,
class [mscorlib]System.IDisposable V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.0
IL_0003: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0008: stloc.0
.try
{
IL_0009: br.s IL_001b
IL_000b: ldloc.0
IL_000c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0011: stloc.1
IL_0012: nop
IL_0013: ldloc.1
IL_0014: call void [mscorlib]System.Console::WriteLine(object)
IL_0019: nop
IL_001a: nop
IL_001b: ldloc.0
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0021: brtrue.s IL_000b
IL_0023: leave.s IL_0037
} // end .try
finally
{
IL_0025: ldloc.0
IL_0026: isinst [mscorlib]System.IDisposable
IL_002b: stloc.2
IL_002c: ldloc.2
IL_002d: brfalse.s IL_0036
IL_002f: ldloc.2
IL_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0035: nop
IL_0036: endfinally
} // end handler
IL_0037: ret
} // end of method NoForEachStatement::SimpleNonGenericForeach
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed
{
// Code size 49 (0x31)
.maxstack 1
.locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_0,
int32 V_1)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.0
IL_0003: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
IL_0008: stloc.0
.try
{
IL_0009: br.s IL_001b
IL_000b: ldloc.0
IL_000c: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
IL_0011: stloc.1
IL_0012: nop
IL_0013: ldloc.1
IL_0014: call void [mscorlib]System.Console::WriteLine(int32)
IL_0019: nop
IL_001a: nop
IL_001b: ldloc.0
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0021: brtrue.s IL_000b
IL_0023: leave.s IL_0030
} // end .try
finally
{
IL_0025: ldloc.0
IL_0026: brfalse.s IL_002f
IL_0028: ldloc.0
IL_0029: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_002e: nop
IL_002f: endfinally
} // end handler
IL_0030: ret
} // end of method NoForEachStatement::SimpleForeachOverInts
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method NoForEachStatement::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

20
ICSharpCode.Decompiler.Tests/UglyTestRunner.cs

@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.Tests
};
[Test]
public void NoArrayInitializers([ValueSource("roslynOnlyOptions")] CompilerOptions cscOptions)
public void NoArrayInitializers([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
ArrayInitializers = false
@ -76,13 +76,29 @@ namespace ICSharpCode.Decompiler.Tests @@ -76,13 +76,29 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public void NoDecimalConstants([ValueSource("roslynOnlyOptions")] CompilerOptions cscOptions)
public void NoDecimalConstants([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
DecimalConstants = false
});
}
[Test]
public void NoExtensionMethods([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
ExtensionMethods = false
});
}
[Test]
public void NoForEachStatement([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
ForEachStatement = false
});
}
void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null)
{
Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings);

10
ICSharpCode.Decompiler/CSharp/Annotations.cs

@ -41,8 +41,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -41,8 +41,8 @@ namespace ICSharpCode.Decompiler.CSharp
/// <summary>
/// Currently unused; we'll probably use the LdToken ILInstruction as annotation instead when LdToken support gets reimplemented.
/// </summary>
public class LdTokenAnnotation {}
public class LdTokenAnnotation { }
public static class AnnotationExtensions
{
internal static ExpressionWithILInstruction WithILInstruction(this Expression expression, ILInstruction instruction)
@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.CSharp
expression.Expression.AddAnnotation(resolveResult);
return new TranslatedExpression(expression, resolveResult);
}
/// <summary>
/// Retrieves the <see cref="ISymbol"/> associated with this AstNode, or null if no symbol is associated with the node.
/// </summary>
@ -208,7 +208,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -208,7 +208,7 @@ namespace ICSharpCode.Decompiler.CSharp
return node;
}
}
/// <summary>
/// Represents a reference to a local variable.
/// </summary>
@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp
public ILVariableResolveResult(ILVariable v, IType type) : base(type)
{
this.Variable = v ?? throw new ArgumentNullException("v");
this.Variable = v ?? throw new ArgumentNullException(nameof(v));
}
}

11
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -105,6 +105,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -105,6 +105,7 @@ namespace ICSharpCode.Decompiler.CSharp
new SwitchOnStringTransform(),
new SwitchOnNullableTransform(),
new SplitVariables(), // split variables once again, because SwitchOnNullableTransform eliminates ldloca
new IntroduceRefReadOnlyModifierOnLocals(),
new BlockILTransform { // per-block transforms
PostOrderTransforms = {
// Even though it's a post-order block-transform as most other transforms,
@ -304,6 +305,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -304,6 +305,8 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
if (settings.AsyncAwait && AsyncAwaitDecompiler.IsCompilerGeneratedStateMachine(typeHandle, metadata))
return true;
if (settings.AsyncEnumerator && AsyncAwaitDecompiler.IsCompilerGeneratorAsyncEnumerator(typeHandle, metadata))
return true;
if (settings.FixedBuffers && name.StartsWith("<", StringComparison.Ordinal) && name.Contains("__FixedBuffer"))
return true;
} else if (type.IsCompilerGenerated(metadata)) {
@ -782,6 +785,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -782,6 +785,7 @@ namespace ICSharpCode.Decompiler.CSharp
syntaxTree = new SyntaxTree();
foreach (var type in types) {
CancellationToken.ThrowIfCancellationRequested();
if (type.IsNil)
throw new ArgumentException("types contains null element");
RequiredNamespaceCollector.CollectNamespaces(type, module, decompileRun.Namespaces);
@ -1296,6 +1300,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1296,6 +1300,7 @@ namespace ICSharpCode.Decompiler.CSharp
parameter.AddAnnotation(new ILVariableResolveResult(v, method.Parameters[i].Type));
i++;
}
entityDecl.AddAnnotation(function);
}
var localSettings = settings.Clone();
@ -1340,7 +1345,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1340,7 +1345,11 @@ namespace ICSharpCode.Decompiler.CSharp
if (localSettings.DecompileMemberBodies && !body.Descendants.Any(d => d is YieldReturnStatement || d is YieldBreakStatement)) {
body.Add(new YieldBreakStatement());
}
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine);
if (function.IsAsync) {
RemoveAttribute(entityDecl, KnownAttribute.AsyncIteratorStateMachine);
} else {
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine);
}
if (function.StateMachineCompiledWithMono) {
RemoveAttribute(entityDecl, KnownAttribute.DebuggerHidden);
}

73
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -989,6 +989,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -989,6 +989,10 @@ namespace ICSharpCode.Decompiler.CSharp
foundMember = null;
bestCandidateIsExpandedForm = false;
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentModule);
Log.WriteLine("IsUnambiguousCall: Performing overload resolution for " + method);
Log.WriteCollection(" Arguments: ", arguments.Select(a => a.ResolveResult));
var or = new OverloadResolution(resolver.Compilation,
firstOptionalArgumentIndex < 0 ? arguments.SelectArray(a => a.ResolveResult) : arguments.Take(firstOptionalArgumentIndex).Select(a => a.ResolveResult).ToArray(),
argumentNames: firstOptionalArgumentIndex < 0 || argumentNames == null ? argumentNames : argumentNames.Take(firstOptionalArgumentIndex).ToArray(),
@ -1043,6 +1047,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1043,6 +1047,9 @@ namespace ICSharpCode.Decompiler.CSharp
bool IsUnambiguousAccess(ExpectedTargetDetails expectedTargetDetails, ResolveResult target, IMethod method,
IList<TranslatedExpression> arguments, string[] argumentNames, out IMember foundMember)
{
Log.WriteLine("IsUnambiguousAccess: Performing overload resolution for " + method);
Log.WriteCollection(" Arguments: ", arguments.Select(a => a.ResolveResult));
foundMember = null;
if (target == null) {
var result = resolver.ResolveSimpleName(method.AccessorOwner.Name,
@ -1235,7 +1242,42 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1235,7 +1242,42 @@ namespace ICSharpCode.Decompiler.CSharp
default:
throw new ArgumentException($"Unknown instruction type: {func.OpCode}");
}
return HandleDelegateConstruction(inst.Method.DeclaringType, method, expectedTargetDetails, thisArg, inst);
if (CanUseDelegateConstruction(method, thisArg, inst.Method.DeclaringType.GetDelegateInvokeMethod())) {
return HandleDelegateConstruction(inst.Method.DeclaringType, method, expectedTargetDetails, thisArg, inst);
} else {
var argumentList = BuildArgumentList(expectedTargetDetails, null, inst.Method,
0, inst.Arguments, null);
return HandleConstructorCall(new ExpectedTargetDetails { CallOpCode = OpCode.NewObj }, null, inst.Method, argumentList).WithILInstruction(inst);
}
}
private bool CanUseDelegateConstruction(IMethod targetMethod, ILInstruction thisArg, IMethod invokeMethod)
{
// Accessors cannot be directly referenced as method group in C#
// see https://github.com/icsharpcode/ILSpy/issues/1741#issuecomment-540179101
if (targetMethod.IsAccessor)
return false;
if (targetMethod.IsStatic) {
// If the invoke method is known, we can compare the parameter counts to figure out whether the
// delegate is static or binds the first argument
if (invokeMethod != null) {
if (invokeMethod.Parameters.Count == targetMethod.Parameters.Count) {
return thisArg.MatchLdNull();
} else if (targetMethod.IsExtensionMethod && invokeMethod.Parameters.Count == targetMethod.Parameters.Count - 1) {
return true;
} else {
return false;
}
} else {
// delegate type unknown:
return thisArg.MatchLdNull() || targetMethod.IsExtensionMethod;
}
} else {
// targetMethod is instance method
if (invokeMethod != null && invokeMethod.Parameters.Count != targetMethod.Parameters.Count)
return false;
return true;
}
}
internal TranslatedExpression Build(LdVirtDelegate inst)
@ -1243,9 +1285,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1243,9 +1285,15 @@ namespace ICSharpCode.Decompiler.CSharp
return HandleDelegateConstruction(inst.Type, inst.Method, new ExpectedTargetDetails { CallOpCode = OpCode.CallVirt }, inst.Argument, inst);
}
TranslatedExpression HandleDelegateConstruction(IType delegateType, IMethod method, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg, ILInstruction inst)
internal ExpressionWithResolveResult BuildMethodReference(IMethod method, bool isVirtual)
{
var expr = BuildDelegateReference(method, invokeMethod: null, new ExpectedTargetDetails { CallOpCode = isVirtual ? OpCode.CallVirt : OpCode.Call }, thisArg: null);
expr.Expression.RemoveAnnotations<ResolveResult>();
return expr.Expression.WithRR(new MemberResolveResult(null, method));
}
ExpressionWithResolveResult BuildDelegateReference(IMethod method, IMethod invokeMethod, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg)
{
var invokeMethod = delegateType.GetDelegateInvokeMethod();
TranslatedExpression target;
IType targetType;
bool requireTarget;
@ -1331,33 +1379,40 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1331,33 +1379,40 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
requireTarget = !method.IsLocalFunction && (step & 1) != 0;
Expression targetExpression;
ExpressionWithResolveResult targetExpression;
Debug.Assert(result != null);
if (requireTarget) {
Debug.Assert(target.Expression != null);
var mre = new MemberReferenceExpression(target, methodName);
if ((step & 2) != 0)
mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
mre.WithRR(result);
targetExpression = mre;
targetExpression = mre.WithRR(result);
} else {
var ide = new IdentifierExpression(methodName);
if ((step & 2) != 0)
ide.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
ide.WithRR(result);
targetExpression = ide;
targetExpression = ide.WithRR(result);
}
return targetExpression;
}
TranslatedExpression HandleDelegateConstruction(IType delegateType, IMethod method, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg, ILInstruction inst)
{
var invokeMethod = delegateType.GetDelegateInvokeMethod();
var targetExpression = BuildDelegateReference(method, invokeMethod, expectedTargetDetails, thisArg);
var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(delegateType), targetExpression)
.WithILInstruction(inst)
.WithRR(new ConversionResolveResult(
delegateType,
result,
targetExpression.ResolveResult,
Conversion.MethodGroupConversion(method, expectedTargetDetails.CallOpCode == OpCode.CallVirt, false)));
return oce;
}
bool IsUnambiguousMethodReference(ExpectedTargetDetails expectedTargetDetails, IMethod method, ResolveResult target, IReadOnlyList<IType> typeArguments, out ResolveResult result)
{
Log.WriteLine("IsUnambiguousMethodReference: Performing overload resolution for " + method);
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentModule);
var or = new OverloadResolution(resolver.Compilation,
arguments: method.Parameters.SelectReadOnlyArray(p => new TypeResolveResult(p.Type)), // there are no arguments, use parameter types

54
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -67,6 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -67,6 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// </remarks>
sealed class ExpressionBuilder : ILVisitor<TranslationContext, TranslatedExpression>
{
readonly StatementBuilder statementBuilder;
readonly IDecompilerTypeSystem typeSystem;
internal readonly ITypeResolveContext decompilationContext;
internal readonly ILFunction currentFunction;
@ -77,9 +78,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -77,9 +78,10 @@ namespace ICSharpCode.Decompiler.CSharp
internal readonly DecompilerSettings settings;
readonly CancellationToken cancellationToken;
public ExpressionBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken)
public ExpressionBuilder(StatementBuilder statementBuilder, IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken)
{
Debug.Assert(decompilationContext != null);
this.statementBuilder = statementBuilder;
this.typeSystem = typeSystem;
this.decompilationContext = decompilationContext;
this.currentFunction = currentFunction;
@ -203,7 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -203,7 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
}
foreach (var f in function.LocalFunctions.OfType<ILFunction>()) {
foreach (var f in function.LocalFunctions) {
if (f.Name == name)
return true;
}
@ -369,7 +371,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -369,7 +371,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
expr.Arguments.AddRange(args.Select(arg => arg.Expression));
return expr.WithILInstruction(inst)
.WithRR(new ArrayCreateResolveResult(new ArrayType(compilation, inst.Type, dimensions), args.Select(a => a.ResolveResult).ToList(), new ResolveResult[0]));
.WithRR(new ArrayCreateResolveResult(new ArrayType(compilation, inst.Type, dimensions), args.Select(a => a.ResolveResult).ToList(), Empty<ResolveResult>.Array));
}
protected internal override TranslatedExpression VisitLocAlloc(LocAlloc inst, TranslationContext context)
@ -1409,7 +1411,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1409,7 +1411,8 @@ namespace ICSharpCode.Decompiler.CSharp
if (UserDefinedCompoundAssign.IsStringConcat(inst.Method)) {
Debug.Assert(inst.Method.Parameters.Count == 2);
var value = Translate(inst.Value).ConvertTo(inst.Method.Parameters[1].Type, this, allowImplicitConversion: true);
return new AssignmentExpression(target, AssignmentOperatorType.Add, value)
var valueExpr = ReplaceMethodCallsWithOperators.RemoveRedundantToStringInConcat(value, inst.Method, isLastArgument: true).Detach();
return new AssignmentExpression(target, AssignmentOperatorType.Add, valueExpr)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(inst.Method.ReturnType, ExpressionType.AddAssign, inst.Method, inst.IsLifted, new[] { target.ResolveResult, value.ResolveResult }));
} else if (inst.Method.Parameters.Count == 2) {
@ -1510,7 +1513,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1510,7 +1513,7 @@ namespace ICSharpCode.Decompiler.CSharp
TranslatedExpression resultExpr;
if (inst.EvalMode == CompoundEvalMode.EvaluatesToOldValue) {
Debug.Assert(op == AssignmentOperatorType.Add || op == AssignmentOperatorType.Subtract);
Debug.Assert(inst.Value.MatchLdcI(1));
Debug.Assert(inst.Value.MatchLdcI(1) || inst.Value.MatchLdcF4(1) || inst.Value.MatchLdcF8(1));
UnaryOperatorType unary;
ExpressionType exprType;
if (op == AssignmentOperatorType.Add) {
@ -1939,6 +1942,31 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1939,6 +1942,31 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
protected internal override TranslatedExpression VisitBlockContainer(BlockContainer container, TranslationContext context)
{
var oldReturnContainer = statementBuilder.currentReturnContainer;
var oldResultType = statementBuilder.currentResultType;
var oldIsIterator = statementBuilder.currentIsIterator;
statementBuilder.currentReturnContainer = container;
statementBuilder.currentResultType = context.TypeHint;
statementBuilder.currentIsIterator = false;
try {
var body = statementBuilder.ConvertAsBlock(container);
body.InsertChildAfter(null, new Comment(" Could not convert BlockContainer to single expression"), Roles.Comment);
var ame = new AnonymousMethodExpression { Body = body };
var delegateType = new ParameterizedType(compilation.FindType(typeof(Func<>)), InferReturnType(body));
var invocationTarget = new CastExpression(ConvertType(delegateType), ame);
return new InvocationExpression(new MemberReferenceExpression(invocationTarget, "Invoke"))
.WithILInstruction(container)
.WithRR(new CSharpInvocationResolveResult(new ResolveResult(delegateType), delegateType.GetDelegateInvokeMethod(), EmptyList<ResolveResult>.Instance));
} finally {
statementBuilder.currentReturnContainer = oldReturnContainer;
statementBuilder.currentResultType = oldResultType;
statementBuilder.currentIsIterator = oldIsIterator;
}
}
internal TranslatedExpression TranslateTarget(ILInstruction target, bool nonVirtualInvocation,
bool memberStatic, IType memberDeclaringType)
{
@ -3134,6 +3162,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3134,6 +3162,22 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new OperatorResolveResult(SpecialType.Dynamic, inst.Operation, new[] { target.ResolveResult, value.ResolveResult }));
}
protected internal override TranslatedExpression VisitLdFtn(LdFtn inst, TranslationContext context)
{
ExpressionWithResolveResult delegateRef = new CallBuilder(this, typeSystem, settings).BuildMethodReference(inst.Method, isVirtual: false);
return new InvocationExpression(new IdentifierExpression("__ldftn"), delegateRef)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.IntPtr)))
.WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitLdVirtFtn(LdVirtFtn inst, TranslationContext context)
{
ExpressionWithResolveResult delegateRef = new CallBuilder(this, typeSystem, settings).BuildMethodReference(inst.Method, isVirtual: true);
return new InvocationExpression(new IdentifierExpression("__ldvirtftn"), delegateRef)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.IntPtr)))
.WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context)
{
string message = "Error";

56
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs

@ -33,33 +33,34 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -33,33 +33,34 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public class CSharpAmbience : IAmbience
{
public ConversionFlags ConversionFlags { get; set; }
#region ConvertSymbol
public string ConvertSymbol(ISymbol symbol)
{
if (symbol == null)
throw new ArgumentNullException("symbol");
throw new ArgumentNullException(nameof(symbol));
StringWriter writer = new StringWriter();
ConvertSymbol(symbol, new TextWriterTokenWriter(writer), FormattingOptionsFactory.CreateEmpty());
return writer.ToString();
}
public void ConvertSymbol(ISymbol symbol, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
if (symbol == null)
throw new ArgumentNullException("symbol");
throw new ArgumentNullException(nameof(symbol));
if (writer == null)
throw new ArgumentNullException("writer");
throw new ArgumentNullException(nameof(writer));
if (formattingPolicy == null)
throw new ArgumentNullException("formattingPolicy");
throw new ArgumentNullException(nameof(formattingPolicy));
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
AstNode node = astBuilder.ConvertSymbol(symbol);
writer.StartNode(node);
EntityDeclaration entityDecl = node as EntityDeclaration;
if (entityDecl != null)
PrintModifiers(entityDecl.Modifiers, writer);
if ((ConversionFlags & ConversionFlags.ShowDefinitionKeyword) == ConversionFlags.ShowDefinitionKeyword) {
if (node is TypeDeclaration) {
switch (((TypeDeclaration)node).ClassType) {
@ -90,24 +91,23 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -90,24 +91,23 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
writer.Space();
}
}
if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) != ConversionFlags.PlaceReturnTypeAfterParameterList
&& (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType)
{
&& (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) {
var rt = node.GetChildByRole(Roles.Type);
if (!rt.IsNull) {
rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
writer.Space();
}
}
if (symbol is ITypeDefinition)
WriteTypeDeclarationName((ITypeDefinition)symbol, writer, formattingPolicy);
else if (symbol is IMember)
WriteMemberDeclarationName((IMember)symbol, writer, formattingPolicy);
else
writer.WriteIdentifier(Identifier.Create(symbol.Name));
if ((ConversionFlags & ConversionFlags.ShowParameterList) == ConversionFlags.ShowParameterList && HasParameters(symbol)) {
writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.LBracket : Roles.LPar, symbol.SymbolKind == SymbolKind.Indexer ? "[" : "(");
bool first = true;
@ -130,8 +130,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -130,8 +130,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) == ConversionFlags.PlaceReturnTypeAfterParameterList
&& (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType)
{
&& (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) {
var rt = node.GetChildByRole(Roles.Type);
if (!rt.IsNull) {
writer.Space();
@ -167,9 +166,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -167,9 +166,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
} else {
writer.WriteToken(Roles.Semicolon, ";");
}
writer.EndNode(node);
}
}
static bool HasParameters(ISymbol e)
{
switch (e.SymbolKind) {
@ -185,11 +185,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -185,11 +185,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return false;
}
}
TypeSystemAstBuilder CreateAstBuilder()
{
TypeSystemAstBuilder astBuilder = new TypeSystemAstBuilder();
astBuilder.AddTypeReferenceAnnotations = true;
astBuilder.AddResolveResultAnnotations = true;
astBuilder.ShowTypeParametersForUnboundTypes = true;
astBuilder.ShowModifiers = (ConversionFlags & ConversionFlags.ShowModifiers) == ConversionFlags.ShowModifiers;
astBuilder.ShowAccessibility = (ConversionFlags & ConversionFlags.ShowAccessibility) == ConversionFlags.ShowAccessibility;
@ -197,7 +197,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -197,7 +197,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
astBuilder.ShowParameterNames = (ConversionFlags & ConversionFlags.ShowParameterNames) == ConversionFlags.ShowParameterNames;
return astBuilder;
}
void WriteTypeDeclarationName(ITypeDefinition typeDef, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
@ -297,7 +297,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -297,7 +297,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
}
}
void WriteQualifiedName(string name, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
var node = AstType.Create(name);
@ -305,25 +305,25 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -305,25 +305,25 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
node.AcceptVisitor(outputVisitor);
}
#endregion
public string ConvertVariable(IVariable v)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
AstNode astNode = astBuilder.ConvertVariable(v);
return astNode.ToString().TrimEnd(';', '\r', '\n', (char)8232);
}
public string ConvertType(IType type)
{
if (type == null)
throw new ArgumentNullException("type");
throw new ArgumentNullException(nameof(type));
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
astBuilder.AlwaysUseShortTypeNames = (ConversionFlags & ConversionFlags.UseFullyQualifiedEntityNames) != ConversionFlags.UseFullyQualifiedEntityNames;
AstType astType = astBuilder.ConvertType(type);
return astType.ToString();
}
public void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
@ -331,12 +331,12 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -331,12 +331,12 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
AstType astType = astBuilder.ConvertType(type);
astType.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
}
public string ConvertConstantValue(object constantValue)
{
return TextWriterTokenWriter.PrintPrimitiveValue(constantValue);
}
public string WrapComment(string comment)
{
return "// " + comment;

398
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

File diff suppressed because it is too large Load Diff

60
ICSharpCode.Decompiler/CSharp/OutputVisitor/ITokenWriter.cs

@ -26,48 +26,53 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -26,48 +26,53 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
public abstract void StartNode(AstNode node);
public abstract void EndNode(AstNode node);
/// <summary>
/// Writes an identifier.
/// </summary>
public abstract void WriteIdentifier(Identifier identifier);
/// <summary>
/// Writes a keyword to the output.
/// </summary>
public abstract void WriteKeyword(Role role, string keyword);
/// <summary>
/// Writes a token to the output.
/// </summary>
public abstract void WriteToken(Role role, string token);
/// <summary>
/// Writes a primitive/literal value
/// </summary>
public abstract void WritePrimitiveValue(object value, string literalValue = null);
public abstract void WritePrimitiveType(string type);
public abstract void Space();
public abstract void Indent();
public abstract void Unindent();
public abstract void NewLine();
public abstract void WriteComment(CommentType commentType, string content);
public abstract void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument);
public static TokenWriter Create(TextWriter writer, string indentation = "\t")
{
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new TextWriterTokenWriter(writer) { IndentationString = indentation }));
}
public static TokenWriter CreateWriterThatSetsLocationsInAST(TextWriter writer, string indentation = "\t")
{
var target = new TextWriterTokenWriter(writer) { IndentationString = indentation };
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new InsertMissingTokensDecorator(target, target)));
}
public static TokenWriter InsertRequiredSpaces(TokenWriter writer)
{
return new InsertRequiredSpacesDecorator(writer);
}
public static TokenWriter WrapInWriterThatSetsLocationsInAST(TokenWriter writer)
{
if (!(writer is ILocatable))
@ -75,83 +80,84 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -75,83 +80,84 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return new InsertMissingTokensDecorator(writer, (ILocatable)writer);
}
}
public interface ILocatable
{
TextLocation Location { get; }
int Length { get; }
}
public abstract class DecoratingTokenWriter : TokenWriter
{
TokenWriter decoratedWriter;
protected DecoratingTokenWriter(TokenWriter decoratedWriter)
{
if (decoratedWriter == null)
throw new ArgumentNullException("decoratedWriter");
throw new ArgumentNullException(nameof(decoratedWriter));
this.decoratedWriter = decoratedWriter;
}
public override void StartNode(AstNode node)
{
decoratedWriter.StartNode(node);
}
public override void EndNode(AstNode node)
{
decoratedWriter.EndNode(node);
}
public override void WriteIdentifier(Identifier identifier)
{
decoratedWriter.WriteIdentifier(identifier);
}
public override void WriteKeyword(Role role, string keyword)
{
decoratedWriter.WriteKeyword(role, keyword);
}
public override void WriteToken(Role role, string token)
{
decoratedWriter.WriteToken(role, token);
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
decoratedWriter.WritePrimitiveValue(value, literalValue);
}
public override void WritePrimitiveType(string type)
{
decoratedWriter.WritePrimitiveType(type);
}
public override void Space()
{
decoratedWriter.Space();
}
public override void Indent()
{
decoratedWriter.Indent();
}
public override void Unindent()
{
decoratedWriter.Unindent();
}
public override void NewLine()
{
decoratedWriter.NewLine();
}
public override void WriteComment(CommentType commentType, string content)
{
decoratedWriter.WriteComment(commentType, content);
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
decoratedWriter.WritePreProcessorDirective(type, argument);

135
ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs

@ -30,98 +30,103 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -30,98 +30,103 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public class TextWriterTokenWriter : TokenWriter, ILocatable
{
readonly TextWriter textWriter;
int indentation;
bool needsIndent = true;
bool isAtStartOfLine = true;
int line, column;
public int Indentation {
get { return this.indentation; }
set { this.indentation = value; }
}
public int Indentation { get; set; }
public TextLocation Location {
get { return new TextLocation(line, column + (needsIndent ? indentation * IndentationString.Length : 0)); }
get { return new TextLocation(line, column + (needsIndent ? Indentation * IndentationString.Length : 0)); }
}
public string IndentationString { get; set; }
public int Length { get; private set; }
public TextWriterTokenWriter(TextWriter textWriter)
{
if (textWriter == null)
throw new ArgumentNullException("textWriter");
throw new ArgumentNullException(nameof(textWriter));
this.textWriter = textWriter;
this.IndentationString = "\t";
this.line = 1;
this.column = 1;
}
public override void WriteIdentifier(Identifier identifier)
{
WriteIndentation();
if (identifier.IsVerbatim || CSharpOutputVisitor.IsKeyword(identifier.Name, identifier)) {
textWriter.Write('@');
column++;
Length++;
}
string name = EscapeIdentifier(identifier.Name);
textWriter.Write(name);
column += name.Length;
Length += name.Length;
isAtStartOfLine = false;
}
public override void WriteKeyword(Role role, string keyword)
{
WriteIndentation();
column += keyword.Length;
Length += keyword.Length;
textWriter.Write(keyword);
isAtStartOfLine = false;
}
public override void WriteToken(Role role, string token)
{
WriteIndentation();
column += token.Length;
Length += token.Length;
textWriter.Write(token);
isAtStartOfLine = false;
}
public override void Space()
{
WriteIndentation();
column++;
Length++;
textWriter.Write(' ');
}
protected void WriteIndentation()
{
if (needsIndent) {
needsIndent = false;
for (int i = 0; i < indentation; i++) {
for (int i = 0; i < Indentation; i++) {
textWriter.Write(this.IndentationString);
}
column += indentation * IndentationString.Length;
column += Indentation * IndentationString.Length;
Length += Indentation * IndentationString.Length;
}
}
public override void NewLine()
{
textWriter.WriteLine();
column = 1;
line++;
Length += textWriter.NewLine.Length;
needsIndent = true;
isAtStartOfLine = true;
}
public override void Indent()
{
indentation++;
Indentation++;
}
public override void Unindent()
{
indentation--;
Indentation--;
}
public override void WriteComment(CommentType commentType, string content)
{
WriteIndentation();
@ -129,6 +134,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -129,6 +134,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case CommentType.SingleLine:
textWriter.Write("//");
textWriter.WriteLine(content);
Length += 2 + content.Length + textWriter.NewLine.Length;
column = 1;
line++;
needsIndent = true;
@ -138,6 +144,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -138,6 +144,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
textWriter.Write("/*");
textWriter.Write(content);
textWriter.Write("*/");
Length += 4 + content.Length;
column += 2;
UpdateEndLocation(content, ref line, ref column);
column += 2;
@ -146,6 +153,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -146,6 +153,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case CommentType.Documentation:
textWriter.Write("///");
textWriter.WriteLine(content);
Length += 3 + content.Length + textWriter.NewLine.Length;
column = 1;
line++;
needsIndent = true;
@ -155,6 +163,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -155,6 +163,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
textWriter.Write("/**");
textWriter.Write(content);
textWriter.Write("*/");
Length += 5 + content.Length;
column += 3;
UpdateEndLocation(content, ref line, ref column);
column += 2;
@ -163,10 +172,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -163,10 +172,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
default:
textWriter.Write(content);
column += content.Length;
Length += content.Length;
break;
}
}
static void UpdateEndLocation(string content, ref int line, ref int column)
{
if (string.IsNullOrEmpty(content))
@ -186,7 +196,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -186,7 +196,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
column++;
}
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
// pre-processor directive must start on its own line
@ -197,14 +207,16 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -197,14 +207,16 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
string directive = type.ToString().ToLowerInvariant();
textWriter.Write(directive);
column += 1 + directive.Length;
Length += 1 + directive.Length;
if (!string.IsNullOrEmpty(argument)) {
textWriter.Write(' ');
textWriter.Write(argument);
column += 1 + argument.Length;
Length += 1 + argument.Length;
}
NewLine();
}
public static string PrintPrimitiveValue(object value)
{
TextWriter writer = new StringWriter();
@ -212,48 +224,55 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -212,48 +224,55 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
tokenWriter.WritePrimitiveValue(value);
return writer.ToString();
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
if (literalValue != null) {
textWriter.Write(literalValue);
column += literalValue.Length;
Length += literalValue.Length;
return;
}
if (value == null) {
// usually NullReferenceExpression should be used for this, but we'll handle it anyways
textWriter.Write("null");
column += 4;
Length += 4;
return;
}
if (value is bool) {
if ((bool)value) {
textWriter.Write("true");
column += 4;
Length += 4;
} else {
textWriter.Write("false");
column += 5;
Length += 5;
}
return;
}
if (value is string) {
string tmp = ConvertString(value.ToString());
column += tmp.Length + 2;
Length += tmp.Length + 2;
textWriter.Write('"');
textWriter.Write(tmp);
textWriter.Write('"');
} else if (value is char) {
string tmp = ConvertCharLiteral((char)value);
column += tmp.Length + 2;
Length += tmp.Length + 2;
textWriter.Write('\'');
textWriter.Write(tmp);
textWriter.Write('\'');
} else if (value is decimal) {
string str = ((decimal)value).ToString(NumberFormatInfo.InvariantInfo) + "m";
column += str.Length;
Length += str.Length;
textWriter.Write(str);
} else if (value is float) {
float f = (float)value;
@ -262,28 +281,32 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -262,28 +281,32 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
// but we still support writing these to make life easier for code generators.
textWriter.Write("float");
column += 5;
Length += 5;
WriteToken(Roles.Dot, ".");
if (float.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
Length += "PositiveInfinity".Length;
} else if (float.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
Length += "NegativeInfinity".Length;
} else {
textWriter.Write("NaN");
column += 3;
Length += 3;
}
return;
}
if (f == 0 && 1 / f == float.NegativeInfinity) {
var str = f.ToString("R", NumberFormatInfo.InvariantInfo) + "f";
if (f == 0 && 1 / f == float.NegativeInfinity && str[0] != '-') {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
textWriter.Write("-");
column++;
str = '-' + str;
}
var str = f.ToString("R", NumberFormatInfo.InvariantInfo) + "f";
column += str.Length;
Length += str.Length;
textWriter.Write(str);
} else if (value is double) {
double f = (double)value;
@ -292,38 +315,43 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -292,38 +315,43 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
// but we still support writing these to make life easier for code generators.
textWriter.Write("double");
column += 6;
Length += 6;
WriteToken(Roles.Dot, ".");
if (double.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
Length += "PositiveInfinity".Length;
} else if (double.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
Length += "NegativeInfinity".Length;
} else {
textWriter.Write("NaN");
column += 3;
Length += 3;
}
return;
}
if (f == 0 && 1 / f == double.NegativeInfinity) {
string number = f.ToString("R", NumberFormatInfo.InvariantInfo);
if (f == 0 && 1 / f == double.NegativeInfinity && number[0] != '-') {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
textWriter.Write("-");
number = '-' + number;
}
string number = f.ToString("R", NumberFormatInfo.InvariantInfo);
if (number.IndexOf('.') < 0 && number.IndexOf('E') < 0) {
number += ".0";
}
textWriter.Write(number);
Length += number.Length;
} else if (value is IFormattable) {
StringBuilder b = new StringBuilder ();
// if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) {
// b.Append("0x");
// b.Append(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo));
// } else {
b.Append(((IFormattable)value).ToString(null, NumberFormatInfo.InvariantInfo));
// }
StringBuilder b = new StringBuilder();
// if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) {
// b.Append("0x");
// b.Append(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo));
// } else {
b.Append(((IFormattable)value).ToString(null, NumberFormatInfo.InvariantInfo));
// }
if (value is uint || value is ulong) {
b.Append("u");
}
@ -332,12 +360,15 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -332,12 +360,15 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
textWriter.Write(b.ToString());
column += b.Length;
Length += b.Length;
} else {
textWriter.Write(value.ToString());
column += value.ToString().Length;
int length = value.ToString().Length;
column += length;
Length += length;
}
}
/// <summary>
/// Gets the escape sequence for the specified character within a char literal.
/// Does not include the single quotes surrounding the char literal.
@ -349,7 +380,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -349,7 +380,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
return ConvertChar(ch) ?? ch.ToString();
}
/// <summary>
/// Gets the escape sequence for the specified character.
/// </summary>
@ -412,7 +443,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -412,7 +443,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
/// </summary>
public static string ConvertString(string str)
{
StringBuilder sb = new StringBuilder ();
StringBuilder sb = new StringBuilder();
foreach (char ch in str) {
string s = ch == '"' ? "\\\"" : ConvertChar(ch);
if (s != null) sb.Append(s);
@ -477,17 +508,19 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -477,17 +508,19 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return true;
}
}
public override void WritePrimitiveType(string type)
{
textWriter.Write(type);
column += type.Length;
Length += type.Length;
if (type == "new") {
textWriter.Write("()");
column += 2;
Length += 2;
}
}
public override void StartNode(AstNode node)
{
// Write out the indentation, so that overrides of this method
@ -495,7 +528,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -495,7 +528,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
// in the output.
WriteIndentation();
}
public override void EndNode(AstNode node)
{
}

40
ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs

@ -55,10 +55,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -55,10 +55,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (entity == null || entity.MetadataToken.IsNil)
return;
if (mappingInfo == null)
mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken);
switch (entity) {
case ITypeDefinition td:
if (mappingInfo == null)
mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken);
namespaces.Add(td.Namespace);
HandleAttributes(td.GetAttributes());
HandleTypeParameters(td.TypeParameters);
@ -100,35 +100,31 @@ namespace ICSharpCode.Decompiler.CSharp @@ -100,35 +100,31 @@ namespace ICSharpCode.Decompiler.CSharp
CollectNamespacesForTypeReference(param.Type);
}
HandleTypeParameters(method.TypeParameters);
if (!method.MetadataToken.IsNil) {
if (mappingInfo == null)
mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken);
var reader = module.PEFile.Reader;
var parts = mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken).ToList();
foreach (var part in parts) {
HandleOverrides(part.GetMethodImplementations(module.metadata), module);
var methodDef = module.metadata.GetMethodDefinition(part);
if (method.HasBody) {
MethodBodyBlock body;
try {
body = reader.GetMethodBody(methodDef.RelativeVirtualAddress);
} catch (BadImageFormatException) {
continue;
}
CollectNamespacesFromMethodBody(body, module);
var reader = module.PEFile.Reader;
var parts = mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken).ToList();
foreach (var part in parts) {
HandleOverrides(part.GetMethodImplementations(module.metadata), module);
var methodDef = module.metadata.GetMethodDefinition(part);
if (method.HasBody) {
MethodBodyBlock body;
try {
body = reader.GetMethodBody(methodDef.RelativeVirtualAddress);
} catch (BadImageFormatException) {
continue;
}
CollectNamespacesFromMethodBody(body, module);
}
}
break;
case IProperty property:
HandleAttributes(property.GetAttributes());
CollectNamespaces(property.Getter, module);
CollectNamespaces(property.Setter, module);
CollectNamespaces(property.Getter, module, mappingInfo);
CollectNamespaces(property.Setter, module, mappingInfo);
break;
case IEvent @event:
HandleAttributes(@event.GetAttributes());
CollectNamespaces(@event.AddAccessor, module);
CollectNamespaces(@event.RemoveAccessor, module);
CollectNamespaces(@event.AddAccessor, module, mappingInfo);
CollectNamespaces(@event.RemoveAccessor, module, mappingInfo);
break;
}
}

11
ICSharpCode.Decompiler/CSharp/Resolver/AwaitResolveResult.cs

@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// This can also refer to an UnsafeOnCompleted method, if the awaiter type implements <c>System.Runtime.CompilerServices.ICriticalNotifyCompletion</c>.
/// </summary>
public readonly IMethod OnCompletedMethod;
/// <summary>
/// Method representing the GetResult method on the awaiter type. Can be null if the awaiter type or the method was not found, or when awaiting a dynamic expression.
/// </summary>
@ -58,21 +58,22 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -58,21 +58,22 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
: base(resultType)
{
if (awaiterType == null)
throw new ArgumentNullException("awaiterType");
throw new ArgumentNullException(nameof(awaiterType));
if (getAwaiterInvocation == null)
throw new ArgumentNullException("getAwaiterInvocation");
throw new ArgumentNullException(nameof(getAwaiterInvocation));
this.GetAwaiterInvocation = getAwaiterInvocation;
this.AwaiterType = awaiterType;
this.IsCompletedProperty = isCompletedProperty;
this.OnCompletedMethod = onCompletedMethod;
this.GetResultMethod = getResultMethod;
}
public override bool IsError {
get { return this.GetAwaiterInvocation.IsError || (AwaiterType.Kind != TypeKind.Dynamic && (this.IsCompletedProperty == null || this.OnCompletedMethod == null || this.GetResultMethod == null)); }
}
public override IEnumerable<ResolveResult> GetChildResults() {
public override IEnumerable<ResolveResult> GetChildResults()
{
return new[] { GetAwaiterInvocation };
}
}

190
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -38,14 +38,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -38,14 +38,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
readonly ConcurrentDictionary<TypePair, Conversion> implicitConversionCache = new ConcurrentDictionary<TypePair, Conversion>();
readonly ICompilation compilation;
public CSharpConversions(ICompilation compilation)
{
if (compilation == null)
throw new ArgumentNullException("compilation");
throw new ArgumentNullException(nameof(compilation));
this.compilation = compilation;
}
/// <summary>
/// Gets the Conversions instance for the specified <see cref="ICompilation"/>.
/// This will make use of the context's cache manager to reuse the Conversions instance.
@ -53,7 +53,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -53,7 +53,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public static CSharpConversions Get(ICompilation compilation)
{
if (compilation == null)
throw new ArgumentNullException("compilation");
throw new ArgumentNullException(nameof(compilation));
CacheManager cache = compilation.CacheManager;
CSharpConversions operators = (CSharpConversions)cache.GetShared(typeof(CSharpConversions));
if (operators == null) {
@ -61,30 +61,30 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -61,30 +61,30 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return operators;
}
#region TypePair (for caching)
struct TypePair : IEquatable<TypePair>
{
public readonly IType FromType;
public readonly IType ToType;
public TypePair(IType fromType, IType toType)
{
Debug.Assert(fromType != null && toType != null);
this.FromType = fromType;
this.ToType = toType;
}
public override bool Equals(object obj)
{
return (obj is TypePair) && Equals((TypePair)obj);
}
public bool Equals(TypePair other)
{
return object.Equals(this.FromType, other.FromType) && object.Equals(this.ToType, other.ToType);
}
public override int GetHashCode()
{
unchecked {
@ -93,7 +93,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -93,7 +93,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region ImplicitConversion
private Conversion ImplicitConversion(ResolveResult resolveResult, IType toType, bool allowUserDefined, bool allowTuple)
{
@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
c = MethodGroupConversion(resolveResult, toType);
return c;
}
private Conversion ImplicitConversion(IType fromType, IType toType, bool allowUserDefined, bool allowTuple)
{
// C# 4.0 spec: §6.1
@ -151,17 +151,17 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -151,17 +151,17 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public Conversion ImplicitConversion(ResolveResult resolveResult, IType toType)
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
throw new ArgumentNullException(nameof(resolveResult));
return ImplicitConversion(resolveResult, toType, allowUserDefined: true, allowTuple: true);
}
public Conversion ImplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
throw new ArgumentNullException(nameof(fromType));
if (toType == null)
throw new ArgumentNullException("toType");
throw new ArgumentNullException(nameof(toType));
TypePair pair = new TypePair(fromType, toType);
Conversion c;
if (implicitConversionCache.TryGetValue(pair, out c))
@ -176,9 +176,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -176,9 +176,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public Conversion StandardImplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
throw new ArgumentNullException(nameof(fromType));
if (toType == null)
throw new ArgumentNullException("toType");
throw new ArgumentNullException(nameof(toType));
return StandardImplicitConversion(fromType, toType, allowTupleConversion: true);
}
@ -220,10 +220,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -220,10 +220,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public bool IsConstraintConvertible(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
throw new ArgumentNullException(nameof(fromType));
if (toType == null)
throw new ArgumentNullException("toType");
throw new ArgumentNullException(nameof(toType));
if (IdentityConversion(fromType, toType))
return true;
if (ImplicitReferenceConversion(fromType, toType, 0))
@ -242,15 +242,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -242,15 +242,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return false;
}
#endregion
#region ExplicitConversion
public Conversion ExplicitConversion(ResolveResult resolveResult, IType toType)
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
throw new ArgumentNullException(nameof(resolveResult));
if (toType == null)
throw new ArgumentNullException("toType");
throw new ArgumentNullException(nameof(toType));
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ExplicitDynamicConversion;
Conversion c = ImplicitConversion(resolveResult, toType, allowUserDefined: false, allowTuple: false);
@ -266,14 +266,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -266,14 +266,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return c;
return UserDefinedExplicitConversion(resolveResult, resolveResult.Type, toType);
}
public Conversion ExplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
throw new ArgumentNullException(nameof(fromType));
if (toType == null)
throw new ArgumentNullException("toType");
throw new ArgumentNullException(nameof(toType));
Conversion c = ImplicitConversion(fromType, toType, allowUserDefined: false, allowTuple: false);
if (c != Conversion.None)
return c;
@ -282,7 +282,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -282,7 +282,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return c;
return UserDefinedExplicitConversion(null, fromType, toType);
}
Conversion ExplicitConversionImpl(IType fromType, IType toType)
{
// This method is called after we already checked for implicit conversions,
@ -319,7 +319,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -319,7 +319,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return fromType.Equals(toType);
}
#endregion
#region Numeric Conversions
static readonly bool[,] implicitNumericConversionLookup = {
// to: short ushort int uint long ulong
@ -332,11 +332,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -332,11 +332,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/* int */ { false, false, false, false, true , false },
/* uint */ { false, false, false, false, true , true },
};
bool ImplicitNumericConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.2
TypeCode from = ReflectionHelper.GetTypeCode(fromType);
TypeCode to = ReflectionHelper.GetTypeCode(toType);
if (to >= TypeCode.Single && to <= TypeCode.Decimal) {
@ -351,20 +351,20 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -351,20 +351,20 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
&& implicitNumericConversionLookup[from - TypeCode.Char, to - TypeCode.Int16];
}
}
bool IsNumericType(IType type)
{
TypeCode c = ReflectionHelper.GetTypeCode(type);
return c >= TypeCode.Char && c <= TypeCode.Decimal;
}
bool AnyNumericConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.2 + §6.2.1
return IsNumericType(fromType) && IsNumericType(toType);
}
#endregion
#region Enumeration Conversions
Conversion ImplicitEnumerationConversion(ResolveResult rr, IType toType)
{
@ -378,7 +378,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -378,7 +378,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return Conversion.None;
}
bool ExplicitEnumerationConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.2.2
@ -390,7 +390,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -390,7 +390,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return false;
}
#endregion
#region Nullable Conversions
Conversion ImplicitNullableConversion(IType fromType, IType toType)
{
@ -405,7 +405,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -405,7 +405,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return Conversion.None;
}
Conversion ExplicitNullableConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.4
@ -422,7 +422,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -422,7 +422,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return Conversion.None;
}
#endregion
#region Null Literal Conversion
bool NullLiteralConversion(IType fromType, IType toType)
{
@ -434,24 +434,24 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -434,24 +434,24 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region Implicit Reference Conversion
public bool IsImplicitReferenceConversion(IType fromType, IType toType)
{
return ImplicitReferenceConversion(fromType, toType, 0);
}
bool ImplicitReferenceConversion(IType fromType, IType toType, int subtypeCheckNestingDepth)
{
// C# 4.0 spec: §6.1.6
// reference conversions are possible:
// - if both types are known to be reference types
// - if both types are type parameters and fromType has a class constraint
// (ImplicitTypeParameterConversionWithClassConstraintOnlyOnT)
if (!(fromType.IsReferenceType == true && toType.IsReferenceType != false))
return false;
ArrayType fromArray = fromType as ArrayType;
if (fromArray != null) {
ArrayType toArray = toType as ArrayType;
@ -471,11 +471,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -471,11 +471,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
IType systemArray = compilation.FindType(KnownTypeCode.Array);
return ImplicitReferenceConversion(systemArray, toType, subtypeCheckNestingDepth);
}
// now comes the hard part: traverse the inheritance chain and figure out generics+variance
return IsSubtypeOf(fromType, toType, subtypeCheckNestingDepth);
}
/// <summary>
/// For IList{T}, ICollection{T}, IEnumerable{T} and IReadOnlyList{T}, returns T.
/// Otherwise, returns null.
@ -494,10 +494,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -494,10 +494,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return null;
}
// Determines whether s is a subtype of t.
// Helper method used for ImplicitReferenceConversion, BoxingConversion and ImplicitTypeParameterConversion
bool IsSubtypeOf(IType s, IType t, int subtypeCheckNestingDepth)
{
// conversion to dynamic + object are always possible
@ -507,7 +507,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -507,7 +507,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// Subtyping in C# is undecidable
// (see "On Decidability of Nominal Subtyping with Variance" by Andrew J. Kennedy and Benjamin C. Pierce),
// so we'll prevent infinite recursions by putting a limit on the nesting depth of variance conversions.
// No real C# code should use generics nested more than 10 levels deep, and even if they do, most of
// those nestings should not involve variance.
return false;
@ -519,7 +519,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -519,7 +519,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return false;
}
bool IdentityOrVarianceConversion(IType s, IType t, int subtypeCheckNestingDepth)
{
ITypeDefinition def = s.GetDefinition();
@ -559,12 +559,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -559,12 +559,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region Explicit Reference Conversion
bool ExplicitReferenceConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.2.4
// test that the types are reference types:
if (toType.IsReferenceType != true)
return false;
@ -576,7 +576,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -576,7 +576,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return IsSubtypeOf(toType, fromType, 0);
return false;
}
if (toType.Kind == TypeKind.Array) {
ArrayType toArray = (ArrayType)toType;
if (fromType.Kind == TypeKind.Array) {
@ -645,7 +645,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -645,7 +645,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
|| IsImplicitReferenceConversion(fromType, toType);
}
}
bool IsSealedReferenceType(IType type)
{
TypeKind kind = type.Kind;
@ -686,7 +686,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -686,7 +686,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return false;
}
#endregion
#region Implicit Constant-Expression Conversion
bool ImplicitConstantExpressionConversion(ResolveResult rr, IType toType)
{
@ -721,7 +721,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -721,7 +721,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return false;
}
#endregion
#region Conversions involving type parameters
/// <summary>
/// Implicit conversions involving type parameters.
@ -734,7 +734,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -734,7 +734,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return false; // already handled by ImplicitReferenceConversion
return IsSubtypeOf(fromType, toType, 0);
}
Conversion ExplicitTypeParameterConversion(IType fromType, IType toType)
{
if (toType.Kind == TypeKind.TypeParameter) {
@ -749,7 +749,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -749,7 +749,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return Conversion.None;
}
#endregion
#region Pointer Conversions
bool ImplicitPointerConversion(IType fromType, IType toType)
{
@ -760,7 +760,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -760,7 +760,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return true;
return false;
}
bool ExplicitPointerConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §18.4 Pointer conversions
@ -770,14 +770,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -770,14 +770,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return toType.Kind == TypeKind.Pointer && IsIntegerType(fromType);
}
}
bool IsIntegerType(IType type)
{
TypeCode c = ReflectionHelper.GetTypeCode(type);
return c >= TypeCode.SByte && c <= TypeCode.UInt64;
}
#endregion
#region User-Defined Conversions
/// <summary>
/// Gets whether type A is encompassed by type B.
@ -786,7 +786,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -786,7 +786,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface && StandardImplicitConversion(a, b).IsValid;
}
bool IsEncompassingOrEncompassedBy(IType a, IType b)
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface
@ -800,7 +800,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -800,7 +800,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (best == null || IsEncompassedBy(current, best))
best = current;
else if (!IsEncompassedBy(best, current))
return null; // Ambiguous
return null; // Ambiguous
}
return best;
}
@ -812,7 +812,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -812,7 +812,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (best == null || IsEncompassedBy(best, current))
best = current;
else if (!IsEncompassedBy(current, best))
return null; // Ambiguous
return null; // Ambiguous
}
return best;
}
@ -831,7 +831,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -831,7 +831,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
var op = selected.First(s => !s.IsLifted);
return Conversion.UserDefinedConversion(op.Method, isLifted: op.IsLifted, isImplicit: isImplicit, conversionBeforeUserDefinedOperator: ExplicitConversion(source, mostSpecificSource), conversionAfterUserDefinedOperator: ExplicitConversion(mostSpecificTarget, target));
}
return Conversion.UserDefinedConversion(selected[0].Method, isLifted: selected[0].IsLifted, isImplicit: isImplicit, isAmbiguous: true, conversionBeforeUserDefinedOperator: ExplicitConversion(source, mostSpecificSource), conversionAfterUserDefinedOperator: ExplicitConversion(mostSpecificTarget, target));
}
@ -861,17 +861,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -861,17 +861,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return other;
}
return selected;
}
else if (NullableType.IsNullable(toType))
} else if (NullableType.IsNullable(toType))
return UserDefinedImplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
else
return Conversion.None;
}
else {
} else {
return Conversion.None;
}
}
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.5 User-defined explicit conversions
@ -913,26 +911,24 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -913,26 +911,24 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return other;
}
return selected;
}
else if (NullableType.IsNullable(toType))
} else if (NullableType.IsNullable(toType))
return UserDefinedExplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
else if (NullableType.IsNullable(fromType))
return UserDefinedExplicitConversion(null, NullableType.GetUnderlyingType(fromType), toType); // A? -> A -> B
return UserDefinedExplicitConversion(null, NullableType.GetUnderlyingType(fromType), toType); // A? -> A -> B
else
return Conversion.None;
}
else {
} else {
return Conversion.None;
}
}
class OperatorInfo
{
public readonly IMethod Method;
public readonly IType SourceType;
public readonly IType TargetType;
public readonly bool IsLifted;
public OperatorInfo(IMethod method, IType sourceType, IType targetType, bool isLifted)
{
this.Method = method;
@ -941,7 +937,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -941,7 +937,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
this.IsLifted = isLifted;
}
}
List<OperatorInfo> GetApplicableConversionOperators(ResolveResult fromResult, IType fromType, IType toType, bool isExplicit)
{
// Find the candidate operators:
@ -950,7 +946,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -950,7 +946,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
opFilter = m => m.IsStatic && m.IsOperator && (m.Name == "op_Explicit" || m.Name == "op_Implicit") && m.Parameters.Count == 1;
else
opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1;
var operators = NullableType.GetUnderlyingType(fromType).GetMethods(opFilter)
.Concat(NullableType.GetUnderlyingType(toType).GetMethods(opFilter)).Distinct();
// Determine whether one of them is applicable:
@ -990,7 +986,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -990,7 +986,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return result;
}
#endregion
#region AnonymousFunctionConversion
Conversion AnonymousFunctionConversion(ResolveResult resolveResult, IType toType)
{
@ -1006,18 +1002,18 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1006,18 +1002,18 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
IMethod d = toType.GetDelegateInvokeMethod();
if (d == null)
return Conversion.None;
IType[] dParamTypes = new IType[d.Parameters.Count];
for (int i = 0; i < dParamTypes.Length; i++) {
dParamTypes[i] = d.Parameters[i].Type;
}
IType dReturnType = d.ReturnType;
if (f.HasParameterList) {
// If F contains an anonymous-function-signature, then D and F have the same number of parameters.
if (d.Parameters.Count != f.Parameters.Count)
return Conversion.None;
if (f.IsImplicitlyTyped) {
// If F has an implicitly typed parameter list, D has no ref or out parameters.
foreach (IParameter p in d.Parameters) {
@ -1044,7 +1040,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1044,7 +1040,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return Conversion.None;
}
}
return f.IsValid(dParamTypes, dReturnType, this);
}
@ -1058,7 +1054,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1058,7 +1054,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region MethodGroupConversion
Conversion MethodGroupConversion(ResolveResult resolveResult, IType toType)
{
@ -1069,7 +1065,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1069,7 +1065,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
IMethod invoke = toType.GetDelegateInvokeMethod();
if (invoke == null)
return Conversion.None;
ResolveResult[] args = new ResolveResult[invoke.Parameters.Count];
for (int i = 0; i < args.Length; i++) {
IParameter param = invoke.Parameters[i];
@ -1096,7 +1092,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1096,7 +1092,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return Conversion.None;
}
}
/// <summary>
/// Gets whether a <paramref name="method"/> is compatible with a delegate type.
/// §15.2 Delegate compatibility
@ -1106,15 +1102,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1106,15 +1102,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public bool IsDelegateCompatible(IMethod method, IType delegateType)
{
if (method == null)
throw new ArgumentNullException("method");
throw new ArgumentNullException(nameof(method));
if (delegateType == null)
throw new ArgumentNullException("delegateType");
throw new ArgumentNullException(nameof(delegateType));
IMethod invoke = delegateType.GetDelegateInvokeMethod();
if (invoke == null)
return false;
return IsDelegateCompatible(method, invoke, false);
}
/// <summary>
/// Gets whether a method <paramref name="m"/> is compatible with a delegate type.
/// §15.2 Delegate compatibility
@ -1126,9 +1122,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1126,9 +1122,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool IsDelegateCompatible(IMethod m, IMethod invoke, bool isExtensionMethodInvocation)
{
if (m == null)
throw new ArgumentNullException("m");
throw new ArgumentNullException(nameof(m));
if (invoke == null)
throw new ArgumentNullException("invoke");
throw new ArgumentNullException(nameof(invoke));
int firstParameterInM = isExtensionMethodInvocation ? 1 : 0;
if (m.Parameters.Count - firstParameterInM != invoke.Parameters.Count)
return false;
@ -1227,14 +1223,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1227,14 +1223,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
if (lambda.HasParameterList && parameterTypes.Length != lambda.Parameters.Count)
return 0;
IType ret1 = m1.ReturnType;
IType ret2 = m2.ReturnType;
if (ret1.Kind == TypeKind.Void && ret2.Kind != TypeKind.Void)
return 2;
if (ret1.Kind != TypeKind.Void && ret2.Kind == TypeKind.Void)
return 1;
IType inferredRet = lambda.GetInferredReturnType(parameterTypes);
int r = BetterConversion(inferredRet, ret1, ret2);
if (r == 0 && lambda.IsAsync) {
@ -1249,7 +1245,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1249,7 +1245,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return BetterConversion(resolveResult.Type, t1, t2);
}
}
/// <summary>
/// Unpacks the generic Task[T]. Returns null if the input is not Task[T].
/// </summary>
@ -1261,7 +1257,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1261,7 +1257,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return null;
}
/// <summary>
/// Gets the better conversion (C# 4.0 spec, §7.5.3.4)
/// </summary>
@ -1276,7 +1272,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1276,7 +1272,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return 2;
return BetterConversionTarget(t1, t2);
}
/// <summary>
/// Gets the better conversion target (C# 4.0 spec, §7.5.3.5)
/// </summary>
@ -1297,7 +1293,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1297,7 +1293,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return 2;
return 0;
}
bool IsBetterIntegralType(TypeCode t1, TypeCode t2)
{
// signed types are better than unsigned types

2
ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs

@ -238,7 +238,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -238,7 +238,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
throw new NotSupportedException();
}
public UnaryOperatorMethod(ICompilation compilaton) : base(compilaton)
public UnaryOperatorMethod(ICompilation compilation) : base(compilation)
{
}
}

32
ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public CSharpResolver(ICompilation compilation)
{
if (compilation == null)
throw new ArgumentNullException("compilation");
throw new ArgumentNullException(nameof(compilation));
this.compilation = compilation;
this.conversions = CSharpConversions.Get(compilation);
this.context = new CSharpTypeResolveContext(compilation.MainModule);
@ -58,7 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -58,7 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public CSharpResolver(CSharpTypeResolveContext context)
{
if (context == null)
throw new ArgumentNullException("context");
throw new ArgumentNullException(nameof(context));
this.compilation = context.Compilation;
this.conversions = CSharpConversions.Get(compilation);
this.context = context;
@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public CSharpResolver AddVariable(IVariable variable)
{
if (variable == null)
throw new ArgumentNullException("variable");
throw new ArgumentNullException(nameof(variable));
return WithLocalVariableStack(localVariableStack.Push(variable));
}
@ -313,7 +313,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -313,7 +313,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public CSharpResolver PushObjectInitializer(ResolveResult initializedObject)
{
if (initializedObject == null)
throw new ArgumentNullException("initializedObject");
throw new ArgumentNullException(nameof(initializedObject));
return WithObjectInitializerStack(new ObjectInitializerContext(initializedObject, objectInitializerStack));
}
@ -379,14 +379,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -379,14 +379,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
case UnaryOperatorType.Await: {
ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0], argumentNames: null, allowOptionalParameters: false);
ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, Empty<ResolveResult>.Array, argumentNames: null, allowOptionalParameters: false);
var lookup = CreateMemberLookup();
IMethod getResultMethod;
IType awaitResultType;
var getResultMethodGroup = lookup.Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
if (getResultMethodGroup != null) {
var getResultOR = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions);
var getResultOR = getResultMethodGroup.PerformOverloadResolution(compilation, Empty<ResolveResult>.Array, allowExtensionMethods: false, conversions: conversions);
getResultMethod = getResultOR.FoundApplicableCandidate ? getResultOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null;
awaitResultType = getResultMethod != null ? getResultMethod.ReturnType : SpecialType.UnknownType;
}
@ -1313,9 +1313,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1313,9 +1313,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// C# 4.0 spec: §3.8 Namespace and type names; §7.6.2 Simple Names
if (identifier == null)
throw new ArgumentNullException("identifier");
throw new ArgumentNullException(nameof(identifier));
if (typeArguments == null)
throw new ArgumentNullException("typeArguments");
throw new ArgumentNullException(nameof(typeArguments));
int k = typeArguments.Count;
@ -1698,12 +1698,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1698,12 +1698,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
getEnumeratorInvocation = ResolveCast(collectionType, expression);
getEnumeratorInvocation = ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
getEnumeratorInvocation = ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]);
getEnumeratorInvocation = ResolveInvocation(getEnumeratorInvocation, Empty<ResolveResult>.Array);
} else {
var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
if (getEnumeratorMethodGroup != null) {
var or = getEnumeratorMethodGroup.PerformOverloadResolution(
compilation, new ResolveResult[0],
compilation, Empty<ResolveResult>.Array,
allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false);
if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.Accessibility == Accessibility.Public) {
collectionType = expression.Type;
@ -1722,7 +1722,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1722,7 +1722,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList<IType>.Instance, false) as MethodGroupResolveResult;
if (moveNextMethodGroup != null) {
var or = moveNextMethodGroup.PerformOverloadResolution(
compilation, new ResolveResult[0],
compilation, Empty<ResolveResult>.Array,
allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false);
moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod;
}
@ -1763,7 +1763,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1763,7 +1763,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
getEnumeratorInvocation = ResolveCast(collectionType, expression);
getEnumeratorInvocation = ResolveMemberAccess(getEnumeratorInvocation, "GetEnumerator", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
getEnumeratorInvocation = ResolveInvocation(getEnumeratorInvocation, new ResolveResult[0]);
getEnumeratorInvocation = ResolveInvocation(getEnumeratorInvocation, Empty<ResolveResult>.Array);
}
#endregion
@ -1866,9 +1866,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1866,9 +1866,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public static bool IsEligibleExtensionMethod(IType targetType, IMethod method, bool useTypeInference, out IType[] outInferredTypes)
{
if (targetType == null)
throw new ArgumentNullException("targetType");
throw new ArgumentNullException(nameof(targetType));
if (method == null)
throw new ArgumentNullException("method");
throw new ArgumentNullException(nameof(method));
var compilation = method.Compilation;
return IsEligibleExtensionMethod(compilation, CSharpConversions.Get(compilation), targetType, method, useTypeInference, out outInferredTypes);
}
@ -2348,7 +2348,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -2348,7 +2348,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public ResolveResult ResolveCondition(ResolveResult input)
{
if (input == null)
throw new ArgumentNullException("input");
throw new ArgumentNullException(nameof(input));
IType boolean = compilation.FindType(KnownTypeCode.Boolean);
Conversion c = conversions.ImplicitConversion(input, boolean);
if (!c.IsValid) {
@ -2368,7 +2368,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -2368,7 +2368,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public ResolveResult ResolveConditionFalse(ResolveResult input)
{
if (input == null)
throw new ArgumentNullException("input");
throw new ArgumentNullException(nameof(input));
IType boolean = compilation.FindType(KnownTypeCode.Boolean);
Conversion c = conversions.ImplicitConversion(input, boolean);
if (!c.IsValid) {

5
ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs

@ -152,7 +152,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -152,7 +152,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (this.Parameters.Count != parameterTypes.Length)
return Conversion.None;
for (int i = 0; i < parameterTypes.Length; ++i) {
if (!parameterTypes[i].Equals(this.Parameters[i].Type)) {
if (!conversions.IdentityConversion(parameterTypes[i], this.Parameters[i].Type)) {
if (IsImplicitlyTyped) {
// it's possible that different parameter types also lead to a valid conversion
return LambdaConversion.Instance;
@ -162,7 +162,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -162,7 +162,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
}
if (returnType.Equals(this.ReturnType)) {
if (conversions.IdentityConversion(this.ReturnType, returnType)
|| conversions.ImplicitConversion(this.InferredReturnType, returnType).IsValid) {
return LambdaConversion.Instance;
} else {
return Conversion.None;

20
ICSharpCode.Decompiler/CSharp/Resolver/MemberLookup.cs

@ -37,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -37,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public static bool IsInvocable(IMember member)
{
if (member == null)
throw new ArgumentNullException("member");
throw new ArgumentNullException(nameof(member));
// C# 4.0 spec, §7.4 member lookup
if (member is IEvent || member is IMethod)
return true;
@ -99,7 +99,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -99,7 +99,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public bool IsAccessible(IEntity entity, bool allowProtectedAccess)
{
if (entity == null)
throw new ArgumentNullException("entity");
throw new ArgumentNullException(nameof(entity));
// C# 4.0 spec, §3.5.2 Accessiblity domains
switch (entity.Accessibility) {
case Accessibility.None:
@ -159,7 +159,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -159,7 +159,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public IEnumerable<IEntity> GetAccessibleMembers(ResolveResult targetResolveResult)
{
if (targetResolveResult == null)
throw new ArgumentNullException("targetResolveResult");
throw new ArgumentNullException(nameof(targetResolveResult));
bool targetIsTypeParameter = targetResolveResult.Type.Kind == TypeKind.TypeParameter;
bool allowProtectedAccess = IsProtectedAccessAllowed(targetResolveResult);
@ -276,11 +276,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -276,11 +276,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public ResolveResult LookupType(IType declaringType, string name, IReadOnlyList<IType> typeArguments, bool parameterizeResultType = true)
{
if (declaringType == null)
throw new ArgumentNullException("declaringType");
throw new ArgumentNullException(nameof(declaringType));
if (name == null)
throw new ArgumentNullException("name");
throw new ArgumentNullException(nameof(name));
if (typeArguments == null)
throw new ArgumentNullException("typeArguments");
throw new ArgumentNullException(nameof(typeArguments));
int typeArgumentCount = typeArguments.Count;
Predicate<ITypeDefinition> filter = delegate (ITypeDefinition d) {
@ -335,11 +335,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -335,11 +335,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public ResolveResult Lookup(ResolveResult targetResolveResult, string name, IReadOnlyList<IType> typeArguments, bool isInvocation)
{
if (targetResolveResult == null)
throw new ArgumentNullException("targetResolveResult");
throw new ArgumentNullException(nameof(targetResolveResult));
if (name == null)
throw new ArgumentNullException("name");
throw new ArgumentNullException(nameof(name));
if (typeArguments == null)
throw new ArgumentNullException("typeArguments");
throw new ArgumentNullException(nameof(typeArguments));
bool targetIsTypeParameter = targetResolveResult.Type.Kind == TypeKind.TypeParameter;
@ -413,7 +413,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -413,7 +413,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public IReadOnlyList<MethodListWithDeclaringType> LookupIndexers(ResolveResult targetResolveResult)
{
if (targetResolveResult == null)
throw new ArgumentNullException("targetResolveResult");
throw new ArgumentNullException(nameof(targetResolveResult));
IType targetType = targetResolveResult.Type;
bool allowProtectedAccess = IsProtectedAccessAllowed(targetResolveResult);

2
ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs

@ -86,7 +86,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -86,7 +86,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
: base(SpecialType.NoType)
{
if (methods == null)
throw new ArgumentNullException("methods");
throw new ArgumentNullException(nameof(methods));
this.targetResult = targetResult;
this.methodName = methodName;
this.methodLists = methods;

186
ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs

@ -35,53 +35,53 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -35,53 +35,53 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
sealed class Candidate
{
public readonly IParameterizedMember Member;
/// <summary>
/// Returns the normal form candidate, if this is an expanded candidate.
/// </summary>
public readonly bool IsExpandedForm;
/// <summary>
/// Gets the parameter types. In the first step, these are the types without any substition.
/// After type inference, substitutions will be performed.
/// </summary>
public readonly IType[] ParameterTypes;
/// <summary>
/// argument index -> parameter index; -1 for arguments that could not be mapped
/// </summary>
public int[] ArgumentToParameterMap;
public OverloadResolutionErrors Errors;
public int ErrorCount;
public bool HasUnmappedOptionalParameters;
public IType[] InferredTypes;
/// <summary>
/// Gets the original member parameters (before any substitution!)
/// </summary>
public readonly IReadOnlyList<IParameter> Parameters;
/// <summary>
/// Gets the original method type parameters (before any substitution!)
/// </summary>
public readonly IReadOnlyList<ITypeParameter> TypeParameters;
/// <summary>
/// Conversions applied to the arguments.
/// This field is set by the CheckApplicability step.
/// </summary>
public Conversion[] ArgumentConversions;
public bool IsGenericMethod {
get {
IMethod method = Member as IMethod;
return method != null && method.TypeParameters.Count > 0;
}
}
public int ArgumentsPassedToParamsArray {
get {
int count = 0;
@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return count;
}
}
public Candidate(IParameterizedMember member, bool isExpanded)
{
this.Member = member;
@ -111,7 +111,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -111,7 +111,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
this.ParameterTypes = new IType[this.Parameters.Count];
}
public void AddError(OverloadResolutionErrors newError)
{
this.Errors |= newError;
@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
this.ErrorCount++;
}
}
readonly ICompilation compilation;
readonly ResolveResult[] arguments;
readonly string[] argumentNames;
@ -130,14 +130,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -130,14 +130,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
IType[] explicitlyGivenTypeArguments;
bool bestCandidateWasValidated;
OverloadResolutionErrors bestCandidateValidationResult;
#region Constructor
public OverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null, CSharpConversions conversions = null)
{
if (compilation == null)
throw new ArgumentNullException("compilation");
throw new ArgumentNullException(nameof(compilation));
if (arguments == null)
throw new ArgumentNullException("arguments");
throw new ArgumentNullException(nameof(arguments));
if (argumentNames == null)
argumentNames = new string[arguments.Length];
else if (argumentNames.Length != arguments.Length)
@ -145,17 +145,17 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -145,17 +145,17 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
this.compilation = compilation;
this.arguments = arguments;
this.argumentNames = argumentNames;
// keep explicitlyGivenTypeArguments==null when no type arguments were specified
if (typeArguments != null && typeArguments.Length > 0)
this.explicitlyGivenTypeArguments = typeArguments;
this.conversions = conversions ?? CSharpConversions.Get(compilation);
this.AllowExpandingParams = true;
this.AllowOptionalParameters = true;
}
#endregion
#region Input Properties
/// <summary>
/// Gets/Sets whether the methods are extension methods that are being called using extension method syntax.
@ -165,27 +165,27 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -165,27 +165,27 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// implicit identity, reference, or boxing conversions.
/// </remarks>
public bool IsExtensionMethodInvocation { get; set; }
/// <summary>
/// Gets/Sets whether expanding 'params' into individual elements is allowed.
/// The default value is true.
/// </summary>
public bool AllowExpandingParams { get; set; }
/// <summary>
/// Gets/Sets whether optional parameters may be left at their default value.
/// The default value is true.
/// If this property is set to false, optional parameters will be treated like regular parameters.
/// </summary>
public bool AllowOptionalParameters { get; set; }
/// <summary>
/// Gets/Sets whether ConversionResolveResults created by this OverloadResolution
/// instance apply overflow checking.
/// The default value is false.
/// </summary>
public bool CheckForOverflow { get; set; }
/// <summary>
/// Gets the arguments for which this OverloadResolution instance was created.
/// </summary>
@ -193,7 +193,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -193,7 +193,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
get { return arguments; }
}
#endregion
#region AddCandidate
/// <summary>
/// Adds a candidate to overload resolution.
@ -205,7 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -205,7 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
return AddCandidate(member, OverloadResolutionErrors.None);
}
/// <summary>
/// Adds a candidate to overload resolution.
/// </summary>
@ -218,30 +218,30 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -218,30 +218,30 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public OverloadResolutionErrors AddCandidate(IParameterizedMember member, OverloadResolutionErrors additionalErrors)
{
if (member == null)
throw new ArgumentNullException("member");
throw new ArgumentNullException(nameof(member));
Candidate c = new Candidate(member, false);
c.AddError(additionalErrors);
if (CalculateCandidate(c)) {
//candidates.Add(c);
}
if (this.AllowExpandingParams && member.Parameters.Count > 0
&& member.Parameters[member.Parameters.Count - 1].IsParams)
&& member.Parameters[member.Parameters.Count - 1].IsParams)
{
Candidate expandedCandidate = new Candidate(member, true);
expandedCandidate.AddError(additionalErrors);
// consider expanded form only if it isn't obviously wrong
if (CalculateCandidate(expandedCandidate)) {
//candidates.Add(expandedCandidate);
if (expandedCandidate.ErrorCount < c.ErrorCount)
return expandedCandidate.Errors;
}
}
return c.Errors;
}
/// <summary>
/// Calculates applicability etc. for the candidate.
/// </summary>
@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
ConsiderIfNewCandidateIsBest(candidate);
return true;
}
bool ResolveParameterTypes(Candidate candidate, bool useSpecializedParameters)
{
for (int i = 0; i < candidate.Parameters.Count; i++) {
@ -281,7 +281,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -281,7 +281,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return true;
}
#endregion
#region AddMethodLists
/// <summary>
/// Adds all candidates from the method lists.
@ -293,7 +293,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -293,7 +293,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public void AddMethodLists(IReadOnlyList<MethodListWithDeclaringType> methodLists)
{
if (methodLists == null)
throw new ArgumentNullException("methodLists");
throw new ArgumentNullException(nameof(methodLists));
// Base types come first, so go through the list backwards (derived types first)
bool[] isHiddenByDerivedType;
if (methodLists.Count > 1)
@ -305,20 +305,20 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -305,20 +305,20 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Log.WriteLine(" Skipping methods in {0} because they are hidden by an applicable method in a derived type", methodLists[i].DeclaringType);
continue;
}
MethodListWithDeclaringType methodList = methodLists[i];
bool foundApplicableCandidateInCurrentList = false;
for (int j = 0; j < methodList.Count; j++) {
IParameterizedMember method = methodList[j];
Log.Indent();
OverloadResolutionErrors errors = AddCandidate(method);
Log.Unindent();
LogCandidateAddingResult(" Candidate", method, errors);
foundApplicableCandidateInCurrentList |= IsApplicable(errors);
}
if (foundApplicableCandidateInCurrentList && i > 0) {
foreach (IType baseType in methodList.DeclaringType.GetAllBaseTypes()) {
for (int j = 0; j < i; j++) {
@ -329,21 +329,21 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -329,21 +329,21 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
}
[Conditional("DEBUG")]
internal void LogCandidateAddingResult(string text, IParameterizedMember method, OverloadResolutionErrors errors)
{
#if DEBUG
Log.WriteLine(string.Format("{0} {1} = {2}{3}",
text, method,
errors == OverloadResolutionErrors.None ? "Success" : errors.ToString(),
this.BestCandidate == method ? " (best candidate so far)" :
this.BestCandidateAmbiguousWith == method ? " (ambiguous)" : ""
));
text, method,
errors == OverloadResolutionErrors.None ? "Success" : errors.ToString(),
this.BestCandidate == method ? " (best candidate so far)" :
this.BestCandidateAmbiguousWith == method ? " (ambiguous)" : ""
));
#endif
}
#endregion
#region MapCorrespondingParameters
void MapCorrespondingParameters(Candidate candidate)
{
@ -386,7 +386,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -386,7 +386,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region RunTypeInference
void RunTypeInference(Candidate candidate)
{
@ -436,18 +436,18 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -436,18 +436,18 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (!substitution.ConstraintsValid)
candidate.AddError(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint);
}
sealed class ConstraintValidatingSubstitution : TypeParameterSubstitution
{
readonly CSharpConversions conversions;
public bool ConstraintsValid = true;
public ConstraintValidatingSubstitution(IReadOnlyList<IType> classTypeArguments, IReadOnlyList<IType> methodTypeArguments, OverloadResolution overloadResolution)
: base(classTypeArguments, methodTypeArguments)
{
this.conversions = overloadResolution.conversions;
}
public override IType VisitParameterizedType(ParameterizedType type)
{
IType newType = base.VisitParameterizedType(type);
@ -470,14 +470,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -470,14 +470,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region Validate Constraints
OverloadResolutionErrors ValidateMethodConstraints(Candidate candidate)
{
// If type inference already failed, we won't check the constraints:
if ((candidate.Errors & OverloadResolutionErrors.TypeInferenceFailed) != 0)
return OverloadResolutionErrors.None;
if (candidate.TypeParameters == null || candidate.TypeParameters.Count == 0)
return OverloadResolutionErrors.None; // the method isn't generic
var substitution = GetSubstitution(candidate);
@ -487,7 +487,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -487,7 +487,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return OverloadResolutionErrors.None;
}
/// <summary>
/// Validates whether the given type argument satisfies the constraints for the given type parameter.
/// </summary>
@ -500,12 +500,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -500,12 +500,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public static bool ValidateConstraints(ITypeParameter typeParameter, IType typeArgument, TypeVisitor substitution = null)
{
if (typeParameter == null)
throw new ArgumentNullException("typeParameter");
throw new ArgumentNullException(nameof(typeParameter));
if (typeArgument == null)
throw new ArgumentNullException("typeArgument");
throw new ArgumentNullException(nameof(typeArgument));
return ValidateConstraints(typeParameter, typeArgument, substitution, CSharpConversions.Get(typeParameter.Owner.Compilation));
}
internal static bool ValidateConstraints(ITypeParameter typeParameter, IType typeArgument, TypeVisitor substitution, CSharpConversions conversions)
{
switch (typeArgument.Kind) { // void, null, and pointers cannot be used as type arguments
@ -543,7 +543,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -543,7 +543,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return true;
}
#endregion
#region CheckApplicability
/// <summary>
/// Returns whether a candidate with the given errors is still considered to be applicable.
@ -554,11 +554,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -554,11 +554,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
OverloadResolutionErrors.AmbiguousMatch | OverloadResolutionErrors.MethodConstraintsNotSatisfied;
return (errors & ~errorsThatDoNotMatterForApplicability) == OverloadResolutionErrors.None;
}
void CheckApplicability(Candidate candidate)
{
// C# 4.0 spec: §7.5.3.1 Applicable function member
// Test whether parameters were mapped the correct number of arguments:
int[] argumentCountPerParameter = new int[candidate.ParameterTypes.Length];
foreach (int parameterIndex in candidate.ArgumentToParameterMap) {
@ -577,7 +577,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -577,7 +577,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
candidate.AddError(OverloadResolutionErrors.MultipleArgumentsForSingleParameter);
}
}
candidate.ArgumentConversions = new Conversion[arguments.Length];
// Test whether argument passing mode matches the parameter passing mode
for (int i = 0; i < arguments.Length; i++) {
@ -586,7 +586,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -586,7 +586,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
candidate.ArgumentConversions[i] = Conversion.None;
continue;
}
ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
if (brrr != null) {
if (brrr.ReferenceKind != candidate.Parameters[parameterIndex].ReferenceKind)
@ -609,7 +609,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -609,7 +609,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region BetterFunctionMember
/// <summary>
/// Returns 1 if c1 is better than c2; 2 if c2 is better than c1; or 0 if neither is better.
@ -621,7 +621,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -621,7 +621,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return 1;
if (c1.ErrorCount > 0 && c2.ErrorCount == 0)
return 2;
// C# 4.0 spec: §7.5.3.2 Better function member
bool c1IsBetter = false;
bool c2IsBetter = false;
@ -650,42 +650,42 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -650,42 +650,42 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return 1;
if (!c1IsBetter && c2IsBetter)
return 2;
// prefer members with less errors (part of heuristic that produces a best candidate even if none is applicable)
if (c1.ErrorCount < c2.ErrorCount) return 1;
if (c1.ErrorCount > c2.ErrorCount) return 2;
if (!c1IsBetter && !c2IsBetter && parameterTypesEqual) {
// we need the tie-breaking rules
// non-generic methods are better
if (!c1.IsGenericMethod && c2.IsGenericMethod)
return 1;
else if (c1.IsGenericMethod && !c2.IsGenericMethod)
return 2;
// non-expanded members are better
if (!c1.IsExpandedForm && c2.IsExpandedForm)
return 1;
else if (c1.IsExpandedForm && !c2.IsExpandedForm)
return 2;
// prefer the member with less arguments mapped to the params-array
int r = c1.ArgumentsPassedToParamsArray.CompareTo(c2.ArgumentsPassedToParamsArray);
if (r < 0) return 1;
else if (r > 0) return 2;
// prefer the member where no default values need to be substituted
if (!c1.HasUnmappedOptionalParameters && c2.HasUnmappedOptionalParameters)
return 1;
else if (c1.HasUnmappedOptionalParameters && !c2.HasUnmappedOptionalParameters)
return 2;
// compare the formal parameters
r = MoreSpecificFormalParameters(c1, c2);
if (r != 0)
return r;
// prefer non-lifted operators
ILiftedOperator lift1 = c1.Member as ILiftedOperator;
ILiftedOperator lift2 = c2.Member as ILiftedOperator;
@ -696,22 +696,22 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -696,22 +696,22 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return 0;
}
int MoreSpecificFormalParameters(Candidate c1, Candidate c2)
{
// prefer the member with more formal parmeters (in case both have different number of optional parameters)
int r = c1.Parameters.Count.CompareTo(c2.Parameters.Count);
if (r > 0) return 1;
else if (r < 0) return 2;
return MoreSpecificFormalParameters(c1.Parameters.Select(p => p.Type), c2.Parameters.Select(p => p.Type));
}
static int MoreSpecificFormalParameters(IEnumerable<IType> t1, IEnumerable<IType> t2)
{
bool c1IsBetter = false;
bool c2IsBetter = false;
foreach (var pair in t1.Zip(t2, (a,b) => new { Item1 = a, Item2 = b })) {
foreach (var pair in t1.Zip(t2, (a, b) => new { Item1 = a, Item2 = b })) {
switch (MoreSpecificFormalParameter(pair.Item1, pair.Item2)) {
case 1:
c1IsBetter = true;
@ -727,14 +727,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -727,14 +727,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return 2;
return 0;
}
static int MoreSpecificFormalParameter(IType t1, IType t2)
{
if ((t1 is ITypeParameter) && !(t2 is ITypeParameter))
return 2;
if ((t2 is ITypeParameter) && !(t1 is ITypeParameter))
return 1;
ParameterizedType p1 = t1 as ParameterizedType;
ParameterizedType p2 = t2 as ParameterizedType;
if (p1 != null && p2 != null && p1.TypeParameterCount == p2.TypeParameterCount) {
@ -750,7 +750,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -750,7 +750,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return 0;
}
#endregion
#region ConsiderIfNewCandidateIsBest
void ConsiderIfNewCandidateIsBest(Candidate candidate)
{
@ -775,12 +775,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -775,12 +775,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
#endregion
#region Output Properties
public IParameterizedMember BestCandidate {
get { return bestCandidate != null ? bestCandidate.Member : null; }
}
/// <summary>
/// Returns the errors that apply to the best candidate.
/// This includes additional errors that do not affect applicability (e.g. AmbiguousMatch, MethodConstraintsNotSatisfied)
@ -799,23 +799,23 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -799,23 +799,23 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return err;
}
}
public bool FoundApplicableCandidate {
get { return bestCandidate != null && IsApplicable(bestCandidate.Errors); }
}
public IParameterizedMember BestCandidateAmbiguousWith {
get { return bestCandidateAmbiguousWith != null ? bestCandidateAmbiguousWith.Member : null; }
}
public bool BestCandidateIsExpandedForm {
get { return bestCandidate != null ? bestCandidate.IsExpandedForm : false; }
}
public bool IsAmbiguous {
get { return bestCandidateAmbiguousWith != null; }
}
public IReadOnlyList<IType> InferredTypeArguments {
get {
if (bestCandidate != null && bestCandidate.InferredTypes != null)
@ -824,7 +824,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -824,7 +824,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return EmptyList<IType>.Instance;
}
}
/// <summary>
/// Gets the implicit conversions that are being applied to the arguments.
/// </summary>
@ -836,7 +836,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -836,7 +836,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return Enumerable.Repeat(Conversion.None, arguments.Length).ToList();
}
}
/// <summary>
/// Gets an array that maps argument indices to parameter indices.
/// For arguments that could not be mapped to any parameter, the value will be -1.
@ -850,7 +850,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -850,7 +850,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
else
return null;
}
/// <summary>
/// Returns the arguments for the method call in the order they were provided (not in the order of the parameters).
/// Arguments are wrapped in a <see cref="ConversionResolveResult"/> if an implicit conversion is being applied
@ -863,7 +863,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -863,7 +863,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
else
return GetArgumentsWithConversions(null, null);
}
/// <summary>
/// Returns the arguments for the method call in the order they were provided (not in the order of the parameters).
/// Arguments are wrapped in a <see cref="ConversionResolveResult"/> if an implicit conversion is being applied
@ -878,7 +878,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -878,7 +878,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
else
return GetArgumentsWithConversions(null, GetBestCandidateWithSubstitutedTypeArguments());
}
IList<ResolveResult> GetArgumentsWithConversions(ResolveResult targetResolveResult, IParameterizedMember bestCandidateForNamedArguments)
{
var conversions = this.ArgumentConversions;
@ -911,7 +911,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -911,7 +911,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return args;
}
public IParameterizedMember GetBestCandidateWithSubstitutedTypeArguments()
{
if (bestCandidate == null)
@ -923,14 +923,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -923,14 +923,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return bestCandidate.Member;
}
}
TypeParameterSubstitution GetSubstitution(Candidate candidate)
{
// Do not compose the substitutions, but merge them.
// This is required for InvocationTests.SubstituteClassAndMethodTypeParametersAtOnce
return new TypeParameterSubstitution(candidate.Member.Substitution.ClassTypeArguments, candidate.InferredTypes);
}
/// <summary>
/// Creates a ResolveResult representing the result of overload resolution.
/// </summary>

60
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public TypeInference(ICompilation compilation)
{
if (compilation == null)
throw new ArgumentNullException("compilation");
throw new ArgumentNullException(nameof(compilation));
this.compilation = compilation;
this.conversions = CSharpConversions.Get(compilation);
}
@ -115,11 +115,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -115,11 +115,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public IType[] InferTypeArguments(IReadOnlyList<ITypeParameter> typeParameters, IReadOnlyList<ResolveResult> arguments, IReadOnlyList<IType> parameterTypes, out bool success, IReadOnlyList<IType> classTypeArguments = null)
{
if (typeParameters == null)
throw new ArgumentNullException("typeParameters");
throw new ArgumentNullException(nameof(typeParameters));
if (arguments == null)
throw new ArgumentNullException("arguments");
throw new ArgumentNullException(nameof(arguments));
if (parameterTypes == null)
throw new ArgumentNullException("parameterTypes");
throw new ArgumentNullException(nameof(parameterTypes));
try {
this.typeParameters = new TP[typeParameters.Count];
for (int i = 0; i < this.typeParameters.Length; i++) {
@ -173,13 +173,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -173,13 +173,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public IType[] InferTypeArgumentsFromBounds(IReadOnlyList<ITypeParameter> typeParameters, IType targetType, IEnumerable<IType> lowerBounds, IEnumerable<IType> upperBounds, out bool success)
{
if (typeParameters == null)
throw new ArgumentNullException("typeParameters");
throw new ArgumentNullException(nameof(typeParameters));
if (targetType == null)
throw new ArgumentNullException("targetType");
throw new ArgumentNullException(nameof(targetType));
if (lowerBounds == null)
throw new ArgumentNullException("lowerBounds");
throw new ArgumentNullException(nameof(lowerBounds));
if (upperBounds == null)
throw new ArgumentNullException("upperBounds");
throw new ArgumentNullException(nameof(upperBounds));
this.typeParameters = new TP[typeParameters.Count];
for (int i = 0; i < this.typeParameters.Length; i++) {
if (i != typeParameters[i].Index)
@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public TP(ITypeParameter typeParameter)
{
if (typeParameter == null)
throw new ArgumentNullException("typeParameter");
throw new ArgumentNullException(nameof(typeParameter));
this.TypeParameter = typeParameter;
}
@ -361,8 +361,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -361,8 +361,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#endregion
#region Input Types / Output Types (§7.5.2.3 + §7.5.2.4)
static readonly IType[] emptyTypeArray = new IType[0];
IType[] InputTypes(ResolveResult e, IType t)
{
// C# 4.0 spec: §7.5.2.3 Input types
@ -377,7 +375,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -377,7 +375,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return inputTypes;
}
}
return emptyTypeArray;
return Empty<IType>.Array;
}
IType[] OutputTypes(ResolveResult e, IType t)
@ -390,16 +388,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -390,16 +388,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return new[] { m.ReturnType };
}
}
return emptyTypeArray;
return Empty<IType>.Array;
}
static IMethod GetDelegateOrExpressionTreeSignature(IType t)
{
ParameterizedType pt = t as ParameterizedType;
if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Expression"
&& pt.Namespace == "System.Linq.Expressions")
if (t.TypeParameterCount == 1 && t.Name == "Expression"
&& t.Namespace == "System.Linq.Expressions")
{
t = pt.GetTypeArgument(0);
t = t.TypeArguments[0];
}
return t.GetDelegateInvokeMethod();
}
@ -571,8 +568,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -571,8 +568,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
Log.WriteLine("MakeExactInference from " + U + " to " + V);
if (V is NullabilityAnnotatedTypeParameter nullableTP) {
V = nullableTP.OriginalTypeParameter;
if (U.Nullability == V.Nullability) {
U = U.WithoutNullability();
V = V.WithoutNullability();
}
// If V is one of the unfixed Xi then U is added to the set of bounds for Xi.
@ -613,8 +611,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -613,8 +611,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
TP GetTPForType(IType v)
{
ITypeParameter p = v as ITypeParameter;
if (p != null) {
if (v is NullabilityAnnotatedTypeParameter natp) {
v = natp.OriginalTypeParameter;
}
if (v is ITypeParameter p) {
int index = p.Index;
if (index < typeParameters.Length && typeParameters[index].TypeParameter == p)
return typeParameters[index];
@ -631,7 +631,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -631,7 +631,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
void MakeLowerBoundInference(IType U, IType V)
{
Log.WriteLine(" MakeLowerBoundInference from " + U + " to " + V);
if (U.Nullability == V.Nullability) {
U = U.WithoutNullability();
V = V.WithoutNullability();
}
// If V is one of the unfixed Xi then U is added to the set of bounds for Xi.
TP tp = GetTPForType(V);
if (tp != null && tp.IsFixed == false) {
@ -728,7 +732,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -728,7 +732,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
void MakeUpperBoundInference(IType U, IType V)
{
Log.WriteLine(" MakeUpperBoundInference from " + U + " to " + V);
if (U.Nullability == V.Nullability) {
U = U.WithoutNullability();
V = V.WithoutNullability();
}
// If V is one of the unfixed Xi then U is added to the set of bounds for Xi.
TP tp = GetTPForType(V);
if (tp != null && tp.IsFixed == false) {
@ -826,7 +834,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -826,7 +834,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public IType GetBestCommonType(IList<ResolveResult> expressions, out bool success)
{
if (expressions == null)
throw new ArgumentNullException("expressions");
throw new ArgumentNullException(nameof(expressions));
if (expressions.Count == 1) {
success = IsValidType(expressions[0].Type);
return expressions[0].Type;
@ -853,9 +861,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -853,9 +861,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public IType FindTypeInBounds(IReadOnlyList<IType> lowerBounds, IReadOnlyList<IType> upperBounds)
{
if (lowerBounds == null)
throw new ArgumentNullException("lowerBounds");
throw new ArgumentNullException(nameof(lowerBounds));
if (upperBounds == null)
throw new ArgumentNullException("upperBounds");
throw new ArgumentNullException(nameof(upperBounds));
var result = FindTypesInBounds(lowerBounds, upperBounds);

2
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -300,7 +300,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -300,7 +300,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (sequencePoint.Offset < pos) {
// overlapping sequence point?
// delete previous sequence points that are after sequencePoint.Offset
while (newList.Count > 0 && newList.Last().EndOffset > pos) {
while (newList.Count > 0 && newList.Last().EndOffset > sequencePoint.Offset) {
var last = newList.Last();
if (last.Offset >= sequencePoint.Offset) {
newList.RemoveAt(newList.Count - 1);

53
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -28,7 +28,6 @@ using System; @@ -28,7 +28,6 @@ using System;
using System.Threading;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.CSharp.Resolver;
namespace ICSharpCode.Decompiler.CSharp
{
@ -40,11 +39,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -40,11 +39,18 @@ namespace ICSharpCode.Decompiler.CSharp
readonly DecompilerSettings settings;
readonly CancellationToken cancellationToken;
internal BlockContainer currentReturnContainer;
internal IType currentResultType;
internal bool currentIsIterator;
public StatementBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken)
{
Debug.Assert(typeSystem != null && decompilationContext != null);
this.exprBuilder = new ExpressionBuilder(typeSystem, decompilationContext, currentFunction, settings, cancellationToken);
this.exprBuilder = new ExpressionBuilder(this, typeSystem, decompilationContext, currentFunction, settings, cancellationToken);
this.currentFunction = currentFunction;
this.currentReturnContainer = (BlockContainer)currentFunction.Body;
this.currentIsIterator = currentFunction.IsIterator;
this.currentResultType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentFunction.ReturnType;
this.typeSystem = typeSystem;
this.settings = settings;
this.cancellationToken = cancellationToken;
@ -300,19 +306,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -300,19 +306,17 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (inst.TargetContainer == breakTarget)
return new BreakStatement();
if (inst.IsLeavingFunction) {
if (currentFunction.IsIterator)
if (inst.TargetContainer == currentReturnContainer) {
if (currentIsIterator)
return new YieldBreakStatement();
else if (!inst.Value.MatchNop()) {
IType targetType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentFunction.ReturnType;
var expr = exprBuilder.Translate(inst.Value, typeHint: targetType)
.ConvertTo(targetType, exprBuilder, allowImplicitConversion: true);
var expr = exprBuilder.Translate(inst.Value, typeHint: currentResultType)
.ConvertTo(currentResultType, exprBuilder, allowImplicitConversion: true);
return new ReturnStatement(expr);
} else
return new ReturnStatement();
}
string label;
if (!endContainerLabels.TryGetValue(inst.TargetContainer, out label)) {
if (!endContainerLabels.TryGetValue(inst.TargetContainer, out string label)) {
label = "end_" + inst.TargetLabel;
endContainerLabels.Add(inst.TargetContainer, label);
}
@ -406,19 +410,35 @@ namespace ICSharpCode.Decompiler.CSharp @@ -406,19 +410,35 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override Statement VisitUsingInstruction(UsingInstruction inst)
{
var transformed = TransformToForeach(inst, out var resource);
var resource = exprBuilder.Translate(inst.ResourceExpression).Expression;
var transformed = TransformToForeach(inst, resource);
if (transformed != null)
return transformed;
AstNode usingInit = resource;
var var = inst.Variable;
if (!inst.ResourceExpression.MatchLdNull() && !NullableType.GetUnderlyingType(var.Type).GetAllBaseTypes().Any(b => b.IsKnownType(KnownTypeCode.IDisposable))) {
KnownTypeCode knownTypeCode;
IType disposeType;
string disposeTypeMethodName;
if (inst.IsAsync) {
knownTypeCode = KnownTypeCode.IAsyncDisposable;
disposeType = exprBuilder.compilation.FindType(KnownTypeCode.IAsyncDisposable);
disposeTypeMethodName = "DisposeAsync";
} else {
knownTypeCode = KnownTypeCode.IDisposable;
disposeType = exprBuilder.compilation.FindType(KnownTypeCode.IDisposable);
disposeTypeMethodName = "Dispose";
}
if (!inst.ResourceExpression.MatchLdNull() && !NullableType.GetUnderlyingType(var.Type).GetAllBaseTypes().Any(b => b.IsKnownType(knownTypeCode))) {
Debug.Assert(var.Kind == VariableKind.UsingLocal);
var.Kind = VariableKind.Local;
var disposeType = exprBuilder.compilation.FindType(KnownTypeCode.IDisposable);
var disposeVariable = currentFunction.RegisterVariable(
VariableKind.Local, disposeType,
AssignVariableNames.GenerateVariableName(currentFunction, disposeType)
);
Expression disposeInvocation = new InvocationExpression(new MemberReferenceExpression(exprBuilder.ConvertVariable(disposeVariable).Expression, disposeTypeMethodName));
if (inst.IsAsync) {
disposeInvocation = new UnaryOperatorExpression { Expression = disposeInvocation, Operator = UnaryOperatorType.Await };
}
return new BlockStatement {
new ExpressionStatement(new AssignmentExpression(exprBuilder.ConvertVariable(var).Expression, resource.Detach())),
new TryCatchStatement {
@ -427,7 +447,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -427,7 +447,7 @@ namespace ICSharpCode.Decompiler.CSharp
new ExpressionStatement(new AssignmentExpression(exprBuilder.ConvertVariable(disposeVariable).Expression, new AsExpression(exprBuilder.ConvertVariable(var).Expression, exprBuilder.ConvertType(disposeType)))),
new IfElseStatement {
Condition = new BinaryOperatorExpression(exprBuilder.ConvertVariable(disposeVariable), BinaryOperatorType.InEquality, new NullReferenceExpression()),
TrueStatement = new ExpressionStatement(new InvocationExpression(new MemberReferenceExpression(exprBuilder.ConvertVariable(disposeVariable).Expression, "Dispose")))
TrueStatement = new ExpressionStatement(disposeInvocation)
}
}
},
@ -441,19 +461,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -441,19 +461,18 @@ namespace ICSharpCode.Decompiler.CSharp
}
return new UsingStatement {
ResourceAcquisition = usingInit,
IsAsync = inst.IsAsync,
EmbeddedStatement = ConvertAsBlock(inst.Body)
};
}
}
Statement TransformToForeach(UsingInstruction inst, out Expression resource)
Statement TransformToForeach(UsingInstruction inst, Expression resource)
{
if (!settings.ForEachStatement) {
resource = null;
return null;
}
// Check if the using resource matches the GetEnumerator pattern.
resource = exprBuilder.Translate(inst.ResourceExpression);
var m = getEnumeratorPattern.Match(resource);
// The using body must be a BlockContainer.
if (!(inst.Body is BlockContainer container) || !m.Success)
@ -791,7 +810,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -791,7 +810,7 @@ namespace ICSharpCode.Decompiler.CSharp
bool ParentIsCurrentGetter(ILInstruction inst)
{
return inst.Parent is CallInstruction cv && cv.Method.IsAccessor &&
cv.Method.AccessorOwner is IProperty p && p.Getter.Equals(cv.Method);
cv.Method.AccessorKind == System.Reflection.MethodSemanticsAttributes.Getter;
}
#endregion

450
ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs

File diff suppressed because it is too large Load Diff

6
ICSharpCode.Decompiler/CSharp/Syntax/AstNodeCollection.cs

@ -37,9 +37,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -37,9 +37,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public AstNodeCollection(AstNode node, Role<T> role)
{
if (node == null)
throw new ArgumentNullException("node");
throw new ArgumentNullException(nameof(node));
if (role == null)
throw new ArgumentNullException("role");
throw new ArgumentNullException(nameof(role));
this.node = node;
this.role = role;
}
@ -96,7 +96,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -96,7 +96,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public void MoveTo(ICollection<T> targetCollection)
{
if (targetCollection == null)
throw new ArgumentNullException("targetCollection");
throw new ArgumentNullException(nameof(targetCollection));
foreach (T node in this) {
node.Remove();
targetCollection.Add(node);

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/Expression.cs

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public Expression ReplaceWith(Func<Expression, Expression> replaceFunction)
{
if (replaceFunction == null)
throw new ArgumentNullException("replaceFunction");
throw new ArgumentNullException(nameof(replaceFunction));
return (Expression)base.ReplaceWith(node => replaceFunction((Expression)node));
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/NamespaceDeclaration.cs

@ -64,7 +64,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -64,7 +64,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
static AstType ConstructType(string[] arr, int i)
{
if (i < 0 || i >= arr.Length)
throw new ArgumentOutOfRangeException("i");
throw new ArgumentOutOfRangeException(nameof(i));
if (i == 0)
return new SimpleType(arr[i]);
return new MemberType(ConstructType(arr, i - 1), arr[i]);

96
ICSharpCode.Decompiler/CSharp/Syntax/IAnnotatable.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
IEnumerable<object> Annotations {
get;
}
/// <summary>
/// Gets the first annotation of the specified type.
/// Returns null if no matching annotation exists.
@ -42,8 +42,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -42,8 +42,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <typeparam name='T'>
/// The type of the annotation.
/// </typeparam>
T Annotation<T> () where T: class;
T Annotation<T>() where T : class;
/// <summary>
/// Gets the first annotation of the specified type.
/// Returns null if no matching annotation exists.
@ -51,24 +51,24 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -51,24 +51,24 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <param name='type'>
/// The type of the annotation.
/// </param>
object Annotation (Type type);
object Annotation(Type type);
/// <summary>
/// Adds an annotation to this instance.
/// </summary>
/// <param name='annotation'>
/// The annotation to add.
/// </param>
void AddAnnotation (object annotation);
void AddAnnotation(object annotation);
/// <summary>
/// Removes all annotations of the specified type.
/// </summary>
/// <typeparam name='T'>
/// The type of the annotations to remove.
/// </typeparam>
void RemoveAnnotations<T> () where T : class;
void RemoveAnnotations<T>() where T : class;
/// <summary>
/// Removes all annotations of the specified type.
/// </summary>
@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </param>
void RemoveAnnotations(Type type);
}
/// <summary>
/// Base class used to implement the IAnnotatable interface.
/// This implementation is thread-safe.
@ -88,9 +88,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -88,9 +88,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
// Annotations: points either null (no annotations), to the single annotation,
// or to an AnnotationList.
// Once it is pointed at an AnnotationList, it will never change (this allows thread-safety support by locking the list)
object annotations;
/// <summary>
/// Clones all annotations.
/// This method is intended to be called by Clone() implementations in derived classes.
@ -111,86 +111,86 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -111,86 +111,86 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
// There are two uses for this custom list type:
// 1) it's private, and thus (unlike List<object>) cannot be confused with real annotations
// 2) It allows us to simplify the cloning logic by making the list behave the same as a clonable annotation.
public AnnotationList (int initialCapacity) : base(initialCapacity)
public AnnotationList(int initialCapacity) : base(initialCapacity)
{
}
public object Clone ()
public object Clone()
{
lock (this) {
AnnotationList copy = new AnnotationList (this.Count);
AnnotationList copy = new AnnotationList(this.Count);
for (int i = 0; i < this.Count; i++) {
object obj = this [i];
object obj = this[i];
ICloneable c = obj as ICloneable;
copy.Add (c != null ? c.Clone () : obj);
copy.Add(c != null ? c.Clone() : obj);
}
return copy;
}
}
}
public virtual void AddAnnotation (object annotation)
public virtual void AddAnnotation(object annotation)
{
if (annotation == null)
throw new ArgumentNullException ("annotation");
throw new ArgumentNullException(nameof(annotation));
retry: // Retry until successful
object oldAnnotation = Interlocked.CompareExchange (ref this.annotations, annotation, null);
object oldAnnotation = Interlocked.CompareExchange(ref this.annotations, annotation, null);
if (oldAnnotation == null) {
return; // we successfully added a single annotation
}
AnnotationList list = oldAnnotation as AnnotationList;
if (list == null) {
// we need to transform the old annotation into a list
list = new AnnotationList (4);
list.Add (oldAnnotation);
list.Add (annotation);
if (Interlocked.CompareExchange (ref this.annotations, list, oldAnnotation) != oldAnnotation) {
list = new AnnotationList(4);
list.Add(oldAnnotation);
list.Add(annotation);
if (Interlocked.CompareExchange(ref this.annotations, list, oldAnnotation) != oldAnnotation) {
// the transformation failed (some other thread wrote to this.annotations first)
goto retry;
}
} else {
// once there's a list, use simple locking
lock (list) {
list.Add (annotation);
list.Add(annotation);
}
}
}
public virtual void RemoveAnnotations<T> () where T : class
public virtual void RemoveAnnotations<T>() where T : class
{
retry: // Retry until successful
retry: // Retry until successful
object oldAnnotations = this.annotations;
AnnotationList list = oldAnnotations as AnnotationList;
if (list != null) {
lock (list)
list.RemoveAll (obj => obj is T);
list.RemoveAll(obj => obj is T);
} else if (oldAnnotations is T) {
if (Interlocked.CompareExchange (ref this.annotations, null, oldAnnotations) != oldAnnotations) {
if (Interlocked.CompareExchange(ref this.annotations, null, oldAnnotations) != oldAnnotations) {
// Operation failed (some other thread wrote to this.annotations first)
goto retry;
}
}
}
public virtual void RemoveAnnotations (Type type)
public virtual void RemoveAnnotations(Type type)
{
if (type == null)
throw new ArgumentNullException ("type");
retry: // Retry until successful
throw new ArgumentNullException(nameof(type));
retry: // Retry until successful
object oldAnnotations = this.annotations;
AnnotationList list = oldAnnotations as AnnotationList;
if (list != null) {
lock (list)
list.RemoveAll(type.IsInstanceOfType);
} else if (type.IsInstanceOfType (oldAnnotations)) {
if (Interlocked.CompareExchange (ref this.annotations, null, oldAnnotations) != oldAnnotations) {
} else if (type.IsInstanceOfType(oldAnnotations)) {
if (Interlocked.CompareExchange(ref this.annotations, null, oldAnnotations) != oldAnnotations) {
// Operation failed (some other thread wrote to this.annotations first)
goto retry;
}
}
}
public T Annotation<T> () where T: class
public T Annotation<T>() where T : class
{
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
@ -207,27 +207,27 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -207,27 +207,27 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return annotations as T;
}
}
public object Annotation (Type type)
public object Annotation(Type type)
{
if (type == null)
throw new ArgumentNullException ("type");
throw new ArgumentNullException(nameof(type));
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
lock (list) {
foreach (object obj in list) {
if (type.IsInstanceOfType (obj))
if (type.IsInstanceOfType(obj))
return obj;
}
}
} else {
if (type.IsInstanceOfType (annotations))
if (type.IsInstanceOfType(annotations))
return annotations;
}
return null;
}
/// <summary>
/// Gets all annotations stored on this AstNode.
/// </summary>
@ -237,13 +237,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -237,13 +237,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
AnnotationList list = annotations as AnnotationList;
if (list != null) {
lock (list) {
return list.ToArray ();
return list.ToArray();
}
} else {
if (annotations != null)
return new object[] { annotations };
else
return Enumerable.Empty<object> ();
return Enumerable.Empty<object>();
}
}
}

4
ICSharpCode.Decompiler/CSharp/Syntax/Identifier.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return this.name; }
set {
if (value == null)
throw new ArgumentNullException("value");
throw new ArgumentNullException(nameof(value));
ThrowIfFrozen();
this.name = value;
}
@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
protected Identifier (string name, TextLocation location)
{
if (name == null)
throw new ArgumentNullException("name");
throw new ArgumentNullException(nameof(name));
this.Name = name;
this.startLocation = location;
}

2
ICSharpCode.Decompiler/CSharp/Syntax/IdentifierExpressionBackreference.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public IdentifierExpressionBackreference(string referencedGroupName)
{
if (referencedGroupName == null)
throw new ArgumentNullException("referencedGroupName");
throw new ArgumentNullException(nameof(referencedGroupName));
this.referencedGroupName = referencedGroupName;
}

2
ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/Backreference.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching @@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching
public Backreference(string referencedGroupName)
{
if (referencedGroupName == null)
throw new ArgumentNullException("referencedGroupName");
throw new ArgumentNullException(nameof(referencedGroupName));
this.referencedGroupName = referencedGroupName;
}

4
ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/Choice.cs

@ -32,14 +32,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching @@ -32,14 +32,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching
public void Add(string name, INode alternative)
{
if (alternative == null)
throw new ArgumentNullException("alternative");
throw new ArgumentNullException(nameof(alternative));
alternatives.Add(new NamedNode(name, alternative));
}
public void Add(INode alternative)
{
if (alternative == null)
throw new ArgumentNullException("alternative");
throw new ArgumentNullException(nameof(alternative));
alternatives.Add(alternative);
}

4
ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/INode.cs

@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching @@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching
public static Match Match(this INode pattern, INode other)
{
if (pattern == null)
throw new ArgumentNullException("pattern");
throw new ArgumentNullException(nameof(pattern));
Match match = PatternMatching.Match.CreateNew();
if (pattern.DoMatch(other, match))
return match;
@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching @@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching
public static bool IsMatch(this INode pattern, INode other)
{
if (pattern == null)
throw new ArgumentNullException("pattern");
throw new ArgumentNullException(nameof(pattern));
return pattern.DoMatch(other, PatternMatching.Match.CreateNew());
}

2
ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/NamedNode.cs

@ -39,7 +39,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching @@ -39,7 +39,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching
public NamedNode(string groupName, INode childNode)
{
if (childNode == null)
throw new ArgumentNullException("childNode");
throw new ArgumentNullException(nameof(childNode));
this.groupName = groupName;
this.childNode = childNode;
}

2
ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/OptionalNode.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching
public OptionalNode(INode childNode)
{
if (childNode == null)
throw new ArgumentNullException("childNode");
throw new ArgumentNullException(nameof(childNode));
this.childNode = childNode;
}

2
ICSharpCode.Decompiler/CSharp/Syntax/PatternMatching/Repeat.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching @@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching
public Repeat(INode childNode)
{
if (childNode == null)
throw new ArgumentNullException("childNode");
throw new ArgumentNullException(nameof(childNode));
this.childNode = childNode;
this.MinCount = 0;
this.MaxCount = int.MaxValue;

6
ICSharpCode.Decompiler/CSharp/Syntax/Role.cs

@ -89,16 +89,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -89,16 +89,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public Role(string name)
{
if (name == null)
throw new ArgumentNullException("name");
throw new ArgumentNullException(nameof(name));
this.name = name;
}
public Role(string name, T nullObject)
{
if (name == null)
throw new ArgumentNullException("name");
throw new ArgumentNullException(nameof(name));
if (nullObject == null)
throw new ArgumentNullException ("nullObject");
throw new ArgumentNullException (nameof(nullObject));
this.nullObject = nullObject;
this.name = name;
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Statements/Statement.cs

@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public Statement ReplaceWith(Func<Statement, Statement> replaceFunction)
{
if (replaceFunction == null)
throw new ArgumentNullException("replaceFunction");
throw new ArgumentNullException(nameof(replaceFunction));
return (Statement)base.ReplaceWith(node => replaceFunction((Statement)node));
}

60
ICSharpCode.Decompiler/CSharp/Syntax/Statements/UsingStatement.cs

@ -28,57 +28,67 @@ @@ -28,57 +28,67 @@
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
/// using (ResourceAcquisition) EmbeddedStatement
/// [ await ] using (ResourceAcquisition) EmbeddedStatement
/// </summary>
public class UsingStatement : Statement
{
public static readonly TokenRole UsingKeywordRole = new TokenRole ("using");
public static readonly TokenRole UsingKeywordRole = new TokenRole("using");
public static readonly TokenRole AwaitRole = UnaryOperatorExpression.AwaitRole;
public static readonly Role<AstNode> ResourceAcquisitionRole = new Role<AstNode>("ResourceAcquisition", AstNode.Null);
public CSharpTokenNode UsingToken {
get { return GetChildByRole (UsingKeywordRole); }
get { return GetChildByRole(UsingKeywordRole); }
}
public CSharpTokenNode AwaitToken {
get { return GetChildByRole(AwaitRole); }
}
public bool IsAsync {
get { return !GetChildByRole(AwaitRole).IsNull; }
set { SetChildByRole(AwaitRole, value ? new CSharpTokenNode(TextLocation.Empty, null) : null); }
}
public CSharpTokenNode LParToken {
get { return GetChildByRole (Roles.LPar); }
get { return GetChildByRole(Roles.LPar); }
}
/// <summary>
/// Either a VariableDeclarationStatement, or an Expression.
/// </summary>
public AstNode ResourceAcquisition {
get { return GetChildByRole (ResourceAcquisitionRole); }
set { SetChildByRole (ResourceAcquisitionRole, value); }
get { return GetChildByRole(ResourceAcquisitionRole); }
set { SetChildByRole(ResourceAcquisitionRole, value); }
}
public CSharpTokenNode RParToken {
get { return GetChildByRole (Roles.RPar); }
get { return GetChildByRole(Roles.RPar); }
}
public Statement EmbeddedStatement {
get { return GetChildByRole (Roles.EmbeddedStatement); }
set { SetChildByRole (Roles.EmbeddedStatement, value); }
get { return GetChildByRole(Roles.EmbeddedStatement); }
set { SetChildByRole(Roles.EmbeddedStatement, value); }
}
public override void AcceptVisitor (IAstVisitor visitor)
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitUsingStatement (this);
visitor.VisitUsingStatement(this);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitUsingStatement (this);
return visitor.VisitUsingStatement(this);
}
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitUsingStatement (this, data);
return visitor.VisitUsingStatement(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
UsingStatement o = other as UsingStatement;
return o != null && this.ResourceAcquisition.DoMatch(o.ResourceAcquisition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match);
return o != null && this.IsAsync == o.IsAsync && this.ResourceAcquisition.DoMatch(o.ResourceAcquisition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match);
}
}
}

81
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public TypeSystemAstBuilder(CSharpResolver resolver)
{
if (resolver == null)
throw new ArgumentNullException("resolver");
throw new ArgumentNullException(nameof(resolver));
this.resolver = resolver;
InitProperties();
}
@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public AstType ConvertType(IType type)
{
if (type == null)
throw new ArgumentNullException("type");
throw new ArgumentNullException(nameof(type));
AstType astType = ConvertTypeHelper(type);
AddTypeAnnotation(astType, type);
return astType;
@ -212,8 +212,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -212,8 +212,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
private void AddTypeAnnotation(AstType astType, IType type)
{
if (AddTypeReferenceAnnotations)
astType.AddAnnotation(type);
if (AddResolveResultAnnotations)
astType.AddAnnotation(new TypeResolveResult(type));
}
@ -564,14 +562,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -564,14 +562,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return attr;
}
private IEnumerable<AttributeSection> ConvertAttributes(IEnumerable<IAttribute> attibutes)
private IEnumerable<AttributeSection> ConvertAttributes(IEnumerable<IAttribute> attributes)
{
return attibutes.Select(a => new AttributeSection(ConvertAttribute(a)));
return attributes.Select(a => new AttributeSection(ConvertAttribute(a)));
}
private IEnumerable<AttributeSection> ConvertAttributes(IEnumerable<IAttribute> attibutes, string target)
private IEnumerable<AttributeSection> ConvertAttributes(IEnumerable<IAttribute> attributes, string target)
{
return attibutes.Select(a => new AttributeSection(ConvertAttribute(a)) {
return attributes.Select(a => new AttributeSection(ConvertAttribute(a)) {
AttributeTarget = target
});
}
@ -581,7 +579,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -581,7 +579,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public AstType ConvertAttributeType(IType type)
{
if (type == null)
throw new ArgumentNullException("type");
throw new ArgumentNullException(nameof(type));
AstType astType = ConvertTypeHelper(type);
string shortName = null;
@ -665,7 +663,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -665,7 +663,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public Expression ConvertConstantValue(ResolveResult rr)
{
if (rr == null)
throw new ArgumentNullException("rr");
throw new ArgumentNullException(nameof(rr));
bool isBoxing = false;
if (rr is ConversionResolveResult crr) {
// unpack ConversionResolveResult if necessary
@ -736,7 +734,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -736,7 +734,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public Expression ConvertConstantValue(IType expectedType, IType type, object constantValue)
{
if (type == null)
throw new ArgumentNullException("type");
throw new ArgumentNullException(nameof(type));
if (constantValue == null) {
if (type.IsReferenceType == true || type.IsKnownType(KnownTypeCode.NullableOfT)) {
var expr = new NullReferenceExpression();
@ -1250,7 +1248,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1250,7 +1248,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ParameterDeclaration ConvertParameter(IParameter parameter)
{
if (parameter == null)
throw new ArgumentNullException("parameter");
throw new ArgumentNullException(nameof(parameter));
ParameterDeclaration decl = new ParameterDeclaration();
if (parameter.IsRef) {
decl.ParameterModifier = ParameterModifier.Ref;
@ -1288,7 +1286,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1288,7 +1286,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public AstNode ConvertSymbol(ISymbol symbol)
{
if (symbol == null)
throw new ArgumentNullException("symbol");
throw new ArgumentNullException(nameof(symbol));
switch (symbol.SymbolKind) {
case SymbolKind.Namespace:
return ConvertNamespaceDeclaration((INamespace)symbol);
@ -1309,7 +1307,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1309,7 +1307,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public EntityDeclaration ConvertEntity(IEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
throw new ArgumentNullException(nameof(entity));
switch (entity.SymbolKind) {
case SymbolKind.TypeDefinition:
return ConvertTypeDefinition((ITypeDefinition)entity);
@ -1408,13 +1406,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1408,13 +1406,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
if (this.ShowBaseTypes) {
foreach (IType baseType in typeDefinition.DirectBaseTypes) {
if (baseType.IsKnownType (KnownTypeCode.Enum)) {
if (!typeDefinition.EnumUnderlyingType.IsKnownType (KnownTypeCode.Int32)) {
decl.BaseTypes.Add (ConvertType (typeDefinition.EnumUnderlyingType));
// if the declared type is an enum, replace all references to System.Enum with the enum-underlying type
if (typeDefinition.Kind == TypeKind.Enum && baseType.IsKnownType(KnownTypeCode.Enum)) {
if (!typeDefinition.EnumUnderlyingType.IsKnownType(KnownTypeCode.Int32)) {
decl.BaseTypes.Add(ConvertType(typeDefinition.EnumUnderlyingType));
}
} else if (!baseType.IsKnownType (KnownTypeCode.Object) &&
!baseType.IsKnownType (KnownTypeCode.ValueType)) {
decl.BaseTypes.Add (ConvertType (baseType));
// if the declared type is a struct, ignore System.ValueType
} else if (typeDefinition.Kind == TypeKind.Struct && baseType.IsKnownType(KnownTypeCode.ValueType)) {
continue;
// always ignore System.Object
} else if (baseType.IsKnownType(KnownTypeCode.Object)) {
continue;
} else {
decl.BaseTypes.Add(ConvertType(baseType));
}
}
}
@ -1522,6 +1526,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1522,6 +1526,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Accessor decl = new Accessor();
if (this.ShowAccessibility && accessor.Accessibility != ownerAccessibility)
decl.Modifiers = ModifierFromAccessibility(accessor.Accessibility);
if (accessor.HasReadonlyModifier())
decl.Modifiers |= Modifiers.Readonly;
if (ShowAttributes) {
decl.Attributes.AddRange(ConvertAttributes(accessor.GetAttributes()));
decl.Attributes.AddRange(ConvertAttributes(accessor.GetReturnTypeAttributes(), "return"));
@ -1551,9 +1557,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1551,9 +1557,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.Getter = ConvertAccessor(property.Getter, property.Accessibility, false);
decl.Setter = ConvertAccessor(property.Setter, property.Accessibility, true);
decl.PrivateImplementationType = GetExplicitInterfaceType (property);
MergeReadOnlyModifiers(decl, decl.Getter, decl.Setter);
return decl;
}
static void MergeReadOnlyModifiers(EntityDeclaration decl, Accessor accessor1, Accessor accessor2)
{
if (accessor1.HasModifier(Modifiers.Readonly) && accessor2.HasModifier(Modifiers.Readonly)) {
accessor1.Modifiers &= ~Modifiers.Readonly;
accessor2.Modifiers &= ~Modifiers.Readonly;
decl.Modifiers |= Modifiers.Readonly;
}
}
IndexerDeclaration ConvertIndexer(IProperty indexer)
{
IndexerDeclaration decl = new IndexerDeclaration();
@ -1571,6 +1586,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1571,6 +1586,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.Getter = ConvertAccessor(indexer.Getter, indexer.Accessibility, false);
decl.Setter = ConvertAccessor(indexer.Setter, indexer.Accessibility, true);
decl.PrivateImplementationType = GetExplicitInterfaceType (indexer);
MergeReadOnlyModifiers(decl, decl.Getter, decl.Setter);
return decl;
}
@ -1590,6 +1606,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1590,6 +1606,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.AddAccessor = ConvertAccessor(ev.AddAccessor, ev.Accessibility, true);
decl.RemoveAccessor = ConvertAccessor(ev.RemoveAccessor, ev.Accessibility, true);
decl.PrivateImplementationType = GetExplicitInterfaceType (ev);
MergeReadOnlyModifiers(decl, decl.AddAccessor, decl.RemoveAccessor);
return decl;
} else {
EventDeclaration decl = new EventDeclaration();
@ -1728,8 +1745,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1728,8 +1745,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
bool NeedsAccessibility(IMember member)
{
var declaringType = member.DeclaringType;
if ((declaringType != null && declaringType.Kind == TypeKind.Interface) || member.IsExplicitInterfaceImplementation)
if (member.IsExplicitInterfaceImplementation)
return false;
if (declaringType != null && declaringType.Kind == TypeKind.Interface) {
return member.Accessibility != Accessibility.Public;
}
switch (member.SymbolKind) {
case SymbolKind.Constructor:
return !member.IsStatic;
@ -1751,14 +1771,21 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1751,14 +1771,21 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
m |= Modifiers.Static;
} else {
var declaringType = member.DeclaringType;
if (member.IsAbstract && declaringType != null && declaringType.Kind != TypeKind.Interface)
m |= Modifiers.Abstract;
if (member.IsOverride)
if (declaringType.Kind == TypeKind.Interface) {
if (!member.IsVirtual && !member.IsAbstract && !member.IsOverride && member.Accessibility != Accessibility.Private && member is IMethod method2 && method2.HasBody)
m |= Modifiers.Sealed;
} else {
if (member.IsAbstract)
m |= Modifiers.Abstract;
else if (member.IsVirtual && !member.IsOverride)
m |= Modifiers.Virtual;
}
if (member.IsOverride && !member.IsExplicitInterfaceImplementation)
m |= Modifiers.Override;
if (member.IsVirtual && !member.IsAbstract && !member.IsOverride && declaringType.Kind != TypeKind.Interface)
m |= Modifiers.Virtual;
if (member.IsSealed)
if (member.IsSealed && !member.IsExplicitInterfaceImplementation)
m |= Modifiers.Sealed;
if (member is IMethod method && method.ThisIsRefReadOnly && method.DeclaringTypeDefinition?.IsReadOnly == false)
m |= Modifiers.Readonly;
}
}
return m;

71
ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -58,30 +58,55 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -58,30 +58,55 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
{
var stmt = constructorDeclaration.Body.Statements.FirstOrDefault() as ExpressionStatement;
if (stmt == null)
if (!(constructorDeclaration.Body.Statements.FirstOrDefault() is ExpressionStatement stmt))
return;
if (!(stmt.Expression is InvocationExpression invocation))
return;
if (invocation.Target is MemberReferenceExpression mre && mre.MemberName == ".ctor") {
ConstructorInitializer ci = new ConstructorInitializer();
var target = mre.Target;
// Ignore casts, those might be added if references are missing.
if (target is CastExpression cast)
target = cast.Expression;
if (target is ThisReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.This;
else if (target is BaseReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.Base;
else
return;
// Move arguments from invocation to initializer:
invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(invocation);
// Remove the statement:
stmt.Remove();
var currentCtor = (IMethod)constructorDeclaration.GetSymbol();
ConstructorInitializer ci;
switch (stmt.Expression) {
// Pattern for reference types:
// this..ctor(...);
case InvocationExpression invocation:
if (!(invocation.Target is MemberReferenceExpression mre) || mre.MemberName != ".ctor")
return;
if (!(invocation.GetSymbol() is IMethod ctor && ctor.IsConstructor))
return;
ci = new ConstructorInitializer();
var target = mre.Target;
// Ignore casts, those might be added if references are missing.
if (target is CastExpression cast)
target = cast.Expression;
if (target is ThisReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.This;
else if (target is BaseReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.Base;
else
return;
// Move arguments from invocation to initializer:
invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(invocation);
// Remove the statement:
stmt.Remove();
break;
// Pattern for value types:
// this = new TSelf(...);
case AssignmentExpression assignment:
if (!(assignment.Right is ObjectCreateExpression oce && oce.GetSymbol() is IMethod ctor2 && ctor2.DeclaringTypeDefinition == currentCtor.DeclaringTypeDefinition))
return;
ci = new ConstructorInitializer();
if (assignment.Left is ThisReferenceExpression)
ci.ConstructorInitializerType = ConstructorInitializerType.This;
else
return;
// Move arguments from invocation to initializer:
oce.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(oce);
// Remove the statement:
stmt.Remove();
break;
}
}

3
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -447,6 +447,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -447,6 +447,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} else {
type = context.TypeSystemAstBuilder.ConvertType(v.Type);
}
if (v.ILVariable.IsRefReadOnly && type is ComposedType composedType && composedType.HasRefSpecifier) {
composedType.HasReadOnlySpecifier = true;
}
var vds = new VariableDeclarationStatement(type, v.Name, assignment.Right.Detach());
var init = vds.Variables.Single();
init.AddAnnotation(assignment.Left.GetResolveResult());

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save