diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
index 0b12dff5b..ee5e00268 100644
--- a/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
+++ b/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
@@ -215,6 +215,7 @@
+
IBackgroundRenderer.cs
diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
index b4860eb7d..c0258db0b 100644
--- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
@@ -125,8 +125,28 @@ namespace ICSharpCode.Decompiler.Ast
public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false)
{
+ if (assemblyDefinition.Name.Version != null) {
+ astCompileUnit.AddChild(
+ new AttributeSection {
+ AttributeTarget = "assembly",
+ Attributes = {
+ new NRefactory.CSharp.Attribute {
+ Type = new SimpleType("AssemblyVersion")
+ .WithAnnotation(new TypeReference(
+ "System.Reflection", "AssemblyVersionAttribute",
+ assemblyDefinition.MainModule, assemblyDefinition.MainModule.TypeSystem.Corlib)),
+ Arguments = {
+ new PrimitiveExpression(assemblyDefinition.Name.Version.ToString())
+ }
+ }
+ }
+ }, AttributedNode.AttributeRole);
+ }
+
ConvertCustomAttributes(astCompileUnit, assemblyDefinition, "assembly");
+ ConvertSecurityAttributes(astCompileUnit, assemblyDefinition, "assembly");
ConvertCustomAttributes(astCompileUnit, assemblyDefinition.MainModule, "module");
+ AddTypeForwarderAttributes(astCompileUnit, assemblyDefinition.MainModule, "assembly");
if (!onlyAssemblyLevel) {
foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) {
@@ -141,6 +161,30 @@ namespace ICSharpCode.Decompiler.Ast
}
}
+ void AddTypeForwarderAttributes(CompilationUnit astCompileUnit, ModuleDefinition module, string target)
+ {
+ if (!module.HasExportedTypes)
+ return;
+ foreach (ExportedType type in module.ExportedTypes) {
+ if (type.IsForwarder) {
+ var forwardedType = CreateTypeOfExpression(new TypeReference(type.Namespace, type.Name, module, type.Scope));
+ astCompileUnit.AddChild(
+ new AttributeSection {
+ AttributeTarget = target,
+ Attributes = {
+ new NRefactory.CSharp.Attribute {
+ Type = new SimpleType("TypeForwardedTo")
+ .WithAnnotation(new TypeReference(
+ "System.Runtime.CompilerServices", "TypeForwardedToAttribute",
+ module, module.TypeSystem.Corlib)),
+ Arguments = { forwardedType }
+ }
+ }
+ }, AttributedNode.AttributeRole);
+ }
+ }
+ }
+
NamespaceDeclaration GetCodeNamespace(string name)
{
if (string.IsNullOrEmpty(name)) {
@@ -228,15 +272,6 @@ namespace ICSharpCode.Decompiler.Ast
astType.TypeParameters.AddRange(MakeTypeParameters(genericParameters));
astType.Constraints.AddRange(MakeConstraints(genericParameters));
- // Nested types
- foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
- if (MemberIsHidden(nestedTypeDef, context.Settings))
- continue;
- var nestedType = CreateType(nestedTypeDef);
- SetNewModifier(nestedType);
- astType.AddChild(nestedType, TypeDeclaration.MemberRole);
- }
-
AttributedNode result = astType;
if (typeDef.IsEnum) {
long expectedEnumMemberValue = 0;
@@ -314,6 +349,45 @@ namespace ICSharpCode.Decompiler.Ast
return name;
}
+ #region Create TypeOf Expression
+ ///
+ /// Creates a typeof-expression for the specified type.
+ ///
+ public static TypeOfExpression CreateTypeOfExpression(TypeReference type)
+ {
+ return new TypeOfExpression(AddEmptyTypeArgumentsForUnboundGenerics(ConvertType(type)));
+ }
+
+ static AstType AddEmptyTypeArgumentsForUnboundGenerics(AstType type)
+ {
+ TypeReference typeRef = type.Annotation();
+ if (typeRef == null)
+ return type;
+ TypeDefinition typeDef = typeRef.Resolve(); // need to resolve to figure out the number of type parameters
+ if (typeDef == null || !typeDef.HasGenericParameters)
+ return type;
+ SimpleType sType = type as SimpleType;
+ MemberType mType = type as MemberType;
+ if (sType != null) {
+ while (typeDef.GenericParameters.Count > sType.TypeArguments.Count) {
+ sType.TypeArguments.Add(new SimpleType(""));
+ }
+ }
+
+ if (mType != null) {
+ AddEmptyTypeArgumentsForUnboundGenerics(mType.Target);
+
+ int outerTypeParamCount = typeDef.DeclaringType == null ? 0 : typeDef.DeclaringType.GenericParameters.Count;
+
+ while (typeDef.GenericParameters.Count - outerTypeParamCount > mType.TypeArguments.Count) {
+ mType.TypeArguments.Add(new SimpleType(""));
+ }
+ }
+
+ return type;
+ }
+ #endregion
+
#region Convert Type Reference
///
/// Converts a type reference.
@@ -597,6 +671,15 @@ namespace ICSharpCode.Decompiler.Ast
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
{
+ // Nested types
+ foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
+ if (MemberIsHidden(nestedTypeDef, context.Settings))
+ continue;
+ var nestedType = CreateType(nestedTypeDef);
+ SetNewModifier(nestedType);
+ astType.AddChild(nestedType, TypeDeclaration.MemberRole);
+ }
+
// Add fields
foreach(FieldDefinition fieldDef in typeDef.Fields) {
if (MemberIsHidden(fieldDef, context.Settings)) continue;
@@ -729,6 +812,9 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef);
astMethod.WithAnnotation(methodMapping);
+ if (methodDef.IsStatic && methodDef.DeclaringType.IsBeforeFieldInit && !astMethod.Body.IsNull) {
+ astMethod.Body.InsertChildAfter(null, new Comment(" Note: this type is marked as 'beforefieldinit'."), AstNode.Roles.Comment);
+ }
return astMethod;
}
@@ -798,7 +884,13 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
astProp.Setter.AddAnnotation(propDef.SetMethod);
ConvertAttributes(astProp.Setter, propDef.SetMethod);
- ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), "param");
+ ParameterDefinition lastParam = propDef.SetMethod.Parameters.LastOrDefault();
+ if (lastParam != null) {
+ ConvertCustomAttributes(astProp.Setter, lastParam, "param");
+ if (lastParam.HasMarshalInfo) {
+ astProp.Setter.Attributes.Add(new AttributeSection(ConvertMarshalInfo(lastParam, propDef.Module)) { AttributeTarget = "param" });
+ }
+ }
if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask;
@@ -981,6 +1073,7 @@ namespace ICSharpCode.Decompiler.Ast
void ConvertAttributes(AttributedNode attributedNode, TypeDefinition typeDefinition)
{
ConvertCustomAttributes(attributedNode, typeDefinition);
+ ConvertSecurityAttributes(attributedNode, typeDefinition);
// Handle the non-custom attributes:
#region SerializableAttribute
@@ -1031,6 +1124,7 @@ namespace ICSharpCode.Decompiler.Ast
void ConvertAttributes(AttributedNode attributedNode, MethodDefinition methodDefinition)
{
ConvertCustomAttributes(attributedNode, methodDefinition);
+ ConvertSecurityAttributes(attributedNode, methodDefinition);
MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
@@ -1167,6 +1261,37 @@ namespace ICSharpCode.Decompiler.Ast
Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module);
var unmanagedType = new TypeReference("System.Runtime.InteropServices", "UnmanagedType", module, module.TypeSystem.Corlib);
attr.Arguments.Add(MakePrimitive((int)marshalInfo.NativeType, unmanagedType));
+
+ FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo;
+ if (fami != null) {
+ attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fami.Size));
+ if (fami.ElementType != NativeType.None)
+ attr.AddNamedArgument("ArraySubType", MakePrimitive((int)fami.ElementType, unmanagedType));
+ }
+ SafeArrayMarshalInfo sami = marshalInfo as SafeArrayMarshalInfo;
+ if (sami != null && sami.ElementType != VariantType.None) {
+ var varEnum = new TypeReference("System.Runtime.InteropServices", "VarEnum", module, module.TypeSystem.Corlib);
+ attr.AddNamedArgument("SafeArraySubType", MakePrimitive((int)sami.ElementType, varEnum));
+ }
+ ArrayMarshalInfo ami = marshalInfo as ArrayMarshalInfo;
+ if (ami != null) {
+ if (ami.ElementType != NativeType.Max)
+ attr.AddNamedArgument("ArraySubType", MakePrimitive((int)ami.ElementType, unmanagedType));
+ if (ami.Size >= 0)
+ attr.AddNamedArgument("SizeConst", new PrimitiveExpression(ami.Size));
+ if (ami.SizeParameterMultiplier != 0 && ami.SizeParameterIndex >= 0)
+ attr.AddNamedArgument("SizeParamIndex", new PrimitiveExpression(ami.SizeParameterIndex));
+ }
+ CustomMarshalInfo cmi = marshalInfo as CustomMarshalInfo;
+ if (cmi != null) {
+ attr.AddNamedArgument("MarshalType", new PrimitiveExpression(cmi.ManagedType.FullName));
+ if (!string.IsNullOrEmpty(cmi.Cookie))
+ attr.AddNamedArgument("MarshalCookie", new PrimitiveExpression(cmi.Cookie));
+ }
+ FixedSysStringMarshalInfo fssmi = marshalInfo as FixedSysStringMarshalInfo;
+ if (fssmi != null) {
+ attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fssmi.Size));
+ }
return attr;
}
#endregion
@@ -1256,6 +1381,65 @@ namespace ICSharpCode.Decompiler.Ast
}
}
+ static void ConvertSecurityAttributes(AstNode attributedNode, ISecurityDeclarationProvider secDeclProvider, string attributeTarget = null)
+ {
+ if (!secDeclProvider.HasSecurityDeclarations)
+ return;
+ var attributes = new List();
+ foreach (var secDecl in secDeclProvider.SecurityDeclarations) {
+ foreach (var secAttribute in secDecl.SecurityAttributes) {
+ var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
+ attribute.AddAnnotation(secAttribute);
+ attribute.Type = ConvertType(secAttribute.AttributeType);
+ attributes.Add(attribute);
+
+ SimpleType st = attribute.Type as SimpleType;
+ if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) {
+ st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length);
+ }
+
+ var module = secAttribute.AttributeType.Module;
+ var securityActionType = new TypeReference("System.Security.Permissions", "SecurityAction", module, module.TypeSystem.Corlib);
+ attribute.Arguments.Add(MakePrimitive((int)secDecl.Action, securityActionType));
+
+ if (secAttribute.HasProperties) {
+ TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve();
+ foreach (var propertyNamedArg in secAttribute.Properties) {
+ var propertyReference = resolvedAttributeType != null ? resolvedAttributeType.Properties.FirstOrDefault(pr => pr.Name == propertyNamedArg.Name) : null;
+ var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference);
+ var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument);
+ attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue));
+ }
+ }
+
+ if (secAttribute.HasFields) {
+ TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve();
+ foreach (var fieldNamedArg in secAttribute.Fields) {
+ var fieldReference = resolvedAttributeType != null ? resolvedAttributeType.Fields.FirstOrDefault(f => f.Name == fieldNamedArg.Name) : null;
+ var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference);
+ var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument);
+ attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue));
+ }
+ }
+ }
+ }
+ if (attributeTarget == "module" || attributeTarget == "assembly") {
+ // use separate section for each attribute
+ foreach (var attribute in attributes) {
+ var section = new AttributeSection();
+ section.AttributeTarget = attributeTarget;
+ section.Attributes.Add(attribute);
+ attributedNode.AddChild(section, AttributedNode.AttributeRole);
+ }
+ } else if (attributes.Count > 0) {
+ // use single section for all attributes
+ var section = new AttributeSection();
+ section.AttributeTarget = attributeTarget;
+ section.Attributes.AddRange(attributes);
+ attributedNode.AddChild(section, AttributedNode.AttributeRole);
+ }
+ }
+
private static Expression ConvertArgumentValue(CustomAttributeArgument argument)
{
if (argument.Value is CustomAttributeArgument[]) {
@@ -1276,9 +1460,7 @@ namespace ICSharpCode.Decompiler.Ast
if (type != null && type.IsEnum) {
return MakePrimitive(Convert.ToInt64(argument.Value), type);
} else if (argument.Value is TypeReference) {
- return new TypeOfExpression() {
- Type = ConvertType((TypeReference)argument.Value),
- };
+ return CreateTypeOfExpression((TypeReference)argument.Value);
} else {
return new PrimitiveExpression(argument.Value);
}
@@ -1433,7 +1615,7 @@ namespace ICSharpCode.Decompiler.Ast
if (baseType.HasFields && AnyIsHiddenBy(baseType.Fields, member))
return true;
if (includeBaseMethods && baseType.HasMethods
- && AnyIsHiddenBy(baseType.Methods, member, m => !m.IsSpecialName))
+ && AnyIsHiddenBy(baseType.Methods, member, m => !m.IsSpecialName))
return true;
if (baseType.HasNestedTypes && AnyIsHiddenBy(baseType.NestedTypes, member))
return true;
@@ -1447,8 +1629,8 @@ namespace ICSharpCode.Decompiler.Ast
where T : IMemberDefinition
{
return members.Any(m => m.Name == derived.Name
- && (condition == null || condition(m))
- && TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
+ && (condition == null || condition(m))
+ && TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
}
///
diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
index b3deb77d2..0e0e8dbd3 100644
--- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
@@ -490,9 +490,12 @@ namespace ICSharpCode.Decompiler.Ast
return arg1;
else
return arg1.CastTo(operandAsTypeRef);
- case ILCode.Isinst: return arg1.CastAs(operandAsTypeRef);
- case ILCode.Box: return arg1;
- case ILCode.Unbox: return InlineAssembly(byteCode, args);
+ case ILCode.Isinst:
+ return arg1.CastAs(operandAsTypeRef);
+ case ILCode.Box:
+ return arg1;
+ case ILCode.Unbox:
+ return MakeRef(arg1.CastTo(operandAsTypeRef));
#endregion
#region Indirect
case ILCode.Ldind_Ref:
@@ -544,11 +547,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Endfilter: return InlineAssembly(byteCode, args);
case ILCode.Endfinally: return null;
case ILCode.Initblk: return InlineAssembly(byteCode, args);
- case ILCode.Initobj:
- if (args[0] is DirectionExpression)
- return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), MakeDefaultValue((TypeReference)operand));
- else
- return InlineAssembly(byteCode, args);
+ case ILCode.Initobj: return InlineAssembly(byteCode, args);
case ILCode.DefaultValue:
return MakeDefaultValue((TypeReference)operand);
case ILCode.Jmp: return InlineAssembly(byteCode, args);
@@ -607,7 +606,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand);
case ILCode.Ldtoken:
if (operand is Cecil.TypeReference) {
- return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
+ return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle");
} else {
return InlineAssembly(byteCode, args);
}
diff --git a/ICSharpCode.Decompiler/Ast/NameVariables.cs b/ICSharpCode.Decompiler/Ast/NameVariables.cs
index 66f50ff13..c7ac8f385 100644
--- a/ICSharpCode.Decompiler/Ast/NameVariables.cs
+++ b/ICSharpCode.Decompiler/Ast/NameVariables.cs
@@ -279,6 +279,8 @@ namespace ICSharpCode.Decompiler.Ast
name = "array";
} else if (type.IsPointer || type.IsByReference) {
name = "ptr";
+ } else if (type.Name.EndsWith("Exception", StringComparison.Ordinal)) {
+ name = "ex";
} else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) {
name = type.Name;
// remove the 'I' for interfaces
diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
index 1e6915872..d0edf5bcc 100644
--- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
+++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
@@ -17,6 +17,7 @@ namespace ICSharpCode.Decompiler.Ast
readonly ITextOutput output;
readonly Stack nodeStack = new Stack();
int braceLevelWithinType = -1;
+ bool inDocumentationComment = false;
public TextOutputFormatter(ITextOutput output)
{
@@ -115,8 +116,17 @@ namespace ICSharpCode.Decompiler.Ast
output.Write("*/");
break;
case CommentType.Documentation:
+ if (!inDocumentationComment)
+ output.MarkFoldStart("///" + content, true);
output.Write("///");
- output.WriteLine(content);
+ output.Write(content);
+ inDocumentationComment = true;
+ bool isLastLine = !(nodeStack.Peek().NextSibling is Comment);
+ if (isLastLine) {
+ inDocumentationComment = false;
+ output.MarkFoldEnd();
+ }
+ output.WriteLine();
break;
}
}
@@ -127,7 +137,7 @@ namespace ICSharpCode.Decompiler.Ast
if (ranges != null && ranges.Count > 0)
{
// find the ancestor that has method mapping as annotation
- if (node.Ancestors != null && node.Ancestors.Count() > 0)
+ if (node.Parent != null)
{
var n = node.Ancestors.FirstOrDefault(a => a.Annotation() != null);
if (n != null) {
diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
index 716754595..054d3066e 100644
--- a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
+++ b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
@@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
@@ -69,9 +70,29 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
- var instanceCtors = typeDeclaration.Members.OfType().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
+ // Handle initializers on instance fields
+ HandleInstanceFieldInitializers(typeDeclaration.Members);
+
+ // Now convert base constructor calls to initializers:
+ base.VisitTypeDeclaration(typeDeclaration, data);
+
+ // Remove single empty constructor:
+ RemoveSingleEmptyConstructor(typeDeclaration);
+
+ // Handle initializers on static fields:
+ HandleStaticFieldInitializers(typeDeclaration.Members);
+ return null;
+ }
+
+ void HandleInstanceFieldInitializers(IEnumerable members)
+ {
+ var instanceCtors = members.OfType().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();
- if (instanceCtorsNotChainingWithThis.Length > 0 && typeDeclaration.ClassType == NRefactory.TypeSystem.ClassType.Class) {
+ if (instanceCtorsNotChainingWithThis.Length > 0) {
+ MethodDefinition ctorMethodDef = instanceCtorsNotChainingWithThis[0].Annotation();
+ if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsValueType)
+ return;
+
// Recognize field initializers:
// Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
bool allSame;
@@ -83,7 +104,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation().ResolveWithinSameModule();
if (fieldDef == null)
break;
- AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation() == fieldDef);
+ AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation() == fieldDef);
if (fieldOrEventDecl == null)
break;
@@ -99,11 +120,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
} while (allSame);
}
-
- // Now convert base constructor calls to initializers:
- base.VisitTypeDeclaration(typeDeclaration, data);
-
- // Remove single empty constructor:
+ }
+
+ void RemoveSingleEmptyConstructor(TypeDeclaration typeDeclaration)
+ {
+ var instanceCtors = typeDeclaration.Members.OfType().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
if (instanceCtors.Length == 1) {
ConstructorDeclaration emptyCtor = new ConstructorDeclaration();
emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public);
@@ -111,12 +132,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (emptyCtor.IsMatch(instanceCtors[0]))
instanceCtors[0].Remove();
}
-
+ }
+
+ void HandleStaticFieldInitializers(IEnumerable members)
+ {
// Convert static constructor into field initializers if the class is BeforeFieldInit
- var staticCtor = typeDeclaration.Members.OfType().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);
+ var staticCtor = members.OfType().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);
if (staticCtor != null) {
- TypeDefinition typeDef = typeDeclaration.Annotation();
- if (typeDef != null && typeDef.IsBeforeFieldInit) {
+ MethodDefinition ctorMethodDef = staticCtor.Annotation();
+ if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsBeforeFieldInit) {
while (true) {
ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement;
if (es == null)
@@ -127,7 +151,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
FieldDefinition fieldDef = assignment.Left.Annotation().ResolveWithinSameModule();
if (fieldDef == null || !fieldDef.IsStatic)
break;
- FieldDeclaration fieldDecl = typeDeclaration.Members.OfType().FirstOrDefault(f => f.Annotation() == fieldDef);
+ FieldDeclaration fieldDecl = members.OfType().FirstOrDefault(f => f.Annotation() == fieldDef);
if (fieldDecl == null)
break;
fieldDecl.Variables.Single().Initializer = assignment.Right.Detach();
@@ -137,11 +161,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
staticCtor.Remove();
}
}
- return null;
}
void IAstTransform.Run(AstNode node)
{
+ // If we're viewing some set of members (fields are direct children of CompilationUnit),
+ // we also need to handle those:
+ HandleInstanceFieldInitializers(node.Children);
+ HandleStaticFieldInitializers(node.Children);
+
node.AcceptVisitor(this, null);
}
}
diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs
new file mode 100644
index 000000000..298682afb
--- /dev/null
+++ b/ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using ICSharpCode.NRefactory.CSharp;
+using ICSharpCode.NRefactory.PatternMatching;
+using Mono.Cecil;
+
+namespace ICSharpCode.Decompiler.Ast.Transforms
+{
+ ///
+ /// Transforms decimal constant fields.
+ ///
+ public class DecimalConstantTransform : DepthFirstAstVisitor
void IntroducePropertyAccessInstructions(ILNode node)
{
@@ -376,6 +382,19 @@ namespace ICSharpCode.Decompiler.ILAst
expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter;
}
}
+ } else if (expr.Code == ILCode.Newobj && expr.Arguments.Count == 2) {
+ // Might be 'newobj(SomeDelegate, target, ldvirtftn(F, target))'.
+ ILVariable target;
+ if (expr.Arguments[0].Match(ILCode.Ldloc, out target)
+ && expr.Arguments[1].Code == ILCode.Ldvirtftn
+ && expr.Arguments[1].Arguments.Count == 1
+ && expr.Arguments[1].Arguments[0].MatchLdloc(target))
+ {
+ // Remove the 'target' argument from the ldvirtftn instruction.
+ // It's not needed in the translation to C#, and needs to be eliminated so that the target expression
+ // can be inlined.
+ expr.Arguments[1].Arguments.Clear();
+ }
}
}
@@ -409,7 +428,7 @@ namespace ICSharpCode.Decompiler.ILAst
lastNode.IsUnconditionalControlFlow())
{
// Try to reuse the label
- ILLabel label = currNode is ILLabel ? ((ILLabel)currNode) : new ILLabel() { Name = "Block_" + (nextLabelIndex++) };
+ ILLabel label = currNode as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++).ToString() };
// Terminate the last block
if (!lastNode.IsUnconditionalControlFlow()) {
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
index 1d366c06c..f86225fb8 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
@@ -141,6 +141,10 @@ namespace ICSharpCode.Decompiler.ILAst
{
output.Write("catch ");
output.WriteReference(ExceptionType.FullName, ExceptionType);
+ if (ExceptionVariable != null) {
+ output.Write(' ');
+ output.Write(ExceptionVariable.Name);
+ }
output.WriteLine(" {");
output.Indent();
base.WriteTo(output);
@@ -378,10 +382,10 @@ namespace ICSharpCode.Decompiler.ILAst
output.Write(((ILVariable)Operand).Name);
if (this.InferredType != null) {
output.Write(':');
- this.InferredType.WriteTo(output, true, true);
+ this.InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
output.Write("[exp:");
- this.ExpectedType.WriteTo(output, true, true);
+ this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write(']');
}
}
@@ -399,15 +403,15 @@ namespace ICSharpCode.Decompiler.ILAst
output.Write(Code.GetName());
if (this.InferredType != null) {
output.Write(':');
- this.InferredType.WriteTo(output, true, true);
+ this.InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
output.Write("[exp:");
- this.ExpectedType.WriteTo(output, true, true);
+ this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write(']');
}
} else if (this.ExpectedType != null) {
output.Write("[exp:");
- this.ExpectedType.WriteTo(output, true, true);
+ this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write(']');
}
output.Write('(');
@@ -425,13 +429,13 @@ namespace ICSharpCode.Decompiler.ILAst
} else if (Operand is MethodReference) {
MethodReference method = (MethodReference)Operand;
if (method.DeclaringType != null) {
- method.DeclaringType.WriteTo(output, true, true);
+ method.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write("::");
}
output.WriteReference(method.Name, method);
} else if (Operand is FieldReference) {
FieldReference field = (FieldReference)Operand;
- field.DeclaringType.WriteTo(output, true, true);
+ field.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write("::");
output.WriteReference(field.Name, field);
} else {
diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs
index 76fde12bf..d839f41ef 100644
--- a/ICSharpCode.Decompiler/ILAst/ILInlining.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILInlining.cs
@@ -47,7 +47,13 @@ namespace ICSharpCode.Decompiler.ILAst
numLdloca.Clear();
// Analyse the whole method
- foreach(ILExpression expr in method.GetSelfAndChildrenRecursive()) {
+ AnalyzeNode(method);
+ }
+
+ void AnalyzeNode(ILNode node)
+ {
+ ILExpression expr = node as ILExpression;
+ if (expr != null) {
ILVariable locVar = expr.Operand as ILVariable;
if (locVar != null) {
if (expr.Code == ILCode.Stloc) {
@@ -60,6 +66,16 @@ namespace ICSharpCode.Decompiler.ILAst
throw new NotSupportedException(expr.Code.ToString());
}
}
+ foreach (ILExpression child in expr.Arguments)
+ AnalyzeNode(child);
+ } else {
+ var catchBlock = node as ILTryCatchBlock.CatchBlock;
+ if (catchBlock != null && catchBlock.ExceptionVariable != null) {
+ numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + 1;
+ }
+
+ foreach (ILNode child in node.GetChildren())
+ AnalyzeNode(child);
}
}
@@ -76,6 +92,20 @@ namespace ICSharpCode.Decompiler.ILAst
{
bool modified = false;
List body = block.Body;
+ if (block is ILTryCatchBlock.CatchBlock && body.Count > 1) {
+ ILVariable v = ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable;
+ if (v != null && v.IsGenerated) {
+ if (numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1 && numLdloc.GetOrDefault(v) == 1) {
+ ILVariable v2;
+ ILExpression ldException;
+ if (body[0].Match(ILCode.Stloc, out v2, out ldException) && ldException.MatchLdloc(v)) {
+ body.RemoveAt(0);
+ ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable = v2;
+ modified = true;
+ }
+ }
+ }
+ }
for(int i = 0; i < body.Count - 1;) {
ILVariable locVar;
ILExpression expr;
diff --git a/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs b/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs
index cd5656c9d..e5409a2e5 100644
--- a/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs
+++ b/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs
@@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
Dictionary labelToCfNode = new Dictionary();
- DecompilerContext context;
+ readonly DecompilerContext context;
uint nextLabelIndex = 0;
@@ -286,7 +286,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILLabel condLabel = caseLabels[i];
// Find or create new case block
- ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.Where(b => b.EntryGoto.Operand == condLabel).FirstOrDefault();
+ ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
if (caseBlock == null) {
caseBlock = new ILSwitch.CaseBlock() {
Values = new List(),
diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
index c6d227ca3..be0a13711 100644
--- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
+++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
@@ -90,6 +90,10 @@ namespace ICSharpCode.Decompiler.ILAst
expr.Code = ILCode.Stobj;
expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
modified = true;
+ } else if (expr.Code == ILCode.Cpobj) {
+ expr.Code = ILCode.Stobj;
+ expr.Arguments[1] = new ILExpression(ILCode.Ldobj, expr.Operand, expr.Arguments[1]);
+ modified = true;
}
ILExpression arg, arg2;
TypeReference type;
@@ -440,6 +444,7 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region IntroducePostIncrement
+
bool IntroducePostIncrement(List body, ILExpression expr, int pos)
{
bool modified = IntroducePostIncrementForVariables(body, expr, pos);
@@ -452,7 +457,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
return modified;
}
-
+
bool IntroducePostIncrementForVariables(List body, ILExpression expr, int pos)
{
// Works for variables and static fields/properties
@@ -465,19 +470,50 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression exprInit;
if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
return false;
- if (!(exprInit.Code == ILCode.Ldloc || exprInit.Code == ILCode.Ldsfld || (exprInit.Code == ILCode.CallGetter && exprInit.Arguments.Count == 0)))
- return false;
+ //The next expression
ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
if (nextExpr == null)
return false;
- if (exprInit.Code == ILCode.CallGetter) {
- if (!(nextExpr.Code == ILCode.CallSetter && IsGetterSetterPair(exprInit.Operand, nextExpr.Operand)))
- return false;
- } else {
- if (!(nextExpr.Code == (exprInit.Code == ILCode.Ldloc ? ILCode.Stloc : ILCode.Stsfld) && nextExpr.Operand == exprInit.Operand))
+
+ ILCode loadInstruction = exprInit.Code;
+ ILCode storeInstruction = nextExpr.Code;
+ bool recombineVariable = false;
+
+ // We only recognise local variables, static fields, and static getters with no arguments
+ switch (loadInstruction) {
+ case ILCode.Ldloc:
+ //Must be a matching store type
+ if (storeInstruction != ILCode.Stloc)
+ return false;
+ ILVariable loadVar = (ILVariable)exprInit.Operand;
+ ILVariable storeVar = (ILVariable)nextExpr.Operand;
+ if (loadVar != storeVar) {
+ if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable)
+ recombineVariable = true;
+ else
+ return false;
+ }
+ break;
+ case ILCode.Ldsfld:
+ if (storeInstruction != ILCode.Stsfld)
+ return false;
+ if (exprInit.Operand != nextExpr.Operand)
+ return false;
+ break;
+ case ILCode.CallGetter:
+ // non-static getters would have the 'this' argument
+ if (exprInit.Arguments.Count != 0)
+ return false;
+ if (storeInstruction != ILCode.CallSetter)
+ return false;
+ if (!IsGetterSetterPair(exprInit.Operand, nextExpr.Operand))
+ return false;
+ break;
+ default:
return false;
}
+
ILExpression addExpr = nextExpr.Arguments[0];
int incrementAmount;
@@ -485,12 +521,23 @@ namespace ICSharpCode.Decompiler.ILAst
if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
return false;
- if (exprInit.Code == ILCode.Ldloc)
- exprInit.Code = ILCode.Ldloca;
- else if (exprInit.Code == ILCode.CallGetter)
- exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
- else
- exprInit.Code = ILCode.Ldsflda;
+ if (recombineVariable) {
+ // Split local variable, unsplit these two instances
+ foreach (var ilExpression in method.GetSelfAndChildrenRecursive(expression => expression.Operand == nextExpr.Operand))
+ ilExpression.Operand = exprInit.Operand;
+ }
+
+ switch (loadInstruction) {
+ case ILCode.Ldloc:
+ exprInit.Code = ILCode.Ldloca;
+ break;
+ case ILCode.Ldsfld:
+ exprInit.Code = ILCode.Ldsflda;
+ break;
+ case ILCode.CallGetter:
+ exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
+ break;
+ }
expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit);
body.RemoveAt(pos + 1); // TODO ILRanges
return true;
diff --git a/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs b/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
index e477dbff5..319e18bbb 100644
--- a/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
+++ b/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
@@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.ILAst
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr);
}
} else {
- // Ternary operator tends to create long complicated return statements
+ // Ternary operator tends to create long complicated return statements
if (opCode == ILCode.Ret)
return false;
@@ -156,7 +156,7 @@ namespace ICSharpCode.Decompiler.ILAst
// ...
// v = NullCoalescing(ldloc(leftVar), rightExpr)
// br(endBBLabel)
-
+
ILVariable v, v2;
ILExpression leftExpr, leftExpr2;
ILVariable leftVar;
@@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILBasicBlock rightBB;
ILExpression rightExpr;
if (head.Body.Count >= 3 &&
- head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
+ head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
leftExpr.Match(ILCode.Ldloc, out leftVar) &&
head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
leftExpr2.MatchLdloc(leftVar) &&
@@ -234,6 +234,107 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
+ public bool SimplifyCustomShortCircuit(List body, ILBasicBlock head, int pos)
+ {
+ Debug.Assert(body.Contains(head));
+
+ // --- looking for the following pattern ---
+ // stloc(targetVar, leftVar)
+ // brtrue(exitLabel, call(op_False, leftVar)
+ // br(followingBlock)
+ //
+ // FollowingBlock:
+ // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
+ // br(exitLabel)
+ // ---
+
+ if (head.Body.Count < 3)
+ return false;
+
+ // looking for:
+ // stloc(targetVar, leftVar)
+ ILVariable targetVar;
+ ILExpression targetVarInitExpr;
+ if (!head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out targetVar, out targetVarInitExpr))
+ return false;
+
+ ILVariable leftVar;
+ if (!targetVarInitExpr.Match(ILCode.Ldloc, out leftVar))
+ return false;
+
+ // looking for:
+ // brtrue(exitLabel, call(op_False, leftVar)
+ // br(followingBlock)
+ ILExpression callExpr;
+ ILLabel exitLabel;
+ ILLabel followingBlock;
+ if(!head.MatchLastAndBr(ILCode.Brtrue, out exitLabel, out callExpr, out followingBlock))
+ return false;
+
+ if (labelGlobalRefCount[followingBlock] > 1)
+ return false;
+
+ MethodReference opFalse;
+ ILExpression opFalseArg;
+ if (!callExpr.Match(ILCode.Call, out opFalse, out opFalseArg))
+ return false;
+
+ // ignore operators other than op_False and op_True
+ if (opFalse.Name != "op_False" && opFalse.Name != "op_True")
+ return false;
+
+ if (!opFalseArg.MatchLdloc(leftVar))
+ return false;
+
+ ILBasicBlock followingBasicBlock = labelToBasicBlock[followingBlock];
+
+ // FollowingBlock:
+ // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
+ // br(exitLabel)
+ ILVariable _targetVar;
+ ILExpression opBitwiseCallExpr;
+ ILLabel _exitLabel;
+ if (!followingBasicBlock.MatchSingleAndBr(ILCode.Stloc, out _targetVar, out opBitwiseCallExpr, out _exitLabel))
+ return false;
+
+ if (_targetVar != targetVar || exitLabel != _exitLabel)
+ return false;
+
+ MethodReference opBitwise;
+ ILExpression leftVarExpression;
+ ILExpression rightExpression;
+ if (!opBitwiseCallExpr.Match(ILCode.Call, out opBitwise, out leftVarExpression, out rightExpression))
+ return false;
+
+ if (!opFalseArg.MatchLdloc(leftVarExpression.Operand as ILVariable))
+ return false;
+
+ // ignore operators other than op_BitwiseAnd and op_BitwiseOr
+ if (opBitwise.Name != "op_BitwiseAnd" && opBitwise.Name != "op_BitwiseOr")
+ return false;
+
+ // insert:
+ // stloc(targetVar, LogicAnd(C::op_BitwiseAnd, leftVar, rightExpression)
+ // br(exitLabel)
+ ILCode op = opBitwise.Name == "op_BitwiseAnd" ? ILCode.LogicAnd : ILCode.LogicOr;
+
+ if (op == ILCode.LogicAnd && opFalse.Name != "op_False")
+ return false;
+
+ if (op == ILCode.LogicOr && opFalse.Name != "op_True")
+ return false;
+
+ ILExpression shortCircuitExpr = MakeLeftAssociativeShortCircuit(op, opFalseArg, rightExpression);
+ shortCircuitExpr.Operand = opBitwise;
+
+ head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
+ head.Body.Add(new ILExpression(ILCode.Stloc, targetVar, shortCircuitExpr));
+ head.Body.Add(new ILExpression(ILCode.Br, exitLabel));
+ body.Remove(followingBasicBlock);
+
+ return true;
+ }
+
ILExpression MakeLeftAssociativeShortCircuit(ILCode code, ILExpression left, ILExpression right)
{
// Assuming that the inputs are already left associative
diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
index 9474725d6..d9261fcc3 100644
--- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
+++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
@@ -267,6 +267,10 @@ namespace ICSharpCode.Decompiler.ILAst
return typeSystem.Boolean;
case ILCode.LogicAnd:
case ILCode.LogicOr:
+ // if Operand is set the logic and/or expression is a custom operator
+ // we can deal with it the same as a normal invocation.
+ if (expr.Operand != null)
+ goto case ILCode.Call;
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);
diff --git a/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs b/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
new file mode 100644
index 000000000..30a94a6e6
--- /dev/null
+++ b/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
@@ -0,0 +1,75 @@
+// 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;
+
+public static class CustomShortCircuitOperators
+{
+ private class B
+ {
+ public static bool operator true(CustomShortCircuitOperators.B x)
+ {
+ return true;
+ }
+
+ public static bool operator false(CustomShortCircuitOperators.B x)
+ {
+ return false;
+ }
+ }
+
+ private class C : CustomShortCircuitOperators.B
+ {
+ public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
+ {
+ return null;
+ }
+
+ public static CustomShortCircuitOperators.C operator |(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
+ {
+ return null;
+ }
+
+ public static bool operator !(CustomShortCircuitOperators.C x)
+ {
+ return false;
+ }
+
+ private static void Main()
+ {
+ CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C();
+ CustomShortCircuitOperators.C c2 = new CustomShortCircuitOperators.C();
+ CustomShortCircuitOperators.C c3 = c && c2;
+ CustomShortCircuitOperators.C c4 = c || c2;
+ Console.WriteLine(c3.ToString());
+ Console.WriteLine(c4.ToString());
+ }
+
+ private static void Test2()
+ {
+ CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C();
+ if (c && c)
+ {
+ Console.WriteLine(c.ToString());
+ }
+
+ if (!(c && c))
+ {
+ Console.WriteLine(c.ToString());
+ }
+ }
+
+ private static void Test3()
+ {
+ CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C();
+ if (c)
+ {
+ Console.WriteLine(c.ToString());
+ }
+ if (!c)
+ {
+ Console.WriteLine(c.ToString());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
index 5fdc27dc5..7f6e506ee 100644
--- a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
+++ b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
@@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
+using System.Threading;
public class ExceptionHandling
{
@@ -55,13 +56,38 @@ public class ExceptionHandling
{
Console.WriteLine(ex.Message);
}
- catch (Exception ex)
+ catch (Exception ex2)
{
- Console.WriteLine(ex.Message);
+ Console.WriteLine(ex2.Message);
}
catch
{
Console.WriteLine("other");
}
}
+
+ public void NoUsingStatementBecauseTheVariableIsAssignedTo()
+ {
+ CancellationTokenSource cancellationTokenSource = null;
+ try
+ {
+ cancellationTokenSource = new CancellationTokenSource();
+ }
+ finally
+ {
+ if (cancellationTokenSource != null)
+ {
+ cancellationTokenSource.Dispose();
+ }
+ }
+ }
+
+ public void UsingStatementThatChangesTheVariable()
+ {
+ CancellationTokenSource cancellationTokenSource = null;
+ using (cancellationTokenSource)
+ {
+ cancellationTokenSource = new CancellationTokenSource();
+ }
+ }
}
diff --git a/ICSharpCode.Decompiler/Tests/Generics.cs b/ICSharpCode.Decompiler/Tests/Generics.cs
index 53cd5f623..e5b6e2eb7 100644
--- a/ICSharpCode.Decompiler/Tests/Generics.cs
+++ b/ICSharpCode.Decompiler/Tests/Generics.cs
@@ -60,6 +60,12 @@ public static class Generics
}
}
+ private static Type type1 = typeof(List<>);
+ private static Type type2 = typeof(Generics.MyArray<>);
+ private static Type type3 = typeof(List<>.Enumerator);
+ private static Type type4 = typeof(Generics.MyArray<>.NestedClass<>);
+ private static Type type5 = typeof(List[]);
+
public static void MethodWithConstraint() where T : class, S where S : ICloneable, new()
{
}
diff --git a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
index 0076eb2ba..251916557 100644
--- a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
+++ b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
@@ -15,7 +15,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var section = (AttributeSection)attribute.Parent;
SimpleType type = attribute.Type as SimpleType;
if (section.AttributeTarget == "assembly" &&
- (type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility"))
+ (type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "AssemblyVersion"))
{
attribute.Remove();
if (section.Attributes.Count == 0)
diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
index b4906c60f..33227a313 100644
--- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -57,8 +57,10 @@
+
+
diff --git a/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs b/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
index 02a72190f..12c47186d 100644
--- a/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
+++ b/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
@@ -176,6 +176,12 @@ public class IncrementDecrement
return i++ + j;
}
+ public void PostIncrementInlineLocalVariable(Func f)
+ {
+ int num = 0;
+ f(num++);
+ }
+
public int PostIncrementArrayElement(int[] array, int pos)
{
return array[pos]--;
diff --git a/ICSharpCode.Decompiler/Tests/PInvoke.cs b/ICSharpCode.Decompiler/Tests/PInvoke.cs
new file mode 100644
index 000000000..fe9b9b5bc
--- /dev/null
+++ b/ICSharpCode.Decompiler/Tests/PInvoke.cs
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+// P/Invoke and marshalling attribute tests
+public class PInvoke
+{
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 2)]
+ public struct MarshalAsTest
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public uint[] FixedArray;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.Bool)]
+ public int[] FixedBoolArray;
+
+ [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
+ public string[] SafeBStrArray;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
+ public string FixedString;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct Rect
+ {
+ [FieldOffset(0)]
+ public int left;
+ [FieldOffset(4)]
+ public int top;
+ [FieldOffset(8)]
+ public int right;
+ [FieldOffset(12)]
+ public int bottom;
+ }
+
+ public static decimal MarshalAttributesOnPropertyAccessors
+ {
+ [return: MarshalAs(UnmanagedType.Currency)]
+ get
+ {
+ return 0m;
+ }
+ [param: MarshalAs(UnmanagedType.Currency)]
+ set
+ {
+ }
+ }
+
+ [DllImport("xyz.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool Method([MarshalAs(UnmanagedType.LPStr)] string input);
+
+ [DllImport("xyz.dll")]
+ private static extern void New1(int ElemCnt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] ar);
+
+ [DllImport("xyz.dll")]
+ private static extern void New2([MarshalAs(UnmanagedType.LPArray, SizeConst = 128)] int[] ar);
+
+ [DllImport("xyz.dll")]
+ private static extern void New3([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Bool, SizeConst = 64, SizeParamIndex = 1)] int[] ar);
+
+ public void CustomMarshal1([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "MyCompany.MyMarshaler")] object o)
+ {
+ }
+
+ public void CustomMarshal2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "MyCompany.MyMarshaler", MarshalCookie = "Cookie")] object o)
+ {
+ }
+}
diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs
index 998c17370..a3100391c 100644
--- a/ICSharpCode.Decompiler/Tests/TestRunner.cs
+++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs
@@ -37,7 +37,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\DelegateConstruction.cs");
}
- [Test, Ignore("arg-Variables in catch clauses")]
+ [Test]
public void ExceptionHandling()
{
TestFile(@"..\..\Tests\ExceptionHandling.cs");
@@ -49,6 +49,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\Generics.cs");
}
+ [Test]
+ public void CustomShortCircuitOperators()
+ {
+ TestFile(@"..\..\Tests\CustomShortCircuitOperators.cs");
+ }
+
[Test]
public void IncrementDecrement()
{
@@ -73,6 +79,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\MultidimensionalArray.cs");
}
+ [Test]
+ public void PInvoke()
+ {
+ TestFile(@"..\..\Tests\PInvoke.cs");
+ }
+
[Test]
public void PropertiesAndEvents()
{
diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs
index c88f832dc..fd4fb4891 100644
--- a/ILSpy/AboutPage.cs
+++ b/ILSpy/AboutPage.cs
@@ -93,7 +93,7 @@ namespace ICSharpCode.ILSpy
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("SharpDevelop", "http://www.icsharpcode.net/opensource/sd/"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("LGPL", "resource:LGPL.txt"));
- textView.Show(output);
+ textView.ShowText(output);
}
sealed class MyLinkElementGenerator : LinkElementGenerator
@@ -130,7 +130,7 @@ namespace ICSharpCode.ILSpy
} catch (Exception ex) {
AvalonEditTextOutput exceptionOutput = new AvalonEditTextOutput();
exceptionOutput.WriteLine(ex.ToString());
- textView.Show(exceptionOutput);
+ textView.ShowText(exceptionOutput);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
};
diff --git a/ILSpy/App.xaml.cs b/ILSpy/App.xaml.cs
index f0644d70a..0eab2937f 100644
--- a/ILSpy/App.xaml.cs
+++ b/ILSpy/App.xaml.cs
@@ -165,7 +165,7 @@ namespace ICSharpCode.ILSpy
}
}
}
- ILSpy.MainWindow.Instance.TextView.Show(output);
+ ILSpy.MainWindow.Instance.TextView.ShowText(output);
} else {
Process.Start(e.Uri.ToString());
}
diff --git a/ILSpy/BamlDecompiler.cs b/ILSpy/BamlDecompiler.cs
index c223dcb82..07c60b13e 100644
--- a/ILSpy/BamlDecompiler.cs
+++ b/ILSpy/BamlDecompiler.cs
@@ -401,7 +401,7 @@ namespace ICSharpCode.ILSpy.Baml
}
return output;
}),
- t => textView.Show(t.Result, highlighting)
+ t => textView.ShowNode(t.Result, this, highlighting)
);
return true;
}
diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs
index 50afed4ea..928e53a37 100644
--- a/ILSpy/CSharpLanguage.cs
+++ b/ILSpy/CSharpLanguage.cs
@@ -47,11 +47,11 @@ namespace ICSharpCode.ILSpy
string name = "C#";
bool showAllMembers = false;
Predicate transformAbortCondition = null;
-
+
public CSharpLanguage()
{
}
-
+
#if DEBUG
internal static IEnumerable GetDebugLanguages()
{
@@ -72,27 +72,72 @@ namespace ICSharpCode.ILSpy
};
}
#endif
-
- public override string Name {
+
+ public override string Name
+ {
get { return name; }
}
-
- public override string FileExtension {
+
+ public override string FileExtension
+ {
get { return ".cs"; }
}
-
- public override string ProjectFileExtension {
+
+ public override string ProjectFileExtension
+ {
get { return ".csproj"; }
}
-
+
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true);
- codeDomBuilder.AddMethod(method);
- RunTransformsAndGenerateCode(codeDomBuilder, output, options);
+ if (method.IsConstructor && !method.IsStatic && !method.DeclaringType.IsValueType) {
+ // also fields and other ctors so that the field initializers can be shown as such
+ AddFieldsAndCtors(codeDomBuilder, method.DeclaringType, method.IsStatic);
+ RunTransformsAndGenerateCode(codeDomBuilder, output, options, new SelectCtorTransform(method));
+ } else {
+ codeDomBuilder.AddMethod(method);
+ RunTransformsAndGenerateCode(codeDomBuilder, output, options);
+ }
}
+ class SelectCtorTransform : IAstTransform
+ {
+ readonly MethodDefinition ctorDef;
+
+ public SelectCtorTransform(MethodDefinition ctorDef)
+ {
+ this.ctorDef = ctorDef;
+ }
+
+ public void Run(AstNode compilationUnit)
+ {
+ ConstructorDeclaration ctorDecl = null;
+ foreach (var node in compilationUnit.Children) {
+ ConstructorDeclaration ctor = node as ConstructorDeclaration;
+ if (ctor != null) {
+ if (ctor.Annotation() == ctorDef) {
+ ctorDecl = ctor;
+ } else {
+ // remove other ctors
+ ctor.Remove();
+ }
+ }
+ // Remove any fields without initializers
+ FieldDeclaration fd = node as FieldDeclaration;
+ if (fd != null && fd.Variables.All(v => v.Initializer.IsNull))
+ fd.Remove();
+ }
+ if (ctorDecl.Initializer.ConstructorInitializerType == ConstructorInitializerType.This) {
+ // remove all fields
+ foreach (var node in compilationUnit.Children)
+ if (node is FieldDeclaration)
+ node.Remove();
+ }
+ }
+ }
+
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
@@ -100,15 +145,55 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddProperty(property);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
-
+
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true);
- codeDomBuilder.AddField(field);
- RunTransformsAndGenerateCode(codeDomBuilder, output, options);
+ if (field.IsLiteral) {
+ codeDomBuilder.AddField(field);
+ } else {
+ // also decompile ctors so that the field initializer can be shown
+ AddFieldsAndCtors(codeDomBuilder, field.DeclaringType, field.IsStatic);
+ }
+ RunTransformsAndGenerateCode(codeDomBuilder, output, options, new SelectFieldTransform(field));
+ }
+
+ ///
+ /// Removes all top-level members except for the specified fields.
+ ///
+ sealed class SelectFieldTransform : IAstTransform
+ {
+ readonly FieldDefinition field;
+
+ public SelectFieldTransform(FieldDefinition field)
+ {
+ this.field = field;
+ }
+
+ public void Run(AstNode compilationUnit)
+ {
+ foreach (var child in compilationUnit.Children) {
+ if (child is AttributedNode) {
+ if (child.Annotation() != field)
+ child.Remove();
+ }
+ }
+ }
}
+ void AddFieldsAndCtors(AstBuilder codeDomBuilder, TypeDefinition declaringType, bool isStatic)
+ {
+ foreach (var field in declaringType.Fields) {
+ if (field.IsStatic == isStatic)
+ codeDomBuilder.AddField(field);
+ }
+ foreach (var ctor in declaringType.Methods) {
+ if (ctor.IsConstructor && ctor.IsStatic == isStatic)
+ codeDomBuilder.AddMethod(ctor);
+ }
+ }
+
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
@@ -116,7 +201,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddEvent(ev);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
-
+
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
@@ -124,14 +209,18 @@ namespace ICSharpCode.ILSpy
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
- void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options)
+ void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options, IAstTransform additionalTransform = null)
{
astBuilder.RunTransformations(transformAbortCondition);
- if (options.DecompilerSettings.ShowXmlDocumentation)
+ if (additionalTransform != null) {
+ additionalTransform.Run(astBuilder.CompilationUnit);
+ }
+ if (options.DecompilerSettings.ShowXmlDocumentation) {
AddXmlDocTransform.Run(astBuilder.CompilationUnit);
+ }
astBuilder.GenerateCode(output);
}
-
+
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
if (options.FullDecompilation && options.SaveAsProjectDirectory != null) {
@@ -150,7 +239,7 @@ namespace ICSharpCode.ILSpy
}
}
}
-
+
#region WriteProjectFile
void WriteProjectFile(TextWriter writer, IEnumerable> files, ModuleDefinition module)
{
@@ -178,20 +267,20 @@ namespace ICSharpCode.ILSpy
w.WriteStartElement("Project", ns);
w.WriteAttributeString("ToolsVersion", "4.0");
w.WriteAttributeString("DefaultTargets", "Build");
-
+
w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString().ToUpperInvariant());
-
+
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
w.WriteValue("Debug");
w.WriteEndElement(); //
-
+
w.WriteStartElement("Platform");
w.WriteAttributeString("Condition", " '$(Platform)' == '' ");
w.WriteValue(platformName);
w.WriteEndElement(); //
-
+
switch (module.Kind) {
case ModuleKind.Windows:
w.WriteElementString("OutputType", "WinExe");
@@ -203,7 +292,7 @@ namespace ICSharpCode.ILSpy
w.WriteElementString("OutputType", "Library");
break;
}
-
+
w.WriteElementString("AssemblyName", module.Assembly.Name.Name);
switch (module.Runtime) {
case TargetRuntime.Net_1_0:
@@ -222,14 +311,14 @@ namespace ICSharpCode.ILSpy
break;
}
w.WriteElementString("WarningLevel", "4");
-
+
w.WriteEndElement(); //
-
+
w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName);
w.WriteEndElement(); // (platform-specific)
-
+
w.WriteStartElement("PropertyGroup"); // Debug
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' ");
w.WriteElementString("OutputPath", "bin\\Debug\\");
@@ -237,7 +326,7 @@ namespace ICSharpCode.ILSpy
w.WriteElementString("DebugType", "full");
w.WriteElementString("Optimize", "false");
w.WriteEndElement(); // (Debug)
-
+
w.WriteStartElement("PropertyGroup"); // Release
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' ");
w.WriteElementString("OutputPath", "bin\\Release\\");
@@ -245,8 +334,8 @@ namespace ICSharpCode.ILSpy
w.WriteElementString("DebugType", "pdbonly");
w.WriteElementString("Optimize", "true");
w.WriteEndElement(); // (Release)
-
-
+
+
w.WriteStartElement("ItemGroup"); // References
foreach (AssemblyNameReference r in module.AssemblyReferences) {
if (r.Name != "mscorlib") {
@@ -257,7 +346,7 @@ namespace ICSharpCode.ILSpy
}
}
w.WriteEndElement(); // (References)
-
+
foreach (IGrouping gr in (from f in files group f.Item2 by f.Item1 into g orderby g.Key select g)) {
w.WriteStartElement("ItemGroup");
foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
@@ -267,16 +356,16 @@ namespace ICSharpCode.ILSpy
}
w.WriteEndElement();
}
-
+
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
w.WriteEndElement();
-
+
w.WriteEndDocument();
}
}
#endregion
-
+
#region WriteCodeFilesInProject
bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions options)
{
@@ -286,11 +375,11 @@ namespace ICSharpCode.ILSpy
return false;
return true;
}
-
+
IEnumerable> WriteCodeFilesInProject(AssemblyDefinition assembly, DecompilationOptions options, HashSet directories)
{
var files = assembly.MainModule.Types.Where(t => IncludeTypeWhenDecompilingProject(t, options)).GroupBy(
- delegate (TypeDefinition type) {
+ delegate(TypeDefinition type) {
string file = TextView.DecompilerTextView.CleanUpName(type.Name) + this.FileExtension;
if (string.IsNullOrEmpty(type.Namespace)) {
return file;
@@ -305,7 +394,7 @@ namespace ICSharpCode.ILSpy
Parallel.ForEach(
files,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
- delegate (IGrouping file) {
+ delegate(IGrouping file) {
using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
foreach (TypeDefinition type in file) {
@@ -319,7 +408,7 @@ namespace ICSharpCode.ILSpy
return files.Select(f => Tuple.Create("Compile", f.Key));
}
#endregion
-
+
#region WriteResourceFilesInProject
IEnumerable> WriteResourceFilesInProject(LoadedAssembly assembly, DecompilationOptions options, HashSet directories)
{
@@ -333,7 +422,8 @@ namespace ICSharpCode.ILSpy
IEnumerable rs = null;
try {
rs = new ResourceSet(s).Cast();
- } catch (ArgumentException) {
+ }
+ catch (ArgumentException) {
}
if (rs != null && rs.All(e => e.Value is Stream)) {
foreach (var pair in rs) {
@@ -351,7 +441,8 @@ namespace ICSharpCode.ILSpy
string xaml = null;
try {
xaml = decompiler.DecompileBaml(ms, assembly.FileName, new ConnectMethodDecompiler(assembly), new AssemblyResolver(assembly));
- } catch (XamlXmlWriterException) {} // ignore XAML writer exceptions
+ }
+ catch (XamlXmlWriterException) { } // ignore XAML writer exceptions
if (xaml != null) {
File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml);
yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml"));
@@ -372,12 +463,13 @@ namespace ICSharpCode.ILSpy
}
yield return Tuple.Create("EmbeddedResource", fileName);
}
- } finally {
+ }
+ finally {
if (bamlDecompilerAppDomain != null)
AppDomain.Unload(bamlDecompilerAppDomain);
}
}
-
+
string GetFileNameForResource(string fullName, HashSet directories)
{
string[] splitName = fullName.Split('.');
@@ -393,7 +485,7 @@ namespace ICSharpCode.ILSpy
return fileName;
}
#endregion
-
+
AstBuilder CreateAstBuilder(DecompilationOptions options, ModuleDefinition currentModule = null, TypeDefinition currentType = null, bool isSingleMember = false)
{
if (currentModule == null)
@@ -417,7 +509,7 @@ namespace ICSharpCode.ILSpy
if (includeNamespace)
options |= ConvertTypeOptions.IncludeNamespace;
AstType astType = AstBuilder.ConvertType(type, typeAttributes, options);
-
+
StringWriter w = new StringWriter();
if (type.IsByReference) {
ParameterDefinition pd = typeAttributes as ParameterDefinition;
@@ -425,11 +517,11 @@ namespace ICSharpCode.ILSpy
w.Write("out ");
else
w.Write("ref ");
-
+
if (astType is ComposedType && ((ComposedType)astType).PointerRank > 0)
((ComposedType)astType).PointerRank--;
}
-
+
astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null);
return w.ToString();
}
@@ -464,12 +556,20 @@ namespace ICSharpCode.ILSpy
} else
return property.Name;
}
-
+
public override bool ShowMember(MemberReference member)
{
return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings);
}
-
+
+ public override MemberReference GetOriginalCodeLocation(MemberReference member)
+ {
+ if (showAllMembers || !DecompilerSettingsPanel.CurrentDecompilerSettings.AnonymousMethods)
+ return member;
+ else
+ return ICSharpCode.ILSpy.TreeNodes.Analyzer.Helpers.GetOriginalCodeLocation(member);
+ }
+
public override string GetTooltip(MemberReference member)
{
MethodDefinition md = member as MethodDefinition;
@@ -490,12 +590,12 @@ namespace ICSharpCode.ILSpy
b.RunTransformations();
foreach (var attribute in b.CompilationUnit.Descendants.OfType())
attribute.Remove();
-
+
StringWriter w = new StringWriter();
b.GenerateCode(new PlainTextOutput(w));
return Regex.Replace(w.ToString(), @"\s+", " ").TrimEnd();
}
-
+
return base.GetTooltip(member);
}
}
diff --git a/ILSpy/Commands.cs b/ILSpy/Commands.cs
index 67775f43d..8d89e9afc 100644
--- a/ILSpy/Commands.cs
+++ b/ILSpy/Commands.cs
@@ -122,7 +122,7 @@ namespace ICSharpCode.ILSpy
return output;
}
),
- task => MainWindow.Instance.TextView.Show(task.Result));
+ task => MainWindow.Instance.TextView.ShowText(task.Result));
}
}
#endif
diff --git a/ILSpy/ConnectMethodDecompiler.cs b/ILSpy/ConnectMethodDecompiler.cs
index b5487f06a..7cb2c1760 100644
--- a/ILSpy/ConnectMethodDecompiler.cs
+++ b/ILSpy/ConnectMethodDecompiler.cs
@@ -1,5 +1,20 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
-// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
diff --git a/ILSpy/DisplaySettings.cs b/ILSpy/DisplaySettings.cs
new file mode 100644
index 000000000..569bc0509
--- /dev/null
+++ b/ILSpy/DisplaySettings.cs
@@ -0,0 +1,93 @@
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.ComponentModel;
+using System.Windows.Media;
+
+namespace ICSharpCode.ILSpy
+{
+ ///
+ /// Description of DisplaySettings.
+ ///
+ public class DisplaySettings : INotifyPropertyChanged
+ {
+ public DisplaySettings()
+ {
+ }
+
+ #region INotifyPropertyChanged implementation
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
+ {
+ if (PropertyChanged != null) {
+ PropertyChanged(this, e);
+ }
+ }
+
+ protected void OnPropertyChanged(string propertyName)
+ {
+ OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
+ }
+ #endregion
+
+ FontFamily selectedFont;
+
+ public FontFamily SelectedFont {
+ get { return selectedFont; }
+ set {
+ if (selectedFont != value) {
+ selectedFont = value;
+ OnPropertyChanged("SelectedFont");
+ }
+ }
+ }
+
+ double selectedFontSize;
+
+ public double SelectedFontSize {
+ get { return selectedFontSize; }
+ set {
+ if (selectedFontSize != value) {
+ selectedFontSize = value;
+ OnPropertyChanged("SelectedFontSize");
+ }
+ }
+ }
+
+ bool showLineNumbers;
+
+ public bool ShowLineNumbers {
+ get { return showLineNumbers; }
+ set {
+ if (showLineNumbers != value) {
+ showLineNumbers = value;
+ OnPropertyChanged("ShowLineNumbers");
+ }
+ }
+ }
+
+ public void CopyValues(DisplaySettings s)
+ {
+ this.SelectedFont = s.selectedFont;
+ this.SelectedFontSize = s.selectedFontSize;
+ this.ShowLineNumbers = s.showLineNumbers;
+ }
+ }
+}
diff --git a/ILSpy/DisplaySettingsPanel.xaml b/ILSpy/DisplaySettingsPanel.xaml
new file mode 100644
index 000000000..97131eca3
--- /dev/null
+++ b/ILSpy/DisplaySettingsPanel.xaml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+
+
+
+
+
+
+
+ Show line numbers
+
+
+
\ No newline at end of file
diff --git a/ILSpy/DisplaySettingsPanel.xaml.cs b/ILSpy/DisplaySettingsPanel.xaml.cs
new file mode 100644
index 000000000..b66bb316d
--- /dev/null
+++ b/ILSpy/DisplaySettingsPanel.xaml.cs
@@ -0,0 +1,154 @@
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Threading;
+using System.Xml.Linq;
+using ICSharpCode.Decompiler;
+
+namespace ICSharpCode.ILSpy
+{
+ ///
+ /// Interaction logic for DisplaySettingsPanel.xaml
+ ///
+ [ExportOptionPage("Display")]
+ public partial class DisplaySettingsPanel : UserControl, IOptionPage
+ {
+ public DisplaySettingsPanel()
+ {
+ InitializeComponent();
+
+ Task task = new Task(FontLoader);
+ task.Start();
+ task.ContinueWith(
+ delegate(Task continuation) {
+ App.Current.Dispatcher.Invoke(
+ DispatcherPriority.Normal,
+ (Action)(
+ () => {
+ fontSelector.ItemsSource = task.Result;
+ if (continuation.Exception != null) {
+ foreach (var ex in continuation.Exception.InnerExceptions) {
+ MessageBox.Show(ex.ToString());
+ }
+ }
+ })
+ );
+ }
+ );
+ }
+
+ public void Load(ILSpySettings settings)
+ {
+ this.DataContext = LoadDisplaySettings(settings);
+ }
+
+ static DisplaySettings currentDisplaySettings;
+
+ public static DisplaySettings CurrentDisplaySettings {
+ get {
+ return currentDisplaySettings ?? (currentDisplaySettings = LoadDisplaySettings(ILSpySettings.Load()));
+ }
+ }
+
+ static bool IsSymbolFont(FontFamily fontFamily)
+ {
+ foreach (var tf in fontFamily.GetTypefaces()) {
+ GlyphTypeface glyph;
+ try {
+ if (tf.TryGetGlyphTypeface(out glyph))
+ return glyph.Symbol;
+ } catch (Exception) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static FontFamily[] FontLoader()
+ {
+ return Fonts.SystemFontFamilies
+ .Where(ff => !IsSymbolFont(ff))
+ .OrderBy(ff => ff.Source)
+ .ToArray();
+ }
+
+ public static DisplaySettings LoadDisplaySettings(ILSpySettings settings)
+ {
+ XElement e = settings["DisplaySettings"];
+ DisplaySettings s = new DisplaySettings();
+ s.SelectedFont = new FontFamily((string)e.Attribute("Font") ?? "Consolas");
+ s.SelectedFontSize = (double?)e.Attribute("FontSize") ?? 10.0 * 4 / 3;
+ s.ShowLineNumbers = (bool?)e.Attribute("ShowLineNumbers") ?? false;
+
+ return s;
+ }
+
+ public void Save(XElement root)
+ {
+ DisplaySettings s = (DisplaySettings)this.DataContext;
+
+ currentDisplaySettings.CopyValues(s);
+
+ XElement section = new XElement("DisplaySettings");
+ section.SetAttributeValue("Font", s.SelectedFont.Source);
+ section.SetAttributeValue("FontSize", s.SelectedFontSize);
+ section.SetAttributeValue("ShowLineNumbers", s.ShowLineNumbers);
+
+ XElement existingElement = root.Element("DisplaySettings");
+ if (existingElement != null)
+ existingElement.ReplaceWith(section);
+ else
+ root.Add(section);
+ }
+ }
+
+ public class FontSizeConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if (value is double) {
+ return Math.Round((double)value / 4 * 3);
+ }
+
+ throw new NotImplementedException();
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if (value is string) {
+ double d;
+ if (double.TryParse((string)value, out d))
+ return d * 4 / 3;
+ return 11 * 4 / 3;
+ }
+
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy/ILAstLanguage.cs b/ILSpy/ILAstLanguage.cs
index 84348a4de..a462c2f21 100644
--- a/ILSpy/ILAstLanguage.cs
+++ b/ILSpy/ILAstLanguage.cs
@@ -68,7 +68,7 @@ namespace ICSharpCode.ILSpy
output.Write(" : ");
if (v.IsPinned)
output.Write("pinned ");
- v.Type.WriteTo(output, true, true);
+ v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
}
output.WriteLine();
}
@@ -100,7 +100,7 @@ namespace ICSharpCode.ILSpy
public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider)
{
PlainTextOutput output = new PlainTextOutput();
- t.WriteTo(output, true, shortName: !includeNamespace);
+ t.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName);
return output.ToString();
}
}
diff --git a/ILSpy/ILLanguage.cs b/ILSpy/ILLanguage.cs
index e77497fa5..7578f107f 100644
--- a/ILSpy/ILLanguage.cs
+++ b/ILSpy/ILLanguage.cs
@@ -62,12 +62,38 @@ namespace ICSharpCode.ILSpy
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
- new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleProperty(property);
+ ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
+ rd.DisassembleProperty(property);
+ if (property.GetMethod != null) {
+ output.WriteLine();
+ rd.DisassembleMethod(property.GetMethod);
+ }
+ if (property.SetMethod != null) {
+ output.WriteLine();
+ rd.DisassembleMethod(property.SetMethod);
+ }
+ foreach (var m in property.OtherMethods) {
+ output.WriteLine();
+ rd.DisassembleMethod(m);
+ }
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
- new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleEvent(ev);
+ ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
+ rd.DisassembleEvent(ev);
+ if (ev.AddMethod != null) {
+ output.WriteLine();
+ rd.DisassembleMethod(ev.AddMethod);
+ }
+ if (ev.RemoveMethod != null) {
+ output.WriteLine();
+ rd.DisassembleMethod(ev.RemoveMethod);
+ }
+ foreach (var m in ev.OtherMethods) {
+ output.WriteLine();
+ rd.DisassembleMethod(m);
+ }
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
@@ -85,13 +111,23 @@ namespace ICSharpCode.ILSpy
output.WriteLine("// " + assembly.FileName);
output.WriteLine();
- new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).WriteAssemblyHeader(assembly.AssemblyDefinition);
+ ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
+ if (options.FullDecompilation)
+ rd.WriteAssemblyReferences(assembly.AssemblyDefinition.MainModule);
+ rd.WriteAssemblyHeader(assembly.AssemblyDefinition);
+ output.WriteLine();
+ rd.WriteModuleHeader(assembly.AssemblyDefinition.MainModule);
+ if (options.FullDecompilation) {
+ output.WriteLine();
+ output.WriteLine();
+ rd.WriteModuleContents(assembly.AssemblyDefinition.MainModule);
+ }
}
public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider)
{
PlainTextOutput output = new PlainTextOutput();
- t.WriteTo(output, true, shortName: !includeNamespace);
+ t.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName);
return output.ToString();
}
}
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index e14465833..0bda1e382 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -102,6 +102,7 @@
DecompilerSettingsPanel.xaml
Code
+
@@ -138,22 +139,27 @@
Code
+
+ DisplaySettingsPanel.xaml
+ Code
+
-
+
+
+
-
@@ -230,6 +236,7 @@
SearchPane.cs
+
DecompilerTextView.cs
@@ -237,6 +244,7 @@
+
@@ -304,6 +312,5 @@
ICSharpCode.TreeView
-
\ No newline at end of file
diff --git a/ILSpy/ILSpySettings.cs b/ILSpy/ILSpySettings.cs
index 7d0fd19cb..053bee7ce 100644
--- a/ILSpy/ILSpySettings.cs
+++ b/ILSpy/ILSpySettings.cs
@@ -19,6 +19,7 @@
using System;
using System.IO;
using System.Linq;
+using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Linq;
@@ -58,7 +59,7 @@ namespace ICSharpCode.ILSpy
{
using (new MutexProtector(ConfigFileMutex)) {
try {
- XDocument doc = XDocument.Load(GetConfigFile());
+ XDocument doc = LoadWithoutCheckingCharacters(GetConfigFile());
return new ILSpySettings(doc.Root);
} catch (IOException) {
return new ILSpySettings();
@@ -68,6 +69,15 @@ namespace ICSharpCode.ILSpy
}
}
+ static XDocument LoadWithoutCheckingCharacters(string fileName)
+ {
+ // XDocument.Load(fileName) validates that no invalid characters appear (not even in escaped form),
+ // but we need those characters for some obfuscated assemblies.
+ using (XmlTextReader r = new XmlTextReader(fileName)) {
+ return XDocument.Load(r);
+ }
+ }
+
///
/// Saves a setting section.
///
@@ -94,7 +104,7 @@ namespace ICSharpCode.ILSpy
string config = GetConfigFile();
XDocument doc;
try {
- doc = XDocument.Load(config);
+ doc = LoadWithoutCheckingCharacters(config);
} catch (IOException) {
// ensure the directory exists
Directory.CreateDirectory(Path.GetDirectoryName(config));
@@ -104,7 +114,12 @@ namespace ICSharpCode.ILSpy
}
doc.Root.SetAttributeValue("version", RevisionClass.Major + "." + RevisionClass.Minor + "." + RevisionClass.Build + "." + RevisionClass.Revision);
action(doc.Root);
- doc.Save(config);
+ // We can't use XDocument.Save(filename) because that checks for invalid characters, but those can appear
+ // in obfuscated assemblies.
+ using (XmlTextWriter writer = new XmlTextWriter(config, Encoding.UTF8)) {
+ writer.Formatting = Formatting.Indented;
+ doc.Save(writer);
+ }
}
}
diff --git a/ILSpy/Images/Images.cs b/ILSpy/Images/Images.cs
index 361f6a5a8..8755e772e 100644
--- a/ILSpy/Images/Images.cs
+++ b/ILSpy/Images/Images.cs
@@ -65,6 +65,7 @@ namespace ICSharpCode.ILSpy
public static readonly BitmapImage Interface = LoadBitmap("Interface");
public static readonly BitmapImage Delegate = LoadBitmap("Delegate");
public static readonly BitmapImage Enum = LoadBitmap("Enum");
+ public static readonly BitmapImage StaticClass = LoadBitmap("StaticClass");
public static readonly BitmapImage Field = LoadBitmap("Field");
@@ -133,6 +134,7 @@ namespace ICSharpCode.ILSpy
PreloadPublicIconToCache(TypeIcon.Struct, Images.Struct);
PreloadPublicIconToCache(TypeIcon.Interface, Images.Interface);
PreloadPublicIconToCache(TypeIcon.Delegate, Images.Delegate);
+ PreloadPublicIconToCache(TypeIcon.StaticClass, Images.StaticClass);
}
protected override ImageSource GetBaseImage(TypeIcon icon)
@@ -154,6 +156,9 @@ namespace ICSharpCode.ILSpy
case TypeIcon.Delegate:
baseImage = Images.Delegate;
break;
+ case TypeIcon.StaticClass:
+ baseImage = Images.StaticClass;
+ break;
default:
throw new NotSupportedException();
}
diff --git a/ILSpy/Images/StaticClass.png b/ILSpy/Images/StaticClass.png
new file mode 100644
index 000000000..af9ebd06a
Binary files /dev/null and b/ILSpy/Images/StaticClass.png differ
diff --git a/ILSpy/Images/TypeIcon.cs b/ILSpy/Images/TypeIcon.cs
index 2e5f3f498..7bbb0d08a 100644
--- a/ILSpy/Images/TypeIcon.cs
+++ b/ILSpy/Images/TypeIcon.cs
@@ -26,6 +26,7 @@ namespace ICSharpCode.ILSpy
Enum,
Struct,
Interface,
- Delegate
+ Delegate,
+ StaticClass
}
}
diff --git a/ILSpy/Language.cs b/ILSpy/Language.cs
index 539de51c8..c29818621 100644
--- a/ILSpy/Language.cs
+++ b/ILSpy/Language.cs
@@ -35,66 +35,69 @@ namespace ICSharpCode.ILSpy
/// Gets the name of the language (as shown in the UI)
///
public abstract string Name { get; }
-
+
///
/// Gets the file extension used by source code files in this language.
///
public abstract string FileExtension { get; }
-
- public virtual string ProjectFileExtension {
+
+ public virtual string ProjectFileExtension
+ {
get { return null; }
}
-
+
///
/// Gets the syntax highlighting used for this language.
///
- public virtual ICSharpCode.AvalonEdit.Highlighting.IHighlightingDefinition SyntaxHighlighting {
- get {
+ public virtual ICSharpCode.AvalonEdit.Highlighting.IHighlightingDefinition SyntaxHighlighting
+ {
+ get
+ {
return ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance.GetDefinitionByExtension(this.FileExtension);
}
}
-
+
public virtual void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(method.DeclaringType, true) + "." + method.Name);
}
-
+
public virtual void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(property.DeclaringType, true) + "." + property.Name);
}
-
+
public virtual void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(field.DeclaringType, true) + "." + field.Name);
}
-
+
public virtual void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(ev.DeclaringType, true) + "." + ev.Name);
}
-
+
public virtual void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(type, true));
}
-
+
public virtual void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, nameSpace);
}
-
+
public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, assembly.FileName);
WriteCommentLine(output, assembly.AssemblyDefinition.FullName);
}
-
+
public virtual void WriteCommentLine(ITextOutput output, string comment)
{
output.WriteLine("// " + comment);
}
-
+
///
/// Converts a type reference into a string. This method is used by the member tree node for parameter and return types.
///
@@ -105,7 +108,7 @@ namespace ICSharpCode.ILSpy
else
return type.Name;
}
-
+
///
/// Converts a member signature to a string.
/// This is used for displaying the tooltip on a member reference.
@@ -117,14 +120,14 @@ namespace ICSharpCode.ILSpy
else
return member.ToString();
}
-
+
public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null)
{
if (property == null)
throw new ArgumentNullException("property");
return property.Name;
}
-
+
///
/// Used for WPF keyboard navigation.
///
@@ -132,39 +135,49 @@ namespace ICSharpCode.ILSpy
{
return Name;
}
-
+
public virtual bool ShowMember(MemberReference member)
{
return true;
}
+
+ ///
+ /// Used by the analyzer to map compiler generated code back to the original code's location
+ ///
+ public virtual MemberReference GetOriginalCodeLocation(MemberReference member)
+ {
+ return member;
+ }
}
-
+
public static class Languages
{
static ReadOnlyCollection allLanguages;
-
+
///
/// A list of all languages.
///
- public static ReadOnlyCollection AllLanguages {
- get {
+ public static ReadOnlyCollection AllLanguages
+ {
+ get
+ {
return allLanguages;
}
}
-
-
+
+
internal static void Initialize(CompositionContainer composition)
{
List languages = new List();
languages.AddRange(composition.GetExportedValues());
languages.Add(new ILLanguage(true));
- #if DEBUG
+#if DEBUG
languages.AddRange(ILAstLanguage.GetDebugLanguages());
languages.AddRange(CSharpLanguage.GetDebugLanguages());
- #endif
+#endif
allLanguages = languages.AsReadOnly();
}
-
+
///
/// Gets a language using its name.
/// If the language is not found, C# is returned instead.
diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs
index 262365ed0..4425555af 100644
--- a/ILSpy/MainWindow.xaml.cs
+++ b/ILSpy/MainWindow.xaml.cs
@@ -242,7 +242,7 @@ namespace ICSharpCode.ILSpy
if (!found) {
AvalonEditTextOutput output = new AvalonEditTextOutput();
output.Write("Cannot find " + args.NavigateTo);
- decompilerTextView.Show(output);
+ decompilerTextView.ShowText(output);
}
}
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
@@ -511,8 +511,12 @@ namespace ICSharpCode.ILSpy
if (ignoreDecompilationRequests)
return;
- if (recordHistory)
- history.Record(new NavigationState(treeView.SelectedItems.OfType(), decompilerTextView.GetState()));
+ if (recordHistory) {
+ var dtState = decompilerTextView.GetState();
+ if(dtState != null)
+ history.UpdateCurrent(new NavigationState(dtState));
+ history.Record(new NavigationState(treeView.SelectedItems.OfType()));
+ }
if (treeView.SelectedItems.Count == 1) {
ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode;
@@ -586,8 +590,9 @@ namespace ICSharpCode.ILSpy
void NavigateHistory(bool forward)
{
- var combinedState = new NavigationState(treeView.SelectedItems.OfType(), decompilerTextView.GetState());
- history.Record(combinedState, replace: true, clearForward: false);
+ var dtState = decompilerTextView.GetState();
+ if(dtState != null)
+ history.UpdateCurrent(new NavigationState(dtState));
var newState = forward ? history.GoForward() : history.GoBack();
ignoreDecompilationRequests = true;
diff --git a/ILSpy/NavigationHistory.cs b/ILSpy/NavigationHistory.cs
index 0fb1bed05..c5983a96d 100644
--- a/ILSpy/NavigationHistory.cs
+++ b/ILSpy/NavigationHistory.cs
@@ -71,13 +71,18 @@ namespace ICSharpCode.ILSpy
back.Clear();
forward.Clear();
}
+
+ public void UpdateCurrent(T node)
+ {
+ current = node;
+ }
- public void Record(T node, bool replace = false, bool clearForward = true)
+ public void Record(T node)
{
var navigationTime = DateTime.Now;
var period = navigationTime - lastNavigationTime;
- if (period.TotalSeconds < NavigationSecondsBeforeNewEntry || replace) {
+ if (period.TotalSeconds < NavigationSecondsBeforeNewEntry) {
current = node;
} else {
if (current != null)
@@ -88,8 +93,7 @@ namespace ICSharpCode.ILSpy
current = node;
}
- if (clearForward)
- forward.Clear();
+ forward.Clear();
lastNavigationTime = navigationTime;
}
diff --git a/ILSpy/NavigationState.cs b/ILSpy/NavigationState.cs
index 7a86ebec5..123c0b642 100644
--- a/ILSpy/NavigationState.cs
+++ b/ILSpy/NavigationState.cs
@@ -32,12 +32,18 @@ namespace ICSharpCode.ILSpy
public IEnumerable TreeNodes { get { return treeNodes; } }
public DecompilerTextViewState ViewState { get; private set; }
- public NavigationState(IEnumerable treeNodes, DecompilerTextViewState viewState)
+ public NavigationState(DecompilerTextViewState viewState)
{
- this.treeNodes = new HashSet(treeNodes);
+ this.treeNodes = new HashSet(viewState.DecompiledNodes);
ViewState = viewState;
}
+ public NavigationState(IEnumerable treeNodes)
+ {
+ this.treeNodes = new HashSet(treeNodes);
+ }
+
+
public bool Equals(NavigationState other)
{
// TODO: should this care about the view state as well?
diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs
index 1241037b1..024994462 100644
--- a/ILSpy/TextView/DecompilerTextView.cs
+++ b/ILSpy/TextView/DecompilerTextView.cs
@@ -29,6 +29,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
@@ -60,6 +61,7 @@ namespace ICSharpCode.ILSpy.TextView
readonly UIElementGenerator uiElementGenerator;
List activeCustomElementGenerators = new List();
FoldingManager foldingManager;
+ ILSpyTreeNode[] decompiledNodes;
DefinitionLookup definitionLookup;
CancellationTokenSource currentCancellationTokenSource;
@@ -85,6 +87,9 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.Options.RequireControlModifierForHyperlinkClick = false;
textEditor.TextArea.TextView.MouseHover += TextViewMouseHover;
textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped;
+ textEditor.SetBinding(TextEditor.FontFamilyProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFont") });
+ textEditor.SetBinding(TextEditor.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFontSize") });
+ textEditor.SetBinding(TextEditor.ShowLineNumbersProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("ShowLineNumbers") });
}
#endregion
@@ -207,11 +212,21 @@ namespace ICSharpCode.ILSpy.TextView
#endregion
#region ShowOutput
+ public void ShowText(AvalonEditTextOutput textOutput)
+ {
+ ShowNodes(textOutput, null);
+ }
+
+ public void ShowNode(AvalonEditTextOutput textOutput, ILSpyTreeNode node, IHighlightingDefinition highlighting = null)
+ {
+ ShowNodes(textOutput, new[] { node }, highlighting);
+ }
+
///
/// Shows the given output in the text view.
/// Cancels any currently running decompilation tasks.
///
- public void Show(AvalonEditTextOutput textOutput, IHighlightingDefinition highlighting = null)
+ public void ShowNodes(AvalonEditTextOutput textOutput, ILSpyTreeNode[] nodes, IHighlightingDefinition highlighting = null)
{
// Cancel the decompilation task:
if (currentCancellationTokenSource != null) {
@@ -220,6 +235,7 @@ namespace ICSharpCode.ILSpy.TextView
}
this.nextDecompilationRun = null; // remove scheduled decompilation run
ShowOutput(textOutput, highlighting);
+ decompiledNodes = nodes;
}
///
@@ -340,6 +356,7 @@ namespace ICSharpCode.ILSpy.TextView
}
ShowOutput(output);
}
+ decompiledNodes = context.TreeNodes;
});
}
@@ -513,6 +530,7 @@ namespace ICSharpCode.ILSpy.TextView
output.WriteLine(ex.ToString());
ShowOutput(output);
}
+ decompiledNodes = context.TreeNodes;
});
}
@@ -575,11 +593,15 @@ namespace ICSharpCode.ILSpy.TextView
public DecompilerTextViewState GetState()
{
+ if (decompiledNodes == null)
+ return null;
+
var state = new DecompilerTextViewState();
if (foldingManager != null)
state.SaveFoldingsState(foldingManager.AllFoldings);
state.VerticalOffset = textEditor.VerticalOffset;
state.HorizontalOffset = textEditor.HorizontalOffset;
+ state.DecompiledNodes = decompiledNodes;
return state;
}
}
@@ -590,16 +612,17 @@ namespace ICSharpCode.ILSpy.TextView
private int FoldingsChecksum;
public double VerticalOffset;
public double HorizontalOffset;
+ public ILSpyTreeNode[] DecompiledNodes;
public void SaveFoldingsState(IEnumerable foldings)
{
ExpandedFoldings = foldings.Where(f => !f.IsFolded).Select(f => Tuple.Create(f.StartOffset, f.EndOffset)).ToList();
- FoldingsChecksum = foldings.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b);
+ FoldingsChecksum = unchecked(foldings.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b));
}
internal void RestoreFoldings(List list)
{
- var checksum = list.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b);
+ var checksum = unchecked(list.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b));
if (FoldingsChecksum == checksum)
foreach (var folding in list)
folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset);
diff --git a/ILSpy/TextView/ILAsm-Mode.xshd b/ILSpy/TextView/ILAsm-Mode.xshd
index 5f582d37c..76fbc1afa 100644
--- a/ILSpy/TextView/ILAsm-Mode.xshd
+++ b/ILSpy/TextView/ILAsm-Mode.xshd
@@ -348,6 +348,7 @@
tls
true
false
+ strict
.class
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs
similarity index 50%
rename from ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs
rename to ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs
index d350147f1..041e4ef86 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs
@@ -21,50 +21,19 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
- internal sealed class AnalyzedEventAccessorsTreeNode : AnalyzerTreeNode
+ internal class AnalyzedEventAccessorTreeNode : AnalyzedMethodTreeNode
{
- public AnalyzedEventAccessorsTreeNode(EventDefinition analyzedEvent)
- {
- if (analyzedEvent == null)
- throw new ArgumentNullException("analyzedEvent");
-
- if (analyzedEvent.AddMethod != null)
- this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add"));
- if (analyzedEvent.RemoveMethod != null)
- this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.RemoveMethod, "remove"));
- foreach (var accessor in analyzedEvent.OtherMethods)
- this.Children.Add(new AnalyzedEventAccessorTreeNode(accessor, null));
- }
+ private string name;
- public override object Icon
+ public AnalyzedEventAccessorTreeNode(MethodDefinition analyzedMethod, string name)
+ : base(analyzedMethod)
{
- get { return Images.Search; }
+ this.name = name;
}
public override object Text
{
- get { return "Accessors"; }
- }
-
- public static bool CanShow(EventDefinition property)
- {
- return !MainWindow.Instance.CurrentLanguage.ShowMember(property.AddMethod ?? property.RemoveMethod);
- }
-
- internal class AnalyzedEventAccessorTreeNode : AnalyzedMethodTreeNode
- {
- private string name;
-
- public AnalyzedEventAccessorTreeNode(MethodDefinition analyzedMethod, string name)
- : base(analyzedMethod)
- {
- this.name = name;
- }
-
- public override object Text
- {
- get { return name ?? base.Text; }
- }
+ get { return name ?? base.Text; }
}
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs
index 113ffd029..549152bb7 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs
@@ -68,36 +68,25 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct);
- }
-
- private IEnumerable FindReferences(IEnumerable assemblies, CancellationToken ct)
- {
- assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
+ ScopedWhereUsedAnalyzer analyzer;
- // use parallelism only on the assembly level (avoid locks within Cecil)
- return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedEvent, FindReferencesInType);
+ return analyzer.PerformAnalysis(ct);
}
- private IEnumerable FindReferences(LoadedAssembly asm, CancellationToken ct)
+ private IEnumerable FindReferencesInType(TypeDefinition type)
{
- string asmName = asm.AssemblyDefinition.Name.Name;
string name = analyzedEvent.Name;
string declTypeName = analyzedEvent.DeclaringType.FullName;
- foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
- ct.ThrowIfCancellationRequested();
-
- if (!TypesHierarchyHelpers.IsBaseType(analyzedEvent.DeclaringType, type, resolveTypeArguments: false))
- continue;
- foreach (EventDefinition eventDef in type.Events) {
- ct.ThrowIfCancellationRequested();
+ if (!TypesHierarchyHelpers.IsBaseType(analyzedEvent.DeclaringType, type, resolveTypeArguments: false))
+ yield break;
- if (TypesHierarchyHelpers.IsBaseEvent(analyzedEvent, eventDef)) {
- MethodDefinition anyAccessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
- bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
- yield return new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : "");
- }
+ foreach (EventDefinition eventDef in type.Events) {
+ if (TypesHierarchyHelpers.IsBaseEvent(analyzedEvent, eventDef)) {
+ MethodDefinition anyAccessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
+ bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
+ yield return new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : "");
}
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs
index 3ebf2d23b..89903abd4 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs
@@ -57,8 +57,13 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override void LoadChildren()
{
- if (AnalyzedEventAccessorsTreeNode.CanShow(analyzedEvent))
- this.Children.Add(new AnalyzedEventAccessorsTreeNode(analyzedEvent));
+ if (analyzedEvent.AddMethod != null)
+ this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add"));
+ if (analyzedEvent.RemoveMethod != null)
+ this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.RemoveMethod, "remove"));
+ foreach (var accessor in analyzedEvent.OtherMethods)
+ this.Children.Add(new AnalyzedEventAccessorTreeNode(accessor, null));
+
if (AnalyzedEventOverridesTreeNode.CanShow(analyzedEvent))
this.Children.Add(new AnalyzedEventOverridesTreeNode(analyzedEvent));
if (AnalyzedInterfaceEventImplementedByTreeNode.CanShow(analyzedEvent))
@@ -75,12 +80,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
public static bool CanShow(MemberReference member)
{
- var property = member as EventDefinition;
- if (property == null)
+ var eventDef = member as EventDefinition;
+ if (eventDef == null)
return false;
- return AnalyzedEventAccessorsTreeNode.CanShow(property)
- || AnalyzedEventOverridesTreeNode.CanShow(property);
+ return !MainWindow.Instance.CurrentLanguage.ShowMember(eventDef.AddMethod ?? eventDef.RemoveMethod)
+ || AnalyzedEventOverridesTreeNode.CanShow(eventDef);
}
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs
index c18b62d0f..850ab3141 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs
@@ -22,6 +22,7 @@ using System.Threading;
using ICSharpCode.TreeView;
using Mono.Cecil;
using Mono.Cecil.Cil;
+using System.Collections;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
@@ -30,6 +31,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private readonly bool showWrites; // true: show writes; false: show read access
private readonly FieldDefinition analyzedField;
private readonly ThreadingSupport threading;
+ private Lazy foundMethods;
+ private object hashLock = new object();
public AnalyzedFieldAccessTreeNode(FieldDefinition analyzedField, bool showWrites)
{
@@ -68,8 +71,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- var analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedField, FindReferencesInType);
- return analyzer.PerformAnalysis(ct);
+ foundMethods = new Lazy(LazyThreadSafetyMode.ExecutionAndPublication);
+
+ var analyzer = new ScopedWhereUsedAnalyzer(analyzedField, FindReferencesInType);
+ foreach (var child in analyzer.PerformAnalysis(ct)) {
+ yield return child;
+ }
+
+ foundMethods = null;
}
private IEnumerable FindReferencesInType(TypeDefinition type)
@@ -95,8 +104,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
method.Body = null;
- if (found)
- yield return new AnalyzedMethodTreeNode(method);
+ if (found) {
+ MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition;
+ if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) {
+ yield return new AnalyzedMethodTreeNode(codeLocation);
+ }
+ }
}
}
@@ -116,5 +129,18 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false;
}
}
+
+ private bool HasAlreadyBeenFound(MethodDefinition method)
+ {
+ Hashtable hashtable = foundMethods.Value;
+ lock (hashLock) {
+ if (hashtable.Contains(method)) {
+ return true;
+ } else {
+ hashtable.Add(method, null);
+ return false;
+ }
+ }
+ }
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs
index c17f3ec36..09cab0bf3 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs
@@ -69,8 +69,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- ScopedWhereUsedScopeAnalyzer analyzer;
- analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedMethod, FindReferencesInType);
+ ScopedWhereUsedAnalyzer analyzer;
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs
index 6ce86fc8b..960f48f89 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs
@@ -67,8 +67,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- ScopedWhereUsedScopeAnalyzer analyzer;
- analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedMethod, FindReferencesInType);
+ ScopedWhereUsedAnalyzer analyzer;
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs
index 06a4fb961..35d9bc3d0 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs
@@ -69,8 +69,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- ScopedWhereUsedScopeAnalyzer analyzer;
- analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedMethod, FindReferencesInType);
+ ScopedWhereUsedAnalyzer analyzer;
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs
index f8f891d2d..05a3f5d6a 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs
@@ -73,45 +73,32 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct);
- }
-
- private IEnumerable FindReferences(IEnumerable assemblies, CancellationToken ct)
- {
- assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
+ ScopedWhereUsedAnalyzer analyzer;
- // use parallelism only on the assembly level (avoid locks within Cecil)
- return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType);
+ return analyzer.PerformAnalysis(ct);
}
- private IEnumerable FindReferences(LoadedAssembly asm, CancellationToken ct)
+ private IEnumerable FindReferencesInType(TypeDefinition type)
{
- string asmName = asm.AssemblyDefinition.Name.Name;
- string name = analyzedMethod.Name;
- string declTypeName = analyzedMethod.DeclaringType.FullName;
- foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
- ct.ThrowIfCancellationRequested();
- SharpTreeNode newNode = null;
- try {
- if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false))
- continue;
-
- foreach (MethodDefinition method in type.Methods) {
- ct.ThrowIfCancellationRequested();
-
- if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) {
- bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
- newNode = new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : "");
- }
+ SharpTreeNode newNode = null;
+ try {
+ if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false))
+ yield break;
+
+ foreach (MethodDefinition method in type.Methods) {
+ if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) {
+ bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
+ newNode = new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : "");
}
}
- catch (ReferenceResolvingException) {
- // ignore this type definition. maybe add a notification about such cases.
- }
-
- if (newNode != null)
- yield return newNode;
}
+ catch (ReferenceResolvingException) {
+ // ignore this type definition. maybe add a notification about such cases.
+ }
+
+ if (newNode != null)
+ yield return newNode;
}
public static bool CanShow(MethodDefinition method)
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
index 2ecc053f8..ad7654eae 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
@@ -58,9 +58,15 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
if (analyzedMethod.HasBody)
this.Children.Add(new AnalyzedMethodUsesTreeNode(analyzedMethod));
- this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));
+
+ if (analyzedMethod.IsVirtual && !(analyzedMethod.IsNewSlot && analyzedMethod.IsFinal))
+ this.Children.Add(new AnalyzedVirtualMethodUsedByTreeNode(analyzedMethod));
+ else
+ this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));
+
if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod));
+
if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod));
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
index 2a7cf784f..f3f9504e6 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
@@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using ICSharpCode.TreeView;
@@ -29,6 +30,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
private readonly MethodDefinition analyzedMethod;
private readonly ThreadingSupport threading;
+ private ConcurrentDictionary foundMethods;
public AnalyzedMethodUsedByTreeNode(MethodDefinition analyzedMethod)
{
@@ -66,10 +68,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- ScopedWhereUsedScopeAnalyzer analyzer;
+ foundMethods = new ConcurrentDictionary();
- analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedMethod, FindReferencesInType);
- return analyzer.PerformAnalysis(ct);
+ var analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType);
+ foreach (var child in analyzer.PerformAnalysis(ct)) {
+ yield return child;
+ }
+
+ foundMethods = null;
}
private IEnumerable FindReferencesInType(TypeDefinition type)
@@ -81,8 +87,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
continue;
foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference;
- if (mr != null &&
- mr.Name == name &&
+ if (mr != null && mr.Name == name &&
Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) &&
mr.Resolve() == analyzedMethod) {
found = true;
@@ -92,9 +97,18 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
method.Body = null;
- if (found)
- yield return new AnalyzedMethodTreeNode(method);
+ if (found) {
+ MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition;
+ if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) {
+ yield return new AnalyzedMethodTreeNode(codeLocation);
+ }
+ }
}
}
+
+ private bool HasAlreadyBeenFound(MethodDefinition method)
+ {
+ return !foundMethods.TryAdd(method, 0);
+ }
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs
similarity index 50%
rename from ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorsTreeNode.cs
rename to ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs
index 621417d2b..e9b898cba 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorsTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs
@@ -21,50 +21,19 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
- internal sealed class AnalyzedPropertyAccessorsTreeNode : AnalyzerTreeNode
+ internal class AnalyzedPropertyAccessorTreeNode : AnalyzedMethodTreeNode
{
- public AnalyzedPropertyAccessorsTreeNode(PropertyDefinition analyzedProperty)
- {
- if (analyzedProperty == null)
- throw new ArgumentNullException("analyzedProperty");
-
- if (analyzedProperty.GetMethod != null)
- this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get"));
- if (analyzedProperty.SetMethod != null)
- this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.SetMethod, "set"));
- foreach (var accessor in analyzedProperty.OtherMethods)
- this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
- }
+ private readonly string name;
- public override object Icon
+ public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name)
+ : base(analyzedMethod)
{
- get { return Images.Search; }
+ this.name = name;
}
public override object Text
{
- get { return "Accessors"; }
- }
-
- public static bool CanShow(PropertyDefinition property)
- {
- return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod ?? property.SetMethod);
- }
-
- private class AnalyzedPropertyAccessorTreeNode : AnalyzedMethodTreeNode
- {
- private readonly string name;
-
- public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name)
- : base(analyzedMethod)
- {
- this.name = name;
- }
-
- public override object Text
- {
- get { return name ?? base.Text; }
- }
+ get { return name ?? base.Text; }
}
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
index 440a54f6e..6a6ea0f32 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
@@ -69,45 +69,27 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct);
- }
-
- private IEnumerable FindReferences(IEnumerable assemblies, CancellationToken ct)
- {
- assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
+ ScopedWhereUsedAnalyzer analyzer;
- // use parallelism only on the assembly level (avoid locks within Cecil)
- return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedProperty, FindReferencesInType);
+ return analyzer.PerformAnalysis(ct);
}
- private IEnumerable FindReferences(LoadedAssembly asm, CancellationToken ct)
+ private IEnumerable FindReferencesInType(TypeDefinition type)
{
- string asmName = asm.AssemblyDefinition.Name.Name;
string name = analyzedProperty.Name;
string declTypeName = analyzedProperty.DeclaringType.FullName;
- foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
- ct.ThrowIfCancellationRequested();
- SharpTreeNode newNode = null;
- try {
- if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false))
- continue;
+ if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false))
+ yield break;
- foreach (PropertyDefinition property in type.Properties) {
- ct.ThrowIfCancellationRequested();
+ foreach (PropertyDefinition property in type.Properties) {
- if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) {
- MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod;
- bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
- newNode = new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : "");
- }
- }
- }
- catch (ReferenceResolvingException) {
- // ignore this type definition.
+ if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) {
+ MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod;
+ bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
+ yield return new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : "");
}
- if (newNode != null)
- yield return newNode;
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
index bba0b3362..b08127b52 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
@@ -60,8 +60,13 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override void LoadChildren()
{
- if (AnalyzedPropertyAccessorsTreeNode.CanShow(analyzedProperty))
- this.Children.Add(new AnalyzedPropertyAccessorsTreeNode(analyzedProperty));
+ if (analyzedProperty.GetMethod != null)
+ this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get"));
+ if (analyzedProperty.SetMethod != null)
+ this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.SetMethod, "set"));
+ foreach (var accessor in analyzedProperty.OtherMethods)
+ this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
+
if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty))
this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty));
if (AnalyzedInterfacePropertyImplementedByTreeNode.CanShow(analyzedProperty))
@@ -82,8 +87,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
if (property == null)
return false;
- return AnalyzedPropertyAccessorsTreeNode.CanShow(property)
- || AnalyzedPropertyOverridesTreeNode.CanShow(property);
+ return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod ?? property.SetMethod)
+ || AnalyzedPropertyOverridesTreeNode.CanShow(property);
}
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
index 00e09e37d..cd14c0575 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
@@ -65,9 +65,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- ScopedWhereUsedScopeAnalyzer analyzer;
+ ScopedWhereUsedAnalyzer analyzer;
- analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedType, FindReferencesInType);
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
index c88ece234..3bd42506c 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
@@ -66,9 +66,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- ScopedWhereUsedScopeAnalyzer analyzer;
+ ScopedWhereUsedAnalyzer analyzer;
- analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedType, FindReferencesInType);
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
index f11fca495..0c2d9465a 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
@@ -71,9 +71,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable FetchChildren(CancellationToken ct)
{
- ScopedWhereUsedScopeAnalyzer analyzer;
+ ScopedWhereUsedAnalyzer analyzer;
- analyzer = new ScopedWhereUsedScopeAnalyzer(analyzedType, FindReferencesInType);
+ analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs
new file mode 100644
index 000000000..993ef36d7
--- /dev/null
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs
@@ -0,0 +1,151 @@
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using ICSharpCode.TreeView;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using ICSharpCode.Decompiler.Ast;
+
+namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
+{
+ internal sealed class AnalyzedVirtualMethodUsedByTreeNode : AnalyzerTreeNode
+ {
+ private readonly MethodDefinition analyzedMethod;
+ private readonly ThreadingSupport threading;
+ private ConcurrentDictionary foundMethods;
+ private MethodDefinition baseMethod;
+ private List possibleTypes;
+
+ public AnalyzedVirtualMethodUsedByTreeNode(MethodDefinition analyzedMethod)
+ {
+ if (analyzedMethod == null)
+ throw new ArgumentNullException("analyzedMethod");
+
+ this.analyzedMethod = analyzedMethod;
+ this.threading = new ThreadingSupport();
+ this.LazyLoading = true;
+ }
+
+ public override object Text
+ {
+ get { return "Used By"; }
+ }
+
+ public override object Icon
+ {
+ get { return Images.Search; }
+ }
+
+ protected override void LoadChildren()
+ {
+ threading.LoadChildren(this, FetchChildren);
+ }
+
+ protected override void OnCollapsing()
+ {
+ if (threading.IsRunning) {
+ this.LazyLoading = true;
+ threading.Cancel();
+ this.Children.Clear();
+ }
+ }
+
+ private IEnumerable FetchChildren(CancellationToken ct)
+ {
+ InitializeAnalyzer();
+
+ var analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType);
+ foreach (var child in analyzer.PerformAnalysis(ct)) {
+ yield return child;
+ }
+
+ ReleaseAnalyzer();
+ }
+
+ private void InitializeAnalyzer()
+ {
+ foundMethods = new ConcurrentDictionary();
+
+ var BaseMethods = TypesHierarchyHelpers.FindBaseMethods(analyzedMethod).ToArray();
+ if (BaseMethods.Length > 0) {
+ baseMethod = BaseMethods[BaseMethods.Length - 1];
+ }
+
+ possibleTypes = new List();
+
+ TypeReference type = analyzedMethod.DeclaringType.BaseType;
+ while (type !=null)
+ {
+ possibleTypes.Add(type);
+ type = type.Resolve().BaseType;
+ }
+ }
+
+ private void ReleaseAnalyzer()
+ {
+ foundMethods = null;
+ baseMethod = null;
+ }
+
+ private IEnumerable FindReferencesInType(TypeDefinition type)
+ {
+ string name = analyzedMethod.Name;
+ foreach (MethodDefinition method in type.Methods) {
+ bool found = false;
+ string prefix = string.Empty;
+ if (!method.HasBody)
+ continue;
+ foreach (Instruction instr in method.Body.Instructions) {
+ MethodReference mr = instr.Operand as MethodReference;
+ if (mr != null && mr.Name == name) {
+ // explicit call to the requested method
+ if (Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) {
+ found = true;
+ prefix = "(as base) ";
+ break;
+ }
+ // virtual call to base method
+ if (instr.OpCode.Code == Code.Callvirt && Helpers.IsReferencedBy(baseMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == baseMethod) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ method.Body = null;
+
+ if (found) {
+ MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition;
+ if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) {
+ yield return new AnalyzedMethodTreeNode(codeLocation, prefix);
+ }
+ }
+ }
+ }
+
+ private bool HasAlreadyBeenFound(MethodDefinition method)
+ {
+ return !foundMethods.TryAdd(method, 0);
+ }
+ }
+}
diff --git a/ILSpy/TreeNodes/Analyzer/Helpers.cs b/ILSpy/TreeNodes/Analyzer/Helpers.cs
index 778996a72..bef4e486a 100644
--- a/ILSpy/TreeNodes/Analyzer/Helpers.cs
+++ b/ILSpy/TreeNodes/Analyzer/Helpers.cs
@@ -20,7 +20,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using ICSharpCode.Decompiler;
using Mono.Cecil;
+using ICSharpCode.Decompiler.ILAst;
+using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
@@ -50,5 +53,65 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return true;
}
+
+ public static MemberReference GetOriginalCodeLocation(MemberReference member)
+ {
+ if (member is MethodDefinition)
+ return GetOriginalCodeLocation((MethodDefinition)member);
+ return member;
+ }
+
+ public static MethodDefinition GetOriginalCodeLocation(MethodDefinition method)
+ {
+ if (method.IsCompilerGenerated()) {
+ return FindMethodUsageInType(method.DeclaringType, method) ?? method;
+ }
+
+ var typeUsage = GetOriginalCodeLocation(method.DeclaringType, method);
+
+ return typeUsage ?? method;
+ }
+ public static MethodDefinition GetOriginalCodeLocation(TypeDefinition type, MethodDefinition method)
+ {
+ if (type != null && type.DeclaringType != null && type.IsCompilerGenerated()) {
+ MethodDefinition constructor = GetTypeConstructor(type);
+ return FindMethodUsageInType(type.DeclaringType, constructor);
+ }
+ return null;
+ }
+
+ private static MethodDefinition GetTypeConstructor(TypeDefinition type)
+ {
+ foreach (MethodDefinition method in type.Methods) {
+ if (method.Name == ".ctor")
+ return method;
+ }
+ return null;
+ }
+
+ private static MethodDefinition FindMethodUsageInType(TypeDefinition type, MethodDefinition analyzedMethod)
+ {
+ string name = analyzedMethod.Name;
+ foreach (MethodDefinition method in type.Methods) {
+ bool found = false;
+ if (!method.HasBody)
+ continue;
+ foreach (Instruction instr in method.Body.Instructions) {
+ MethodReference mr = instr.Operand as MethodReference;
+ if (mr != null && mr.Name == name &&
+ Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) &&
+ mr.Resolve() == analyzedMethod) {
+ found = true;
+ break;
+ }
+ }
+
+ method.Body = null;
+
+ if (found)
+ return method;
+ }
+ return null;
+ }
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs
index 48eb21bc5..2840901a9 100644
--- a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs
+++ b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs
@@ -28,7 +28,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
///
/// Determines the accessibility domain of a member for where-used analysis.
///
- internal class ScopedWhereUsedScopeAnalyzer
+ internal class ScopedWhereUsedAnalyzer
{
private AssemblyDefinition assemblyScope;
private TypeDefinition typeScope;
@@ -37,40 +37,36 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private Accessibility typeAccessibility = Accessibility.Public;
private Func> typeAnalysisFunction;
- public ScopedWhereUsedScopeAnalyzer(TypeDefinition type, Func> typeAnalysisFunction)
+ public ScopedWhereUsedAnalyzer(TypeDefinition type, Func> typeAnalysisFunction)
{
this.typeScope = type;
this.assemblyScope = type.Module.Assembly;
this.typeAnalysisFunction = typeAnalysisFunction;
}
- public ScopedWhereUsedScopeAnalyzer(MethodDefinition method, Func> typeAnalysisFunction)
+ public ScopedWhereUsedAnalyzer(MethodDefinition method, Func> typeAnalysisFunction)
: this(method.DeclaringType, typeAnalysisFunction)
{
- switch (method.Attributes & MethodAttributes.MemberAccessMask) {
- case MethodAttributes.Private:
- default:
- memberAccessibility = Accessibility.Private;
- break;
- case MethodAttributes.FamANDAssem:
- memberAccessibility = Accessibility.FamilyAndInternal;
- break;
- case MethodAttributes.Family:
- memberAccessibility = Accessibility.Family;
- break;
- case MethodAttributes.Assembly:
- memberAccessibility = Accessibility.Internal;
- break;
- case MethodAttributes.FamORAssem:
- memberAccessibility = Accessibility.FamilyOrInternal;
- break;
- case MethodAttributes.Public:
- memberAccessibility = Accessibility.Public;
- break;
- }
+ this.memberAccessibility = GetMethodAccessibility(method);
+ }
+
+ public ScopedWhereUsedAnalyzer(PropertyDefinition property, Func> typeAnalysisFunction)
+ : this(property.DeclaringType, typeAnalysisFunction)
+ {
+ Accessibility getterAccessibility = (property.GetMethod == null) ? Accessibility.Private : GetMethodAccessibility(property.GetMethod);
+ Accessibility setterAccessibility = (property.SetMethod == null) ? Accessibility.Private : GetMethodAccessibility(property.SetMethod);
+ this.memberAccessibility = (Accessibility)Math.Max((int)getterAccessibility, (int)setterAccessibility);
}
- public ScopedWhereUsedScopeAnalyzer(FieldDefinition field, Func> typeAnalysisFunction)
+ public ScopedWhereUsedAnalyzer(EventDefinition eventDef, Func> typeAnalysisFunction)
+ : this(eventDef.DeclaringType, typeAnalysisFunction)
+ {
+ // we only have to check the accessibility of the the get method
+ // [CLS Rule 30: The accessibility of an event and of its accessors shall be identical.]
+ this.memberAccessibility = GetMethodAccessibility(eventDef.AddMethod);
+ }
+
+ public ScopedWhereUsedAnalyzer(FieldDefinition field, Func> typeAnalysisFunction)
: this(field.DeclaringType, typeAnalysisFunction)
{
switch (field.Attributes & FieldAttributes.FieldAccessMask) {
@@ -96,6 +92,33 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
}
}
+ private Accessibility GetMethodAccessibility(MethodDefinition method)
+ {
+ Accessibility accessibility;
+ switch (method.Attributes & MethodAttributes.MemberAccessMask) {
+ case MethodAttributes.Private:
+ default:
+ accessibility = Accessibility.Private;
+ break;
+ case MethodAttributes.FamANDAssem:
+ accessibility = Accessibility.FamilyAndInternal;
+ break;
+ case MethodAttributes.Family:
+ accessibility = Accessibility.Family;
+ break;
+ case MethodAttributes.Assembly:
+ accessibility = Accessibility.Internal;
+ break;
+ case MethodAttributes.FamORAssem:
+ accessibility = Accessibility.FamilyOrInternal;
+ break;
+ case MethodAttributes.Public:
+ accessibility = Accessibility.Public;
+ break;
+ }
+ return accessibility;
+ }
+
public IEnumerable PerformAnalysis(CancellationToken ct)
{
if (memberAccessibility == Accessibility.Private) {
@@ -231,7 +254,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
break;
}
}
- if (found)
+ if (found && AssemblyReferencesScopeType(assembly.AssemblyDefinition))
yield return assembly.AssemblyDefinition;
}
}
@@ -255,12 +278,24 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (var assembly in assemblies) {
ct.ThrowIfCancellationRequested();
- if (friendAssemblies.Contains(assembly.ShortName)) {
+ if (friendAssemblies.Contains(assembly.ShortName) && AssemblyReferencesScopeType(assembly.AssemblyDefinition)) {
yield return assembly.AssemblyDefinition;
}
}
}
}
}
+
+ private bool AssemblyReferencesScopeType(AssemblyDefinition asm)
+ {
+ bool hasRef = false;
+ foreach (var typeref in asm.MainModule.GetTypeReferences()) {
+ if (typeref.Name == typeScope.Name && typeref.Namespace == typeScope.Namespace) {
+ hasRef = true;
+ break;
+ }
+ }
+ return hasRef;
+ }
}
}
diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs
index 73dbb38da..864759152 100644
--- a/ILSpy/TreeNodes/AssemblyTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs
@@ -134,6 +134,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.Children.Add(ns);
}
}
+
+ public override bool CanExpandRecursively {
+ get { return true; }
+ }
public TypeTreeNode FindTypeNode(TypeDefinition def)
{
diff --git a/ILSpy/TreeNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceEntryNode.cs
index 787c82dc3..43638064d 100644
--- a/ILSpy/TreeNodes/ResourceEntryNode.cs
+++ b/ILSpy/TreeNodes/ResourceEntryNode.cs
@@ -144,7 +144,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
output.AddUIElement(() => new Image { Source = image });
output.WriteLine();
output.AddButton(Images.Save, "Save", delegate { Save(null); });
- textView.Show(output, null);
+ textView.ShowNode(output, this, null);
return true;
}
catch (Exception) {
diff --git a/ILSpy/TreeNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceTreeNode.cs
index 3b277a983..5e79845ba 100644
--- a/ILSpy/TreeNodes/ResourceTreeNode.cs
+++ b/ILSpy/TreeNodes/ResourceTreeNode.cs
@@ -95,7 +95,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
ext = ".xml";
else
ext = Path.GetExtension(DecompilerTextView.CleanUpName(er.Name));
- textView.Show(output, HighlightingManager.Instance.GetDefinitionByExtension(ext));
+ textView.ShowNode(output, this, HighlightingManager.Instance.GetDefinitionByExtension(ext));
return true;
}
}
diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs
index 23bce5df7..85568708a 100644
--- a/ILSpy/TreeNodes/TypeTreeNode.cs
+++ b/ILSpy/TreeNodes/TypeTreeNode.cs
@@ -117,6 +117,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
+ public override bool CanExpandRecursively {
+ get { return true; }
+ }
+
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileType(type, output, options);
@@ -146,8 +150,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
} else {
if (type.IsInterface)
return TypeIcon.Interface;
- else if (type.BaseType != null && type.BaseType.FullName == typeof(MulticastDelegate).FullName)
+ else if (IsDelegate(type))
return TypeIcon.Delegate;
+ else if (IsStaticClass(type))
+ return TypeIcon.StaticClass;
else
return TypeIcon.Class;
}
@@ -178,6 +184,17 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
return overlay;
}
+
+ private static bool IsDelegate(TypeDefinition type)
+ {
+ return type.BaseType != null && type.BaseType.FullName == typeof(MulticastDelegate).FullName;
+ }
+
+ private static bool IsStaticClass(TypeDefinition type)
+ {
+ return type.IsSealed && type.IsAbstract;
+ }
+
#endregion
MemberReference IMemberTreeNode.Member {
diff --git a/ILSpy/TreeNodes/XamlResourceNode.cs b/ILSpy/TreeNodes/XamlResourceNode.cs
index 9e42fb431..0ed226a1d 100644
--- a/ILSpy/TreeNodes/XamlResourceNode.cs
+++ b/ILSpy/TreeNodes/XamlResourceNode.cs
@@ -74,7 +74,7 @@ namespace ICSharpCode.ILSpy.Xaml
}
return output;
}),
- t => textView.Show(t.Result, highlighting)
+ t => textView.ShowNode(t.Result, this, highlighting)
);
return true;
}
diff --git a/ILSpy/XmlDoc/XmlDocKeyProvider.cs b/ILSpy/XmlDoc/XmlDocKeyProvider.cs
index 7e9960067..fc503c115 100644
--- a/ILSpy/XmlDoc/XmlDocKeyProvider.cs
+++ b/ILSpy/XmlDoc/XmlDocKeyProvider.cs
@@ -79,6 +79,10 @@ namespace ICSharpCode.ILSpy.XmlDoc
static void AppendTypeName(StringBuilder b, TypeReference type)
{
+ if (type == null) {
+ // could happen when a TypeSpecification has no ElementType; e.g. function pointers in C++/CLI assemblies
+ return;
+ }
if (type is GenericInstanceType) {
GenericInstanceType giType = (GenericInstanceType)type;
if (type.DeclaringType != null) {
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/DefiniteAssignmentAnalysis.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/DefiniteAssignmentAnalysis.cs
index d4cc6e1c5..452ca686a 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/DefiniteAssignmentAnalysis.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/DefiniteAssignmentAnalysis.cs
@@ -167,12 +167,14 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// This method can be used to restrict the analysis to only a part of the method.
/// Only the control flow paths that are fully contained within the selected part will be analyzed.
///
- /// Both 'start' and 'end' are inclusive.
- public void SetAnalyzedRange(Statement start, Statement end)
+ /// By default, both 'start' and 'end' are inclusive.
+ public void SetAnalyzedRange(Statement start, Statement end, bool startInclusive = true, bool endInclusive = true)
{
- Debug.Assert(beginNodeDict.ContainsKey(start) && endNodeDict.ContainsKey(end));
- int startIndex = beginNodeDict[start].Index;
- int endIndex = endNodeDict[end].Index;
+ var dictForStart = startInclusive ? beginNodeDict : endNodeDict;
+ var dictForEnd = endInclusive ? endNodeDict : beginNodeDict;
+ Debug.Assert(dictForStart.ContainsKey(start) && dictForEnd.ContainsKey(end));
+ int startIndex = dictForStart[start].Index;
+ int endIndex = dictForEnd[end].Index;
if (startIndex > endIndex)
throw new ArgumentException("The start statement must be lexically preceding the end statement");
this.analyzedRangeStart = startIndex;
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs
index b888cdea2..813f47213 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs
@@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
public int PointerRank {
get {
- return GetChildrenByRole(PointerRole).Count();
+ return GetChildrenByRole(PointerRole).Count;
}
set {
if (value < 0)
@@ -141,7 +141,7 @@ namespace ICSharpCode.NRefactory.CSharp
}
public int Dimensions {
- get { return 1 + GetChildrenByRole(Roles.Comma).Count(); }
+ get { return 1 + GetChildrenByRole(Roles.Comma).Count; }
set {
int d = this.Dimensions;
while (d > value) {
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs
index 70f1ddca4..6db26e523 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs
@@ -96,7 +96,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
if (name == null)
throw new ArgumentNullException("name");
- IsVerbatim = name.StartsWith ("@");
+ IsVerbatim = name.Length > 0 && name[0] == '@';
this.Name = IsVerbatim ? name.Substring (1) : name;
this.startLocation = location;
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs
index 1c770b634..da524257d 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs
@@ -941,7 +941,11 @@ namespace ICSharpCode.NRefactory.CSharp
return ConvertChar(ch);
}
- static string ConvertChar(char ch)
+ ///
+ /// Gets the escape sequence for the specified character.
+ ///
+ /// This method does not convert ' or ".
+ public static string ConvertChar(char ch)
{
switch (ch) {
case '\\':
@@ -963,7 +967,9 @@ namespace ICSharpCode.NRefactory.CSharp
case '\v':
return "\\v";
default:
- if (char.IsControl(ch) || char.IsSurrogate(ch)) {
+ if (char.IsControl(ch) || char.IsSurrogate(ch) ||
+ // print all uncommon white spaces as numbers
+ (char.IsWhiteSpace(ch) && ch != ' ')) {
return "\\u" + ((int)ch).ToString("x4");
} else {
return ch.ToString();
@@ -971,7 +977,10 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- static string ConvertString(string str)
+ ///
+ /// Converts special characters to escape sequences within the given string.
+ ///
+ public static string ConvertString(string str)
{
StringBuilder sb = new StringBuilder();
foreach (char ch in str) {
@@ -2145,7 +2154,9 @@ namespace ICSharpCode.NRefactory.CSharp
// "1.0 / /*comment*/a", then we need to insert a space in front of the comment.
formatter.Space();
}
+ formatter.StartNode(comment);
formatter.WriteComment(comment.CommentType, comment.Content);
+ formatter.EndNode(comment);
lastWritten = LastWritten.Whitespace;
return null;
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs
index 66865d53c..756adce40 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs
@@ -263,7 +263,7 @@ namespace ICSharpCode.NRefactory.CSharp
#region Fields
public override IEntity VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data)
{
- bool isSingleField = fieldDeclaration.Variables.Count() == 1;
+ bool isSingleField = fieldDeclaration.Variables.Count == 1;
Modifiers modifiers = fieldDeclaration.Modifiers;
DefaultField field = null;
foreach (VariableInitializer vi in fieldDeclaration.Variables) {
@@ -476,7 +476,7 @@ namespace ICSharpCode.NRefactory.CSharp
#region Events
public override IEntity VisitEventDeclaration(EventDeclaration eventDeclaration, object data)
{
- bool isSingleEvent = eventDeclaration.Variables.Count() == 1;
+ bool isSingleEvent = eventDeclaration.Variables.Count == 1;
Modifiers modifiers = eventDeclaration.Modifiers;
DefaultEvent ev = null;
foreach (VariableInitializer vi in eventDeclaration.Variables) {
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
index 3bcea943b..162f5c2bf 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
@@ -241,7 +241,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult VisitFieldOrEventDeclaration(AttributedNode fieldOrEventDeclaration)
{
- int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(FieldDeclaration.Roles.Variable).Count();
+ int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(FieldDeclaration.Roles.Variable).Count;
ResolveResult result = null;
for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) {
if (node.Role == FieldDeclaration.Roles.Variable) {
@@ -939,7 +939,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
firstInitializer != null ? firstInitializer.Initializer : null,
false);
- int initializerCount = variableDeclarationStatement.Variables.Count();
+ int initializerCount = variableDeclarationStatement.Variables.Count;
ResolveResult result = null;
for (AstNode node = variableDeclarationStatement.FirstChild; node != null; node = node.NextSibling) {
if (node.Role == FieldDeclaration.Roles.Variable) {
diff --git a/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs b/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
index 315f212eb..70d88aa16 100644
--- a/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
+++ b/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
@@ -120,7 +120,7 @@ namespace ICSharpCode.NRefactory.Documentation
static string GetRedirectionTarget(string target)
{
- string programFilesDir = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
+ string programFilesDir = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
programFilesDir = AppendDirectorySeparator(programFilesDir);
string corSysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
diff --git a/SharpTreeView/SharpTreeNode.cs b/SharpTreeView/SharpTreeNode.cs
index 3de3c9f9f..ae0a0e646 100644
--- a/SharpTreeView/SharpTreeNode.cs
+++ b/SharpTreeView/SharpTreeNode.cs
@@ -267,12 +267,26 @@ namespace ICSharpCode.TreeView
lazyLoading = value;
if (lazyLoading) {
IsExpanded = false;
+ if (canExpandRecursively) {
+ canExpandRecursively = false;
+ RaisePropertyChanged("CanExpandRecursively");
+ }
}
RaisePropertyChanged("LazyLoading");
RaisePropertyChanged("ShowExpander");
}
}
+ bool canExpandRecursively = true;
+
+ ///
+ /// Gets whether this node can be expanded recursively.
+ /// If not overridden, this property returns false if the node is using lazy-loading, and true otherwise.
+ ///
+ public virtual bool CanExpandRecursively {
+ get { return canExpandRecursively; }
+ }
+
public virtual bool ShowIcon
{
get { return Icon != null; }
diff --git a/SharpTreeView/SharpTreeView.cs b/SharpTreeView/SharpTreeView.cs
index d9409b79b..f2a66c797 100644
--- a/SharpTreeView/SharpTreeView.cs
+++ b/SharpTreeView/SharpTreeView.cs
@@ -227,11 +227,28 @@ namespace ICSharpCode.TreeView
e.Handled = true;
}
break;
+ case Key.Multiply:
+ if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) {
+ container.Node.IsExpanded = true;
+ ExpandRecursively(container.Node);
+ e.Handled = true;
+ }
+ break;
}
if (!e.Handled)
base.OnKeyDown(e);
}
+ void ExpandRecursively(SharpTreeNode node)
+ {
+ if (node.CanExpandRecursively) {
+ node.IsExpanded = true;
+ foreach (SharpTreeNode child in node.Children) {
+ ExpandRecursively(child);
+ }
+ }
+ }
+
///
/// Scrolls the specified node in view and sets keyboard focus on it.
///