Browse Source

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

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
35e781f2f5
  1. 139
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 3
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 6
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  4. 229
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  5. 2
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  6. 60
      ICSharpCode.Decompiler/DecompilerSettings.cs
  7. 11
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  8. 15
      ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
  9. 85
      ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs
  10. 6
      ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
  11. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  12. 3
      ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs
  13. 305
      ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
  14. 5
      ICSharpCode.Decompiler/Tests/Types/TypeTests.cs
  15. 15
      ICSharpCode.Decompiler/Tests/YieldReturn.cs
  16. 1
      ILSpy/ILSpy.csproj
  17. 67
      ILSpy/XamlResourceNode.cs
  18. 9
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs
  19. 24
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs
  20. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs
  21. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Modifiers.cs
  22. 10
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs
  23. 29
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs
  24. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs
  25. 2
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs
  26. 16
      NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

139
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -50,10 +50,15 @@ namespace ICSharpCode.Decompiler.Ast
return true; return true;
} }
FieldDefinition field = member as FieldDefinition; FieldDefinition field = member as FieldDefinition;
if (field != null) { if (field != null && field.IsCompilerGenerated()) {
if (settings.AnonymousMethods && field.Name.StartsWith("CS$<>", StringComparison.Ordinal) && field.IsCompilerGenerated()) if (settings.AnonymousMethods && field.Name.StartsWith("CS$<>", StringComparison.Ordinal))
return true;
if (settings.AutomaticProperties && field.Name.StartsWith("<", StringComparison.Ordinal) && field.Name.EndsWith("BackingField", StringComparison.Ordinal))
return true; return true;
} }
// event-fields are not [CompilerGenerated]
if (field != null && settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
return true;
return false; return false;
} }
@ -161,6 +166,7 @@ namespace ICSharpCode.Decompiler.Ast
TypeDefinition oldCurrentType = context.CurrentType; TypeDefinition oldCurrentType = context.CurrentType;
context.CurrentType = typeDef; context.CurrentType = typeDef;
TypeDeclaration astType = new TypeDeclaration(); TypeDeclaration astType = new TypeDeclaration();
ConvertAttributes(astType, typeDef);
astType.AddAnnotation(typeDef); astType.AddAnnotation(typeDef);
astType.Modifiers = ConvertModifiers(typeDef); astType.Modifiers = ConvertModifiers(typeDef);
astType.Name = CleanName(typeDef.Name); astType.Name = CleanName(typeDef.Name);
@ -224,7 +230,6 @@ namespace ICSharpCode.Decompiler.Ast
AddTypeMembers(astType, typeDef); AddTypeMembers(astType, typeDef);
} }
ConvertAttributes(astType, typeDef);
context.CurrentType = oldCurrentType; context.CurrentType = oldCurrentType;
return astType; return astType;
} }
@ -239,9 +244,12 @@ namespace ICSharpCode.Decompiler.Ast
int pos = name.LastIndexOf('`'); int pos = name.LastIndexOf('`');
if (pos >= 0) if (pos >= 0)
name = name.Substring(0, pos); name = name.Substring(0, pos);
pos = name.LastIndexOf('.');
if (pos >= 0)
name = name.Substring(pos + 1);
return name; return name;
} }
#region Convert Type Reference #region Convert Type Reference
/// <summary> /// <summary>
/// Converts a type reference. /// Converts a type reference.
@ -497,6 +505,7 @@ namespace ICSharpCode.Decompiler.Ast
return modifiers; return modifiers;
} }
#endregion #endregion
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
@ -511,11 +520,9 @@ namespace ICSharpCode.Decompiler.Ast
foreach(EventDefinition eventDef in typeDef.Events) { foreach(EventDefinition eventDef in typeDef.Events) {
astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole); astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole);
} }
// Add properties // Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) { CreateProperties(astType, typeDef);
astType.AddChild(CreateProperty(propDef), TypeDeclaration.MemberRole);
}
// Add constructors // Add constructors
foreach(MethodDefinition methodDef in typeDef.Methods) { foreach(MethodDefinition methodDef in typeDef.Methods) {
@ -532,6 +539,35 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
private void CreateProperties(TypeDeclaration astType, TypeDefinition typeDef)
{
CustomAttribute attributeToRemove = null;
foreach (PropertyDefinition propDef in typeDef.Properties) {
MemberDeclaration astProp = CreateProperty(propDef);
if (astProp.Name == "Item" && propDef.HasParameters) {
var defaultMember = GetDefaultMember(astType.Annotation<TypeDefinition>());
if (defaultMember.Item1 == "Item") {
astProp = ConvertPropertyToIndexer((PropertyDeclaration)astProp, propDef);
attributeToRemove = defaultMember.Item2;
} else if ((propDef.GetMethod ?? propDef.SetMethod).HasOverrides) {
astProp = ConvertPropertyToIndexer((PropertyDeclaration)astProp, propDef);
}
}
astType.AddChild(astProp, TypeDeclaration.MemberRole);
}
if (attributeToRemove != null) {
var astAttr = astType.Attributes.SelectMany(sec => sec.Attributes).First(attr => attr.Annotation<CustomAttribute>() == attributeToRemove);
var attrSection = (AttributeSection)astAttr.Parent;
if (attrSection.Attributes.Count == 1)
attrSection.Remove();
else
astAttr.Remove();
}
}
MethodDeclaration CreateMethod(MethodDefinition methodDef) MethodDeclaration CreateMethod(MethodDefinition methodDef)
{ {
// Create mapping - used in debugger // Create mapping - used in debugger
@ -547,7 +583,10 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters)); astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
if (!methodDef.DeclaringType.IsInterface) { if (!methodDef.DeclaringType.IsInterface) {
astMethod.Modifiers = ConvertModifiers(methodDef); if (!methodDef.HasOverrides)
astMethod.Modifiers = ConvertModifiers(methodDef);
else
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
} }
ConvertAttributes(astMethod, methodDef); ConvertAttributes(astMethod, methodDef);
@ -613,11 +652,48 @@ namespace ICSharpCode.Decompiler.Ast
return astMethod; return astMethod;
} }
IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef)
{
var astIndexer = new IndexerDeclaration();
astIndexer.Name = astProp.Name;
astIndexer.CopyAnnotationsFrom(astProp);
astProp.Attributes.MoveTo(astIndexer.Attributes);
astIndexer.Modifiers = astProp.Modifiers;
astIndexer.PrivateImplementationType = astProp.PrivateImplementationType.Detach();
astIndexer.ReturnType = astProp.ReturnType.Detach();
astIndexer.Getter = astProp.Getter.Detach();
astIndexer.Setter = astProp.Setter.Detach();
astIndexer.Parameters.AddRange(MakeParameters(propDef.Parameters));
return astIndexer;
}
Modifiers FixUpVisibility(Modifiers m)
{
Modifiers v = m & Modifiers.VisibilityMask;
// If any of the modifiers is public, use that
if ((v & Modifiers.Public) == Modifiers.Public)
return Modifiers.Public | (m & ~Modifiers.VisibilityMask);
// If both modifiers are private, no need to fix anything
if (v == Modifiers.Private)
return m;
// Otherwise, use the other modifiers (internal and/or protected)
return m & ~Modifiers.Private;
}
PropertyDeclaration CreateProperty(PropertyDefinition propDef) PropertyDeclaration CreateProperty(PropertyDefinition propDef)
{ {
PropertyDeclaration astProp = new PropertyDeclaration(); PropertyDeclaration astProp = new PropertyDeclaration();
astProp.AddAnnotation(propDef); astProp.AddAnnotation(propDef);
astProp.Modifiers = ConvertModifiers(propDef.GetMethod ?? propDef.SetMethod); var accessor = propDef.GetMethod ?? propDef.SetMethod;
Modifiers getterModifiers = Modifiers.None;
Modifiers setterModifiers = Modifiers.None;
if (!propDef.DeclaringType.IsInterface && !accessor.HasOverrides) {
getterModifiers = ConvertModifiers(propDef.GetMethod);
setterModifiers = ConvertModifiers(propDef.SetMethod);
astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers);
} else if (accessor.HasOverrides) {
astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType);
}
astProp.Name = CleanName(propDef.Name); astProp.Name = CleanName(propDef.Name);
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
@ -627,8 +703,12 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Getter = new Accessor { astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context)
}.WithAnnotation(propDef.GetMethod); }.WithAnnotation(propDef.GetMethod);
ConvertAttributes(astProp.Getter, propDef.GetMethod); ConvertAttributes(astProp.Getter, propDef.GetMethod);
if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask;
if (methodMapping != null) if (methodMapping != null)
astProp.Getter.AddAnnotation(methodMapping); astProp.Getter.AddAnnotation(methodMapping);
} }
@ -639,9 +719,13 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Setter = new Accessor { astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context)
}.WithAnnotation(propDef.SetMethod); }.WithAnnotation(propDef.SetMethod);
ConvertAttributes(astProp.Setter, propDef.SetMethod); ConvertAttributes(astProp.Setter, propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param); ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param);
if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask;
if (methodMapping != null) if (methodMapping != null)
astProp.Setter.AddAnnotation(methodMapping); astProp.Setter.AddAnnotation(methodMapping);
} }
@ -655,7 +739,10 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.AddAnnotation(eventDef); astEvent.AddAnnotation(eventDef);
astEvent.Name = CleanName(eventDef.Name); astEvent.Name = CleanName(eventDef.Name);
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef); astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); if (eventDef.AddMethod == null || !eventDef.AddMethod.HasOverrides)
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
else
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
if (eventDef.AddMethod != null) { if (eventDef.AddMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MethodMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(CSharpCodeMapping.SourceCodeMappings); MethodMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(CSharpCodeMapping.SourceCodeMappings);
@ -882,20 +969,27 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
void ConvertAttributes(AttributedNode attributedNode, FieldDefinition fieldDefinition) internal static void ConvertAttributes(AttributedNode attributedNode, FieldDefinition fieldDefinition, AttributeTarget target = AttributeTarget.None)
{ {
ConvertCustomAttributes(attributedNode, fieldDefinition); ConvertCustomAttributes(attributedNode, fieldDefinition);
#region FieldOffsetAttribute #region FieldOffsetAttribute
if (fieldDefinition.HasLayoutInfo) { if (fieldDefinition.HasLayoutInfo) {
Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute)); Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute), fieldDefinition.Module);
fieldOffset.Arguments.Add(new PrimitiveExpression(fieldDefinition.Offset)); fieldOffset.Arguments.Add(new PrimitiveExpression(fieldDefinition.Offset));
attributedNode.Attributes.Add(new AttributeSection(fieldOffset)); attributedNode.Attributes.Add(new AttributeSection(fieldOffset) { AttributeTarget = target });
}
#endregion
#region NonSerializedAttribute
if (fieldDefinition.IsNotSerialized) {
Ast.Attribute nonSerialized = CreateNonCustomAttribute(typeof(NonSerializedAttribute), fieldDefinition.Module);
attributedNode.Attributes.Add(new AttributeSection(nonSerialized) { AttributeTarget = target });
} }
#endregion #endregion
if (fieldDefinition.HasMarshalInfo) { if (fieldDefinition.HasMarshalInfo) {
attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module))); attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module)) { AttributeTarget = target });
} }
} }
@ -936,6 +1030,7 @@ namespace ICSharpCode.Decompiler.Ast
var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>(); var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
foreach (var customAttribute in customAttributeProvider.CustomAttributes) { foreach (var customAttribute in customAttributeProvider.CustomAttributes) {
var attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
attribute.AddAnnotation(customAttribute);
attribute.Type = ConvertType(customAttribute.AttributeType); attribute.Type = ConvertType(customAttribute.AttributeType);
attributes.Add(attribute); attributes.Add(attribute);
@ -1066,5 +1161,19 @@ namespace ICSharpCode.Decompiler.Ast
return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute"); return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute");
} }
/// <summary>
/// Gets the name of the default member of the type pointed by the <see cref="System.Reflection.DefaultMemberAttribute"/> attribute.
/// </summary>
/// <param name="type">The type definition.</param>
/// <returns>The name of the default member or null if no <see cref="System.Reflection.DefaultMemberAttribute"/> attribute has been found.</returns>
private static Tuple<string, CustomAttribute> GetDefaultMember(TypeDefinition type)
{
foreach (CustomAttribute ca in type.CustomAttributes)
if (ca.Constructor.FullName == "System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)")
return Tuple.Create(ca.ConstructorArguments.Single().Value as string, ca);
return new Tuple<string,CustomAttribute>(null, null);
}
} }
} }

3
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -610,6 +610,9 @@ namespace ICSharpCode.Decompiler.Ast
}; };
} }
} }
} else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") {
AdjustArgumentsForMethodCall(cecilMethod, methodArgs);
return target.Invoke(methodArgs);
} }
} }
// Default invocation // Default invocation

6
ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -65,8 +65,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation<FieldDefinition>(); FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation<FieldDefinition>();
if (fieldDef == null) if (fieldDef == null)
break; break;
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef); AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldDecl == null) if (fieldOrEventDecl == null)
break; break;
allSame = true; allSame = true;
@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (allSame) { if (allSame) {
foreach (var ctor in instanceCtors) foreach (var ctor in instanceCtors)
ctor.Body.First().Remove(); ctor.Body.First().Remove();
fieldDecl.Variables.Single().Initializer = m.Get<Expression>("initializer").Single().Detach(); fieldOrEventDecl.GetChildrenByRole(AstNode.Roles.Variable).Single().Initializer = m.Get<Expression>("initializer").Single().Detach();
} }
} while (allSame); } while (allSame);
} }

229
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -14,11 +14,27 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
/// </summary> /// </summary>
public class PatternStatementTransform : IAstTransform public class PatternStatementTransform : IAstTransform
{ {
DecompilerContext context;
public PatternStatementTransform(DecompilerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public void Run(AstNode compilationUnit) public void Run(AstNode compilationUnit)
{ {
TransformUsings(compilationUnit); if (context.Settings.UsingStatement)
TransformForeach(compilationUnit); TransformUsings(compilationUnit);
if (context.Settings.ForEachStatement)
TransformForeach(compilationUnit);
TransformFor(compilationUnit); TransformFor(compilationUnit);
TransformDoWhile(compilationUnit);
if (context.Settings.AutomaticProperties)
TransformAutomaticProperties(compilationUnit);
if (context.Settings.AutomaticEvents)
TransformAutomaticEvents(compilationUnit);
} }
/// <summary> /// <summary>
@ -99,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#endregion #endregion
#region foreach #region foreach
UsingStatement foreachPattern = new UsingStatement { static readonly UsingStatement foreachPattern = new UsingStatement {
ResourceAcquisition = new VariableDeclarationStatement { ResourceAcquisition = new VariableDeclarationStatement {
Type = new AnyNode("enumeratorType"), Type = new AnyNode("enumeratorType"),
Variables = { Variables = {
@ -188,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#endregion #endregion
#region for #region for
WhileStatement forPattern = new WhileStatement { static readonly WhileStatement forPattern = new WhileStatement {
Condition = new BinaryOperatorExpression { Condition = new BinaryOperatorExpression {
Left = new NamedNode("ident", new IdentifierExpression()), Left = new NamedNode("ident", new IdentifierExpression()),
Operator = BinaryOperatorType.Any, Operator = BinaryOperatorType.Any,
@ -206,8 +222,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Right = new AnyNode() Right = new AnyNode()
})) }))
} }
} }};
};
public void TransformFor(AstNode compilationUnit) public void TransformFor(AstNode compilationUnit)
{ {
@ -237,5 +252,207 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
} }
#endregion #endregion
#region doWhile
static readonly WhileStatement doWhilePattern = new WhileStatement {
Condition = new PrimitiveExpression(true),
EmbeddedStatement = new BlockStatement {
Statements = {
new Repeat(new AnyNode("statement")),
new IfElseStatement {
Condition = new AnyNode("condition"),
TrueStatement = new BlockStatement { new BreakStatement() }
}
}
}};
public void TransformDoWhile(AstNode compilationUnit)
{
foreach (WhileStatement whileLoop in compilationUnit.Descendants.OfType<WhileStatement>().ToArray()) {
Match m = doWhilePattern.Match(whileLoop);
if (m != null) {
DoWhileStatement doLoop = new DoWhileStatement();
doLoop.Condition = new UnaryOperatorExpression(UnaryOperatorType.Not, m.Get<Expression>("condition").Single().Detach());
doLoop.Condition.AcceptVisitor(new PushNegation(), null);
BlockStatement block = (BlockStatement)whileLoop.EmbeddedStatement;
block.Statements.Last().Remove(); // remove if statement
doLoop.EmbeddedStatement = block.Detach();
whileLoop.ReplaceWith(doLoop);
// we may have to extract variable definitions out of the loop if they were used in the condition:
foreach (var varDecl in block.Statements.OfType<VariableDeclarationStatement>()) {
VariableInitializer v = varDecl.Variables.Single();
if (doLoop.Condition.DescendantsAndSelf.OfType<IdentifierExpression>().Any(i => i.Identifier == v.Name)) {
AssignmentExpression assign = new AssignmentExpression(new IdentifierExpression(v.Name), v.Initializer.Detach());
// move annotations from v to assign:
assign.CopyAnnotationsFrom(v);
v.RemoveAnnotations<object>();
// remove varDecl with assignment; and move annotations from varDecl to the ExpressionStatement:
varDecl.ReplaceWith(new ExpressionStatement(assign).CopyAnnotationsFrom(varDecl));
varDecl.RemoveAnnotations<object>();
// insert the varDecl above the do-while loop:
doLoop.Parent.InsertChildBefore(doLoop, varDecl, BlockStatement.StatementRole);
}
}
}
}
}
#endregion
#region Automatic Properties
static readonly PropertyDeclaration automaticPropertyPattern = new PropertyDeclaration {
Attributes = { new Repeat(new AnyNode()) },
Modifiers = Modifiers.Any,
ReturnType = new AnyNode(),
Getter = new Accessor {
Attributes = { new Repeat(new AnyNode()) },
Modifiers = Modifiers.Any,
Body = new BlockStatement {
new ReturnStatement {
Expression = new NamedNode("fieldReference", new MemberReferenceExpression { Target = new ThisReferenceExpression() })
}
}
},
Setter = new Accessor {
Attributes = { new Repeat(new AnyNode()) },
Modifiers = Modifiers.Any,
Body = new BlockStatement {
new AssignmentExpression {
Left = new Backreference("fieldReference"),
Right = new IdentifierExpression("value")
}
}}};
void TransformAutomaticProperties(AstNode compilationUnit)
{
foreach (var property in compilationUnit.Descendants.OfType<PropertyDeclaration>()) {
PropertyDefinition cecilProperty = property.Annotation<PropertyDefinition>();
if (cecilProperty == null || cecilProperty.GetMethod == null || cecilProperty.SetMethod == null)
continue;
if (!(cecilProperty.GetMethod.IsCompilerGenerated() && cecilProperty.SetMethod.IsCompilerGenerated()))
continue;
Match m = automaticPropertyPattern.Match(property);
if (m != null) {
FieldDefinition field = m.Get("fieldReference").Single().Annotation<FieldDefinition>();
if (field.IsCompilerGenerated()) {
RemoveCompilerGeneratedAttribute(property.Getter.Attributes);
RemoveCompilerGeneratedAttribute(property.Setter.Attributes);
property.Getter.Body = null;
property.Setter.Body = null;
}
}
}
}
void RemoveCompilerGeneratedAttribute(AstNodeCollection<AttributeSection> attributeSections)
{
foreach (AttributeSection section in attributeSections) {
foreach (var attr in section.Attributes) {
TypeReference tr = attr.Type.Annotation<TypeReference>();
if (tr != null && tr.Namespace == "System.Runtime.CompilerServices" && tr.Name == "CompilerGeneratedAttribute") {
attr.Remove();
}
}
if (section.Attributes.Count == 0)
section.Remove();
}
}
#endregion
#region Automatic Events
Accessor automaticEventPatternV4 = new Accessor {
Body = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("type"),
Variables = {
new NamedNode(
"var1", new VariableInitializer {
Initializer = new NamedNode("field", new MemberReferenceExpression { Target = new ThisReferenceExpression() })
})}
},
new VariableDeclarationStatement {
Type = new Backreference("type"),
Variables = { new NamedNode("var2", new VariableInitializer()) }
},
new DoWhileStatement {
EmbeddedStatement = new BlockStatement {
new AssignmentExpression(new IdentifierExpressionBackreference("var2"), new IdentifierExpressionBackreference("var1")),
new VariableDeclarationStatement {
Type = new Backreference("type"),
Variables = {
new NamedNode(
"var3", new VariableInitializer {
Initializer = new AnyNode("delegateCombine").ToExpression().Invoke(
new IdentifierExpressionBackreference("var2"),
new IdentifierExpression("value")
).CastTo(new Backreference("type"))
})
}},
new AssignmentExpression {
Left = new IdentifierExpressionBackreference("var1"),
Right = new AnyNode("Interlocked").ToType().Invoke(
"CompareExchange",
new AstType[] { new Backreference("type") }, // type argument
new Expression[] { // arguments
new DirectionExpression { FieldDirection = FieldDirection.Ref, Expression = new Backreference("field") },
new IdentifierExpressionBackreference("var3"),
new IdentifierExpressionBackreference("var2")
}
)}
},
Condition = new BinaryOperatorExpression {
Left = new IdentifierExpressionBackreference("var1"),
Operator = BinaryOperatorType.InEquality,
Right = new IdentifierExpressionBackreference("var2")
}}
}};
bool CheckAutomaticEventV4Match(Match m, CustomEventDeclaration ev, bool isAddAccessor)
{
if (m == null)
return false;
if (m.Get<MemberReferenceExpression>("field").Single().MemberName != ev.Name)
return false; // field name must match event name
if (ev.ReturnType.Match(m.Get("type").Single()) == null)
return false; // variable types must match event type
var combineMethod = m.Get("delegateCombine").Single().Parent.Annotation<MethodReference>();
if (combineMethod == null || combineMethod.Name != (isAddAccessor ? "Combine" : "Remove"))
return false;
if (combineMethod.DeclaringType.FullName != "System.Delegate")
return false;
var ice = m.Get("Interlocked").Single().Annotation<TypeReference>();
return ice != null && ice.FullName == "System.Threading.Interlocked";
}
void TransformAutomaticEvents(AstNode compilationUnit)
{
foreach (var ev in compilationUnit.Descendants.OfType<CustomEventDeclaration>().ToArray()) {
Match m1 = automaticEventPatternV4.Match(ev.AddAccessor);
if (!CheckAutomaticEventV4Match(m1, ev, true))
continue;
Match m2 = automaticEventPatternV4.Match(ev.RemoveAccessor);
if (!CheckAutomaticEventV4Match(m2, ev, false))
continue;
EventDeclaration ed = new EventDeclaration();
ev.Attributes.MoveTo(ed.Attributes);
ed.ReturnType = ev.ReturnType.Detach();
ed.Modifiers = ev.Modifiers;
ed.Variables.Add(new VariableInitializer(ev.Name));
ed.CopyAnnotationsFrom(ev);
EventDefinition eventDef = ev.Annotation<EventDefinition>();
if (eventDef != null) {
FieldDefinition field = eventDef.DeclaringType.Fields.FirstOrDefault(f => f.Name == ev.Name);
if (field != null) {
ed.AddAnnotation(field);
AstBuilder.ConvertAttributes(ed, field, AttributeTarget.Field);
}
}
ev.ReplaceWith(ed);
}
}
#endregion
} }
} }

2
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -19,7 +19,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return new IAstTransform[] { return new IAstTransform[] {
new PushNegation(), new PushNegation(),
new DelegateConstruction(context), new DelegateConstruction(context),
new PatternStatementTransform(), new PatternStatementTransform(context),
new ConvertConstructorCallIntoInitializer(), new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(), new ReplaceMethodCallsWithOperators(),
}; };

60
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -41,6 +41,66 @@ namespace ICSharpCode.Decompiler
} }
} }
bool automaticProperties = true;
/// <summary>
/// Decompile automatic properties
/// </summary>
public bool AutomaticProperties {
get { return automaticProperties; }
set {
if (automaticProperties != value) {
automaticProperties = value;
OnPropertyChanged("AutomaticProperties");
}
}
}
bool automaticEvents = true;
/// <summary>
/// Decompile automatic events
/// </summary>
public bool AutomaticEvents {
get { return automaticEvents; }
set {
if (automaticEvents != value) {
automaticEvents = value;
OnPropertyChanged("AutomaticEvents");
}
}
}
bool usingStatement = true;
/// <summary>
/// Decompile using statements.
/// </summary>
public bool UsingStatement {
get { return usingStatement; }
set {
if (usingStatement != value) {
usingStatement = value;
OnPropertyChanged("UsingStatement");
}
}
}
bool forEachStatement = true;
/// <summary>
/// Decompile foreach statements.
/// </summary>
public bool ForEachStatement {
get { return forEachStatement; }
set {
if (forEachStatement != value) {
forEachStatement = value;
OnPropertyChanged("ForEachStatement");
}
}
}
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) protected virtual void OnPropertyChanged(string propertyName)

11
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -458,11 +458,22 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Rethrow: case ILCode.Rethrow:
case ILCode.LoopOrSwitchBreak: case ILCode.LoopOrSwitchBreak:
case ILCode.LoopContinue: case ILCode.LoopContinue:
case ILCode.YieldBreak:
return null; return null;
case ILCode.Ret: case ILCode.Ret:
if (forceInferChildren && expr.Arguments.Count == 1) if (forceInferChildren && expr.Arguments.Count == 1)
InferTypeForExpression(expr.Arguments[0], context.CurrentMethod.ReturnType); InferTypeForExpression(expr.Arguments[0], context.CurrentMethod.ReturnType);
return null; return null;
case ILCode.YieldReturn:
if (forceInferChildren) {
GenericInstanceType genericType = context.CurrentMethod.ReturnType as GenericInstanceType;
if (genericType != null) { // IEnumerable<T> or IEnumerator<T>
InferTypeForExpression(expr.Arguments[0], genericType.GenericArguments[0]);
} else { // non-generic IEnumerable or IEnumerator
InferTypeForExpression(expr.Arguments[0], typeSystem.Object);
}
}
return null;
#endregion #endregion
case ILCode.Pop: case ILCode.Pop:
return null; return null;

15
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -690,18 +690,19 @@ namespace ICSharpCode.Decompiler.ILAst
// Now verify that the last instruction in the body is 'ret(false)' // Now verify that the last instruction in the body is 'ret(false)'
if (returnVariable != null) { if (returnVariable != null) {
// If we don't have a return variable, we already verified that above. // If we don't have a return variable, we already verified that above.
if (bodyLength < 2) // If we do have one, check for 'stloc(returnVariable, ldc.i4(0))'
throw new YieldAnalysisFailedException();
ILExpression leave = body[bodyLength - 1] as ILExpression; // Maybe might be a jump to the return label after the stloc:
if (leave == null || leave.Operand != returnLabel || !(leave.Code == ILCode.Br || leave.Code == ILCode.Leave)) ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
throw new YieldAnalysisFailedException(); if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel)
ILExpression store0 = body[bodyLength - 2] as ILExpression; bodyLength--;
ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable) if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0) if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
bodyLength -= 2; // don't conside the 'ret(false)' part of the body bodyLength--; // don't conside the stloc instruction to be part of the body
} }
// verify that the last element in the body is a label pointing to the 'ret(false)' // verify that the last element in the body is a label pointing to the 'ret(false)'
returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel; returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;

85
ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs

@ -134,7 +134,21 @@ namespace AppliedToPropertySet
[MyAttribute] [MyAttribute]
set set
{ {
return; }
}
}
}
//$$ AppliedToIndexer
namespace AppliedToIndexer
{
public class TestClass
{
[Obsolete("reason")]
public int this[int i]
{
get
{
return 0;
} }
} }
} }
@ -177,7 +191,7 @@ namespace AppliedToParameter
} }
public class MyClass public class MyClass
{ {
public void Method([MyAttribute]int val) public void Method([MyAttribute] int val)
{ {
} }
} }
@ -204,7 +218,6 @@ namespace NamedInitializerPropertyString
} }
set set
{ {
return;
} }
} }
} }
@ -227,7 +240,6 @@ namespace NamedInitializerPropertyType
} }
set set
{ {
return;
} }
} }
} }
@ -250,7 +262,6 @@ namespace NamedInitializerPropertyEnum
} }
set set
{ {
return;
} }
} }
} }
@ -321,7 +332,6 @@ namespace TargetPropertySetParam
[param: MyAttribute] [param: MyAttribute]
set set
{ {
return;
} }
} }
} }
@ -344,13 +354,66 @@ namespace TargetPropertySetReturn
[return: MyAttribute] [return: MyAttribute]
set set
{ {
return;
} }
} }
} }
} }
//$$ TargetPropertyIndexSetParam //$$ TargetPropertyIndexGetReturn
namespace TargetPropertyIndexSetParam namespace TargetPropertyIndexGetReturn
{
[AttributeUsage(AttributeTargets.All)]
public class MyAttributeAttribute : Attribute
{
}
public class MyClass
{
public int this[string s]
{
[return: MyAttribute]
get
{
return 3;
}
}
}
}
//$$ TargetPropertyIndexParamOnlySet
namespace TargetPropertyIndexParamOnlySet
{
[AttributeUsage(AttributeTargets.All)]
public class MyAttributeAttribute : Attribute
{
}
public class MyClass
{
public int this[[MyAttribute] string s]
{
set
{
}
}
}
}
//$$ TargetPropertyIndexParamOnlyGet
namespace TargetPropertyIndexParamOnlyGet
{
[AttributeUsage(AttributeTargets.All)]
public class MyAttributeAttribute : Attribute
{
}
public class MyClass
{
public int this[[MyAttribute] string s]
{
get
{
return 3;
}
}
}
}
//$$ TargetPropertyIndexSetReturn
namespace TargetPropertyIndexSetReturn
{ {
[AttributeUsage(AttributeTargets.All)] [AttributeUsage(AttributeTargets.All)]
public class MyAttributeAttribute : Attribute public class MyAttributeAttribute : Attribute
@ -364,10 +427,9 @@ namespace TargetPropertyIndexSetParam
{ {
return ""; return "";
} }
[param: MyAttribute] [return: MyAttribute]
set set
{ {
return;
} }
} }
} }
@ -391,7 +453,6 @@ namespace TargetPropertyIndexSetMultiParam
[param: MyAttribute] [param: MyAttribute]
set set
{ {
return;
} }
} }
} }

6
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

@ -43,7 +43,8 @@ public static class DelegateConstruction
public static List<Action<int>> AnonymousMethodStoreWithinLoop() public static List<Action<int>> AnonymousMethodStoreWithinLoop()
{ {
List<Action<int>> list = new List<Action<int>>(); List<Action<int>> list = new List<Action<int>>();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++)
{
int counter; int counter;
list.Add(x => counter = x); list.Add(x => counter = x);
} }
@ -54,7 +55,8 @@ public static class DelegateConstruction
{ {
List<Action<int>> list = new List<Action<int>>(); List<Action<int>> list = new List<Action<int>>();
int counter; int counter;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++)
{
list.Add(x => counter = x); list.Add(x => counter = x);
} }
return list; return list;

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

@ -57,6 +57,7 @@
<None Include="Types\S_EnumSamples.cs" /> <None Include="Types\S_EnumSamples.cs" />
<None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" /> <None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" />
<Compile Include="Helpers\RemoveCompilerAttribute.cs" /> <Compile Include="Helpers\RemoveCompilerAttribute.cs" />
<None Include="Types\S_TypeMemberDeclarations.cs" />
<Compile Include="Types\EnumTests.cs" /> <Compile Include="Types\EnumTests.cs" />
<Compile Include="Types\TypeTests.cs" /> <Compile Include="Types\TypeTests.cs" />
<Compile Include="DelegateConstruction.cs" /> <Compile Include="DelegateConstruction.cs" />

3
ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs

@ -39,6 +39,9 @@ public class PropertiesAndEvents
public event EventHandler AutomaticEvent; public event EventHandler AutomaticEvent;
[field: NonSerialized]
public event EventHandler AutomaticEventWithInitializer = delegate {};
public event EventHandler CustomEvent { public event EventHandler CustomEvent {
add { add {
this.AutomaticEvent += value; this.AutomaticEvent += value;

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

@ -0,0 +1,305 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
//$CS
using System;
//$CE
//$$ IndexerWithGetOnly
namespace IndexerWithGetOnly
{
public class MyClass
{
public int this[int i]
{
get
{
return i;
}
}
}
}
//$$ IndexerWithSetOnly
namespace IndexerWithSetOnly
{
public class MyClass
{
public int this[int i]
{
set
{
}
}
}
}
//$$ IndexerWithMoreParameters
namespace IndexerWithMoreParameters
{
public class MyClass
{
public int this[int i, string s, Type t]
{
get
{
return 0;
}
}
}
}
//$$ IndexerInGenericClass
namespace IndexerInGenericClass
{
public class MyClass<T>
{
public int this[T t]
{
get
{
return 0;
}
}
}
}
//$$ OverloadedIndexer
namespace OverloadedIndexer
{
public class MyClass
{
public int this[int t]
{
get
{
return 0;
}
}
public int this[string s]
{
get
{
return 0;
}
set
{
Console.WriteLine(value + " " + s);
}
}
}
}
//$$ IndexerInInterface
namespace IndexerInInterface
{
public interface IInterface
{
int this[string s, string s2]
{
set;
}
}
}
//$$ IndexerInterfaceExplicitImplementation
namespace IndexerInterfaceExplicitImplementation
{
public interface IMyInterface
{
int this[string s]
{
get;
}
}
public class MyClass : IMyInterface
{
int IMyInterface.this[string s]
{
get
{
return 3;
}
}
}
}
//$$ IndexerInterfaceImplementation
namespace IndexerInterfaceImplementation
{
public interface IMyInterface
{
int this[string s]
{
get;
}
}
public class MyClass : IMyInterface
{
public int this[string s]
{
get
{
return 3;
}
}
}
}
//$$ IndexerAbstract
namespace IndexerAbstract
{
public abstract class MyClass
{
public abstract int this[string s, string s2]
{
set;
}
protected abstract string this[int index]
{
get;
}
}
}
//$$ MethodExplicit
namespace MethodExplicit
{
public interface IMyInterface
{
void MyMethod();
}
public class MyClass : IMyInterface
{
void IMyInterface.MyMethod()
{
}
}
}
//$$ MethodFromInterfaceVirtual
namespace MethodFromInterfaceVirtual
{
public interface IMyInterface
{
void MyMethod();
}
public class MyClass : IMyInterface
{
public virtual void MyMethod()
{
}
}
}
//$$ MethodFromInterface
namespace MethodFromInterface
{
public interface IMyInterface
{
void MyMethod();
}
public class MyClass : IMyInterface
{
public void MyMethod()
{
}
}
}
//$$ MethodFromInterfaceAbstract
namespace MethodFromInterfaceAbstract
{
public interface IMyInterface
{
void MyMethod();
}
public abstract class MyClass : IMyInterface
{
public abstract void MyMethod();
}
}
//$$ PropertyInterface
namespace PropertyInterface
{
public interface IMyInterface
{
int MyProperty
{
get;
set;
}
}
}
//$$ PropertyInterfaceExplicitImplementation
namespace PropertyInterfaceExplicitImplementation
{
public interface IMyInterface
{
int MyProperty
{
get;
set;
}
}
public class MyClass : IMyInterface
{
int IMyInterface.MyProperty
{
get
{
return 0;
}
set
{
}
}
}
}
//$$ PropertyInterfaceImplementation
namespace PropertyInterfaceImplementation
{
public interface IMyInterface
{
int MyProperty
{
get;
set;
}
}
public class MyClass : IMyInterface
{
public int MyProperty
{
get
{
return 0;
}
set
{
}
}
}
}
//$$ PropertyPrivateGetPublicSet
namespace PropertyPrivateGetPublicSet
{
public class MyClass
{
public int MyProperty
{
private get
{
return 3;
}
set
{
}
}
}
}
//$$ PropertyPublicGetProtectedSet
namespace PropertyPublicGetProtectedSet
{
public class MyClass
{
public int MyProperty
{
get
{
return 3;
}
protected set
{
}
}
}
}

5
ICSharpCode.Decompiler/Tests/Types/TypeTests.cs

@ -8,5 +8,10 @@ namespace ICSharpCode.Decompiler.Tests.Types
{ {
public class TypeTests : DecompilerTestBase public class TypeTests : DecompilerTestBase
{ {
[Test]
public void TypeMemberDeclarations()
{
ValidateFileRoundtrip(@"Types\S_TypeMemberDeclarations.cs");
}
} }
} }

15
ICSharpCode.Decompiler/Tests/YieldReturn.cs

@ -100,4 +100,19 @@ public static class YieldReturn
yield return () => copy; yield return () => copy;
} }
} }
public static IEnumerable<int> GetEvenNumbers(int n)
{
for (int i = 0; i < n; i++) {
if (i % 2 == 0)
yield return i;
}
}
public static IEnumerable<char> YieldChars()
{
yield return 'a';
yield return 'b';
yield return 'c';
}
} }

1
ILSpy/ILSpy.csproj

@ -122,6 +122,7 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="XamlResourceNode.cs" />
<EmbeddedResource Include="..\README.txt"> <EmbeddedResource Include="..\README.txt">
<Link>README.txt</Link> <Link>README.txt</Link>
</EmbeddedResource> </EmbeddedResource>

67
ILSpy/XamlResourceNode.cs

@ -0,0 +1,67 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading.Tasks;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.Xaml
{
[Export(typeof(IResourceNodeFactory))]
sealed class XamlResourceNodeFactory : IResourceNodeFactory
{
public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource)
{
return null;
}
public ILSpyTreeNode CreateNode(string key, Stream data)
{
if (key.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase))
return new XamlResourceEntryNode(key, data);
else
return null;
}
}
sealed class XamlResourceEntryNode : ResourceEntryNode
{
string xaml;
public XamlResourceEntryNode(string key, Stream data) : base(key, data)
{
}
internal override bool View(DecompilerTextView textView)
{
AvalonEditTextOutput output = new AvalonEditTextOutput();
IHighlightingDefinition highlighting = null;
textView.RunWithCancellation(
token => Task.Factory.StartNew(
() => {
try {
// cache read XAML because stream will be closed after first read
if (xaml == null) {
using (var reader = new StreamReader(data)) {
xaml = reader.ReadToEnd();
}
}
output.Write(xaml);
highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml");
} catch (Exception ex) {
output.Write(ex.ToString());
}
return output;
}),
t => textView.Show(t.Result, highlighting)
);
return true;
}
}
}

9
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs

@ -157,6 +157,15 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
/// <summary>
/// Gets all descendants of this node (including this node itself).
/// </summary>
public IEnumerable<AstNode> DescendantsAndSelf {
get {
return Utils.TreeTraversal.PreOrder(this, n => n.Children);
}
}
/// <summary> /// <summary>
/// Gets the first child with the specified role. /// Gets the first child with the specified role.
/// Returns the role's null object if the child is not found. /// Returns the role's null object if the child is not found.

24
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs

@ -53,6 +53,30 @@ namespace ICSharpCode.NRefactory.CSharp
return new TypeReferenceExpression { Type = this }.Member(memberName); return new TypeReferenceExpression { Type = this }.Member(memberName);
} }
/// <summary>
/// Builds an invocation expression using this type as target.
/// </summary>
public InvocationExpression Invoke(string methodName, IEnumerable<Expression> arguments)
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, arguments);
}
/// <summary>
/// Builds an invocation expression using this type as target.
/// </summary>
public InvocationExpression Invoke(string methodName, params Expression[] arguments)
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, arguments);
}
/// <summary>
/// Builds an invocation expression using this type as target.
/// </summary>
public InvocationExpression Invoke(string methodName, IEnumerable<AstType> typeArguments, IEnumerable<Expression> arguments)
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, typeArguments, arguments);
}
public static AstType Create(Type type) public static AstType Create(Type type)
{ {
switch (Type.GetTypeCode(type)) { switch (Type.GetTypeCode(type)) {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs

@ -72,7 +72,10 @@ namespace ICSharpCode.NRefactory.CSharp
new KeyValuePair<Modifiers, int>(Modifiers.Volatile, "volatile".Length), new KeyValuePair<Modifiers, int>(Modifiers.Volatile, "volatile".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Extern, "extern".Length), new KeyValuePair<Modifiers, int>(Modifiers.Extern, "extern".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Partial, "partial".Length), new KeyValuePair<Modifiers, int>(Modifiers.Partial, "partial".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Const, "const".Length) new KeyValuePair<Modifiers, int>(Modifiers.Const, "const".Length),
// even though it's used for patterns only, it needs to be in this table to be usable in the AST
new KeyValuePair<Modifiers, int>(Modifiers.Any, "any".Length)
}; };
public static IEnumerable<Modifiers> AllModifiers { public static IEnumerable<Modifiers> AllModifiers {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Modifiers.cs

@ -66,4 +66,9 @@ namespace ICSharpCode.NRefactory.CSharp
//Final = 0x400000, //Final = 0x400000,
//Literal = 0x800000, //Literal = 0x800000,
VisibilityMask = Private | Internal | Protected | Public, VisibilityMask = Private | Internal | Protected | Public,
/// <summary>
/// Special value used to match any modifiers during pattern matching.
/// </summary>
Any = unchecked((int)0x80000000)
}} }}

10
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs

@ -34,6 +34,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return p != null ? new TypePlaceholder(p) : null; return p != null ? new TypePlaceholder(p) : null;
} }
public AstType ToType()
{
return new TypePlaceholder(this);
}
public static implicit operator Expression(Pattern p) public static implicit operator Expression(Pattern p)
{ {
return p != null ? new ExpressionPlaceholder(p) : null; return p != null ? new ExpressionPlaceholder(p) : null;
@ -64,6 +69,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return p != null ? new VariablePlaceholder(p) : null; return p != null ? new VariablePlaceholder(p) : null;
} }
public static implicit operator AttributeSection(Pattern p)
{
return p != null ? new AttributeSectionPlaceholder(p) : null;
}
// Make debugging easier by giving Patterns a ToString() implementation // Make debugging easier by giving Patterns a ToString() implementation
public override string ToString() public override string ToString()
{ {

29
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs

@ -152,4 +152,33 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return child.DoMatchCollection(role, pos, match, backtrackingStack); return child.DoMatchCollection(role, pos, match, backtrackingStack);
} }
} }
sealed class AttributeSectionPlaceholder : AttributeSection
{
readonly AstNode child;
public AttributeSectionPlaceholder(AstNode child)
{
this.child = child;
}
public override NodeType NodeType {
get { return NodeType.Placeholder; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, child, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return child.DoMatch(other, match);
}
internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack<Pattern.PossibleMatch> backtrackingStack)
{
return child.DoMatchCollection(role, pos, match, backtrackingStack);
}
}
} }

8
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs

@ -56,8 +56,12 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.Body); } get { return GetChildByRole (Roles.Body); }
set { SetChildByRole (Roles.Body, value); } set { SetChildByRole (Roles.Body, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole(Roles.Parameter); }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{ {
return visitor.VisitAccessor (this, data); return visitor.VisitAccessor (this, data);
} }

2
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs

@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected bool MatchAttributesAndModifiers(AttributedNode o, PatternMatching.Match match) protected bool MatchAttributesAndModifiers(AttributedNode o, PatternMatching.Match match)
{ {
return this.Modifiers == o.Modifiers && this.Attributes.DoMatch(o.Attributes, match); return (this.Modifiers == Modifiers.Any || this.Modifiers == o.Modifiers) && this.Attributes.DoMatch(o.Attributes, match);
} }
} }
} }

16
NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

@ -202,8 +202,20 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
WriteCommaSeparatedListInParenthesis(list.SafeCast<ParameterDeclaration, AstNode>(), spaceWithin); WriteCommaSeparatedListInParenthesis(list.SafeCast<ParameterDeclaration, AstNode>(), spaceWithin);
} }
#endif #endif
void WriteCommaSeparatedListInBrackets(IEnumerable<ParameterDeclaration> list, bool spaceWithin)
{
WriteToken("[", AstNode.Roles.LBracket);
if (list.Any()) {
Space(spaceWithin);
WriteCommaSeparatedList(list.SafeCast<ParameterDeclaration, AstNode>());
Space(spaceWithin);
}
WriteToken("]", AstNode.Roles.RBracket);
}
void WriteCommaSeparatedListInBrackets(IEnumerable<Expression> list) void WriteCommaSeparatedListInBrackets(IEnumerable<Expression> list)
{ {
WriteToken("[", AstNode.Roles.LBracket); WriteToken("[", AstNode.Roles.LBracket);
@ -1815,7 +1827,7 @@ namespace ICSharpCode.NRefactory.CSharp
WritePrivateImplementationType(indexerDeclaration.PrivateImplementationType); WritePrivateImplementationType(indexerDeclaration.PrivateImplementationType);
WriteKeyword("this"); WriteKeyword("this");
Space(policy.BeforeMethodDeclarationParentheses); Space(policy.BeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(indexerDeclaration.Parameters, policy.WithinMethodDeclarationParentheses); WriteCommaSeparatedListInBrackets(indexerDeclaration.Parameters, policy.WithinMethodDeclarationParentheses);
OpenBrace(policy.PropertyBraceStyle); OpenBrace(policy.PropertyBraceStyle);
// output get/set in their original order // output get/set in their original order
foreach (AstNode node in indexerDeclaration.Children) { foreach (AstNode node in indexerDeclaration.Children) {

Loading…
Cancel
Save