Browse Source

Fix undocumented expressions

pull/728/head
Daniel Grunwald 9 years ago
parent
commit
5bcd6142de
  1. 33
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 9
      ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  3. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  5. 28
      ICSharpCode.Decompiler/Tests/TestCases/UndocumentedExpressions.cs
  6. 10
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  7. 28
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  8. 356
      ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs
  9. 2
      NRefactory

33
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -602,6 +602,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -602,6 +602,7 @@ namespace ICSharpCode.Decompiler.CSharp
TranslatedExpression HandleCallInstruction(CallInstruction inst)
{
IMethod method = inst.Method;
// Used for Call, CallVirt and NewObj
TranslatedExpression target;
if (inst.OpCode == OpCode.NewObj) {
@ -610,30 +611,41 @@ namespace ICSharpCode.Decompiler.CSharp @@ -610,30 +611,41 @@ namespace ICSharpCode.Decompiler.CSharp
}
target = default(TranslatedExpression); // no target
} else {
target = TranslateTarget(inst.Method, inst.Arguments.FirstOrDefault(), inst.OpCode == OpCode.Call);
target = TranslateTarget(method, inst.Arguments.FirstOrDefault(), inst.OpCode == OpCode.Call);
}
var arguments = inst.Arguments.SelectArray(Translate);
int firstParamIndex = (inst.Method.IsStatic || inst.OpCode == OpCode.NewObj) ? 0 : 1;
int firstParamIndex = (method.IsStatic || inst.OpCode == OpCode.NewObj) ? 0 : 1;
// Translate arguments to the expected parameter types
Debug.Assert(arguments.Length == firstParamIndex + inst.Method.Parameters.Count);
for (int i = firstParamIndex; i < arguments.Length; i++) {
var parameter = inst.Method.Parameters[i - firstParamIndex];
var parameter = method.Parameters[i - firstParamIndex];
arguments[i] = arguments[i].ConvertTo(parameter.Type, this);
if (parameter.IsOut && arguments[i].Expression is DirectionExpression) {
((DirectionExpression)arguments[i].Expression).FieldDirection = FieldDirection.Out;
}
}
if (method is VarArgInstanceMethod) {
int regularParameterCount = ((VarArgInstanceMethod)method).RegularParameterCount;
var argListArg = new UndocumentedExpression();
argListArg.UndocumentedExpressionType = UndocumentedExpressionType.ArgList;
argListArg.Arguments.AddRange(arguments.Skip(regularParameterCount).Select(arg => arg.Expression));
var argListRR = new ResolveResult(SpecialType.ArgList);
arguments = arguments.Take(regularParameterCount)
.Concat(new[] { argListArg.WithoutILInstruction().WithRR(argListRR) }).ToArray();
method = (IMethod)method.MemberDefinition;
}
var argumentResolveResults = arguments.Skip(firstParamIndex).Select(arg => arg.ResolveResult).ToList();
ResolveResult rr;
if (inst.Method.IsAccessor)
rr = new MemberResolveResult(target.ResolveResult, inst.Method.AccessorOwner);
rr = new MemberResolveResult(target.ResolveResult, method.AccessorOwner);
else
rr = new CSharpInvocationResolveResult(target.ResolveResult, inst.Method, argumentResolveResults);
rr = new CSharpInvocationResolveResult(target.ResolveResult, method, argumentResolveResults);
var argumentExpressions = arguments.Skip(firstParamIndex).Select(arg => arg.Expression).ToList();
if (inst.OpCode == OpCode.NewObj) {
@ -641,7 +653,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -641,7 +653,6 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(inst).WithRR(rr);
} else {
Expression expr;
IMethod method = inst.Method;
if (method.IsAccessor) {
if (method.ReturnType.IsKnownType(KnownTypeCode.Void)) {
var value = argumentExpressions.Last();
@ -669,14 +680,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -669,14 +680,14 @@ namespace ICSharpCode.Decompiler.CSharp
}
} else {
Expression targetExpr = target.Expression;
string methodName = inst.Method.Name;
string methodName = method.Name;
// HACK : convert this.Dispose() to ((IDisposable)this).Dispose(), if Dispose is an explicitly implemented interface method.
if (inst.Method.IsExplicitInterfaceImplementation && targetExpr is ThisReferenceExpression) {
targetExpr = targetExpr.CastTo(ConvertType(inst.Method.ImplementedInterfaceMembers[0].DeclaringType));
methodName = inst.Method.ImplementedInterfaceMembers[0].Name;
targetExpr = targetExpr.CastTo(ConvertType(method.ImplementedInterfaceMembers[0].DeclaringType));
methodName = method.ImplementedInterfaceMembers[0].Name;
}
var mre = new MemberReferenceExpression(targetExpr, methodName);
mre.TypeArguments.AddRange(inst.Method.TypeArguments.Select(a => ConvertType(a)));
mre.TypeArguments.AddRange(method.TypeArguments.Select(a => ConvertType(a)));
expr = new InvocationExpression(mre, argumentExpressions);
}
return expr.WithILInstruction(inst).WithRR(rr);
@ -869,7 +880,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -869,7 +880,7 @@ namespace ICSharpCode.Decompiler.CSharp
var expr = new UndocumentedExpression {
UndocumentedExpressionType = UndocumentedExpressionType.RefValue,
Arguments = { Translate(inst.Argument).Expression, new TypeReferenceExpression(ConvertType(inst.Type)) }
};
}.WithRR(new ResolveResult(inst.Type));
return new DirectionExpression(FieldDirection.Ref, expr.WithILInstruction(inst)).WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(inst.Type, false));
}

9
ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -129,6 +129,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -129,6 +129,9 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (method.HasThis) {
writer.Write("instance ");
}
if (method.CallingConvention == MethodCallingConvention.VarArg) {
writer.Write("vararg ");
}
method.ReturnType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters);
writer.Write(' ');
if (method.DeclaringType != null) {
@ -154,7 +157,8 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -154,7 +157,8 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.Write("(");
var parameters = method.Parameters;
for (int i = 0; i < parameters.Count; ++i) {
if (i > 0) writer.Write(", ");
if (i > 0)
writer.Write(", ");
parameters[i].ParameterType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters);
}
writer.Write(")");
@ -285,6 +289,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -285,6 +289,9 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.Write(" modreq(");
((RequiredModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write(") ");
} else if (type is SentinelType) {
writer.Write("..., ");
((SentinelType)type).ElementType.WriteTo(writer, syntax);
} else {
string name = PrimitiveTypeName(type.FullName);
if (syntax == ILNameSyntax.ShortTypeName) {

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -158,6 +158,7 @@ @@ -158,6 +158,7 @@
<Compile Include="TypeSystem\IDecompilerTypeSystem.cs" />
<Compile Include="TypeSystem\ReferenceResolvingException.cs" />
<Compile Include="TypeSystem\TypesHierarchyHelpers.cs" />
<Compile Include="TypeSystem\VarArgInstanceMethod.cs" />
<Compile Include="Util\CollectionExtensions.cs" />
<Compile Include="Util\BitSet.cs" />
<Compile Include="Util\Interval.cs" />

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -125,6 +125,7 @@ @@ -125,6 +125,7 @@
<Compile Include="TestCases\InitializerTests.cs" />
<Compile Include="TestCases\PropertiesAndEvents.cs" />
<Compile Include="TestCases\Switch.cs" />
<Compile Include="TestCases\UndocumentedExpressions.cs" />
<Compile Include="TestCases\ValueTypeCall.cs" />
<Compile Include="TestRunner.cs" />
<Compile Include="Util\IntervalTests.cs" />

28
ICSharpCode.Decompiler/Tests/UndocumentedExpressions.cs → ICSharpCode.Decompiler/Tests/TestCases/UndocumentedExpressions.cs

@ -20,10 +20,34 @@ using System; @@ -20,10 +20,34 @@ using System;
public class UndocumentedExpressions
{
public static int GetArgCount(__arglist)
static void Main(string[] args)
{
MakeTypedRef("abc");
VarArgs(1, __arglist());
VarArgs(__arglist(1));
VarArgs(1, __arglist("abc", 2, true));
}
public static void VarArgs(int normalArg, __arglist)
{
ArgIterator argIterator = new ArgIterator(__arglist);
return argIterator.GetRemainingCount();
Console.WriteLine("Called with {0} arguments", argIterator.GetRemainingCount());
int pos = 0;
while (argIterator.GetRemainingCount() > 0) {
TypedReference tr = argIterator.GetNextArg();
object val;
try {
val = __refvalue(tr, object);
} catch (Exception ex) {
val = ex.GetType().Name;
}
Console.WriteLine("{0} : {1} = {2}", pos++, __reftype(tr).Name, val);
}
}
public static void VarArgs(__arglist)
{
Console.WriteLine("The other varargs overload");
}
public static void MakeTypedRef(object o)

10
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -93,6 +93,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -93,6 +93,12 @@ namespace ICSharpCode.Decompiler.Tests
{
TestCompileDecompileCompileOutputAll("DecimalFields.cs");
}
[Test]
public void UndocumentedExpressions()
{
TestCompileDecompileCompileOutputAll("UndocumentedExpressions.cs");
}
void TestCompileDecompileCompileOutputAll(string testFileName)
{
@ -138,6 +144,10 @@ namespace ICSharpCode.Decompiler.Tests @@ -138,6 +144,10 @@ namespace ICSharpCode.Decompiler.Tests
Assert.AreEqual(result1, result2, "Exit codes differ; did the decompiled code crash?");
Assert.AreEqual(error1, error2);
Assert.AreEqual(output1, output2);
File.Delete(decompiledCodeFile);
File.Delete(outputFile.PathToAssembly);
File.Delete(decompiledOutputFile.PathToAssembly);
} finally {
if (outputFile != null)
outputFile.TempFiles.Delete();

28
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -120,6 +120,9 @@ namespace ICSharpCode.Decompiler @@ -120,6 +120,9 @@ namespace ICSharpCode.Decompiler
{
if (typeReference == null)
return SpecialType.UnknownType;
if (typeReference is SentinelType) {
typeReference = ((SentinelType)typeReference).ElementType;
}
ITypeReference typeRef;
if (typeReference is PinnedType) {
typeRef = new NRefactory.TypeSystem.ByReferenceType(Resolve(((PinnedType)typeReference).ElementType)).ToTypeReference();
@ -197,7 +200,12 @@ namespace ICSharpCode.Decompiler @@ -197,7 +200,12 @@ namespace ICSharpCode.Decompiler
IMethod method;
if (!methodLookupCache.TryGetValue(methodReference, out method)) {
method = FindNonGenericMethod(methodReference.GetElementMethod());
if (methodReference.IsGenericInstance || methodReference.DeclaringType.IsGenericInstance) {
if (methodReference.CallingConvention == MethodCallingConvention.VarArg) {
method = new VarArgInstanceMethod(
method,
methodReference.Parameters.SkipWhile(p => !p.ParameterType.IsSentinel).Select(p => Resolve(p.ParameterType))
);
} else if (methodReference.IsGenericInstance || methodReference.DeclaringType.IsGenericInstance) {
IList<IType> classTypeArguments = null;
IList<IType> methodTypeArguments = null;
if (methodReference.IsGenericInstance) {
@ -234,7 +242,16 @@ namespace ICSharpCode.Decompiler @@ -234,7 +242,16 @@ namespace ICSharpCode.Decompiler
if (GetCecil(method) == methodReference)
return method;
}
var parameterTypes = methodReference.Parameters.SelectArray(p => Resolve(p.ParameterType));
IType[] parameterTypes;
if (methodReference.CallingConvention == MethodCallingConvention.VarArg) {
parameterTypes = methodReference.Parameters
.TakeWhile(p => !p.ParameterType.IsSentinel)
.Select(p => Resolve(p.ParameterType))
.Concat(new[] { SpecialType.ArgList })
.ToArray();
} else {
parameterTypes = methodReference.Parameters.SelectArray(p => Resolve(p.ParameterType));
}
var returnType = Resolve(methodReference.ReturnType);
foreach (var method in methods) {
if (method.TypeParameters.Count != methodReference.GenericParameters.Count)
@ -245,7 +262,7 @@ namespace ICSharpCode.Decompiler @@ -245,7 +262,7 @@ namespace ICSharpCode.Decompiler
}
return CreateFakeMethod(methodReference);
}
static bool CompareTypes(IType a, IType b)
{
IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(a);
@ -253,6 +270,11 @@ namespace ICSharpCode.Decompiler @@ -253,6 +270,11 @@ namespace ICSharpCode.Decompiler
return type1.Equals(type2);
}
static bool IsVarArgMethod(IMethod method)
{
return method.Parameters.Count > 0 && method.Parameters[method.Parameters.Count - 1].Type.Kind == TypeKind.ArgList;
}
static bool CompareSignatures(IList<IParameter> parameters, IType[] parameterTypes)
{
if (parameterTypes.Length != parameters.Count)

356
ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs

@ -0,0 +1,356 @@ @@ -0,0 +1,356 @@
// Copyright (c) 2016 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler
{
/// <summary>
/// Used when calling a vararg method. Stores the actual parameter types being passed.
/// </summary>
public class VarArgInstanceMethod : IMethod
{
readonly IMethod baseMethod;
readonly IParameter[] parameters;
public VarArgInstanceMethod(IMethod baseMethod, IEnumerable<IType> varArgTypes)
{
this.baseMethod = baseMethod;
var paramList = new List<IParameter>(baseMethod.Parameters);
Debug.Assert(paramList.Last().Type.Kind == TypeKind.ArgList);
paramList.RemoveAt(paramList.Count - 1);
foreach (IType varArg in varArgTypes) {
paramList.Add(new DefaultParameter(varArg, name: string.Empty, owner: this));
}
this.parameters = paramList.ToArray();
}
public int RegularParameterCount {
get { return baseMethod.Parameters.Count - 1; }
}
public IList<IParameter> Parameters {
get { return parameters; }
}
public override bool Equals(object obj)
{
VarArgInstanceMethod other = obj as VarArgInstanceMethod;
return other != null && baseMethod.Equals(other.baseMethod);
}
public override int GetHashCode()
{
return baseMethod.GetHashCode();
}
public override string ToString()
{
StringBuilder b = new StringBuilder("[");
b.Append(this.SymbolKind);
if (this.DeclaringType != null) {
b.Append(this.DeclaringType.ReflectionName);
b.Append('.');
}
b.Append(this.Name);
if (this.TypeParameters.Count > 0) {
b.Append("``");
b.Append(this.TypeParameters.Count);
}
b.Append('(');
for (int i = 0; i < this.Parameters.Count; i++) {
if (i > 0)
b.Append(", ");
if (i == this.RegularParameterCount)
b.Append("..., ");
b.Append(this.Parameters[i].Type.ReflectionName);
}
if (this.Parameters.Count == this.RegularParameterCount) {
b.Append(", ...");
}
b.Append("):");
b.Append(this.ReturnType.ReflectionName);
b.Append(']');
return b.ToString();
}
#region IMethod implementation
public IMethod Specialize(TypeParameterSubstitution substitution)
{
return new VarArgInstanceMethod(
baseMethod.Specialize(substitution),
parameters.Skip(baseMethod.Parameters.Count - 1).Select(p => p.Type.AcceptVisitor(substitution)).ToList());
}
public IList<IUnresolvedMethod> Parts {
get { return baseMethod.Parts; }
}
public IList<IAttribute> ReturnTypeAttributes {
get { return baseMethod.ReturnTypeAttributes; }
}
public IList<ITypeParameter> TypeParameters {
get { return baseMethod.TypeParameters; }
}
public bool IsParameterized {
get { return baseMethod.IsParameterized; }
}
public IList<IType> TypeArguments {
get { return baseMethod.TypeArguments; }
}
public bool IsExtensionMethod {
get { return baseMethod.IsExtensionMethod; }
}
public bool IsConstructor {
get { return baseMethod.IsConstructor; }
}
public bool IsDestructor {
get { return baseMethod.IsDestructor; }
}
public bool IsOperator {
get { return baseMethod.IsOperator; }
}
public bool IsPartial {
get { return baseMethod.IsPartial; }
}
public bool IsAsync {
get { return baseMethod.IsAsync; }
}
public bool HasBody {
get { return baseMethod.HasBody; }
}
public bool IsAccessor {
get { return baseMethod.IsAccessor; }
}
public IMember AccessorOwner {
get { return baseMethod.AccessorOwner; }
}
public IMethod ReducedFrom {
get { return baseMethod.ReducedFrom; }
}
#endregion
#region IMember implementation
[Obsolete("Use the ToReference method instead.")]
public IMemberReference ToMemberReference()
{
return ToReference();
}
public IMemberReference ToReference()
{
throw new NotImplementedException();
}
IMember IMember.Specialize(TypeParameterSubstitution substitution)
{
return Specialize(substitution);
}
public IMember MemberDefinition {
get { return baseMethod.MemberDefinition; }
}
public IUnresolvedMember UnresolvedMember {
get { return baseMethod.UnresolvedMember; }
}
public IType ReturnType {
get { return baseMethod.ReturnType; }
}
public IList<IMember> ImplementedInterfaceMembers {
get { return baseMethod.ImplementedInterfaceMembers; }
}
public bool IsExplicitInterfaceImplementation {
get { return baseMethod.IsExplicitInterfaceImplementation; }
}
public bool IsVirtual {
get { return baseMethod.IsVirtual; }
}
public bool IsOverride {
get { return baseMethod.IsOverride; }
}
public bool IsOverridable {
get { return baseMethod.IsOverridable; }
}
public TypeParameterSubstitution Substitution {
get { return baseMethod.Substitution; }
}
#endregion
#region ISymbol implementation
ISymbolReference ISymbol.ToReference()
{
return ToReference();
}
public SymbolKind SymbolKind {
get { return baseMethod.SymbolKind; }
}
public string Name {
get { return baseMethod.Name; }
}
#endregion
#region IEntity implementation
[Obsolete]
public EntityType EntityType {
get {
throw new NotImplementedException();
}
}
public DomRegion Region {
get { return baseMethod.Region; }
}
public DomRegion BodyRegion {
get { return baseMethod.BodyRegion; }
}
public ITypeDefinition DeclaringTypeDefinition {
get { return baseMethod.DeclaringTypeDefinition; }
}
public IType DeclaringType {
get { return baseMethod.DeclaringType; }
}
public IAssembly ParentAssembly {
get { return baseMethod.ParentAssembly; }
}
public IList<IAttribute> Attributes {
get { return baseMethod.Attributes; }
}
public ICSharpCode.NRefactory.Documentation.DocumentationComment Documentation {
get { return baseMethod.Documentation; }
}
public bool IsStatic {
get { return baseMethod.IsStatic; }
}
public bool IsAbstract {
get { return baseMethod.IsAbstract; }
}
public bool IsSealed {
get { return baseMethod.IsSealed; }
}
public bool IsShadowing {
get { return baseMethod.IsShadowing; }
}
public bool IsSynthetic {
get { return baseMethod.IsSynthetic; }
}
#endregion
#region IHasAccessibility implementation
public Accessibility Accessibility {
get { return baseMethod.Accessibility; }
}
public bool IsPrivate {
get { return baseMethod.IsPrivate; }
}
public bool IsPublic {
get { return baseMethod.IsPublic; }
}
public bool IsProtected {
get { return baseMethod.IsProtected; }
}
public bool IsInternal {
get { return baseMethod.IsInternal; }
}
public bool IsProtectedOrInternal {
get { return baseMethod.IsProtectedOrInternal; }
}
public bool IsProtectedAndInternal {
get { return baseMethod.IsProtectedAndInternal; }
}
#endregion
#region INamedElement implementation
public string FullName {
get { return baseMethod.FullName; }
}
public string ReflectionName {
get { return baseMethod.ReflectionName; }
}
public string Namespace {
get { return baseMethod.Namespace; }
}
#endregion
#region ICompilationProvider implementation
public ICompilation Compilation {
get { return baseMethod.Compilation; }
}
#endregion
}
}

2
NRefactory

@ -1 +1 @@ @@ -1 +1 @@
Subproject commit 43306b8912c6806f3c19d8a288ddeeaca07df5d2
Subproject commit 8369bc77d14701792c05fa6bb50f7d299072041b
Loading…
Cancel
Save