Browse Source

Fix lower case type name conflicting with variable name

pull/3572/head
ds5678 3 months ago committed by Jeremy Pritts
parent
commit
c54318173b
  1. 3
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 18
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 33
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3571_A.cs
  4. 33
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3571_B.cs
  5. 36
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3571_C.cs
  6. 4
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QualifierTests.cs
  7. 10
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  8. 2
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  9. 34
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

3
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -155,6 +155,9 @@
<Compile Include="TestCases\Pretty\ExpandParamsArgumentsDisabled.cs" /> <Compile Include="TestCases\Pretty\ExpandParamsArgumentsDisabled.cs" />
<Compile Include="TestCases\Pretty\ExtensionProperties.cs" /> <Compile Include="TestCases\Pretty\ExtensionProperties.cs" />
<Compile Include="TestCases\Pretty\Issue3541.cs" /> <Compile Include="TestCases\Pretty\Issue3541.cs" />
<Compile Include="TestCases\Pretty\Issue3571_C.cs" />
<Compile Include="TestCases\Pretty\Issue3571_B.cs" />
<Compile Include="TestCases\Pretty\Issue3571_A.cs" />
<None Include="TestCases\ILPretty\Issue3504.cs" /> <None Include="TestCases\ILPretty\Issue3504.cs" />
<Compile Include="TestCases\ILPretty\MonoFixed.cs" /> <Compile Include="TestCases\ILPretty\MonoFixed.cs" />
<Compile Include="TestCases\Pretty\Comparisons.cs" /> <Compile Include="TestCases\Pretty\Comparisons.cs" />

18
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -678,6 +678,24 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions); await RunForLibrary(cscOptions: cscOptions);
} }
[Test]
public async Task Issue3571_A([ValueSource(nameof(roslyn2OrNewerWithNet40Options))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
[Test]
public async Task Issue3571_B([ValueSource(nameof(roslyn2OrNewerWithNet40Options))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
[Test]
public async Task Issue3571_C([ValueSource(nameof(roslyn2OrNewerWithNet40Options))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
[Test] [Test]
public async Task AssemblyCustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) public async Task AssemblyCustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{ {

33
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3571_A.cs

@ -0,0 +1,33 @@
using System;
using System.Runtime.InteropServices;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal static class Issue3571_A
{
[StructLayout(LayoutKind.Sequential, Size = 1)]
public readonly struct fsResult
{
public static fsResult Success => default(fsResult);
public static fsResult Failure => default(fsResult);
public bool Succeeded => true;
public bool Failed => false;
public static fsResult operator +(fsResult a, fsResult b)
{
return default(fsResult);
}
}
public static fsResult M()
{
fsResult success = fsResult.Success;
fsResult fsResult2 = success + fsResult.Success;
if (fsResult2.Succeeded)
{
return success;
}
Console.WriteLine("Failed");
return fsResult2 + fsResult.Failure;
}
}
}

33
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3571_B.cs

@ -0,0 +1,33 @@
using System;
using System.Runtime.InteropServices;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.Issue3571_B
{
[StructLayout(LayoutKind.Sequential, Size = 1)]
public readonly struct fsResult
{
public static fsResult Success => default(fsResult);
public static fsResult Failure => default(fsResult);
public bool Succeeded => true;
public bool Failed => false;
public static fsResult operator +(fsResult a, fsResult b)
{
return default(fsResult);
}
}
internal static class Issue3571_B
{
public static fsResult M()
{
fsResult success = fsResult.Success;
fsResult fsResult2 = success + fsResult.Success;
if (fsResult2.Succeeded)
{
return success;
}
Console.WriteLine("Failed");
return fsResult2 + fsResult.Failure;
}
}
}

36
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3571_C.cs

@ -0,0 +1,36 @@
using System;
using System.Runtime.InteropServices;
using ICSharpCode.Decompiler.Tests.TestCases.Pretty.Issue3571_Helper;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal static class Issue3571_C
{
public static fsResult M()
{
fsResult success = fsResult.Success;
fsResult fsResult2 = success + fsResult.Success;
if (fsResult2.Succeeded)
{
return success;
}
Console.WriteLine("Failed");
return fsResult2 + fsResult.Failure;
}
}
}
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.Issue3571_Helper
{
[StructLayout(LayoutKind.Sequential, Size = 1)]
public readonly struct fsResult
{
public static fsResult Success => default(fsResult);
public static fsResult Failure => default(fsResult);
public bool Succeeded => true;
public bool Failed => false;
public static fsResult operator +(fsResult a, fsResult b)
{
return default(fsResult);
}
}
}

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

@ -308,9 +308,9 @@ namespace ICSharpCode.Decompiler.Tests.Pretty
private void LocalConflictsWithTypeName() private void LocalConflictsWithTypeName()
{ {
for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++)
{ {
QualifierTests.i.Test(); i.Test();
} }
} }
#if CS70 #if CS70

10
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -551,7 +551,7 @@ namespace ICSharpCode.Decompiler.CSharp
var.Kind = VariableKind.Local; var.Kind = VariableKind.Local;
var disposeVariable = currentFunction.RegisterVariable( var disposeVariable = currentFunction.RegisterVariable(
VariableKind.Local, disposeType, VariableKind.Local, disposeType,
AssignVariableNames.GenerateVariableName(currentFunction, disposeType) AssignVariableNames.GenerateVariableName(currentFunction, disposeType, decompileRun.UsingScope)
); );
Expression disposeInvocation = new InvocationExpression(new MemberReferenceExpression(exprBuilder.ConvertVariable(disposeVariable).Expression, disposeTypeMethodName)); Expression disposeInvocation = new InvocationExpression(new MemberReferenceExpression(exprBuilder.ConvertVariable(disposeVariable).Expression, disposeTypeMethodName));
if (inst.IsAsync) if (inst.IsAsync)
@ -712,12 +712,12 @@ namespace ICSharpCode.Decompiler.CSharp
if (foreachVariable.Type.Kind != TypeKind.Dynamic) if (foreachVariable.Type.Kind != TypeKind.Dynamic)
foreachVariable.Type = type; foreachVariable.Type = type;
foreachVariable.Kind = VariableKind.ForeachLocal; foreachVariable.Kind = VariableKind.ForeachLocal;
foreachVariable.Name = AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), foreachVariable); foreachVariable.Name = AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), decompileRun.UsingScope, foreachVariable);
break; break;
case RequiredGetCurrentTransformation.IntroduceNewVariable: case RequiredGetCurrentTransformation.IntroduceNewVariable:
foreachVariable = currentFunction.RegisterVariable( foreachVariable = currentFunction.RegisterVariable(
VariableKind.ForeachLocal, type, VariableKind.ForeachLocal, type,
AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>()) AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), decompileRun.UsingScope)
); );
instToReplace.ReplaceWith(new LdLoc(foreachVariable)); instToReplace.ReplaceWith(new LdLoc(foreachVariable));
body.Instructions.Insert(0, new StLoc(foreachVariable, instToReplace)); body.Instructions.Insert(0, new StLoc(foreachVariable, instToReplace));
@ -725,11 +725,11 @@ namespace ICSharpCode.Decompiler.CSharp
case RequiredGetCurrentTransformation.IntroduceNewVariableAndLocalCopy: case RequiredGetCurrentTransformation.IntroduceNewVariableAndLocalCopy:
foreachVariable = currentFunction.RegisterVariable( foreachVariable = currentFunction.RegisterVariable(
VariableKind.ForeachLocal, type, VariableKind.ForeachLocal, type,
AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>()) AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), decompileRun.UsingScope)
); );
var localCopyVariable = currentFunction.RegisterVariable( var localCopyVariable = currentFunction.RegisterVariable(
VariableKind.Local, type, VariableKind.Local, type,
AssignVariableNames.GenerateVariableName(currentFunction, type) AssignVariableNames.GenerateVariableName(currentFunction, type, decompileRun.UsingScope)
); );
instToReplace.Parent.ReplaceWith(new LdLoca(localCopyVariable)); instToReplace.Parent.ReplaceWith(new LdLoca(localCopyVariable));
body.Instructions.Insert(0, new StLoc(localCopyVariable, new LdLoc(foreachVariable))); body.Instructions.Insert(0, new StLoc(localCopyVariable, new LdLoc(foreachVariable)));

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

@ -227,7 +227,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var v = function.RegisterVariable( var v = function.RegisterVariable(
VariableKind.StackSlot, VariableKind.StackSlot,
type, type,
AssignVariableNames.GenerateVariableName(function, type, AssignVariableNames.GenerateVariableName(function, type, context.DecompileRun.UsingScope,
stmt.Expression.Annotations.OfType<ILInstruction>() stmt.Expression.Annotations.OfType<ILInstruction>()
.Where(AssignVariableNames.IsSupportedInstruction).FirstOrDefault(), .Where(AssignVariableNames.IsSupportedInstruction).FirstOrDefault(),
mustResolveConflicts: true) mustResolveConflicts: true)

34
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -28,6 +28,7 @@ using Humanizer.Inflections;
using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor; using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -110,6 +111,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
currentLowerCaseTypeOrMemberNames.Add(name); currentLowerCaseTypeOrMemberNames.Add(name);
AddExistingName(reservedVariableNames, name); AddExistingName(reservedVariableNames, name);
} }
foreach (var name in CollectAllLowerCaseTypeNames(context.UsingScope))
{
currentLowerCaseTypeOrMemberNames.Add(name);
AddExistingName(reservedVariableNames, name);
}
this.currentLowerCaseTypeOrMemberNames = currentLowerCaseTypeOrMemberNames.ToImmutableHashSet(); this.currentLowerCaseTypeOrMemberNames = currentLowerCaseTypeOrMemberNames.ToImmutableHashSet();
// handle implicit parameters of set or event accessors // handle implicit parameters of set or event accessors
@ -618,6 +624,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (IsLowerCase(item.Name)) if (IsLowerCase(item.Name))
yield return item.Name; yield return item.Name;
} }
var current = type;
while (current != null)
{
foreach (var nested in current.NestedTypes)
{
if (IsLowerCase(nested.Name))
yield return nested.Name;
}
current = current.DeclaringTypeDefinition;
}
}
static IEnumerable<string> CollectAllLowerCaseTypeNames(UsingScope usingScope)
{
return usingScope.Usings.SelectMany(n => n.Types).Select(t => t.Name).Where(IsLowerCase);
} }
static bool IsLowerCase(string name) static bool IsLowerCase(string name)
@ -870,7 +891,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
static Dictionary<string, int> CollectReservedVariableNames(ILFunction function, static Dictionary<string, int> CollectReservedVariableNames(ILFunction function,
ILVariable existingVariable, bool mustResolveConflicts) ILVariable existingVariable, bool mustResolveConflicts, UsingScope usingScope)
{ {
var reservedVariableNames = new Dictionary<string, int>(); var reservedVariableNames = new Dictionary<string, int>();
var rootFunction = function.Ancestors.OfType<ILFunction>().Single(f => f.Parent == null); var rootFunction = function.Ancestors.OfType<ILFunction>().Single(f => f.Parent == null);
@ -889,14 +910,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (mustResolveConflicts) if (mustResolveConflicts)
{ {
var memberNames = CollectAllLowerCaseMemberNames(function.Method.DeclaringTypeDefinition) var memberNames = CollectAllLowerCaseMemberNames(function.Method.DeclaringTypeDefinition)
.Concat(CollectAllLowerCaseTypeNames(function.Method.DeclaringTypeDefinition)); .Concat(CollectAllLowerCaseTypeNames(function.Method.DeclaringTypeDefinition))
.Concat(CollectAllLowerCaseTypeNames(usingScope));
foreach (var name in memberNames) foreach (var name in memberNames)
AddExistingName(reservedVariableNames, name); AddExistingName(reservedVariableNames, name);
} }
return reservedVariableNames; return reservedVariableNames;
} }
internal static string GenerateForeachVariableName(ILFunction function, ILInstruction valueContext, internal static string GenerateForeachVariableName(ILFunction function, ILInstruction valueContext, UsingScope usingScope,
ILVariable existingVariable = null, bool mustResolveConflicts = false) ILVariable existingVariable = null, bool mustResolveConflicts = false)
{ {
if (function == null) if (function == null)
@ -905,7 +927,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
return existingVariable.Name; return existingVariable.Name;
} }
var reservedVariableNames = CollectReservedVariableNames(function, existingVariable, mustResolveConflicts); var reservedVariableNames = CollectReservedVariableNames(function, existingVariable, mustResolveConflicts, usingScope);
string baseName = GetNameFromInstruction(valueContext); string baseName = GetNameFromInstruction(valueContext);
if (string.IsNullOrEmpty(baseName)) if (string.IsNullOrEmpty(baseName))
@ -955,13 +977,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
} }
internal static string GenerateVariableName(ILFunction function, IType type, internal static string GenerateVariableName(ILFunction function, IType type, UsingScope usingScope,
ILInstruction valueContext = null, ILVariable existingVariable = null, ILInstruction valueContext = null, ILVariable existingVariable = null,
bool mustResolveConflicts = false) bool mustResolveConflicts = false)
{ {
if (function == null) if (function == null)
throw new ArgumentNullException(nameof(function)); throw new ArgumentNullException(nameof(function));
var reservedVariableNames = CollectReservedVariableNames(function, existingVariable, mustResolveConflicts); var reservedVariableNames = CollectReservedVariableNames(function, existingVariable, mustResolveConflicts, usingScope);
string baseName = valueContext != null ? GetNameFromInstruction(valueContext) ?? GetNameByType(type) : GetNameByType(type); string baseName = valueContext != null ? GetNameFromInstruction(valueContext) ?? GetNameByType(type) : GetNameByType(type);
string proposedName = "obj"; string proposedName = "obj";

Loading…
Cancel
Save