Browse Source

Fix detection and display of explicitly implemented operators.

pull/3410/head
Siegfried Pammer 4 months ago
parent
commit
3c70224441
  1. 25
      ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs
  2. 50
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
  3. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  4. 17
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

25
ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs

@ -283,7 +283,17 @@ namespace ICSharpCode.Decompiler.Tests.Output @@ -283,7 +283,17 @@ namespace ICSharpCode.Decompiler.Tests.Output
[TestCase(ILSpyMainTreeViewMemberFlags, "this[int] : int")]
public void Indexer(ConversionFlags flags, string expectedOutput)
{
var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetProperties(p => p.IsIndexer).Single();
var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetProperties(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation).Single();
ambience.ConversionFlags = flags;
Assert.That(ambience.ConvertSymbol(prop), Is.EqualTo(expectedOutput));
}
[TestCase(StandardConversionFlags, "int Interface.this[int index] { get; }")]
[TestCase(ILSpyMainTreeViewMemberFlags, "Interface.this[int] : int")]
public void ExplicitIndexer(ConversionFlags flags, string expectedOutput)
{
var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetProperties(p => p.IsIndexer && p.IsExplicitInterfaceImplementation).Single();
ambience.ConversionFlags = flags;
Assert.That(ambience.ConvertSymbol(prop), Is.EqualTo(expectedOutput));
@ -323,7 +333,12 @@ namespace ICSharpCode.Decompiler.Tests.Output @@ -323,7 +333,12 @@ namespace ICSharpCode.Decompiler.Tests.Output
readonly struct ReadonlyStruct { }
readonly ref struct ReadonlyRefStruct { }
class Program
interface Interface
{
int this[int x] { get; }
}
class Program : Interface
{
int test;
const int TEST2 = 2;
@ -336,6 +351,12 @@ namespace ICSharpCode.Decompiler.Tests.Output @@ -336,6 +351,12 @@ namespace ICSharpCode.Decompiler.Tests.Output
}
}
int Interface.this[int index] {
get {
return index;
}
}
public event EventHandler ProgramChanged;
public event EventHandler SomeEvent {

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

@ -279,9 +279,20 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -279,9 +279,20 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
ConvertType(member.DeclaringType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
IType explicitInterfaceType = GetExplicitInterfaceType(member);
string name = member.Name;
if (explicitInterfaceType != null)
{
name = name.Substring(name.LastIndexOf('.') + 1);
}
switch (member.SymbolKind)
{
case SymbolKind.Indexer:
if (explicitInterfaceType != null)
{
ConvertType(explicitInterfaceType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
writer.WriteKeyword(Roles.Identifier, "this");
break;
case SymbolKind.Constructor:
@ -292,11 +303,16 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -292,11 +303,16 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
WriteQualifiedName(member.DeclaringType.Name, writer, formattingPolicy);
break;
case SymbolKind.Operator:
switch (member.Name)
switch (name)
{
case "op_Implicit":
writer.WriteKeyword(OperatorDeclaration.ImplicitRole, "implicit");
writer.Space();
if (explicitInterfaceType != null)
{
ConvertType(explicitInterfaceType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
writer.WriteKeyword(OperatorDeclaration.OperatorKeywordRole, "operator");
writer.Space();
ConvertType(member.ReturnType, writer, formattingPolicy);
@ -305,9 +321,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -305,9 +321,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case "op_CheckedExplicit":
writer.WriteKeyword(OperatorDeclaration.ExplicitRole, "explicit");
writer.Space();
if (explicitInterfaceType != null)
{
ConvertType(explicitInterfaceType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
writer.WriteKeyword(OperatorDeclaration.OperatorKeywordRole, "operator");
writer.Space();
if (member.Name == "op_CheckedExplicit")
if (name == "op_CheckedExplicit")
{
writer.WriteToken(OperatorDeclaration.CheckedKeywordRole, "checked");
writer.Space();
@ -315,9 +336,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -315,9 +336,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
ConvertType(member.ReturnType, writer, formattingPolicy);
break;
default:
if (explicitInterfaceType != null)
{
ConvertType(explicitInterfaceType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
writer.WriteKeyword(OperatorDeclaration.OperatorKeywordRole, "operator");
writer.Space();
var operatorType = OperatorDeclaration.GetOperatorType(member.Name);
var operatorType = OperatorDeclaration.GetOperatorType(name);
if (operatorType.HasValue && !((ConversionFlags & ConversionFlags.SupportOperatorChecked) == 0 && OperatorDeclaration.IsChecked(operatorType.Value)))
{
if (OperatorDeclaration.IsChecked(operatorType.Value))
@ -335,7 +361,12 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -335,7 +361,12 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
break;
default:
writer.WriteIdentifier(Identifier.Create(member.Name));
if (explicitInterfaceType != null)
{
ConvertType(explicitInterfaceType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
writer.WriteIdentifier(Identifier.Create(name));
break;
}
WriteTypeParameters(node, writer, formattingPolicy);
@ -407,6 +438,17 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -407,6 +438,17 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
astType.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
}
IType GetExplicitInterfaceType(IMember member)
{
if (member.IsExplicitInterfaceImplementation)
{
var baseMember = member.ExplicitlyImplementedInterfaceMembers.FirstOrDefault();
if (baseMember != null)
return baseMember.DeclaringType;
}
return null;
}
public string ConvertConstantValue(object constantValue)
{
return TextWriterTokenWriter.PrintPrimitiveValue(constantValue);

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

@ -1784,10 +1784,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1784,10 +1784,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
case SymbolKind.Event:
return ConvertEvent((IEvent)entity);
case SymbolKind.Method:
if (entity.Name.Contains(".op_"))
{
goto case SymbolKind.Operator;
}
return ConvertMethod((IMethod)entity);
case SymbolKind.Operator:
return ConvertOperator((IMethod)entity);

17
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

@ -96,6 +96,23 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -96,6 +96,23 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.symbolKind = SymbolKind.Destructor;
}
}
else if ((attributes & MethodAttributes.Static) != 0 && typeParameters.Length == 0)
{
// Operators that are explicit interface implementations are not marked
// with MethodAttributes.SpecialName or MethodAttributes.RTSpecialName
string name = this.Name;
int index = name.LastIndexOf('.');
if (index > 0)
{
name = name.Substring(index + 1);
if (name.StartsWith("op_", StringComparison.Ordinal)
&& CSharp.Syntax.OperatorDeclaration.GetOperatorType(name) != null)
{
this.symbolKind = SymbolKind.Operator;
}
}
}
this.IsExtensionMethod = (attributes & MethodAttributes.Static) == MethodAttributes.Static
&& (module.TypeSystemOptions & TypeSystemOptions.ExtensionMethods) == TypeSystemOptions.ExtensionMethods
&& def.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.Extension);

Loading…
Cancel
Save