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 @@ -50,10 +50,15 @@ namespace ICSharpCode.Decompiler.Ast
return true;
}
FieldDefinition field = member as FieldDefinition;
if (field != null) {
if (settings.AnonymousMethods && field.Name.StartsWith("CS$<>", StringComparison.Ordinal) && field.IsCompilerGenerated())
if (field != null && 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;
}
// event-fields are not [CompilerGenerated]
if (field != null && settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
return true;
return false;
}
@ -161,6 +166,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -161,6 +166,7 @@ namespace ICSharpCode.Decompiler.Ast
TypeDefinition oldCurrentType = context.CurrentType;
context.CurrentType = typeDef;
TypeDeclaration astType = new TypeDeclaration();
ConvertAttributes(astType, typeDef);
astType.AddAnnotation(typeDef);
astType.Modifiers = ConvertModifiers(typeDef);
astType.Name = CleanName(typeDef.Name);
@ -224,7 +230,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -224,7 +230,6 @@ namespace ICSharpCode.Decompiler.Ast
AddTypeMembers(astType, typeDef);
}
ConvertAttributes(astType, typeDef);
context.CurrentType = oldCurrentType;
return astType;
}
@ -239,9 +244,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -239,9 +244,12 @@ namespace ICSharpCode.Decompiler.Ast
int pos = name.LastIndexOf('`');
if (pos >= 0)
name = name.Substring(0, pos);
pos = name.LastIndexOf('.');
if (pos >= 0)
name = name.Substring(pos + 1);
return name;
}
#region Convert Type Reference
/// <summary>
/// Converts a type reference.
@ -497,6 +505,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -497,6 +505,7 @@ namespace ICSharpCode.Decompiler.Ast
return modifiers;
}
#endregion
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
@ -511,11 +520,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -511,11 +520,9 @@ namespace ICSharpCode.Decompiler.Ast
foreach(EventDefinition eventDef in typeDef.Events) {
astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole);
}
// Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) {
astType.AddChild(CreateProperty(propDef), TypeDeclaration.MemberRole);
}
CreateProperties(astType, typeDef);
// Add constructors
foreach(MethodDefinition methodDef in typeDef.Methods) {
@ -532,6 +539,35 @@ namespace ICSharpCode.Decompiler.Ast @@ -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)
{
// Create mapping - used in debugger
@ -547,7 +583,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -547,7 +583,10 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
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);
}
ConvertAttributes(astMethod, methodDef);
@ -613,11 +652,48 @@ namespace ICSharpCode.Decompiler.Ast @@ -613,11 +652,48 @@ namespace ICSharpCode.Decompiler.Ast
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 astProp = new PropertyDeclaration();
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.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) {
@ -627,8 +703,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -627,8 +703,12 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context)
}.WithAnnotation(propDef.GetMethod);
ConvertAttributes(astProp.Getter, propDef.GetMethod);
if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask;
if (methodMapping != null)
astProp.Getter.AddAnnotation(methodMapping);
}
@ -639,9 +719,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -639,9 +719,13 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context)
}.WithAnnotation(propDef.SetMethod);
ConvertAttributes(astProp.Setter, propDef.SetMethod);
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)
astProp.Setter.AddAnnotation(methodMapping);
}
@ -655,7 +739,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -655,7 +739,10 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.AddAnnotation(eventDef);
astEvent.Name = CleanName(eventDef.Name);
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) {
// Create mapping - used in debugger
MethodMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(CSharpCodeMapping.SourceCodeMappings);
@ -882,20 +969,27 @@ namespace ICSharpCode.Decompiler.Ast @@ -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);
#region FieldOffsetAttribute
if (fieldDefinition.HasLayoutInfo) {
Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute));
Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute), fieldDefinition.Module);
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
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 @@ -936,6 +1030,7 @@ namespace ICSharpCode.Decompiler.Ast
var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
foreach (var customAttribute in customAttributeProvider.CustomAttributes) {
var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
attribute.AddAnnotation(customAttribute);
attribute.Type = ConvertType(customAttribute.AttributeType);
attributes.Add(attribute);
@ -1066,5 +1161,19 @@ namespace ICSharpCode.Decompiler.Ast @@ -1066,5 +1161,19 @@ namespace ICSharpCode.Decompiler.Ast
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 @@ -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

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

@ -65,8 +65,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -65,8 +65,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation<FieldDefinition>();
if (fieldDef == null)
break;
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldDecl == null)
AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldOrEventDecl == null)
break;
allSame = true;
@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (allSame) {
foreach (var ctor in instanceCtors)
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);
}

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

@ -14,11 +14,27 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -14,11 +14,27 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
/// </summary>
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)
{
TransformUsings(compilationUnit);
TransformForeach(compilationUnit);
if (context.Settings.UsingStatement)
TransformUsings(compilationUnit);
if (context.Settings.ForEachStatement)
TransformForeach(compilationUnit);
TransformFor(compilationUnit);
TransformDoWhile(compilationUnit);
if (context.Settings.AutomaticProperties)
TransformAutomaticProperties(compilationUnit);
if (context.Settings.AutomaticEvents)
TransformAutomaticEvents(compilationUnit);
}
/// <summary>
@ -99,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -99,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#endregion
#region foreach
UsingStatement foreachPattern = new UsingStatement {
static readonly UsingStatement foreachPattern = new UsingStatement {
ResourceAcquisition = new VariableDeclarationStatement {
Type = new AnyNode("enumeratorType"),
Variables = {
@ -188,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -188,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#endregion
#region for
WhileStatement forPattern = new WhileStatement {
static readonly WhileStatement forPattern = new WhileStatement {
Condition = new BinaryOperatorExpression {
Left = new NamedNode("ident", new IdentifierExpression()),
Operator = BinaryOperatorType.Any,
@ -206,8 +222,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -206,8 +222,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Right = new AnyNode()
}))
}
}
};
}};
public void TransformFor(AstNode compilationUnit)
{
@ -237,5 +252,207 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -237,5 +252,207 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
}
#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 @@ -19,7 +19,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return new IAstTransform[] {
new PushNegation(),
new DelegateConstruction(context),
new PatternStatementTransform(),
new PatternStatementTransform(context),
new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(),
};

60
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -41,6 +41,66 @@ namespace ICSharpCode.Decompiler @@ -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;
protected virtual void OnPropertyChanged(string propertyName)

11
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -458,11 +458,22 @@ namespace ICSharpCode.Decompiler.ILAst @@ -458,11 +458,22 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Rethrow:
case ILCode.LoopOrSwitchBreak:
case ILCode.LoopContinue:
case ILCode.YieldBreak:
return null;
case ILCode.Ret:
if (forceInferChildren && expr.Arguments.Count == 1)
InferTypeForExpression(expr.Arguments[0], context.CurrentMethod.ReturnType);
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
case ILCode.Pop:
return null;

15
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

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

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

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

6
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

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

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

@ -57,6 +57,7 @@ @@ -57,6 +57,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\EnumTests.cs" />
<Compile Include="Types\TypeTests.cs" />
<Compile Include="DelegateConstruction.cs" />

3
ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs

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

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

@ -0,0 +1,305 @@ @@ -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 @@ -8,5 +8,10 @@ namespace ICSharpCode.Decompiler.Tests.Types
{
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 @@ -100,4 +100,19 @@ public static class YieldReturn
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 @@ @@ -122,6 +122,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="XamlResourceNode.cs" />
<EmbeddedResource Include="..\README.txt">
<Link>README.txt</Link>
</EmbeddedResource>

67
ILSpy/XamlResourceNode.cs

@ -0,0 +1,67 @@ @@ -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 @@ -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>
/// Gets the first child with the specified role.
/// 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 @@ -53,6 +53,30 @@ namespace ICSharpCode.NRefactory.CSharp
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)
{
switch (Type.GetTypeCode(type)) {

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

@ -72,7 +72,10 @@ namespace ICSharpCode.NRefactory.CSharp @@ -72,7 +72,10 @@ namespace ICSharpCode.NRefactory.CSharp
new KeyValuePair<Modifiers, int>(Modifiers.Volatile, "volatile".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Extern, "extern".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 {

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

@ -66,4 +66,9 @@ namespace ICSharpCode.NRefactory.CSharp @@ -66,4 +66,9 @@ namespace ICSharpCode.NRefactory.CSharp
//Final = 0x400000,
//Literal = 0x800000,
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 @@ -34,6 +34,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return p != null ? new TypePlaceholder(p) : null;
}
public AstType ToType()
{
return new TypePlaceholder(this);
}
public static implicit operator Expression(Pattern p)
{
return p != null ? new ExpressionPlaceholder(p) : null;
@ -64,6 +69,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -64,6 +69,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
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
public override string ToString()
{

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

@ -152,4 +152,33 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -152,4 +152,33 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
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 @@ -56,8 +56,12 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.Body); }
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);
}

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

@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp
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 @@ -202,8 +202,20 @@ namespace ICSharpCode.NRefactory.CSharp
{
WriteCommaSeparatedListInParenthesis(list.SafeCast<ParameterDeclaration, AstNode>(), spaceWithin);
}
#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)
{
WriteToken("[", AstNode.Roles.LBracket);
@ -1815,7 +1827,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1815,7 +1827,7 @@ namespace ICSharpCode.NRefactory.CSharp
WritePrivateImplementationType(indexerDeclaration.PrivateImplementationType);
WriteKeyword("this");
Space(policy.BeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(indexerDeclaration.Parameters, policy.WithinMethodDeclarationParentheses);
WriteCommaSeparatedListInBrackets(indexerDeclaration.Parameters, policy.WithinMethodDeclarationParentheses);
OpenBrace(policy.PropertyBraceStyle);
// output get/set in their original order
foreach (AstNode node in indexerDeclaration.Children) {

Loading…
Cancel
Save