Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy

pull/205/head
Pent Ploompuu 15 years ago
parent
commit
d5b9d33b73
  1. 117
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 219
      ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
  3. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs
  4. 4
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  5. 460
      ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
  6. 24
      ILSpy/CSharpLanguage.cs
  7. 1
      ILSpy/DecompilerSettingsPanel.xaml
  8. 2
      ILSpy/DecompilerSettingsPanel.xaml.cs
  9. 1
      ILSpy/ILSpy.csproj
  10. 6
      ILSpy/TextView/DecompilerTextView.cs
  11. 80
      ILSpy/XmlDoc/AddXmlDocTransform.cs

117
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -232,7 +232,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -232,7 +232,9 @@ namespace ICSharpCode.Decompiler.Ast
foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
if (MemberIsHidden(nestedTypeDef, context.Settings))
continue;
astType.AddChild(CreateType(nestedTypeDef), TypeDeclaration.MemberRole);
var nestedType = CreateType(nestedTypeDef);
SetNewModifier(nestedType);
astType.AddChild(nestedType, TypeDeclaration.MemberRole);
}
AttributedNode result = astType;
@ -627,7 +629,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -627,7 +629,7 @@ namespace ICSharpCode.Decompiler.Ast
// Create mapping - used in debugger
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings);
MethodDeclaration astMethod = new MethodDeclaration();
MethodDeclaration astMethod = new MethodDeclaration().WithAnnotation(methodMapping);
astMethod.AddAnnotation(methodDef);
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Name = CleanName(methodDef.Name);
@ -638,14 +640,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -638,14 +640,8 @@ namespace ICSharpCode.Decompiler.Ast
if (!methodDef.DeclaringType.IsInterface) {
if (!methodDef.HasOverrides) {
astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsVirtual ^ !methodDef.IsNewSlot) {
try {
if (TypesHierarchyHelpers.FindBaseMethods(methodDef).Any())
astMethod.Modifiers |= Modifiers.New;
} catch (ReferenceResolvingException) {
// TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references.
}
}
if (methodDef.IsVirtual == methodDef.IsNewSlot)
SetNewModifier(astMethod);
} else {
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
}
@ -675,7 +671,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -675,7 +671,6 @@ namespace ICSharpCode.Decompiler.Ast
return op;
}
}
astMethod.WithAnnotation(methodMapping);
return astMethod;
}
@ -775,10 +770,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -775,10 +770,6 @@ namespace ICSharpCode.Decompiler.Ast
}
}
}
if (accessor.IsVirtual ^ !accessor.IsNewSlot) {
if (TypesHierarchyHelpers.FindBaseProperties(propDef).Any())
astProp.Modifiers |= Modifiers.New;
}
} catch (ReferenceResolvingException) {
// TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references.
}
@ -791,7 +782,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -791,7 +782,7 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Getter = new Accessor();
astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
astProp.AddAnnotation(propDef.GetMethod);
astProp.Getter.AddAnnotation(propDef.GetMethod);
ConvertAttributes(astProp.Getter, propDef.GetMethod);
if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
@ -815,11 +806,14 @@ namespace ICSharpCode.Decompiler.Ast @@ -815,11 +806,14 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Setter.WithAnnotation(methodMapping);
}
ConvertCustomAttributes(astProp, propDef);
MemberDeclaration member = astProp;
if(propDef.IsIndexer())
return ConvertPropertyToIndexer(astProp, propDef);
else
return astProp;
member = ConvertPropertyToIndexer(astProp, propDef);
if(!accessor.HasOverrides && !accessor.DeclaringType.IsInterface)
if (accessor.IsVirtual == accessor.IsNewSlot)
SetNewModifier(member);
return member;
}
IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef)
@ -882,9 +876,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -882,9 +876,8 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.RemoveAccessor.WithAnnotation(methodMapping);
}
MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
if (accessor.IsVirtual ^ !accessor.IsNewSlot) {
if (TypesHierarchyHelpers.FindBaseMethods(accessor).Any())
astEvent.Modifiers |= Modifiers.New;
if (accessor.IsVirtual == accessor.IsNewSlot) {
SetNewModifier(astEvent);
}
return astEvent;
}
@ -912,6 +905,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -912,6 +905,7 @@ namespace ICSharpCode.Decompiler.Ast
initializer.Initializer = CreateExpressionForConstant(fieldDef.Constant, fieldDef.FieldType, fieldDef.DeclaringType.IsEnum);
}
ConvertAttributes(astField, fieldDef);
SetNewModifier(astField);
return astField;
}
@ -1379,6 +1373,83 @@ namespace ICSharpCode.Decompiler.Ast @@ -1379,6 +1373,83 @@ namespace ICSharpCode.Decompiler.Ast
return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute");
}
/// <summary>
/// Sets new modifier if the member hides some other member from a base type.
/// </summary>
/// <param name="member">The node of the member which new modifier state should be determined.</param>
static void SetNewModifier(AttributedNode member)
{
try {
bool addNewModifier = false;
if (member is IndexerDeclaration) {
var propertyDef = member.Annotation<PropertyDefinition>();
var baseProperties =
TypesHierarchyHelpers.FindBaseProperties(propertyDef);
addNewModifier = baseProperties.Any();
} else
addNewModifier = HidesBaseMember(member);
if (addNewModifier)
member.Modifiers |= Modifiers.New;
}
catch (ReferenceResolvingException) {
// TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references.
}
}
private static bool HidesBaseMember(AttributedNode member)
{
var memberDefinition = member.Annotation<IMemberDefinition>();
bool addNewModifier = false;
var methodDefinition = memberDefinition as MethodDefinition;
if (methodDefinition != null) {
addNewModifier = HidesByName(memberDefinition, includeBaseMethods: false);
if (!addNewModifier)
addNewModifier = TypesHierarchyHelpers.FindBaseMethods(methodDefinition).Any();
} else
addNewModifier = HidesByName(memberDefinition, includeBaseMethods: true);
return addNewModifier;
}
/// <summary>
/// Determines whether any base class member has the same name as the given member.
/// </summary>
/// <param name="member">The derived type's member.</param>
/// <param name="includeBaseMethods">true if names of methods declared in base types should also be checked.</param>
/// <returns>true if any base member has the same name as given member, otherwise false.</returns>
static bool HidesByName(IMemberDefinition member, bool includeBaseMethods)
{
Debug.Assert(!(member is PropertyDefinition) || !((PropertyDefinition)member).IsIndexer());
if (member.DeclaringType.BaseType != null) {
var baseTypeRef = member.DeclaringType.BaseType;
while (baseTypeRef != null) {
var baseType = baseTypeRef.ResolveOrThrow();
if (baseType.HasProperties && AnyIsHiddenBy(baseType.Properties, member, m => !m.IsIndexer()))
return true;
if (baseType.HasEvents && AnyIsHiddenBy(baseType.Events, member))
return true;
if (baseType.HasFields && AnyIsHiddenBy(baseType.Fields, member))
return true;
if (includeBaseMethods && baseType.HasMethods
&& AnyIsHiddenBy(baseType.Methods, member, m => !m.IsSpecialName))
return true;
if (baseType.HasNestedTypes && AnyIsHiddenBy(baseType.NestedTypes, member))
return true;
baseTypeRef = baseType.BaseType;
}
}
return false;
}
static bool AnyIsHiddenBy<T>(IEnumerable<T> members, IMemberDefinition derived, Predicate<T> condition = null)
where T : IMemberDefinition
{
return members.Any(m => m.Name == derived.Name
&& (condition == null || condition(m))
&& TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
}
/// <summary>
/// <inheritdoc/>

219
ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs

@ -27,6 +27,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -27,6 +27,13 @@ namespace ICSharpCode.Decompiler.Ast
}
}
/// <summary>
/// Determines whether one method overrides or hides another method.
/// </summary>
/// <param name="parentMethod">The method declared in a base type.</param>
/// <param name="childMethod">The method declared in a derived type.</param>
/// <returns>true if <paramref name="childMethod"/> hides or overrides <paramref name="parentMethod"/>,
/// otherwise false.</returns>
public static bool IsBaseMethod(MethodDefinition parentMethod, MethodDefinition childMethod)
{
if (parentMethod == null)
@ -44,6 +51,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -44,6 +51,13 @@ namespace ICSharpCode.Decompiler.Ast
return FindBaseMethods(childMethod).Any(m => m == parentMethod);// || (parentMethod.HasGenericParameters && m.);
}
/// <summary>
/// Determines whether a property overrides or hides another property.
/// </summary>
/// <param name="parentProperty">The property declared in a base type.</param>
/// <param name="childProperty">The property declared in a derived type.</param>
/// <returns>true if the <paramref name="childProperty"/> hides or overrides <paramref name="parentProperty"/>,
/// otherwise false.</returns>
public static bool IsBaseProperty(PropertyDefinition parentProperty, PropertyDefinition childProperty)
{
if (parentProperty == null)
@ -69,6 +83,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -69,6 +83,11 @@ namespace ICSharpCode.Decompiler.Ast
return FindBaseEvents(childEvent).Any(m => m == parentEvent);
}
/// <summary>
/// Finds all methods from base types overridden or hidden by the specified method.
/// </summary>
/// <param name="method">The method which overrides or hides methods from base types.</param>
/// <returns>Methods overriden or hidden by the specified method.</returns>
public static IEnumerable<MethodDefinition> FindBaseMethods(MethodDefinition method)
{
if (method == null)
@ -79,30 +98,41 @@ namespace ICSharpCode.Decompiler.Ast @@ -79,30 +98,41 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var baseType in BaseTypes(method.DeclaringType))
foreach (var baseMethod in baseType.Item.Methods)
if (MatchMethod(baseType.ApplyTo(baseMethod), gMethod) && IsVisbleFrom(baseMethod, method)) {
if (MatchMethod(baseType.ApplyTo(baseMethod), gMethod) && IsVisibleFromDerived(baseMethod, method.DeclaringType)) {
yield return baseMethod;
if (!(baseMethod.IsNewSlot ^ baseMethod.IsVirtual))
if (baseMethod.IsNewSlot == baseMethod.IsVirtual)
yield break;
}
}
public static IEnumerable<PropertyDefinition> FindBaseProperties(PropertyDefinition property, bool ignoreResolveExceptions = false)
/// <summary>
/// Finds all properties from base types overridden or hidden by the specified property.
/// </summary>
/// <param name="property">The property which overrides or hides properties from base types.</param>
/// <returns>Properties overriden or hidden by the specified property.</returns>
public static IEnumerable<PropertyDefinition> FindBaseProperties(PropertyDefinition property)
{
if (property == null)
throw new ArgumentNullException("property");
if ((property.GetMethod ?? property.SetMethod).HasOverrides)
yield break;
var typeContext = CreateGenericContext(property.DeclaringType);
var gProperty = typeContext.ApplyTo(property);
bool isIndexer = property.IsIndexer();
foreach (var baseType in BaseTypes(property.DeclaringType))
foreach (var baseProperty in baseType.Item.Properties)
if (MatchProperty(baseType.ApplyTo(baseProperty), gProperty) && IsVisbleFrom(baseProperty, property)) {
if (MatchProperty(baseType.ApplyTo(baseProperty), gProperty)
&& IsVisibleFromDerived(baseProperty, property.DeclaringType)) {
if (isIndexer != baseProperty.IsIndexer())
continue;
yield return baseProperty;
var anyPropertyAccessor = baseProperty.GetMethod ?? baseProperty.SetMethod;
if (!(anyPropertyAccessor.IsNewSlot ^ anyPropertyAccessor.IsVirtual))
if (anyPropertyAccessor.IsNewSlot == anyPropertyAccessor.IsVirtual)
yield break;
}
}
public static IEnumerable<EventDefinition> FindBaseEvents(EventDefinition eventDef)
@ -115,40 +145,78 @@ namespace ICSharpCode.Decompiler.Ast @@ -115,40 +145,78 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var baseType in BaseTypes(eventDef.DeclaringType))
foreach (var baseEvent in baseType.Item.Events)
if (MatchEvent(baseType.ApplyTo(baseEvent), gEvent) && IsVisbleFrom(baseEvent, eventDef)) {
if (MatchEvent(baseType.ApplyTo(baseEvent), gEvent) && IsVisibleFromDerived(baseEvent, eventDef.DeclaringType)) {
yield return baseEvent;
var anyEventAccessor = baseEvent.AddMethod ?? baseEvent.RemoveMethod;
if (!(anyEventAccessor.IsNewSlot ^ anyEventAccessor.IsVirtual))
if (anyEventAccessor.IsNewSlot == anyEventAccessor.IsVirtual)
yield break;
}
}
private static bool IsVisbleFrom(MethodDefinition baseCandidate, MethodDefinition method)
/// <summary>
/// Determinates whether member of the base type is visible from a derived type.
/// </summary>
/// <param name="baseMember">The member which visibility is checked.</param>
/// <param name="derivedType">The derived type.</param>
/// <returns>true if the member is visible from derived type, othewise false.</returns>
public static bool IsVisibleFromDerived(IMemberDefinition baseMember, TypeDefinition derivedType)
{
if (baseCandidate.IsPrivate)
return false;
if ((baseCandidate.IsAssembly || baseCandidate.IsFamilyAndAssembly) && baseCandidate.Module != method.Module)
if (baseMember == null)
throw new ArgumentNullException("baseMember");
if (derivedType == null)
throw new ArgumentNullException("derivedType");
var visibility = IsVisibleFromDerived(baseMember);
if (visibility.HasValue)
return visibility.Value;
if (baseMember.DeclaringType.Module == derivedType.Module)
return true;
// TODO: Check also InternalsVisibleToAttribute.
return false;
return true;
}
private static bool IsVisbleFrom(PropertyDefinition baseCandidate, PropertyDefinition property)
private static bool? IsVisibleFromDerived(IMemberDefinition member)
{
if (baseCandidate.GetMethod != null && property.GetMethod != null && IsVisbleFrom(baseCandidate.GetMethod, property.GetMethod))
return true;
if (baseCandidate.SetMethod != null && property.SetMethod != null && IsVisbleFrom(baseCandidate.SetMethod, property.SetMethod))
MethodAttributes attrs = GetAccessAttributes(member) & MethodAttributes.MemberAccessMask;
if (attrs == MethodAttributes.Private)
return false;
if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem)
return null;
return true;
return false;
}
private static bool IsVisbleFrom(EventDefinition baseCandidate, EventDefinition eventDef)
private static MethodAttributes GetAccessAttributes(IMemberDefinition member)
{
if (baseCandidate.AddMethod != null && eventDef.AddMethod != null && IsVisbleFrom(baseCandidate.AddMethod, eventDef.AddMethod))
return true;
if (baseCandidate.RemoveMethod != null && eventDef.RemoveMethod != null && IsVisbleFrom(baseCandidate.RemoveMethod, eventDef.RemoveMethod))
return true;
return false;
var fld = member as FieldDefinition;
if (fld != null)
return (MethodAttributes)fld.Attributes;
var method = member as MethodDefinition;
if (method != null)
return method.Attributes;
var prop = member as PropertyDefinition;
if (prop != null) {
return (prop.GetMethod ?? prop.SetMethod).Attributes;
}
var evnt = member as EventDefinition;
if (evnt != null) {
return (evnt.AddMethod ?? evnt.RemoveMethod).Attributes;
}
var nestedType = member as TypeDefinition;
if (nestedType != null) {
if (nestedType.IsNestedPrivate)
return MethodAttributes.Private;
if (nestedType.IsNestedAssembly || nestedType.IsNestedFamilyAndAssembly)
return MethodAttributes.Assembly;
return MethodAttributes.Public;
}
throw new NotSupportedException();
}
private static bool MatchMethod(GenericContext<MethodDefinition> candidate, GenericContext<MethodDefinition> method)
@ -161,7 +229,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -161,7 +229,7 @@ namespace ICSharpCode.Decompiler.Ast
if (mCandidate.HasOverrides)
return false;
if (!IsSameType(candidate.ResolveWithContext(mCandidate.ReturnType), method.ResolveWithContext(mMethod.ReturnType)))
if (mCandidate.IsSpecialName != method.Item.IsSpecialName)
return false;
if (mCandidate.HasGenericParameters || mMethod.HasGenericParameters) {
@ -208,9 +276,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -208,9 +276,6 @@ namespace ICSharpCode.Decompiler.Ast
if ((mCandidate.GetMethod ?? mCandidate.SetMethod).HasOverrides)
return false;
if (!IsSameType(candidate.ResolveWithContext(mCandidate.PropertyType), property.ResolveWithContext(mProperty.PropertyType)))
return false;
if (mCandidate.HasParameters || mProperty.HasParameters) {
if (!mCandidate.HasParameters || !mProperty.HasParameters || mCandidate.Parameters.Count != mProperty.Parameters.Count)
return false;
@ -242,6 +307,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -242,6 +307,9 @@ namespace ICSharpCode.Decompiler.Ast
private static bool MatchParameters(GenericContext<ParameterDefinition> baseParameterType, GenericContext<ParameterDefinition> parameterType)
{
if (baseParameterType.Item.IsIn != parameterType.Item.IsIn ||
baseParameterType.Item.IsOut != parameterType.Item.IsOut)
return false;
var baseParam = baseParameterType.ResolveWithContext(baseParameterType.Item.ParameterType);
var param = parameterType.ResolveWithContext(parameterType.Item.ParameterType);
return IsSameType(baseParam, param);
@ -254,8 +322,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -254,8 +322,12 @@ namespace ICSharpCode.Decompiler.Ast
if (tr1 == null || tr2 == null)
return false;
if (tr1.GetType() != tr2.GetType())
return false;
if (tr1.Name == tr2.Name && tr1.FullName == tr2.FullName)
return true;
return false;
}
@ -288,6 +360,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -288,6 +360,10 @@ namespace ICSharpCode.Decompiler.Ast
struct GenericContext<T> where T : class
{
private static readonly ReadOnlyCollection<TypeReference> Empty = new ReadOnlyCollection<TypeReference>(new List<TypeReference>());
private static readonly GenericParameter UnresolvedGenericTypeParameter =
new DummyGenericParameterProvider(false).DummyParameter;
private static readonly GenericParameter UnresolvedGenericMethodParameter =
new DummyGenericParameterProvider(true).DummyParameter;
public readonly T Item;
public readonly ReadOnlyCollection<TypeReference> TypeArguments;
@ -324,28 +400,99 @@ namespace ICSharpCode.Decompiler.Ast @@ -324,28 +400,99 @@ namespace ICSharpCode.Decompiler.Ast
public TypeReference ResolveWithContext(TypeReference type)
{
var genericParameter = type as GenericParameter;
if (genericParameter != null && genericParameter.Owner.GenericParameterType == GenericParameterType.Type) {
if (genericParameter != null)
if (genericParameter.Owner.GenericParameterType == GenericParameterType.Type)
return this.TypeArguments[genericParameter.Position];
else
return genericParameter.Owner.GenericParameterType == GenericParameterType.Type
? UnresolvedGenericTypeParameter : UnresolvedGenericMethodParameter;
var typeSpecification = type as TypeSpecification;
if (typeSpecification != null) {
var resolvedElementType = ResolveWithContext(typeSpecification.ElementType);
return ReplaceElementType(typeSpecification, resolvedElementType);
}
var arrayType = type as ArrayType;
return type.ResolveOrThrow();
}
private TypeReference ReplaceElementType(TypeSpecification ts, TypeReference newElementType)
{
var arrayType = ts as ArrayType;
if (arrayType != null) {
var resolvedElementType = ResolveWithContext(arrayType.ElementType);
if (resolvedElementType == null)
return null;
if (resolvedElementType == arrayType.ElementType)
if (newElementType == arrayType.ElementType)
return arrayType;
var newArrayType = new ArrayType(resolvedElementType, arrayType.Rank);
var newArrayType = new ArrayType(newElementType, arrayType.Rank);
for (int dimension = 0; dimension < arrayType.Rank; dimension++)
newArrayType.Dimensions[dimension] = arrayType.Dimensions[dimension];
return newArrayType;
}
return type.ResolveOrThrow();
var byReferenceType = ts as ByReferenceType;
if (byReferenceType != null) {
return new ByReferenceType(newElementType);
}
// TODO: should we throw an exception instead calling Resolve method?
return ts.ResolveOrThrow();
}
public GenericContext<T2> ApplyTo<T2>(T2 item) where T2 : class
{
return new GenericContext<T2>(item, this.TypeArguments);
}
private class DummyGenericParameterProvider : IGenericParameterProvider
{
readonly Mono.Cecil.GenericParameterType type;
readonly Mono.Collections.Generic.Collection<GenericParameter> parameters;
public DummyGenericParameterProvider(bool methodTypeParameter)
{
type = methodTypeParameter ? Mono.Cecil.GenericParameterType.Method :
Mono.Cecil.GenericParameterType.Type;
parameters = new Mono.Collections.Generic.Collection<GenericParameter>(1);
parameters.Add(new GenericParameter(this));
}
public GenericParameter DummyParameter
{
get { return parameters[0]; }
}
bool IGenericParameterProvider.HasGenericParameters
{
get { throw new NotImplementedException(); }
}
bool IGenericParameterProvider.IsDefinition
{
get { throw new NotImplementedException(); }
}
ModuleDefinition IGenericParameterProvider.Module
{
get { throw new NotImplementedException(); }
}
Mono.Collections.Generic.Collection<GenericParameter> IGenericParameterProvider.GenericParameters
{
get { return parameters; }
}
GenericParameterType IGenericParameterProvider.GenericParameterType
{
get { return type; }
}
MetadataToken IMetadataTokenProvider.MetadataToken
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
}
}
}

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -209,6 +209,21 @@ namespace ICSharpCode.Decompiler @@ -209,6 +209,21 @@ namespace ICSharpCode.Decompiler
}
}
bool showXmlDocumentation = true;
/// <summary>
/// Gets/Sets whether to include XML documentation comments in the decompiled code
/// </summary>
public bool ShowXmlDocumentation {
get { return showXmlDocumentation; }
set {
if (showXmlDocumentation != value) {
showXmlDocumentation = value;
OnPropertyChanged("ShowXmlDocumentation");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)

4
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -69,7 +69,7 @@ @@ -69,7 +69,7 @@
<None Include="Types\S_EnumSamples.cs" />
<None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" />
<Compile Include="Helpers\RemoveCompilerAttribute.cs" />
<None Include="Types\S_TypeMemberDeclarations.cs" />
<Compile Include="Types\S_TypeMemberDeclarations.cs" />
<Compile Include="Types\EnumTests.cs" />
<Compile Include="Types\TypeTests.cs" />
<Compile Include="DelegateConstruction.cs" />
@ -107,4 +107,4 @@ @@ -107,4 +107,4 @@
<None Include="StackTests\StackTests.il" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>
</Project>

460
ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs

@ -428,8 +428,8 @@ namespace IndexerOverrideRestrictedAccessorOnly @@ -428,8 +428,8 @@ namespace IndexerOverrideRestrictedAccessorOnly
}
}
}
//$$ PropertyHiding
namespace PropertyHiding
//$$ HideProperty
namespace HideProperty
{
public class A
{
@ -467,8 +467,397 @@ namespace PropertyHiding @@ -467,8 +467,397 @@ namespace PropertyHiding
}
}
}
//$$ IndexerHidingGeneric
namespace IndexerHidingGeneric
//$$ HideMembers
namespace HideMembers
{
public class A
{
public int F;
public int Prop
{
get
{
return 3;
}
}
public int G
{
get
{
return 3;
}
}
}
public class B : A
{
public new int F
{
get
{
return 3;
}
}
public new string Prop
{
get
{
return "a";
}
}
}
public class C : A
{
public new int G;
}
public class D : A
{
public new void F()
{
}
}
public class D1 : D
{
public new int F;
}
public class E : A
{
private new class F
{
}
}
}
//$$ HideMembers2
namespace HideMembers2
{
public class G
{
public int Item
{
get
{
return 1;
}
}
}
public class G2 : G
{
public int this[int i]
{
get
{
return 2;
}
}
}
public class G3 : G2
{
public new int Item
{
get
{
return 4;
}
}
}
public class H
{
public int this[int j]
{
get
{
return 0;
}
}
}
public class H2 : H
{
public int Item
{
get
{
return 2;
}
}
}
public class H3 : H2
{
public new string this[int j]
{
get
{
return null;
}
}
}
}
//$$ HideMembers2a
namespace HideMembers2a
{
public interface IA
{
int this[int i]
{
get;
}
}
public class A : IA
{
int IA.this[int i]
{
get
{
throw new NotImplementedException();
}
}
}
public class A1 : A
{
public int this[int i]
{
get
{
return 3;
}
}
}
}
//$$ HideMembers3
namespace HideMembers3
{
public class G<T>
{
public void M1(T p)
{
}
public int M2(int t)
{
return 3;
}
}
public class G1<T> : G<int>
{
public new int M1(int i)
{
return 0;
}
public int M2(T i)
{
return 2;
}
}
public class G2<T> : G<int>
{
public int M1(T p)
{
return 4;
}
}
public class J
{
public int P
{
get
{
return 2;
}
}
}
public class J2 : J
{
public int get_P;
}
}
//$$ HideMembers4
namespace HideMembers4
{
public class A
{
public void M<T>(T t)
{
}
}
public class A1 : A
{
public new void M<K>(K t)
{
}
public void M(int t)
{
}
}
public class B
{
public void M<T>()
{
}
public void M1<T>()
{
}
public void M2<T>(T t)
{
}
}
public class B1 : B
{
public void M<T1, T2>()
{
}
public new void M1<R>()
{
}
public new void M2<R>(R r)
{
}
}
public class C<T>
{
public void M<TT>(T t)
{
}
}
public class C1<K> : C<K>
{
public void M<TT>(TT t)
{
}
}
}
//$$ HideMembers5
namespace HideMembers5
{
public class A
{
public void M(int t)
{
}
}
public class A1 : A
{
public void M(ref int t)
{
}
}
public class B
{
public void M(ref int l)
{
}
}
public class B1 : B
{
public void M(out int l)
{
l = 2;
}
public void M(ref long l)
{
}
}
}
//$$ HideMemberSkipNotVisible
namespace HideMemberSkipNotVisible
{
public class A
{
protected int F;
protected string P
{
get
{
return null;
}
}
}
public class B : A
{
private new string F;
private new int P
{
set
{
}
}
}
}
//$$ HideNestedClass
namespace HideNestedClass
{
public class A
{
public class N1
{
}
protected class N2
{
}
private class N3
{
}
internal class N4
{
}
protected internal class N5
{
}
}
public class B : A
{
public new int N1;
public new int N2;
public int N3;
public new int N4;
public new int N5;
}
}
//$$ HidePropertyReservedMethod
namespace HidePropertyReservedMethod
{
public class A
{
public int P
{
get
{
return 1;
}
}
}
public class B : A
{
public int get_P()
{
return 2;
}
public void set_P(int value)
{
}
}
}
//$$ HideIndexerDiffAccessor
namespace HideIndexerDiffAccessor
{
public class A
{
public int this[int i]
{
get
{
return 2;
}
}
}
public class B : A
{
public new int this[int j]
{
set
{
}
}
}
}
//$$ HideIndexerGeneric
namespace HideIndexerGeneric
{
public class A<T>
{
@ -515,8 +904,8 @@ namespace IndexerHidingGeneric @@ -515,8 +904,8 @@ namespace IndexerHidingGeneric
}
}
}
//$$ MethodHiding
namespace MethodHiding
//$$ HideMethod
namespace HideMethod
{
public class A
{
@ -539,8 +928,8 @@ namespace MethodHiding @@ -539,8 +928,8 @@ namespace MethodHiding
}
}
}
//$$ MethodHideGeneric
namespace MethodHideGeneric
//$$ HideMethodGeneric
namespace HideMethodGeneric
{
public class A<T>
{
@ -583,8 +972,8 @@ namespace MethodHideGeneric @@ -583,8 +972,8 @@ namespace MethodHideGeneric
}
}
}
//$$ MethodHideGenericSkipPrivate
namespace MethodHideGenericSkipPrivate
//$$ HideMethodGenericSkipPrivate
namespace HideMethodGenericSkipPrivate
{
public class A<T>
{
@ -617,8 +1006,8 @@ namespace MethodHideGenericSkipPrivate @@ -617,8 +1006,8 @@ namespace MethodHideGenericSkipPrivate
}
}
}
//$$ MethodHideGeneric2
namespace MethodHideGeneric2
//$$ HideMethodGeneric2
namespace HideMethodGeneric2
{
public class A
{
@ -669,8 +1058,51 @@ namespace MethodHideGeneric2 @@ -669,8 +1058,51 @@ namespace MethodHideGeneric2
}
}
}
//$$ EventHiding
namespace EventHiding
//$$ HideMethodDiffSignatures
namespace HideMethodDiffSignatures
{
public class C1<T>
{
public virtual void M(T arg)
{
}
}
public class C2<T1, T2> : C1<T2>
{
public new virtual void M(T2 arg)
{
}
}
public class C3 : C2<int, bool>
{
public new virtual void M(bool arg)
{
}
}
}
//$$ HideMethodStatic
namespace HideMethodStatic
{
public class A
{
public int N
{
get
{
return 0;
}
}
}
public class B
{
public int N()
{
return 0;
}
}
}
//$$ HideEvent
namespace HideEvent
{
public class A
{

24
ILSpy/CSharpLanguage.cs

@ -32,6 +32,7 @@ using ICSharpCode.Decompiler; @@ -32,6 +32,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.ILSpy.Baml;
using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -89,8 +90,7 @@ namespace ICSharpCode.ILSpy @@ -89,8 +90,7 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true);
codeDomBuilder.AddMethod(method);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
@ -98,8 +98,7 @@ namespace ICSharpCode.ILSpy @@ -98,8 +98,7 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true);
codeDomBuilder.AddProperty(property);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
@ -107,8 +106,7 @@ namespace ICSharpCode.ILSpy @@ -107,8 +106,7 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true);
codeDomBuilder.AddField(field);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
@ -116,16 +114,22 @@ namespace ICSharpCode.ILSpy @@ -116,16 +114,22 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true);
codeDomBuilder.AddEvent(ev);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
codeDomBuilder.AddType(type);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options)
{
astBuilder.RunTransformations(transformAbortCondition);
if (options.DecompilerSettings.ShowXmlDocumentation)
AddXmlDocTransform.Run(astBuilder.CompilationUnit);
astBuilder.GenerateCode(output);
}
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)

1
ILSpy/DecompilerSettingsPanel.xaml

@ -7,5 +7,6 @@ @@ -7,5 +7,6 @@
<CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox>
<CheckBox IsChecked="{Binding QueryExpressions}" IsEnabled="{Binding AnonymousMethods}">Decompile query expressions</CheckBox>
<CheckBox IsChecked="{Binding UseDebugSymbols}">Use variable names from debug symbols, if available</CheckBox>
<CheckBox IsChecked="{Binding ShowXmlDocumentation}">Show XML documentation in decompiled code</CheckBox>
</StackPanel>
</UserControl>

2
ILSpy/DecompilerSettingsPanel.xaml.cs

@ -62,6 +62,7 @@ namespace ICSharpCode.ILSpy @@ -62,6 +62,7 @@ namespace ICSharpCode.ILSpy
s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn;
s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions;
s.UseDebugSymbols = (bool?)e.Attribute("useDebugSymbols") ?? s.UseDebugSymbols;
s.ShowXmlDocumentation = (bool?)e.Attribute("xmlDoc") ?? s.ShowXmlDocumentation;
return s;
}
@ -73,6 +74,7 @@ namespace ICSharpCode.ILSpy @@ -73,6 +74,7 @@ namespace ICSharpCode.ILSpy
section.SetAttributeValue("yieldReturn", s.YieldReturn);
section.SetAttributeValue("queryExpressions", s.QueryExpressions);
section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols);
section.SetAttributeValue("xmlDoc", s.ShowXmlDocumentation);
XElement existingElement = root.Element("DecompilerSettings");
if (existingElement != null)

1
ILSpy/ILSpy.csproj

@ -156,6 +156,7 @@ @@ -156,6 +156,7 @@
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />
<Compile Include="XmlDoc\AddXmlDocTransform.cs" />
<Compile Include="XmlDoc\XmlDocKeyProvider.cs" />
<Compile Include="XmlDoc\XmlDocLoader.cs" />
<Compile Include="XmlDoc\XmlDocRenderer.cs" />

6
ILSpy/TextView/DecompilerTextView.cs

@ -138,17 +138,17 @@ namespace ICSharpCode.ILSpy.TextView @@ -138,17 +138,17 @@ namespace ICSharpCode.ILSpy.TextView
} else if (mr is MethodReference) {
mr = ((MethodReference)mr).Resolve() ?? mr;
}
XmlDocRenderer renderer = new XmlDocRenderer();
renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr));
XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module);
if (docProvider != null) {
XmlDocRenderer renderer = new XmlDocRenderer();
renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr));
string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
if (documentation != null) {
renderer.AppendText(Environment.NewLine);
renderer.AddXmlDocumentation(documentation);
}
return renderer.CreateTextBlock();
}
return renderer.CreateTextBlock();
}
return null;
}

80
ILSpy/XmlDoc/AddXmlDocTransform.cs

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// 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.IO;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.XmlDoc
{
/// <summary>
/// Adds XML documentation for member definitions.
/// </summary>
static class AddXmlDocTransform
{
public static void Run(AstNode node)
{
if (node is AttributedNode) {
MemberReference mr = node.Annotation<MemberReference>();
if (mr != null && mr.Module != null) {
var xmldoc = XmlDocLoader.LoadDocumentation(mr.Module);
if (xmldoc != null) {
string doc = xmldoc.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
if (doc != null) {
InsertXmlDocumentation(node, new StringReader(doc));
}
}
}
if (!(node is TypeDeclaration))
return; // don't recurse into attributed nodes, except for type definitions
}
foreach (AstNode child in node.Children)
Run(child);
}
static void InsertXmlDocumentation(AstNode node, StringReader r)
{
// Find the first non-empty line:
string firstLine;
do {
firstLine = r.ReadLine();
if (firstLine == null)
return;
} while (string.IsNullOrWhiteSpace(firstLine));
string indentation = firstLine.Substring(0, firstLine.Length - firstLine.TrimStart().Length);
string line = firstLine;
int skippedWhitespaceLines = 0;
// Copy all lines from input to output, except for empty lines at the end.
while (line != null) {
if (string.IsNullOrWhiteSpace(line)) {
skippedWhitespaceLines++;
} else {
while (skippedWhitespaceLines > 0) {
node.Parent.InsertChildBefore(node, new Comment(string.Empty, CommentType.Documentation), AstNode.Roles.Comment);
skippedWhitespaceLines--;
}
if (line.StartsWith(indentation, StringComparison.Ordinal))
line = line.Substring(indentation.Length);
node.Parent.InsertChildBefore(node, new Comment(" " + line, CommentType.Documentation), AstNode.Roles.Comment);
}
line = r.ReadLine();
}
}
}
}
Loading…
Cancel
Save