diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..b7c3b6dc2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,23 @@
+; Top-most EditorConfig file
+root = true
+
+[*]
+indent_style = tab
+indent_size = 4
+
+[*.il]
+indent_style = space
+indent_size = 2
+
+[*.csproj]
+indent_style = space
+indent_size = 2
+[*.config]
+indent_style = space
+indent_size = 2
+[*.vsixmanifest]
+indent_style = space
+indent_size = 2
+[*.vsct]
+indent_style = space
+indent_size = 2
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index b003bfeba..5ab4836f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,5 +10,5 @@ obj/
_ReSharper*/
*.ReSharper
*.patch
-/ILSpy.sln.ide
-/packages/*
+/packages
+*.ide/
diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
index 11fb65fd0..3b5ac89f4 100644
--- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
@@ -160,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast
RunTransformations();
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
- var outputFormatter = new TextOutputFormatter(output) { FoldBraces = context.Settings.FoldBraces };
+ var outputFormatter = new TextOutputFormatter(output, context) { FoldBraces = context.Settings.FoldBraces };
var formattingPolicy = context.Settings.CSharpFormattingOptions;
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy));
}
@@ -321,11 +321,13 @@ namespace ICSharpCode.Decompiler.Ast
if (typeDef.IsEnum) {
long expectedEnumMemberValue = 0;
bool forcePrintingInitializers = IsFlagsEnum(typeDef);
+ TypeCode baseType = TypeCode.Int32;
foreach (FieldDefinition field in typeDef.Fields) {
if (!field.IsStatic) {
// the value__ field
if (field.FieldType != typeDef.Module.TypeSystem.Int32) {
astType.AddChild(ConvertType(field.FieldType), Roles.BaseType);
+ baseType = TypeAnalysis.GetTypeCode(field.FieldType);
}
} else {
EnumMemberDeclaration enumMember = new EnumMemberDeclaration();
@@ -333,7 +335,7 @@ namespace ICSharpCode.Decompiler.Ast
enumMember.Name = CleanName(field.Name);
long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false);
if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) {
- enumMember.AddChild(new PrimitiveExpression(field.Constant), EnumMemberDeclaration.InitializerRole);
+ enumMember.AddChild(new PrimitiveExpression(CSharpPrimitiveCast.Cast(baseType, field.Constant, false)), EnumMemberDeclaration.InitializerRole);
}
expectedEnumMemberValue = memberValue + 1;
astType.AddChild(enumMember, Roles.TypeMemberRole);
diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
index 078fd4fa7..3180d3842 100644
--- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
@@ -52,8 +52,8 @@ namespace ICSharpCode.Decompiler.Ast
/// These are used to update the parameter names when the decompiler generates names for the parameters.
/// Block for the method body
public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
- DecompilerContext context,
- IEnumerable parameters = null)
+ DecompilerContext context,
+ IEnumerable parameters = null)
{
MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
@@ -103,8 +103,8 @@ namespace ICSharpCode.Decompiler.Ast
if (parameters != null) {
foreach (var pair in (from p in parameters
- join v in astBuilder.Parameters on p.Annotation() equals v.OriginalParameter
- select new { p, v.Name }))
+ join v in astBuilder.Parameters on p.Annotation() equals v.OriginalParameter
+ select new { p, v.Name }))
{
pair.p.Name = pair.Name;
}
@@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) {
if (catchClause.ExceptionVariable == null
- && (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
+ && (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
{
tryCatchStmt.CatchClauses.Add(new Ast.CatchClause { Body = TransformBlock(catchClause) });
} else {
@@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler.Ast
result = node;
if (result != null)
- result = result.WithAnnotation(new TypeInformation(expr.InferredType));
+ result = result.WithAnnotation(new TypeInformation(expr.InferredType, expr.ExpectedType));
if (result != null)
return result.WithAnnotation(ilRanges);
@@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
- if (byteCode.Arguments[0].ExpectedType is PointerType) {
- arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
- boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
- } else if (byteCode.Arguments[1].ExpectedType is PointerType) {
- arg1 = DivideBySize(arg1, ((PointerType)byteCode.InferredType).ElementType);
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
+ boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
+ if (byteCode.Arguments[0].ExpectedType is PointerType ||
+ byteCode.Arguments[1].ExpectedType is PointerType) {
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
- } else {
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
+ boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
if (byteCode.Arguments[0].ExpectedType is PointerType) {
- arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
- } else {
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
@@ -460,12 +451,30 @@ namespace ICSharpCode.Decompiler.Ast
// can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne;
+
+ // when comparing signed integral values using Cgt_Un with 0
+ // the Ast should actually contain InEquality since "(uint)a > 0u" is identical to "a != 0"
+ if (arg1Type.IsSignedIntegralType())
+ {
+ var p = arg2 as Ast.PrimitiveExpression;
+ if (p != null && p.Value.IsZero()) goto case ILCode.Cne;
+ }
+
goto case ILCode.Cgt;
}
case ILCode.Cle_Un: {
// can also mean Equality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq;
+
+ // when comparing signed integral values using Cle_Un with 0
+ // the Ast should actually contain Equality since "(uint)a <= 0u" is identical to "a == 0"
+ if (arg1Type.IsSignedIntegralType())
+ {
+ var p = arg2 as Ast.PrimitiveExpression;
+ if (p != null && p.Value.IsZero()) goto case ILCode.Ceq;
+ }
+
goto case ILCode.Cle;
}
case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
@@ -706,7 +715,7 @@ namespace ICSharpCode.Decompiler.Ast
}
return new StackAllocExpression {
Type = AstBuilder.ConvertType(type),
- CountExpression = DivideBySize(arg1, type)
+ CountExpression = arg1
};
}
case ILCode.Mkrefany:
@@ -902,45 +911,6 @@ namespace ICSharpCode.Decompiler.Ast
}
}
- ///
- /// Divides expr by the size of 'type'.
- ///
- Expression DivideBySize(Expression expr, TypeReference type)
- {
- CastExpression cast = expr as CastExpression;
- if (cast != null && cast.Type is PrimitiveType && ((PrimitiveType)cast.Type).Keyword == "int")
- expr = cast.Expression.Detach();
-
- Expression sizeOfExpression;
- switch (TypeAnalysis.GetInformationAmount(type)) {
- case 1:
- case 8:
- sizeOfExpression = new PrimitiveExpression(1);
- break;
- case 16:
- sizeOfExpression = new PrimitiveExpression(2);
- break;
- case 32:
- sizeOfExpression = new PrimitiveExpression(4);
- break;
- case 64:
- sizeOfExpression = new PrimitiveExpression(8);
- break;
- default:
- sizeOfExpression = new SizeOfExpression { Type = AstBuilder.ConvertType(type) };
- break;
- }
-
- BinaryOperatorExpression boe = expr as BinaryOperatorExpression;
- if (boe != null && boe.Operator == BinaryOperatorType.Multiply && sizeOfExpression.IsMatch(boe.Right))
- return boe.Left.Detach();
-
- if (sizeOfExpression.IsMatch(expr))
- return new PrimitiveExpression(1);
-
- return new BinaryOperatorExpression(expr, BinaryOperatorType.Divide, sizeOfExpression);
- }
-
Expression MakeDefaultValue(TypeReference type)
{
TypeDefinition typeDef = type.Resolve();
diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
index 0f1889b48..e7af6d26e 100644
--- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
+++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
@@ -30,6 +30,7 @@ namespace ICSharpCode.Decompiler.Ast
public class TextOutputFormatter : IOutputFormatter
{
readonly ITextOutput output;
+ readonly DecompilerContext context;
readonly Stack nodeStack = new Stack();
int braceLevelWithinType = -1;
bool inDocumentationComment = false;
@@ -38,11 +39,14 @@ namespace ICSharpCode.Decompiler.Ast
public bool FoldBraces = false;
- public TextOutputFormatter(ITextOutput output)
+ public TextOutputFormatter(ITextOutput output, DecompilerContext context)
{
if (output == null)
throw new ArgumentNullException("output");
+ if (context == null)
+ throw new ArgumentNullException("context");
this.output = output;
+ this.context = context;
}
public void WriteIdentifier(string identifier)
@@ -89,6 +93,24 @@ namespace ICSharpCode.Decompiler.Ast
{
memberRef = node.Parent.Annotation();
}
+ if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && memberRef != null) {
+ var declaringType = memberRef.DeclaringType.Resolve();
+ if (declaringType != null && declaringType.IsDelegate())
+ return null;
+ }
+ return FilterMemberReference(memberRef);
+ }
+
+ MemberReference FilterMemberReference(MemberReference memberRef)
+ {
+ if (memberRef == null)
+ return null;
+
+ if (context.Settings.AutomaticEvents && memberRef is FieldDefinition) {
+ var field = (FieldDefinition)memberRef;
+ return field.DeclaringType.Events.FirstOrDefault(ev => ev.Name == field.Name) ?? memberRef;
+ }
+
return memberRef;
}
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
index 0838c2489..d0768af64 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
@@ -144,6 +144,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName))
continue;
}
+ IfElseStatement ies = stmt as IfElseStatement;
+ if (ies != null) {
+ foreach (var child in IfElseChainChildren(ies)) {
+ BlockStatement subBlock = child as BlockStatement;
+ if (subBlock != null)
+ DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops);
+ }
+ continue;
+ }
foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) {
@@ -268,6 +277,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
}
+
+ IfElseStatement ies = stmt as IfElseStatement;
+ if (ies != null) {
+ foreach (var child in IfElseChainChildren(ies)) {
+ if (!(child is BlockStatement) && UsesVariable(child, variableName))
+ return false;
+ }
+ return true;
+ }
// We can move the variable into a sub-block only if the variable is used in only that sub-block (and not in expressions such as the loop condition)
for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) {
@@ -285,6 +303,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
return true;
}
+
+ static IEnumerable IfElseChainChildren(IfElseStatement ies)
+ {
+ IfElseStatement prev;
+ do {
+ yield return ies.Condition;
+ yield return ies.TrueStatement;
+ prev = ies;
+ ies = ies.FalseStatement as IfElseStatement;
+ } while (ies != null);
+ if (!prev.FalseStatement.IsNull)
+ yield return prev.FalseStatement;
+ }
static bool HasNestedBlocks(AstNode node)
{
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs
index ee03ce2b8..026288fd9 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs
@@ -180,8 +180,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
foreach (AstNode node in body.Descendants) {
if (node is ThisReferenceExpression)
node.ReplaceWith(target.Clone());
-
}
+ Expression replacement;
if (isLambda) {
LambdaExpression lambda = new LambdaExpression();
lambda.CopyAnnotationsFrom(ame);
@@ -189,11 +189,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression;
returnExpr.Remove();
lambda.Body = returnExpr;
- objectCreateExpression.ReplaceWith(lambda);
+ replacement = lambda;
} else {
ame.Body = body;
- objectCreateExpression.ReplaceWith(ame);
+ replacement = ame;
+ }
+ var expectedType = objectCreateExpression.Annotation().ExpectedType.Resolve();
+ if (expectedType != null && !expectedType.IsDelegate()) {
+ var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Clone();
+ simplifiedDelegateCreation.Arguments.Clear();
+ simplifiedDelegateCreation.Arguments.Add(replacement);
+ replacement = simplifiedDelegateCreation;
}
+ objectCreateExpression.ReplaceWith(replacement);
return true;
}
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
index fd899430f..6d8608794 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
@@ -99,6 +99,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (result != null)
return result;
}
+ AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement);
+ if (simplifiedIfElse != null)
+ return simplifiedIfElse;
return base.VisitIfElseStatement(ifElseStatement, data);
}
@@ -614,6 +617,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
static readonly AstNode lockTryCatchPattern = new TryCatchStatement {
TryBlock = new BlockStatement {
+ new OptionalNode(new VariableDeclarationStatement()).ToStatement(),
new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke(
"Enter", new AnyNode("enter"),
new DirectionExpression {
@@ -626,21 +630,57 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
new IfElseStatement {
Condition = new Backreference("flag"),
TrueStatement = new BlockStatement {
- new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new NamedNode("exit", new IdentifierExpression(Pattern.AnyString)))
+ new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit"))
}
}
}};
+
+ static readonly AstNode oldMonitorCallPattern = new ExpressionStatement(
+ new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Enter", new AnyNode("enter"))
+ );
+
+ static readonly AstNode oldLockTryCatchPattern = new TryCatchStatement
+ {
+ TryBlock = new BlockStatement {
+ new Repeat(new AnyNode()).ToStatement()
+ },
+ FinallyBlock = new BlockStatement {
+ new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit"))
+ }
+ };
+
+ bool AnalyzeLockV2(ExpressionStatement node, out Expression enter, out Expression exit)
+ {
+ enter = null;
+ exit = null;
+ Match m1 = oldMonitorCallPattern.Match(node);
+ if (!m1.Success) return false;
+ Match m2 = oldLockTryCatchPattern.Match(node.NextSibling);
+ if (!m2.Success) return false;
+ enter = m1.Get("enter").Single();
+ exit = m2.Get("exit").Single();
+ return true;
+ }
+
+ bool AnalyzeLockV4(ExpressionStatement node, out Expression enter, out Expression exit)
+ {
+ enter = null;
+ exit = null;
+ Match m1 = lockFlagInitPattern.Match(node);
+ if (!m1.Success) return false;
+ Match m2 = lockTryCatchPattern.Match(node.NextSibling);
+ if (!m2.Success) return false;
+ enter = m2.Get("enter").Single();
+ exit = m2.Get("exit").Single();
+ return m1.Get("variable").Single().Identifier == m2.Get("flag").Single().Identifier;
+ }
public LockStatement TransformLock(ExpressionStatement node)
{
- Match m1 = lockFlagInitPattern.Match(node);
- if (!m1.Success) return null;
- AstNode tryCatch = node.NextSibling;
- Match m2 = lockTryCatchPattern.Match(tryCatch);
- if (!m2.Success) return null;
- if (m1.Get("variable").Single().Identifier == m2.Get("flag").Single().Identifier) {
- Expression enter = m2.Get("enter").Single();
- IdentifierExpression exit = m2.Get("exit").Single();
+ Expression enter, exit;
+ bool isV2 = AnalyzeLockV2(node, out enter, out exit);
+ if (isV2 || AnalyzeLockV4(node, out enter, out exit)) {
+ AstNode tryCatch = node.NextSibling;
if (!exit.IsMatch(enter)) {
// If exit and enter are not the same, then enter must be "exit = ..."
AssignmentExpression assign = enter as AssignmentExpression;
@@ -656,7 +696,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
LockStatement l = new LockStatement();
l.Expression = enter.Detach();
l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach();
- ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); // Remove 'Enter()' call
+ if (!isV2) // Remove 'Enter()' call
+ ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove();
tryCatch.ReplaceWith(l);
node.Remove(); // remove flag variable
return l;
@@ -1047,5 +1088,36 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
}
#endregion
+
+ #region Simplify cascading if-else-if statements
+ static readonly IfElseStatement cascadingIfElsePattern = new IfElseStatement
+ {
+ Condition = new AnyNode(),
+ TrueStatement = new AnyNode(),
+ FalseStatement = new BlockStatement {
+ Statements = {
+ new NamedNode(
+ "nestedIfStatement",
+ new IfElseStatement {
+ Condition = new AnyNode(),
+ TrueStatement = new AnyNode(),
+ FalseStatement = new OptionalNode(new AnyNode())
+ }
+ )
+ }
+ }
+ };
+
+ AstNode SimplifyCascadingIfElseStatements(IfElseStatement node)
+ {
+ Match m = cascadingIfElsePattern.Match(node);
+ if (m.Success) {
+ IfElseStatement elseIf = m.Get("nestedIfStatement").Single();
+ node.FalseStatement = elseIf.Detach();
+ }
+
+ return null;
+ }
+ #endregion
}
}
diff --git a/ICSharpCode.Decompiler/CecilExtensions.cs b/ICSharpCode.Decompiler/CecilExtensions.cs
index 25faad4fe..76665d3f0 100644
--- a/ICSharpCode.Decompiler/CecilExtensions.cs
+++ b/ICSharpCode.Decompiler/CecilExtensions.cs
@@ -126,6 +126,41 @@ namespace ICSharpCode.Decompiler
return false;
return type.IsValueType || type.IsVoid();
}
+
+ ///
+ /// checks if the given TypeReference is one of the following types:
+ /// [sbyte, short, int, long, IntPtr]
+ ///
+ public static bool IsSignedIntegralType(this TypeReference type)
+ {
+ return type.MetadataType == MetadataType.SByte ||
+ type.MetadataType == MetadataType.Int16 ||
+ type.MetadataType == MetadataType.Int32 ||
+ type.MetadataType == MetadataType.Int64 ||
+ type.MetadataType == MetadataType.IntPtr;
+ }
+
+ ///
+ /// checks if the given value is a numeric zero-value.
+ /// NOTE that this only works for types: [sbyte, short, int, long, IntPtr, byte, ushort, uint, ulong, float, double and decimal]
+ ///
+ public static bool IsZero(this object value)
+ {
+ return value.Equals((sbyte)0) ||
+ value.Equals((short)0) ||
+ value.Equals(0) ||
+ value.Equals(0L) ||
+ value.Equals(IntPtr.Zero) ||
+ value.Equals((byte)0) ||
+ value.Equals((ushort)0) ||
+ value.Equals(0u) ||
+ value.Equals(0UL) ||
+ value.Equals(0.0f) ||
+ value.Equals(0.0) ||
+ value.Equals((decimal)0);
+
+ }
+
#endregion
///
@@ -190,6 +225,7 @@ namespace ICSharpCode.Decompiler
return null;
}
+ [Obsolete("throwing exceptions is considered a bug")]
public static TypeDefinition ResolveOrThrow(this TypeReference typeReference)
{
var resolved = typeReference.Resolve();
@@ -346,5 +382,16 @@ namespace ICSharpCode.Decompiler
{
return new ICSharpCode.NRefactory.TypeSystem.FullTypeName(typeDef.FullName);
}
+
+ public static bool IsDelegate(this TypeDefinition type)
+ {
+ if (type.BaseType != null && type.BaseType.Namespace == "System") {
+ if (type.BaseType.Name == "MulticastDelegate")
+ return true;
+ if (type.BaseType.Name == "Delegate" && type.Name != "MulticastDelegate")
+ return true;
+ }
+ return false;
+ }
}
}
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
index 6c8ccbe74..bd8543cf5 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
@@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst
PropertyAccessInstructions,
SplitToMovableBlocks,
TypeInference,
+ HandlePointerArithmetic,
SimplifyShortCircuit,
SimplifyTernaryOperator,
SimplifyNullCoalescing,
@@ -125,6 +126,9 @@ namespace ICSharpCode.Decompiler.ILAst
// Types are needed for the ternary operator optimization
TypeAnalysis.Run(context, method);
+ if (abortBeforeStep == ILAstOptimizationStep.HandlePointerArithmetic) return;
+ HandlePointerArithmetic(method);
+
foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) {
bool modified;
do {
@@ -664,6 +668,107 @@ namespace ICSharpCode.Decompiler.ILAst
return combinedVariable;
});
}
+
+ static void HandlePointerArithmetic(ILNode method)
+ {
+ foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) {
+ List args = expr.Arguments;
+ switch (expr.Code) {
+ case ILCode.Localloc:
+ args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType);
+ break;
+ case ILCode.Add:
+ case ILCode.Add_Ovf:
+ case ILCode.Add_Ovf_Un:
+ if (expr.InferredType is PointerType) {
+ if (args[0].ExpectedType is PointerType)
+ args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType);
+ else if (args[1].ExpectedType is PointerType)
+ args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType);
+ }
+ break;
+ case ILCode.Sub:
+ case ILCode.Sub_Ovf:
+ case ILCode.Sub_Ovf_Un:
+ if (expr.InferredType is PointerType) {
+ if (args[0].ExpectedType is PointerType)
+ args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType);
+ }
+ break;
+ }
+ }
+ }
+
+ static ILExpression UnwrapIntPtrCast(ILExpression expr)
+ {
+ if (expr.Code != ILCode.Conv_I && expr.Code != ILCode.Conv_U)
+ return expr;
+
+ ILExpression arg = expr.Arguments[0];
+ switch (arg.InferredType.MetadataType) {
+ case MetadataType.Byte:
+ case MetadataType.SByte:
+ case MetadataType.UInt16:
+ case MetadataType.Int16:
+ case MetadataType.UInt32:
+ case MetadataType.Int32:
+ case MetadataType.UInt64:
+ case MetadataType.Int64:
+ return arg;
+ }
+
+ return expr;
+ }
+
+ static ILExpression DivideBySize(ILExpression expr, TypeReference type)
+ {
+ expr = UnwrapIntPtrCast(expr);
+
+ ILExpression sizeOfExpression;
+ switch (TypeAnalysis.GetInformationAmount(type)) {
+ case 1:
+ case 8:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 1);
+ break;
+ case 16:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 2);
+ break;
+ case 32:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 4);
+ break;
+ case 64:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 8);
+ break;
+ default:
+ sizeOfExpression = new ILExpression(ILCode.Sizeof, type);
+ break;
+ }
+
+ if (expr.Code == ILCode.Mul || expr.Code == ILCode.Mul_Ovf || expr.Code == ILCode.Mul_Ovf_Un) {
+ ILExpression mulArg = expr.Arguments[1];
+ if (mulArg.Code == sizeOfExpression.Code && sizeOfExpression.Operand.Equals(mulArg.Operand))
+ return UnwrapIntPtrCast(expr.Arguments[0]);
+ }
+
+ if (expr.Code == sizeOfExpression.Code) {
+ if (sizeOfExpression.Operand.Equals(expr.Operand))
+ return new ILExpression(ILCode.Ldc_I4, 1);
+
+ if (expr.Code == ILCode.Ldc_I4) {
+ int offsetInBytes = (int)expr.Operand;
+ int elementSize = (int)sizeOfExpression.Operand;
+ int offsetInElements = offsetInBytes / elementSize;
+
+ // ensure integer division
+ if (offsetInElements * elementSize == offsetInBytes) {
+ expr.Operand = offsetInElements;
+ return expr;
+ }
+ }
+ }
+
+ return new ILExpression(ILCode.Div_Un, null, expr, sizeOfExpression);
+ }
public static void ReplaceVariables(ILNode node, Func variableMapping)
{
diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
index 243897e36..1931d390d 100644
--- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
+++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
@@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.ILAst
return (TypeReference)expr.Operand;
case ILCode.Localloc:
if (forceInferChildren) {
- InferTypeForExpression(expr.Arguments[0], typeSystem.Int32);
+ InferTypeForExpression(expr.Arguments[0], null);
}
if (expectedType is PointerType)
return expectedType;
@@ -1013,7 +1013,7 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred;
- InferTypeForExpression(right, typeSystem.IntPtr);
+ InferTypeForExpression(right, null);
return leftPreferred;
}
if (IsEnum(leftPreferred)) {
@@ -1024,7 +1024,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) {
- InferTypeForExpression(left, typeSystem.IntPtr);
+ InferTypeForExpression(left, null);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
}
@@ -1044,7 +1044,7 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred;
- InferTypeForExpression(right, typeSystem.IntPtr);
+ InferTypeForExpression(right, null);
return leftPreferred;
}
if (IsEnum(leftPreferred)) {
diff --git a/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs b/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs
index 059625750..e45f93319 100644
--- a/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs
+++ b/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs
@@ -12,7 +12,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("IL decompiler engine")]
[assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")]
-[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPapa for the SharpDevelop Team")]
+[assembly: AssemblyCopyright("Copyright 2011-2015 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs b/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs
index 552d092ee..5cb49aad7 100644
--- a/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs
+++ b/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs
@@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Tests
{
if(String.IsNullOrWhiteSpace(s))
return true;
- return s.Trim().StartsWith("//");
+ s = s.Trim();
+ return s.StartsWith("//") || s.StartsWith("#"); // Also ignore #pragmas for warning suppression
}
public static string ConcatLines(IEnumerable lines)
diff --git a/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs b/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
index f51908659..5bd0ec516 100644
--- a/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
+++ b/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
@@ -20,21 +20,19 @@ using System;
public static class CustomShortCircuitOperators
{
- private class B
+ // TODO: Restore base class after https://roslyn.codeplex.com/workitem/358 is fixed.
+ private class C
{
- public static bool operator true(CustomShortCircuitOperators.B x)
+ public static bool operator true(CustomShortCircuitOperators.C x)
{
return true;
}
- public static bool operator false(CustomShortCircuitOperators.B x)
+ public static bool operator false(CustomShortCircuitOperators.C x)
{
return false;
}
- }
- private class C : CustomShortCircuitOperators.B
- {
public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
{
return null;
diff --git a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
index 8205042a9..659bb2be6 100644
--- a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
+++ b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
@@ -35,10 +35,8 @@ namespace ICSharpCode.Decompiler.Tests
{
protected static void ValidateFileRoundtrip(string samplesFileName)
{
- var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName));
- var testCode = RemoveIgnorableLines(lines);
- var decompiledTestCode = RoundtripCode(testCode);
- CodeAssert.AreEqual(testCode, decompiledTestCode);
+ var fullPath = Path.Combine(@"..\..\Tests", samplesFileName);
+ AssertRoundtripCode(fullPath);
}
static string RemoveIgnorableLines(IEnumerable lines)
@@ -46,29 +44,27 @@ namespace ICSharpCode.Decompiler.Tests
return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l)));
}
- ///
- /// Compiles and decompiles a source code.
- ///
- /// The source code to copile.
- /// The decompilation result of compiled source code.
- static string RoundtripCode(string code)
+ protected static void AssertRoundtripCode(string fileName, bool optimize = false, bool useDebug = false, int compilerVersion = 4)
{
- DecompilerSettings settings = new DecompilerSettings();
- settings.FullyQualifyAmbiguousTypeNames = false;
- AssemblyDefinition assembly = Compile(code);
- AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule) { Settings = settings });
+ var code = RemoveIgnorableLines(File.ReadLines(fileName));
+ AssemblyDefinition assembly = CompileLegacy(code, optimize, useDebug, compilerVersion);
+
+ AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree);
+
StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output));
- return output.ToString();
+ CodeAssert.AreEqual(code, output.ToString());
}
- static AssemblyDefinition Compile(string code)
+ protected static AssemblyDefinition CompileLegacy(string code, bool optimize, bool useDebug, int compilerVersion)
{
- CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } });
+ CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v" + new Version(compilerVersion, 0) } });
CompilerParameters options = new CompilerParameters();
- options.ReferencedAssemblies.Add("System.Core.dll");
+ options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-") + (useDebug ? " /debug" : "");
+ if (compilerVersion >= 4)
+ options.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try
{
diff --git a/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs b/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs
index 0a82fb82a..3e5a42ff4 100644
--- a/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs
+++ b/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs
@@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
private static IEnumerable NormalizeAndSplitCode(string input)
{
- return input.Split(new[] { "\r\n", "\n\r", "\n", "\r" }, StringSplitOptions.None);
+ return input.Split(new[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
}
}
}
diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
index 072c2efdc..ad7c18b66 100644
--- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -107,7 +107,6 @@
-
diff --git a/ICSharpCode.Decompiler/Tests/Lock.cs b/ICSharpCode.Decompiler/Tests/Lock.cs
new file mode 100644
index 000000000..da5a59c74
--- /dev/null
+++ b/ICSharpCode.Decompiler/Tests/Lock.cs
@@ -0,0 +1,38 @@
+// Copyright (c) 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;
+
+public class Lock
+{
+ public void LockThis()
+ {
+ lock (this)
+ {
+ Console.WriteLine();
+ }
+ }
+
+ public void LockOnType()
+ {
+ lock (typeof(Lock))
+ {
+ Console.WriteLine();
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs b/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
index 22458bcfc..d8857c30a 100644
--- a/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
+++ b/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
@@ -664,7 +664,9 @@ namespace HideMembers3
}
public class J2 : J
{
+#pragma warning disable 0108 // Deliberate bad code for test case
public int get_P;
+#pragma warning restore 0108
}
}
//$$ HideMembers4
diff --git a/ICSharpCode.Decompiler/Tests/UnsafeCode.cs b/ICSharpCode.Decompiler/Tests/UnsafeCode.cs
index 66fb29529..1a3bd6a0f 100644
--- a/ICSharpCode.Decompiler/Tests/UnsafeCode.cs
+++ b/ICSharpCode.Decompiler/Tests/UnsafeCode.cs
@@ -122,7 +122,22 @@ public class UnsafeCode
}
return this.PointerReferenceExpression((double*)ptr);
}
-
+
+ public unsafe int* PointerArithmetic(int* p)
+ {
+ return p + 2;
+ }
+
+ public unsafe byte* PointerArithmetic2(long* p, int y, int x)
+ {
+ return (byte*)p + (y * x);
+ }
+
+ public unsafe long* PointerArithmetic3(long* p)
+ {
+ return (long*)((byte*)p + 3);
+ }
+
unsafe ~UnsafeCode()
{
this.PassPointerAsRefParameter(this.NullPointer);
diff --git a/ICSharpCode.Decompiler/Tests/ValueTypes.cs b/ICSharpCode.Decompiler/Tests/ValueTypes.cs
index b3aa64478..1493cff4c 100644
--- a/ICSharpCode.Decompiler/Tests/ValueTypes.cs
+++ b/ICSharpCode.Decompiler/Tests/ValueTypes.cs
@@ -168,4 +168,21 @@ public static class ValueTypes
Console.WriteLine("true");
}
}
+
+ public static void CompareNotEqual0IsReallyNotEqual(IComparable a)
+ {
+ if (a.CompareTo(0) != 0)
+ {
+ Console.WriteLine("true");
+ }
+ }
+
+ public static void CompareEqual0IsReallyEqual(IComparable a)
+ {
+ if (a.CompareTo(0) == 0)
+ {
+ Console.WriteLine("true");
+ }
+ }
+
}
diff --git a/ICSharpCode.Decompiler/TypeSystem/TypesHierarchyHelpers.cs b/ICSharpCode.Decompiler/TypeSystem/TypesHierarchyHelpers.cs
index 8de45cca5..f0f5ece53 100644
--- a/ICSharpCode.Decompiler/TypeSystem/TypesHierarchyHelpers.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/TypesHierarchyHelpers.cs
@@ -32,9 +32,11 @@ namespace ICSharpCode.Decompiler.Ast
if (resolveTypeArguments)
return BaseTypes(derivedType).Any(t => t.Item == baseType);
else {
- var comparableBaseType = baseType.ResolveOrThrow();
+ var comparableBaseType = baseType.Resolve();
+ if (comparableBaseType == null)
+ return false;
while (derivedType.BaseType != null) {
- var resolvedBaseType = derivedType.BaseType.ResolveOrThrow();
+ var resolvedBaseType = derivedType.BaseType.Resolve();
if (resolvedBaseType == null)
return false;
if (comparableBaseType == resolvedBaseType)
@@ -185,24 +187,32 @@ namespace ICSharpCode.Decompiler.Ast
if (derivedType == null)
throw new ArgumentNullException("derivedType");
- var visibility = IsVisibleFromDerived(baseMember);
- if (visibility.HasValue)
- return visibility.Value;
+ MethodAttributes attrs = GetAccessAttributes(baseMember) & MethodAttributes.MemberAccessMask;
+ if (attrs == MethodAttributes.Private)
+ return false;
if (baseMember.DeclaringType.Module == derivedType.Module)
return true;
- // TODO: Check also InternalsVisibleToAttribute.
- return false;
- }
- private static bool? IsVisibleFromDerived(IMemberDefinition member)
- {
- MethodAttributes attrs = GetAccessAttributes(member) & MethodAttributes.MemberAccessMask;
- if (attrs == MethodAttributes.Private)
+ if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem) {
+ var derivedTypeAsm = derivedType.Module.Assembly;
+ var asm = baseMember.DeclaringType.Module.Assembly;
+
+ if (asm.HasCustomAttributes) {
+ var attributes = asm.CustomAttributes
+ .Where(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.InternalsVisibleToAttribute");
+ foreach (var attribute in attributes) {
+ string assemblyName = attribute.ConstructorArguments[0].Value as string;
+ assemblyName = assemblyName.Split(',')[0]; // strip off any public key info
+ if (assemblyName == derivedTypeAsm.Name.Name)
+ return true;
+ }
+ }
+
return false;
- if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem)
- return null;
- return true;
+ }
+
+ return true;
}
private static MethodAttributes GetAccessAttributes(IMemberDefinition member)
diff --git a/ILSpy.AddIn/GlobalSuppressions.cs b/ILSpy.AddIn/GlobalSuppressions.cs
new file mode 100644
index 000000000..a893f9d25
--- /dev/null
+++ b/ILSpy.AddIn/GlobalSuppressions.cs
@@ -0,0 +1,11 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project. Project-level
+// suppressions either have no target or are given a specific target
+// and scoped to a namespace, type, member, etc.
+//
+// To add a suppression to this file, right-click the message in the
+// Error List, point to "Suppress Message(s)", and click "In Project
+// Suppression File". You do not need to add suppressions to this
+// file manually.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]
diff --git a/ILSpy.AddIn/Guids.cs b/ILSpy.AddIn/Guids.cs
new file mode 100644
index 000000000..bbca1aa1a
--- /dev/null
+++ b/ILSpy.AddIn/Guids.cs
@@ -0,0 +1,14 @@
+// Guids.cs
+// MUST match guids.h
+using System;
+
+namespace ICSharpCode.ILSpy.AddIn
+{
+ static class GuidList
+ {
+ public const string guidILSpyAddInPkgString = "a9120dbe-164a-4891-842f-fb7829273838";
+ public const string guidILSpyAddInCmdSetString = "85ddb8ca-a842-4b1c-ba1a-94141fdf19d0";
+
+ public static readonly Guid guidILSpyAddInCmdSet = new Guid(guidILSpyAddInCmdSetString);
+ };
+}
\ No newline at end of file
diff --git a/ILSpy.AddIn/ILSpy-Large.ico b/ILSpy.AddIn/ILSpy-Large.ico
new file mode 100644
index 000000000..14a26f95a
Binary files /dev/null and b/ILSpy.AddIn/ILSpy-Large.ico differ
diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj
new file mode 100644
index 000000000..7c56424cb
--- /dev/null
+++ b/ILSpy.AddIn/ILSpy.AddIn.csproj
@@ -0,0 +1,246 @@
+
+
+
+
+ $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\VSSDK\Microsoft.VsSDK.targets
+ $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\VSSDK\Microsoft.VsSDK.targets
+
+
+
+
+ $(VisualStudioVersion)
+
+
+
+ Debug
+ AnyCPU
+ 2.0
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}
+ {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ ICSharpCode.ILSpy.AddIn
+ ILSpy.AddIn
+ True
+ Key.snk
+ v4.0
+
+
+
+ Program
+ $(DevEnvDir)\devenv.exe
+ /rootSuffix Exp
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+ true
+
+
+
+ ..\packages\VSSDK.DTE.7.0.3\lib\net20\envdte.dll
+ False
+ False
+
+
+
+ False
+ ..\packages\VSSDK.OLE.Interop.7.0.3\lib\net20\Microsoft.VisualStudio.OLE.Interop.dll
+
+
+ False
+ ..\packages\VSSDK.Shell.10.10.0.3\lib\net40\Microsoft.VisualStudio.Shell.10.0.dll
+
+
+ False
+ ..\packages\VSSDK.Shell.Immutable.10.10.0.3\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll
+
+
+ False
+ ..\packages\VSSDK.Shell.Interop.7.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.dll
+
+
+ False
+ ..\packages\VSSDK.Shell.Interop.8.8.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.8.0.dll
+
+
+
+ False
+ ..\packages\VSSDK.Shell.Interop.9.9.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.9.0.dll
+
+
+ False
+ ..\packages\VSSDK.TextManager.Interop.7.0.3\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll
+
+
+ False
+ ..\packages\VSSDK.TextManager.Interop.8.8.0.3\lib\net20\Microsoft.VisualStudio.TextManager.Interop.8.0.dll
+
+
+
+
+ ..\packages\VSSDK.DTE.7.0.3\lib\net20\stdole.dll
+ False
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+ {26AD1324-4B7C-44BC-84F8-B86AED45729F}
+ 10
+ 0
+ 0
+ primary
+ False
+ False
+
+
+ {1A31287A-4D7D-413E-8E32-3B374931BD89}
+ 8
+ 0
+ 0
+ primary
+ False
+ False
+
+
+ {2CE2370E-D744-4936-A090-3FFFE667B0E1}
+ 9
+ 0
+ 0
+ primary
+ False
+ False
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ true
+ VSPackage
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+ Menus.ctmenu
+ Designer
+
+
+
+
+
+
+
+ Always
+ true
+
+
+ Always
+ true
+
+
+
+
+
+ {6c55b776-26d4-4db3-a6ab-87e783b2f3d1}
+ ICSharpCode.AvalonEdit
+
+
+ {984cc812-9470-4a13-aff9-cc44068d666c}
+ ICSharpCode.Decompiler
+
+
+ {a6bad2ba-76ba-461c-8b6d-418607591247}
+ ILSpy.BamlDecompiler
+
+
+ {1e85eff9-e370-4683-83e4-8a3d063ff791}
+ ILSpy
+
+
+ {d68133bd-1e63-496e-9ede-4fbdbf77b486}
+ Mono.Cecil
+
+
+ {63e6915c-7ea4-4d76-ab28-0d7191eea626}
+ Mono.Cecil.Pdb
+
+
+ {53dca265-3c3c-42f9-b647-f72ba678122b}
+ ICSharpCode.NRefactory.CSharp
+
+
+ {7b82b671-419f-45f4-b778-d9286f996efa}
+ ICSharpCode.NRefactory.VB
+
+
+ {3b2a5653-ec97-4001-bb9b-d90f1af2c371}
+ ICSharpCode.NRefactory
+
+
+ {dde2a481-8271-4eac-a330-8fa6a38d13d1}
+ ICSharpCode.TreeView
+
+
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy.AddIn/ILSpyAddIn.vsct b/ILSpy.AddIn/ILSpyAddIn.vsct
new file mode 100644
index 000000000..69af34274
--- /dev/null
+++ b/ILSpy.AddIn/ILSpyAddIn.vsct
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ILSpy.AddIn/ILSpyAddInPackage.cs b/ILSpy.AddIn/ILSpyAddInPackage.cs
new file mode 100644
index 000000000..de2ddd160
--- /dev/null
+++ b/ILSpy.AddIn/ILSpyAddInPackage.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.ComponentModel.Design;
+using Microsoft.Win32;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.OLE.Interop;
+using Microsoft.VisualStudio.Shell;
+using System.Reflection;
+using System.IO;
+using Mono.Cecil;
+
+namespace ICSharpCode.ILSpy.AddIn
+{
+ ///
+ /// This is the class that implements the package exposed by this assembly.
+ ///
+ /// The minimum requirement for a class to be considered a valid package for Visual Studio
+ /// is to implement the IVsPackage interface and register itself with the shell.
+ /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
+ /// to do it: it derives from the Package class that provides the implementation of the
+ /// IVsPackage interface and uses the registration attributes defined in the framework to
+ /// register itself and its components with the shell.
+ ///
+ // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
+ // a package.
+ [PackageRegistration(UseManagedResourcesOnly = true)]
+ // This attribute is used to register the information needed to show this package
+ // in the Help/About dialog of Visual Studio.
+ [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+ // This attribute is needed to let the shell know that this package exposes some menus.
+ [ProvideMenuResource("Menus.ctmenu", 1)]
+ [Guid(GuidList.guidILSpyAddInPkgString)]
+ [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExistsAndFullyLoaded_string)]
+ public sealed class ILSpyAddInPackage : Package
+ {
+ ///
+ /// Default constructor of the package.
+ /// Inside this method you can place any initialization code that does not require
+ /// any Visual Studio service because at this point the package object is created but
+ /// not sited yet inside Visual Studio environment. The place to do all the other
+ /// initialization is the Initialize method.
+ ///
+ public ILSpyAddInPackage()
+ {
+ Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
+ }
+
+
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Overridden Package Implementation
+ #region Package Members
+
+ ///
+ /// Initialization of the package; this method is called right after the package is sited, so this is the place
+ /// where you can put all the initialization code that rely on services provided by VisualStudio.
+ ///
+ protected override void Initialize()
+ {
+ Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
+ base.Initialize();
+
+ // Add our command handlers for menu (commands must exist in the .vsct file)
+ OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
+ if (null != mcs) {
+ // Create the command for the menu item.
+ CommandID menuCommandID = new CommandID(GuidList.guidILSpyAddInCmdSet, (int)PkgCmdIDList.cmdidOpenReferenceInILSpy);
+ MenuCommand menuItem = new MenuCommand(OpenReferenceInILSpyCallback, menuCommandID);
+ mcs.AddCommand(menuItem);
+
+ // Create the command for the menu item.
+ CommandID menuCommandID2 = new CommandID(GuidList.guidILSpyAddInCmdSet, (int)PkgCmdIDList.cmdidOpenProjectOutputInILSpy);
+ MenuCommand menuItem2 = new MenuCommand(OpenProjectOutputInILSpyCallback, menuCommandID2);
+ mcs.AddCommand(menuItem2);
+
+ // Create the command for the menu item.
+ CommandID menuCommandID3 = new CommandID(GuidList.guidILSpyAddInCmdSet, (int)PkgCmdIDList.cmdidOpenILSpy);
+ MenuCommand menuItem3 = new MenuCommand(OpenILSpyCallback, menuCommandID3);
+ mcs.AddCommand(menuItem3);
+ }
+ }
+ #endregion
+
+ ///
+ /// This function is the callback used to execute a command when the a menu item is clicked.
+ /// See the Initialize method to see how the menu item is associated to this function using
+ /// the OleMenuCommandService service and the MenuCommand class.
+ ///
+ private void OpenReferenceInILSpyCallback(object sender, EventArgs e)
+ {
+ var explorer = ((EnvDTE80.DTE2)GetGlobalService(typeof(EnvDTE.DTE))).ToolWindows.SolutionExplorer;
+ var items =(object[]) explorer.SelectedItems;
+
+ foreach (EnvDTE.UIHierarchyItem item in items) {
+ dynamic reference = item.Object;
+ string path = null;
+ if (reference.PublicKeyToken != "") {
+ var token = Utils.HexStringToBytes(reference.PublicKeyToken);
+ path = GacInterop.FindAssemblyInNetGac(new AssemblyNameReference(reference.Identity, new Version(reference.Version)) { PublicKeyToken = token });
+ }
+ if (path == null)
+ path = reference.Path;
+ OpenAssemblyInILSpy(path);
+ }
+ }
+
+ private void OpenProjectOutputInILSpyCallback(object sender, EventArgs e)
+ {
+ var explorer = ((EnvDTE80.DTE2)GetGlobalService(typeof(EnvDTE.DTE))).ToolWindows.SolutionExplorer;
+ var items = (object[])explorer.SelectedItems;
+
+ foreach (EnvDTE.UIHierarchyItem item in items) {
+ EnvDTE.Project project = (EnvDTE.Project)item.Object;
+ EnvDTE.Configuration config = project.ConfigurationManager.ActiveConfiguration;
+ string projectPath = Path.GetDirectoryName(project.FileName);
+ string outputPath = config.Properties.Item("OutputPath").Value.ToString();
+ string assemblyFileName = project.Properties.Item("OutputFileName").Value.ToString();
+ OpenAssemblyInILSpy(Path.Combine(projectPath, outputPath, assemblyFileName));
+ }
+ }
+
+ private void OpenILSpyCallback(object sender, EventArgs e)
+ {
+ Process.Start(GetILSpyPath());
+ }
+
+ private string GetILSpyPath()
+ {
+ var basePath = Path.GetDirectoryName(typeof(ILSpyAddInPackage).Assembly.Location);
+ return Path.Combine(basePath, "ILSpy.exe");
+ }
+
+ private void OpenAssemblyInILSpy(string assemblyFileName)
+ {
+ if (!File.Exists(assemblyFileName)) {
+ ShowMessage("Could not find assembly '{0}', please ensure the project and all references were built correctly!", assemblyFileName);
+ return;
+ }
+ Process.Start(GetILSpyPath(), Utils.ArgumentArrayToCommandLine(assemblyFileName));
+ }
+
+ private void ShowMessage(string format, params object[] items)
+ {
+ IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
+ Guid clsid = Guid.Empty;
+ int result;
+ Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(
+ uiShell.ShowMessageBox(
+ 0,
+ ref clsid,
+ "ILSpy.AddIn",
+ string.Format(CultureInfo.CurrentCulture, format, items),
+ string.Empty,
+ 0,
+ OLEMSGBUTTON.OLEMSGBUTTON_OK,
+ OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
+ OLEMSGICON.OLEMSGICON_INFO,
+ 0, // false
+ out result
+ )
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy.AddIn/Key.snk b/ILSpy.AddIn/Key.snk
new file mode 100644
index 000000000..727377dec
Binary files /dev/null and b/ILSpy.AddIn/Key.snk differ
diff --git a/ILSpy.AddIn/PkgCmdID.cs b/ILSpy.AddIn/PkgCmdID.cs
new file mode 100644
index 000000000..1cc38a3fd
--- /dev/null
+++ b/ILSpy.AddIn/PkgCmdID.cs
@@ -0,0 +1,13 @@
+// PkgCmdID.cs
+// MUST match PkgCmdID.h
+using System;
+
+namespace ICSharpCode.ILSpy.AddIn
+{
+ static class PkgCmdIDList
+ {
+ public const uint cmdidOpenILSpy = 0x100;
+ public const uint cmdidOpenReferenceInILSpy = 0x200;
+ public const uint cmdidOpenProjectOutputInILSpy = 0x300;
+ };
+}
\ No newline at end of file
diff --git a/ILSpy.AddIn/Properties/AssemblyInfo.cs b/ILSpy.AddIn/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..037d95e27
--- /dev/null
+++ b/ILSpy.AddIn/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ILSpy.AddIn")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("IC#Code")]
+[assembly: AssemblyProduct("ILSpy.AddIn")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: CLSCompliant(false)]
+[assembly: NeutralResourcesLanguage("en-US")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+
+[assembly: InternalsVisibleTo("ILSpy.AddIn_IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100653c4a319be4f524972c3c5bba5fd243330f8e900287d9022d7821a63fd0086fd3801e3683dbe9897f2ecc44727023e9b40adcf180730af70c81c54476b3e5ba8b0f07f5132b2c3cc54347a2c1a9d64ebaaaf3cbffc1a18c427981e2a51d53d5ab02536b7550e732f795121c38a0abfdb38596353525d034baf9e6f1fd8ac4ac")]
+[assembly: InternalsVisibleTo("ILSpy.AddIn_UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100653c4a319be4f524972c3c5bba5fd243330f8e900287d9022d7821a63fd0086fd3801e3683dbe9897f2ecc44727023e9b40adcf180730af70c81c54476b3e5ba8b0f07f5132b2c3cc54347a2c1a9d64ebaaaf3cbffc1a18c427981e2a51d53d5ab02536b7550e732f795121c38a0abfdb38596353525d034baf9e6f1fd8ac4ac")]
diff --git a/ILSpy.AddIn/Resources.Designer.cs b/ILSpy.AddIn/Resources.Designer.cs
new file mode 100644
index 000000000..646632f04
--- /dev/null
+++ b/ILSpy.AddIn/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.35317
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ICSharpCode.ILSpy.AddIn {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ICSharpCode.ILSpy.AddIn.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/ILSpy.AddIn/Resources.resx b/ILSpy.AddIn/Resources.resx
new file mode 100644
index 000000000..891c592b4
--- /dev/null
+++ b/ILSpy.AddIn/Resources.resx
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ILSpy.AddIn/Resources/Images.png b/ILSpy.AddIn/Resources/Images.png
new file mode 100644
index 000000000..4a217fa71
Binary files /dev/null and b/ILSpy.AddIn/Resources/Images.png differ
diff --git a/ILSpy.AddIn/Resources/Package.ico b/ILSpy.AddIn/Resources/Package.ico
new file mode 100644
index 000000000..900abec81
Binary files /dev/null and b/ILSpy.AddIn/Resources/Package.ico differ
diff --git a/ILSpy.AddIn/Utils.cs b/ILSpy.AddIn/Utils.cs
new file mode 100644
index 000000000..ce850fcfe
--- /dev/null
+++ b/ILSpy.AddIn/Utils.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ICSharpCode.ILSpy.AddIn
+{
+ class Utils
+ {
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ static extern unsafe char** CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
+ [DllImport("kernel32.dll")]
+ static extern IntPtr LocalFree(IntPtr hMem);
+
+ #region CommandLine <-> Argument Array
+ ///
+ /// Decodes a command line into an array of arguments according to the CommandLineToArgvW rules.
+ ///
+ ///
+ /// Command line parsing rules:
+ /// - 2n backslashes followed by a quotation mark produce n backslashes, and the quotation mark is considered to be the end of the argument.
+ /// - (2n) + 1 backslashes followed by a quotation mark again produce n backslashes followed by a quotation mark.
+ /// - n backslashes not followed by a quotation mark simply produce n backslashes.
+ ///
+ public static unsafe string[] CommandLineToArgumentArray(string commandLine)
+ {
+ if (string.IsNullOrEmpty(commandLine))
+ return new string[0];
+ int numberOfArgs;
+ char** arr = CommandLineToArgvW(commandLine, out numberOfArgs);
+ if (arr == null)
+ throw new Win32Exception();
+ try {
+ string[] result = new string[numberOfArgs];
+ for (int i = 0; i < numberOfArgs; i++) {
+ result[i] = new string(arr[i]);
+ }
+ return result;
+ } finally {
+ // Free memory obtained by CommandLineToArgW.
+ LocalFree(new IntPtr(arr));
+ }
+ }
+
+ static readonly char[] charsNeedingQuoting = { ' ', '\t', '\n', '\v', '"' };
+
+ ///
+ /// Escapes a set of arguments according to the CommandLineToArgvW rules.
+ ///
+ ///
+ /// Command line parsing rules:
+ /// - 2n backslashes followed by a quotation mark produce n backslashes, and the quotation mark is considered to be the end of the argument.
+ /// - (2n) + 1 backslashes followed by a quotation mark again produce n backslashes followed by a quotation mark.
+ /// - n backslashes not followed by a quotation mark simply produce n backslashes.
+ ///
+ public static string ArgumentArrayToCommandLine(params string[] arguments)
+ {
+ if (arguments == null)
+ return null;
+ StringBuilder b = new StringBuilder();
+ for (int i = 0; i < arguments.Length; i++) {
+ if (i > 0)
+ b.Append(' ');
+ AppendArgument(b, arguments[i]);
+ }
+ return b.ToString();
+ }
+
+ static void AppendArgument(StringBuilder b, string arg)
+ {
+ if (arg.Length > 0 && arg.IndexOfAny(charsNeedingQuoting) < 0) {
+ b.Append(arg);
+ } else {
+ b.Append('"');
+ for (int j = 0; ; j++) {
+ int backslashCount = 0;
+ while (j < arg.Length && arg[j] == '\\') {
+ backslashCount++;
+ j++;
+ }
+ if (j == arg.Length) {
+ b.Append('\\', backslashCount * 2);
+ break;
+ } else if (arg[j] == '"') {
+ b.Append('\\', backslashCount * 2 + 1);
+ b.Append('"');
+ } else {
+ b.Append('\\', backslashCount);
+ b.Append(arg[j]);
+ }
+ }
+ b.Append('"');
+ }
+ }
+ #endregion
+
+ public static byte[] HexStringToBytes(string hex)
+ {
+ var result = new byte[hex.Length / 2];
+ for (int i = 0; i < hex.Length / 2; i++) {
+ result[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
+ }
+ return result;
+ }
+ }
+}
diff --git a/ILSpy.AddIn/VSPackage.resx b/ILSpy.AddIn/VSPackage.resx
new file mode 100644
index 000000000..345019f09
--- /dev/null
+++ b/ILSpy.AddIn/VSPackage.resx
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ ILSpy.AddIn
+
+
+ Integration of the ILSpy Decompiler into Visual Studio.
+
+
+ Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/ILSpy.AddIn/license.txt b/ILSpy.AddIn/license.txt
new file mode 100644
index 000000000..0bfb45649
--- /dev/null
+++ b/ILSpy.AddIn/license.txt
@@ -0,0 +1,12 @@
+The following MIT license applies to ILSpy, NRefactory and ICSharpCode.Decompiler. Mono.Cecil also uses the MIT license (Copyright JB Evain). AvalonEdit and SharpTreeView use LGPL, which can be found in the LGPL.txt file. ILSpy.BamlDecompiler uses the MS-PL, which can be found in the MS-PL.txt file.
+
+
+MIT license:
+
+Copyright (c) 2011-2014 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.
\ No newline at end of file
diff --git a/ILSpy.AddIn/packages.config b/ILSpy.AddIn/packages.config
new file mode 100644
index 000000000..14a098365
--- /dev/null
+++ b/ILSpy.AddIn/packages.config
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy.AddIn/source.extension.vsixmanifest b/ILSpy.AddIn/source.extension.vsixmanifest
new file mode 100644
index 000000000..7be4f368e
--- /dev/null
+++ b/ILSpy.AddIn/source.extension.vsixmanifest
@@ -0,0 +1,32 @@
+
+
+
+ ILSpy
+ IC#Code
+ 1.2
+ Integrates the ILSpy decompiler into Visual Studio.
+ ILSpy-Large.ico
+ license.txt
+
+ http://ilspy.net
+ 1033
+
+
+
+ Pro
+
+
+ Pro
+
+
+ Pro
+
+
+ Pro
+
+
+
+
+ |%CurrentProject%;PkgdefProjectOutputGroup|
+
+
diff --git a/ILSpy.BamlDecompiler/CecilTypeResolver.cs b/ILSpy.BamlDecompiler/CecilTypeResolver.cs
index 9de73931a..ba9299fd6 100644
--- a/ILSpy.BamlDecompiler/CecilTypeResolver.cs
+++ b/ILSpy.BamlDecompiler/CecilTypeResolver.cs
@@ -39,12 +39,13 @@ namespace ILSpy.BamlDecompiler
public IType GetTypeByAssemblyQualifiedName(string name)
{
- int comma = name.IndexOf(',');
+ int bracket = name.LastIndexOf(']');
+ int comma = bracket > -1 ? name.IndexOf(',', bracket) : name.IndexOf(',');
if (comma == -1)
throw new ArgumentException("invalid name");
-
- string fullName = name.Substring(0, comma);
+
+ string fullName = bracket > -1 ? name.Substring(0, name.IndexOf('[')) : name.Substring(0, comma);
string assemblyName = name.Substring(comma + 1).Trim();
var type = thisAssembly.MainModule.GetType(fullName);
diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs
index 95ae027ab..6454fe1ed 100644
--- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs
+++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs
@@ -131,7 +131,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ParseName(string assemblyQualifiedName, out string name, out string @namespace, out string assembly)
{
- int commaSeparator = assemblyQualifiedName.IndexOf(", ");
+ int bracket = assemblyQualifiedName.LastIndexOf(']');
+ int commaSeparator = bracket > -1 ? assemblyQualifiedName.IndexOf(", ", bracket) : assemblyQualifiedName.IndexOf(", ");
assembly = "";
if (commaSeparator >= 0) {
assembly = assemblyQualifiedName.Substring(commaSeparator + 2);
diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
index 9676243c9..b80d2ae5b 100644
--- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
+++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
@@ -868,11 +868,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
switch (x) {
case 0x25a:
// StaticExtension
- object resource = this.GetResourceName(valueIdentifier);
- if (resource is ResourceName)
- value = this.GetStaticExtension(((ResourceName)resource).Name);
- else if (resource is PropertyDeclaration)
- value = this.GetStaticExtension(FormatPropertyDeclaration(((PropertyDeclaration)resource), true, false, false));
+ value = this.GetStaticExtension(this.GetResourceName(valueIdentifier));
break;
case 0x25b: // StaticResource
case 0xbd: // DynamicResource
@@ -883,7 +879,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
else if (isStaticType)
{
TypeDeclaration extensionDeclaration = this.GetTypeDeclaration(extensionIdentifier);
- value = GetExtension(extensionDeclaration, GetStaticExtension(GetResourceName(valueIdentifier).ToString()));
+ value = GetExtension(extensionDeclaration, GetStaticExtension(GetResourceName(valueIdentifier)));
}
else
{
@@ -912,7 +908,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
short identifier = reader.ReadInt16();
string text = reader.ReadString();
- EnqueueProperty(identifier, text);
+ EnqueueProperty(identifier, EscapeCurlyBraces(text));
}
void ReadPropertyWithConverter()
@@ -921,7 +917,16 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
string text = reader.ReadString();
reader.ReadInt16();
- EnqueueProperty(identifier, text);
+ EnqueueProperty(identifier, EscapeCurlyBraces(text));
+ }
+
+ string EscapeCurlyBraces(string text)
+ {
+ if (!text.StartsWith("{", StringComparison.OrdinalIgnoreCase))
+ return text;
+ if (text.StartsWith("{}", StringComparison.OrdinalIgnoreCase))
+ return text;
+ return "{}" + text;
}
bool HaveSeenNestedElement()
@@ -1316,7 +1321,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
{
reader.ReadInt16();
- // Non serve aprire niente, è il default
+ // Non serve aprire niente, ?il default
}
static void ReadConstructorParametersStart()
@@ -1449,15 +1454,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
if (isValueType)
resource = GetTypeExtension(typeIdentifier);
else if (isStaticType) {
- object name = GetResourceName(typeIdentifier);
- if (name == null)
- resource = null;
- else if (name is ResourceName)
- resource = GetStaticExtension(((ResourceName)name).Name);
- else if (name is PropertyDeclaration)
- resource = GetStaticExtension(FormatPropertyDeclaration(((PropertyDeclaration)name), true, false, false));
- else
- throw new InvalidOperationException("Invalid resource: " + name.GetType());
+ resource = GetStaticExtension(GetResourceName(typeIdentifier));
} else {
resource = this.stringTable[typeIdentifier];
}
@@ -1473,8 +1470,18 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return String.Format("{{TemplateBinding {0}}}", FormatPropertyDeclaration(propertyDeclaration, true, false, false));
}
- string GetStaticExtension(string name)
+ string GetStaticExtension(object resource)
{
+ if (resource == null)
+ return null;
+ string name;
+ if (resource is ResourceName)
+ name = ((ResourceName)resource).Name;
+ else if (resource is PropertyDeclaration)
+ name = this.FormatPropertyDeclaration(((PropertyDeclaration)resource), true, false, false);
+ else
+ throw new InvalidOperationException("Invalid resource: " + resource.GetType());
+
string prefix = this.LookupPrefix(XmlPIMapping.XamlNamespace, false);
if (String.IsNullOrEmpty(prefix))
return String.Format("{{Static {0}}}", name);
@@ -1588,7 +1595,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
string fullName = reader.ReadString();
assemblyId = (short)(assemblyId & 0xfff);
TypeDeclaration declaration;
- int length = fullName.LastIndexOf('.');
+ int bracket = fullName.IndexOf('[');
+ int length = bracket > -1 ? fullName.LastIndexOf('.', bracket) : fullName.LastIndexOf('.');
if (length != -1)
{
string name = fullName.Substring(length + 1);
diff --git a/ILSpy.BamlDecompiler/Tests/Cases/CustomControl.cs b/ILSpy.BamlDecompiler/Tests/Cases/CustomControl.cs
index f85c51a4e..e48b20d8a 100644
--- a/ILSpy.BamlDecompiler/Tests/Cases/CustomControl.cs
+++ b/ILSpy.BamlDecompiler/Tests/Cases/CustomControl.cs
@@ -10,6 +10,8 @@ namespace ILSpy.BamlDecompiler.Tests.Cases
{
public class CustomControl : ContentControl
{
+ public static string SimpleProperty = "Hi!";
+
public static readonly DependencyProperty CustomNameProperty = DependencyProperty.RegisterAttached("CustomName", typeof(string), typeof(CustomControl));
public static string GetCustomName(DependencyObject target)
diff --git a/ILSpy.BamlDecompiler/Tests/Cases/EscapeSequence.xaml b/ILSpy.BamlDecompiler/Tests/Cases/EscapeSequence.xaml
new file mode 100644
index 000000000..6487f47a8
--- /dev/null
+++ b/ILSpy.BamlDecompiler/Tests/Cases/EscapeSequence.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml b/ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml
index 5073d3e29..565fb2e1c 100644
--- a/ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml
+++ b/ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml
@@ -3,6 +3,6 @@
-
+
\ No newline at end of file
diff --git a/ILSpy.BamlDecompiler/Tests/Cases/NamespacePrefix.xaml b/ILSpy.BamlDecompiler/Tests/Cases/NamespacePrefix.xaml
index 5fb529054..42e2f2f33 100644
--- a/ILSpy.BamlDecompiler/Tests/Cases/NamespacePrefix.xaml
+++ b/ILSpy.BamlDecompiler/Tests/Cases/NamespacePrefix.xaml
@@ -1,12 +1,13 @@
-
+
0
+ {}{Test}
Custom1
-
+
@@ -124,6 +125,10 @@
+
+ Designer
+ MSBuild:Compile
+
diff --git a/ILSpy.BamlDecompiler/Tests/TestRunner.cs b/ILSpy.BamlDecompiler/Tests/TestRunner.cs
index 70b656d9c..678463fa1 100644
--- a/ILSpy.BamlDecompiler/Tests/TestRunner.cs
+++ b/ILSpy.BamlDecompiler/Tests/TestRunner.cs
@@ -91,6 +91,12 @@ namespace ILSpy.BamlDecompiler.Tests
{
RunTest("cases/namespaceprefix");
}
+
+ [Test]
+ public void EscapeSequence()
+ {
+ RunTest("cases/escapesequence");
+ }
#region RunTest
void RunTest(string name)
diff --git a/ILSpy.sln b/ILSpy.sln
index 2a37cd780..1ee34aaa2 100644
--- a/ILSpy.sln
+++ b/ILSpy.sln
@@ -2,7 +2,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
# SharpDevelop 5.1
-VisualStudioVersion = 14.0.21730.1
+VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}"
ProjectSection(SolutionItems) = preProject
@@ -34,7 +34,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSha
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.Cecil", "NRefactory\ICSharpCode.NRefactory.Cecil\ICSharpCode.NRefactory.Cecil.csproj", "{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7BB4F277-CB4E-432D-B503-841CE1918294}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.AddIn", "ILSpy.AddIn\ILSpy.AddIn.csproj", "{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0A344E19-D1FC-4F4C-8883-0844AC669113}"
ProjectSection(SolutionItems) = preProject
Rebracer.xml = Rebracer.xml
EndProjectSection
@@ -225,6 +227,20 @@ Global
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|Any CPU.Build.0 = Release|Any CPU
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|x86.ActiveCfg = Release|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|Any CPU.ActiveCfg = net_4_5_Debug|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|Any CPU.Build.0 = net_4_5_Debug|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|x86.ActiveCfg = net_4_5_Debug|x86
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|x86.Build.0 = net_4_5_Debug|x86
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|Any CPU.ActiveCfg = net_4_5_Release|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|Any CPU.Build.0 = net_4_5_Release|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|x86.ActiveCfg = net_4_5_Release|x86
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|x86.Build.0 = net_4_5_Release|x86
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs
index 850836068..edf4d8a1d 100644
--- a/ILSpy/AboutPage.cs
+++ b/ILSpy/AboutPage.cs
@@ -95,6 +95,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"));
+ output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MS-PL", "resource:MS-PL.txt"));
textView.ShowText(output);
}
diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs
index a620408f0..a32a06291 100644
--- a/ILSpy/AssemblyList.cs
+++ b/ILSpy/AssemblyList.cs
@@ -88,7 +88,7 @@ namespace ICSharpCode.ILSpy
return new XElement(
"List",
new XAttribute("name", this.ListName),
- assemblies.Select(asm => new XElement("Assembly", asm.FileName))
+ assemblies.Where(asm => !asm.IsAutoLoaded).Select(asm => new XElement("Assembly", asm.FileName))
);
}
@@ -117,6 +117,21 @@ namespace ICSharpCode.ILSpy
);
}
}
+
+ internal void RefreshSave()
+ {
+ if (!dirty) {
+ dirty = true;
+ App.Current.Dispatcher.BeginInvoke(
+ DispatcherPriority.Background,
+ new Action(
+ delegate {
+ dirty = false;
+ AssemblyListManager.SaveList(this);
+ })
+ );
+ }
+ }
internal void ClearCache()
{
@@ -128,7 +143,7 @@ namespace ICSharpCode.ILSpy
/// Opens an assembly from disk.
/// Returns the existing assembly node if it is already loaded.
///
- public LoadedAssembly OpenAssembly(string file)
+ public LoadedAssembly OpenAssembly(string file, bool isAutoLoaded=false)
{
App.Current.Dispatcher.VerifyAccess();
@@ -140,11 +155,36 @@ namespace ICSharpCode.ILSpy
}
var newAsm = new LoadedAssembly(this, file);
+ newAsm.IsAutoLoaded = isAutoLoaded;
lock (assemblies) {
this.assemblies.Add(newAsm);
}
return newAsm;
}
+
+ ///
+ /// Replace the assembly object model from a crafted stream, without disk I/O
+ /// Returns null if it is not already loaded.
+ ///
+ public LoadedAssembly HotReplaceAssembly(string file, Stream stream)
+ {
+ App.Current.Dispatcher.VerifyAccess();
+ file = Path.GetFullPath(file);
+
+ var target = this.assemblies.FirstOrDefault(asm => file.Equals(asm.FileName, StringComparison.OrdinalIgnoreCase));
+ if (target == null)
+ return null;
+
+ var index = this.assemblies.IndexOf(target);
+ var newAsm = new LoadedAssembly(this, file, stream);
+ newAsm.IsAutoLoaded = target.IsAutoLoaded;
+ lock (assemblies)
+ {
+ this.assemblies.Remove(target);
+ this.assemblies.Insert(index, newAsm);
+ }
+ return newAsm;
+ }
public void Unload(LoadedAssembly assembly)
{
diff --git a/ILSpy/CommandLineArguments.cs b/ILSpy/CommandLineArguments.cs
index a82b9eac1..0c4aa3e4c 100644
--- a/ILSpy/CommandLineArguments.cs
+++ b/ILSpy/CommandLineArguments.cs
@@ -27,8 +27,11 @@ namespace ICSharpCode.ILSpy
public List AssembliesToLoad = new List();
public bool? SingleInstance;
public string NavigateTo;
+ public string Search;
public string Language;
public bool NoActivate;
+ public Guid? FixedGuid;
+ public string SaveDirectory;
public CommandLineArguments(IEnumerable arguments)
{
@@ -42,10 +45,21 @@ namespace ICSharpCode.ILSpy
this.SingleInstance = false;
else if (arg.StartsWith("/navigateTo:", StringComparison.OrdinalIgnoreCase))
this.NavigateTo = arg.Substring("/navigateTo:".Length);
+ else if (arg.StartsWith("/search:", StringComparison.OrdinalIgnoreCase))
+ this.Search = arg.Substring("/search:".Length);
else if (arg.StartsWith("/language:", StringComparison.OrdinalIgnoreCase))
this.Language = arg.Substring("/language:".Length);
else if (arg.Equals("/noActivate", StringComparison.OrdinalIgnoreCase))
this.NoActivate = true;
+ else if (arg.StartsWith("/fixedGuid:", StringComparison.OrdinalIgnoreCase)) {
+ string guid = arg.Substring("/fixedGuid:".Length);
+ if (guid.Length < 32)
+ guid = guid + new string('0', 32 - guid.Length);
+ Guid fixedGuid;
+ if (Guid.TryParse(guid, out fixedGuid))
+ this.FixedGuid = fixedGuid;
+ } else if (arg.StartsWith("/saveDir:", StringComparison.OrdinalIgnoreCase))
+ this.SaveDirectory = arg.Substring("/saveDir:".Length);
} else {
this.AssembliesToLoad.Add(arg);
}
diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs
index b00d54124..3d34322d8 100644
--- a/ILSpy/ContextMenuEntry.cs
+++ b/ILSpy/ContextMenuEntry.cs
@@ -55,6 +55,12 @@ namespace ICSharpCode.ILSpy
///
public DecompilerTextView TextView { get; private set; }
+ ///
+ /// Returns the list box the context menu is assigned to.
+ /// Returns null, if context menu is not assigned to a list box.
+ ///
+ public ListBox ListBox { get; private set; }
+
///
/// Returns the reference the mouse cursor is currently hovering above.
/// Returns null, if there was no reference found.
@@ -67,9 +73,15 @@ namespace ICSharpCode.ILSpy
///
public TextViewPosition? Position { get; private set; }
- public static TextViewContext Create(SharpTreeView treeView = null, DecompilerTextView textView = null)
+ public static TextViewContext Create(SharpTreeView treeView = null, DecompilerTextView textView = null, ListBox listBox = null)
{
- var reference = textView != null ? textView.GetReferenceSegmentAtMousePosition() : null;
+ ReferenceSegment reference;
+ if (textView != null)
+ reference = textView.GetReferenceSegmentAtMousePosition();
+ else if (listBox != null)
+ reference = new ReferenceSegment { Reference = ((SearchResult)listBox.SelectedItem).Member };
+ else
+ reference = null;
var position = textView != null ? textView.GetPositionFromMousePosition() : null;
var selectedTreeNodes = treeView != null ? treeView.GetTopLevelSelection().ToArray() : null;
return new TextViewContext {
@@ -126,8 +138,16 @@ namespace ICSharpCode.ILSpy
}
}
+ public static void Add(ListBox listBox)
+ {
+ var provider = new ContextMenuProvider(listBox);
+ listBox.ContextMenuOpening += provider.listBox_ContextMenuOpening;
+ listBox.ContextMenu = new ContextMenu();
+ }
+
readonly SharpTreeView treeView;
readonly DecompilerTextView textView;
+ readonly ListBox listBox;
[ImportMany(typeof(IContextMenuEntry))]
Lazy[] entries = null;
@@ -139,6 +159,12 @@ namespace ICSharpCode.ILSpy
App.CompositionContainer.ComposeParts(this);
}
+ ContextMenuProvider(ListBox listBox)
+ {
+ this.listBox = listBox;
+ App.CompositionContainer.ComposeParts(this);
+ }
+
void treeView_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
TextViewContext context = TextViewContext.Create(treeView);
@@ -165,6 +191,17 @@ namespace ICSharpCode.ILSpy
e.Handled = true;
}
+ void listBox_ContextMenuOpening(object sender, ContextMenuEventArgs e)
+ {
+ TextViewContext context = TextViewContext.Create(listBox: listBox);
+ ContextMenu menu;
+ if (ShowContextMenu(context, out menu))
+ listBox.ContextMenu = menu;
+ else
+ // hide the context menu.
+ e.Handled = true;
+ }
+
bool ShowContextMenu(TextViewContext context, out ContextMenu menu)
{
menu = new ContextMenu();
diff --git a/ILSpy/Controls/ResourceObjectTable.xaml.cs b/ILSpy/Controls/ResourceObjectTable.xaml.cs
index 9c23e31b3..019a1daeb 100644
--- a/ILSpy/Controls/ResourceObjectTable.xaml.cs
+++ b/ILSpy/Controls/ResourceObjectTable.xaml.cs
@@ -30,24 +30,32 @@ namespace ICSharpCode.ILSpy.Controls
///
public partial class ResourceObjectTable : UserControl
{
- public ResourceObjectTable(IEnumerable resources,Size maxSize)
+ public ResourceObjectTable(IEnumerable resources, ContentPresenter contentPresenter)
{
InitializeComponent();
// set size to fit decompiler window
- // TODO: there should be a more transparent way to do this
- Width = maxSize.Width;
- MaxHeight = maxSize.Height;
+ contentPresenter.SizeChanged += OnParentSizeChanged;
+ Width = contentPresenter.ActualWidth - 45;
+ MaxHeight = contentPresenter.ActualHeight;
resourceListView.ItemsSource = resources;
}
+
+ private void OnParentSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ if (e.WidthChanged)
+ Width = e.NewSize.Width - 45;
+ if (e.HeightChanged)
+ MaxHeight = e.NewSize.Height;
+ }
void ExecuteCopy(object sender, ExecutedRoutedEventArgs args)
{
- StringBuilder sb = new StringBuilder();
- foreach (var item in resourceListView.SelectedItems)
- {
- sb.AppendLine(item.ToString());
- }
- Clipboard.SetText(sb.ToString());
+ StringBuilder sb = new StringBuilder();
+ foreach (var item in resourceListView.SelectedItems)
+ {
+ sb.AppendLine(item.ToString());
+ }
+ Clipboard.SetText(sb.ToString());
}
void CanExecuteCopy(object sender, CanExecuteRoutedEventArgs args)
diff --git a/ILSpy/Controls/ResourceStringTable.xaml.cs b/ILSpy/Controls/ResourceStringTable.xaml.cs
index 51430fee9..25233a437 100644
--- a/ILSpy/Controls/ResourceStringTable.xaml.cs
+++ b/ILSpy/Controls/ResourceStringTable.xaml.cs
@@ -30,24 +30,32 @@ namespace ICSharpCode.ILSpy.Controls
///
public partial class ResourceStringTable : UserControl
{
- public ResourceStringTable(IEnumerable strings,Size maxSize)
+ public ResourceStringTable(IEnumerable strings, ContentPresenter contentPresenter)
{
InitializeComponent();
// set size to fit decompiler window
- // TODO: there should be a more transparent way to do this
- Width = maxSize.Width;
- MaxHeight = maxSize.Height;
+ contentPresenter.SizeChanged += OnParentSizeChanged;
+ Width = contentPresenter.ActualWidth - 45;
+ MaxHeight = contentPresenter.ActualHeight;
resourceListView.ItemsSource = strings;
}
+
+ private void OnParentSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ if (e.WidthChanged)
+ Width = e.NewSize.Width - 45;
+ if (e.HeightChanged)
+ MaxHeight = e.NewSize.Height;
+ }
void ExecuteCopy(object sender, ExecutedRoutedEventArgs args)
{
- StringBuilder sb = new StringBuilder();
- foreach (var item in resourceListView.SelectedItems)
- {
- sb.AppendLine(item.ToString());
- }
- Clipboard.SetText(sb.ToString());
+ StringBuilder sb = new StringBuilder();
+ foreach (var item in resourceListView.SelectedItems)
+ {
+ sb.AppendLine(item.ToString());
+ }
+ Clipboard.SetText(sb.ToString());
}
void CanExecuteCopy(object sender, CanExecuteRoutedEventArgs args)
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index 85cb63a96..363a842da 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -199,7 +199,9 @@
Code
+
+
@@ -216,6 +218,7 @@
+
@@ -228,6 +231,7 @@
+
@@ -249,6 +253,9 @@
license.txt
+
+ MS-PL.txt
+
diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs
index 834f09d5f..a8263c009 100644
--- a/ILSpy/Languages/CSharpLanguage.cs
+++ b/ILSpy/Languages/CSharpLanguage.cs
@@ -225,7 +225,14 @@ namespace ICSharpCode.ILSpy
additionalTransform.Run(astBuilder.SyntaxTree);
}
if (options.DecompilerSettings.ShowXmlDocumentation) {
- AddXmlDocTransform.Run(astBuilder.SyntaxTree);
+ try {
+ AddXmlDocTransform.Run(astBuilder.SyntaxTree);
+ } catch (XmlException ex) {
+ string[] msg = (" Exception while reading XmlDoc: " + ex.ToString()).Split(new[]{'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries);
+ var insertionPoint = astBuilder.SyntaxTree.FirstChild;
+ for (int i = 0; i < msg.Length; i++)
+ astBuilder.SyntaxTree.InsertChildBefore(insertionPoint, new Comment(msg[i], CommentType.Documentation), Roles.Comment);
+ }
}
astBuilder.GenerateCode(output);
}*/
@@ -267,6 +274,21 @@ namespace ICSharpCode.ILSpy
return module.Architecture.ToString();
}
}
+
+ public static string GetRuntimeDisplayName(ModuleDefinition module)
+ {
+ switch (module.Runtime) {
+ case TargetRuntime.Net_1_0:
+ return ".NET 1.0";
+ case TargetRuntime.Net_1_1:
+ return ".NET 1.1";
+ case TargetRuntime.Net_2_0:
+ return ".NET 2.0";
+ case TargetRuntime.Net_4_0:
+ return ".NET 4.0";
+ }
+ return null;
+ }
/*
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
@@ -279,6 +301,11 @@ namespace ICSharpCode.ILSpy
base.DecompileAssembly(assembly, output, options);
output.WriteLine();
ModuleDefinition mainModule = assembly.ModuleDefinition;
+ if (mainModule.Types.Count > 0) {
+ output.Write("// Global type: ");
+ output.WriteReference(mainModule.Types[0].FullName, mainModule.Types[0]);
+ output.WriteLine();
+ }
if (mainModule.EntryPoint != null) {
output.Write("// Entry point: ");
output.WriteReference(mainModule.EntryPoint.DeclaringType.FullName + "." + mainModule.EntryPoint.Name, mainModule.EntryPoint);
@@ -288,19 +315,9 @@ namespace ICSharpCode.ILSpy
if ((mainModule.Attributes & ModuleAttributes.ILOnly) == 0) {
output.WriteLine("// This assembly contains unmanaged code.");
}
- switch (mainModule.Runtime) {
- case TargetRuntime.Net_1_0:
- output.WriteLine("// Runtime: .NET 1.0");
- break;
- case TargetRuntime.Net_1_1:
- output.WriteLine("// Runtime: .NET 1.1");
- break;
- case TargetRuntime.Net_2_0:
- output.WriteLine("// Runtime: .NET 2.0");
- break;
- case TargetRuntime.Net_4_0:
- output.WriteLine("// Runtime: .NET 4.0");
- break;
+ string runtimeName = GetRuntimeDisplayName(mainModule);
+ if (runtimeName != null) {
+ output.WriteLine("// Runtime: " + runtimeName);
}
output.WriteLine();
@@ -319,6 +336,7 @@ namespace ICSharpCode.ILSpy
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = GetPlatformName(module);
+ Guid guid = App.CommandLineArguments.FixedGuid ?? Guid.NewGuid();
using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented;
w.WriteStartDocument();
@@ -327,7 +345,7 @@ namespace ICSharpCode.ILSpy
w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup");
- w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString("B").ToUpperInvariant());
+ w.WriteElementString("ProjectGuid", guid.ToString("B").ToUpperInvariant());
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs
index 43f2e12b2..f9cc50ad1 100644
--- a/ILSpy/LoadedAssembly.cs
+++ b/ILSpy/LoadedAssembly.cs
@@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy
readonly string fileName;
readonly string shortName;
- public LoadedAssembly(AssemblyList assemblyList, string fileName)
+ public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null)
{
if (assemblyList == null)
throw new ArgumentNullException("assemblyList");
@@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy
this.assemblyList = assemblyList;
this.fileName = fileName;
- this.assemblyTask = Task.Factory.StartNew(LoadAssembly); // requires that this.fileName is set
+ this.assemblyTask = Task.Factory.StartNew(LoadAssembly, stream); // requires that this.fileName is set
this.shortName = Path.GetFileNameWithoutExtension(fileName);
}
@@ -84,6 +84,16 @@ namespace ICSharpCode.ILSpy
public string ShortName {
get { return shortName; }
}
+
+ public string Text {
+ get {
+ if (AssemblyDefinition != null) {
+ return String.Format("{0} ({1})", ShortName, AssemblyDefinition.Name.Version);
+ } else {
+ return ShortName;
+ }
+ }
+ }
public bool IsLoaded {
get { return assemblyTask.IsCompleted; }
@@ -92,13 +102,29 @@ namespace ICSharpCode.ILSpy
public bool HasLoadError {
get { return assemblyTask.IsFaulted; }
}
-
- ModuleDefinition LoadAssembly()
+
+ public bool IsAutoLoaded { get; set; }
+
+ ModuleDefinition LoadAssembly(object state)
{
+ var stream = state as Stream;
+ ModuleDefinition module;
+
// runs on background thread
ReaderParameters p = new ReaderParameters();
p.AssemblyResolver = new MyAssemblyResolver(this);
- ModuleDefinition module = ModuleDefinition.ReadModule(fileName, p);
+
+ if (stream != null)
+ {
+ // Read the module from a precrafted stream
+ module = ModuleDefinition.ReadModule(stream, p);
+ }
+ else
+ {
+ // Read the module from disk (by default)
+ module = ModuleDefinition.ReadModule(fileName, p);
+ }
+
if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) {
try {
LoadSymbols(module);
@@ -228,7 +254,8 @@ namespace ICSharpCode.ILSpy
file = Path.Combine(dir, name.Name + ".exe");
}
if (file != null) {
- return assemblyList.OpenAssembly(file);
+ var loaded = assemblyList.OpenAssembly(file, true);
+ return loaded;
} else {
return null;
}
@@ -249,7 +276,7 @@ namespace ICSharpCode.ILSpy
string file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name + ".winmd");
if (File.Exists(file)) {
- return assemblyList.OpenAssembly(file);
+ return assemblyList.OpenAssembly(file, true);
} else {
return null;
}
@@ -268,5 +295,6 @@ namespace ICSharpCode.ILSpy
{
assemblyTask.Wait();
}
+
}
}
diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml
index 3c7610baf..9aec1acde 100644
--- a/ILSpy/MainWindow.xaml
+++ b/ILSpy/MainWindow.xaml
@@ -125,6 +125,7 @@
BorderThickness="5,0"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
+ Focusable="False"
BorderBrush="Transparent" />
@@ -162,6 +163,7 @@
BorderBrush="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
+ Focusable="False"
Visibility="{Binding Visibility, ElementName=topPane}" />
@@ -175,6 +177,7 @@
BorderBrush="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
+ Focusable="False"
Visibility="{Binding Visibility, ElementName=bottomPane}" />
moduleTask) => {
+ OnExportAssembly(moduleTask, args.SaveDirectory);
+ }, TaskScheduler.FromCurrentSynchronizationContext());
+ }
+ }
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
}
+ void OnExportAssembly(Task moduleTask, string path)
+ {
+ AssemblyTreeNode asmNode = assemblyListTreeNode.FindAssemblyNode(moduleTask.Result);
+ if (asmNode != null) {
+ string file = DecompilerTextView.CleanUpName(asmNode.LoadedAssembly.ShortName);
+ Language language = sessionSettings.FilterSettings.Language;
+ DecompilationOptions options = new DecompilationOptions();
+ options.FullDecompilation = true;
+ options.SaveAsProjectDirectory = Path.Combine(App.CommandLineArguments.SaveDirectory, file);
+ if (!Directory.Exists(options.SaveAsProjectDirectory)) {
+ Directory.CreateDirectory(options.SaveAsProjectDirectory);
+ }
+ string fullFile = Path.Combine(options.SaveAsProjectDirectory, file + language.ProjectFileExtension);
+ TextView.SaveToDisk(language, new[] { asmNode }, options, fullFile);
+ }
+ }
+
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
ILSpySettings spySettings = this.spySettings;
@@ -319,7 +348,14 @@ namespace ICSharpCode.ILSpy
HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments);
if (App.CommandLineArguments.NavigateTo == null && App.CommandLineArguments.AssembliesToLoad.Count != 1) {
- SharpTreeNode node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
+ SharpTreeNode node = null;
+ if (sessionSettings.ActiveTreeViewPath != null) {
+ node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
+ if (node == this.assemblyListTreeNode & sessionSettings.ActiveAutoLoadedAssembly != null) {
+ this.assemblyList.OpenAssembly(sessionSettings.ActiveAutoLoadedAssembly, true);
+ node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
+ }
+ }
if (node != null) {
SelectNode(node);
@@ -330,8 +366,6 @@ namespace ICSharpCode.ILSpy
}
}
- NavigationCommands.Search.InputGestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
-
AvalonEditTextOutput output = new AvalonEditTextOutput();
if (FormatExceptions(App.StartupExceptions.ToArray(), output))
decompilerTextView.ShowText(output);
@@ -458,7 +492,7 @@ namespace ICSharpCode.ILSpy
{
RefreshTreeViewFilter();
if (e.PropertyName == "Language") {
- DecompileSelectedNodes();
+ DecompileSelectedNodes(recordHistory: false);
}
}
@@ -476,7 +510,8 @@ namespace ICSharpCode.ILSpy
}
#region Node Selection
- internal void SelectNode(SharpTreeNode obj)
+
+ public void SelectNode(SharpTreeNode obj)
{
if (obj != null) {
if (!obj.AncestorsAndSelf().Any(node => node.IsHidden)) {
@@ -495,7 +530,7 @@ namespace ICSharpCode.ILSpy
///
/// Retrieves a node using the .ToString() representations of its ancestors.
///
- SharpTreeNode FindNodeByPath(string[] path, bool returnBestMatch)
+ public SharpTreeNode FindNodeByPath(string[] path, bool returnBestMatch)
{
if (path == null)
return null;
@@ -517,7 +552,7 @@ namespace ICSharpCode.ILSpy
///
/// Gets the .ToString() representation of the node's ancestors.
///
- string[] GetPathForNode(SharpTreeNode node)
+ public string[] GetPathForNode(SharpTreeNode node)
{
if (node == null)
return null;
@@ -634,6 +669,9 @@ namespace ICSharpCode.ILSpy
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DecompileSelectedNodes();
+
+ if (SelectionChanged != null)
+ SelectionChanged(sender, e);
}
Task decompilationTask;
@@ -684,7 +722,9 @@ namespace ICSharpCode.ILSpy
return sessionSettings.FilterSettings.Language;
}
}
-
+
+ public event SelectionChangedEventHandler SelectionChanged;
+
public IEnumerable SelectedNodes {
get {
return treeView.GetTopLevelSelection().OfType();
@@ -755,6 +795,7 @@ namespace ICSharpCode.ILSpy
base.OnClosing(e);
sessionSettings.ActiveAssemblyList = assemblyList.ListName;
sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
+ sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(treeView.SelectedItem as SharpTreeNode);
sessionSettings.WindowBounds = this.RestoreBounds;
sessionSettings.SplitterPosition = leftColumn.Width.Value / (leftColumn.Width.Value + rightColumn.Width.Value);
if (topPane.Visibility == Visibility.Visible)
@@ -763,6 +804,22 @@ namespace ICSharpCode.ILSpy
sessionSettings.BottomPaneSplitterPosition = bottomPaneRow.Height.Value / (bottomPaneRow.Height.Value + textViewRow.Height.Value);
sessionSettings.Save();
}
+
+ private string GetAutoLoadedAssemblyNode(SharpTreeNode node)
+ {
+ if (node == null)
+ return null;
+ while (!(node is TreeNodes.AssemblyTreeNode) && node.Parent != null) {
+ node = node.Parent;
+ }
+ //this should be an assembly node
+ var assyNode = node as TreeNodes.AssemblyTreeNode;
+ var loadedAssy = assyNode.LoadedAssembly;
+ if (!(loadedAssy.IsLoaded && loadedAssy.IsAutoLoaded))
+ return null;
+
+ return loadedAssy.FileName;
+ }
#region Top/Bottom Pane management
public void ShowInTopPane(string title, object content)
@@ -773,7 +830,12 @@ namespace ICSharpCode.ILSpy
topPaneRow.Height = new GridLength(sessionSettings.TopPaneSplitterPosition, GridUnitType.Star);
}
topPane.Title = title;
- topPane.Content = content;
+ if (topPane.Content != content) {
+ IPane pane = topPane.Content as IPane;
+ if (pane != null)
+ pane.Closed();
+ topPane.Content = content;
+ }
topPane.Visibility = Visibility.Visible;
}
@@ -798,7 +860,12 @@ namespace ICSharpCode.ILSpy
bottomPaneRow.Height = new GridLength(sessionSettings.BottomPaneSplitterPosition, GridUnitType.Star);
}
bottomPane.Title = title;
- bottomPane.Content = content;
+ if (bottomPane.Content != content) {
+ IPane pane = bottomPane.Content as IPane;
+ if (pane != null)
+ pane.Closed();
+ bottomPane.Content = content;
+ }
bottomPane.Visibility = Visibility.Visible;
}
diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml b/ILSpy/Options/DecompilerSettingsPanel.xaml
index e6a60055d..fb73798a0 100644
--- a/ILSpy/Options/DecompilerSettingsPanel.xaml
+++ b/ILSpy/Options/DecompilerSettingsPanel.xaml
@@ -7,6 +7,7 @@
Decompile enumerators (yield return)
Decompile async methods (async/await)
Decompile query expressions
+ Decompile expression trees
Use variable names from debug symbols, if available
Show XML documentation in decompiled code
Enable folding on all blocks in braces
diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
index c686152f3..90cf3d1a8 100644
--- a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
+++ b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
@@ -55,6 +55,7 @@ namespace ICSharpCode.ILSpy.Options
s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn;
s.AsyncAwait = (bool?)e.Attribute("asyncAwait") ?? s.AsyncAwait;
s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions;
+ s.ExpressionTrees = (bool?)e.Attribute("expressionTrees") ?? s.ExpressionTrees;
s.UseDebugSymbols = (bool?)e.Attribute("useDebugSymbols") ?? s.UseDebugSymbols;
s.ShowXmlDocumentation = (bool?)e.Attribute("xmlDoc") ?? s.ShowXmlDocumentation;
s.FoldBraces = (bool?)e.Attribute("foldBraces") ?? s.FoldBraces;
@@ -69,6 +70,7 @@ namespace ICSharpCode.ILSpy.Options
section.SetAttributeValue("yieldReturn", s.YieldReturn);
section.SetAttributeValue("asyncAwait", s.AsyncAwait);
section.SetAttributeValue("queryExpressions", s.QueryExpressions);
+ section.SetAttributeValue("expressionTrees", s.ExpressionTrees);
section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols);
section.SetAttributeValue("xmlDoc", s.ShowXmlDocumentation);
section.SetAttributeValue("foldBraces", s.FoldBraces);
diff --git a/ILSpy/Properties/AssemblyInfo.template.cs b/ILSpy/Properties/AssemblyInfo.template.cs
index c05ed222d..8148a959b 100644
--- a/ILSpy/Properties/AssemblyInfo.template.cs
+++ b/ILSpy/Properties/AssemblyInfo.template.cs
@@ -3,6 +3,7 @@
using System;
using System.Resources;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#endregion
@@ -14,7 +15,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription(".NET assembly inspector and decompiler")]
[assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")]
-[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPapa for the SharpDevelop Team")]
+[assembly: AssemblyCopyright("Copyright 2011-2015 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -29,6 +30,8 @@ using System.Runtime.InteropServices;
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly",
Justification = "AssemblyInformationalVersion does not need to be a parsable version")]
+[assembly: InternalsVisibleTo("ILSpy.AddIn, PublicKey=0024000004800000940000000602000000240000525341310004000001000100653c4a319be4f524972c3c5bba5fd243330f8e900287d9022d7821a63fd0086fd3801e3683dbe9897f2ecc44727023e9b40adcf180730af70c81c54476b3e5ba8b0f07f5132b2c3cc54347a2c1a9d64ebaaaf3cbffc1a18c427981e2a51d53d5ab02536b7550e732f795121c38a0abfdb38596353525d034baf9e6f1fd8ac4ac")]
+
internal static class RevisionClass
{
public const string Major = "3";
diff --git a/ILSpy/SearchPane.cs b/ILSpy/SearchPane.cs
index 90b121388..27177f7e7 100644
--- a/ILSpy/SearchPane.cs
+++ b/ILSpy/SearchPane.cs
@@ -17,10 +17,12 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
-using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
@@ -53,17 +55,14 @@ namespace ICSharpCode.ILSpy
}
}
- const int SearchMode_Type = 0;
- const int SearchMode_Member = 1;
- const int SearchMode_Literal = 2;
-
private SearchPane()
{
InitializeComponent();
searchModeComboBox.Items.Add(new { Image = Images.Class, Name = "Type" });
searchModeComboBox.Items.Add(new { Image = Images.Property, Name = "Member" });
searchModeComboBox.Items.Add(new { Image = Images.Literal, Name = "Constant" });
- searchModeComboBox.SelectedIndex = SearchMode_Type;
+ searchModeComboBox.SelectedIndex = (int)SearchMode.Type;
+ ContextMenuProvider.Add(listBox);
MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged;
}
@@ -127,7 +126,7 @@ namespace ICSharpCode.ILSpy
listBox.ItemsSource = null;
} else {
MainWindow mainWindow = MainWindow.Instance;
- currentSearch = new RunningSearch(mainWindow.CurrentAssemblyList.GetAssemblies(), searchTerm, searchModeComboBox.SelectedIndex, mainWindow.CurrentLanguage);
+ currentSearch = new RunningSearch(mainWindow.CurrentAssemblyList.GetAssemblies(), searchTerm, (SearchMode)searchModeComboBox.SelectedIndex, mainWindow.CurrentLanguage);
listBox.ItemsSource = currentSearch.Results;
new Thread(currentSearch.Run).Start();
}
@@ -164,13 +163,13 @@ namespace ICSharpCode.ILSpy
{
base.OnKeyDown(e);
if (e.Key == Key.T && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
- searchModeComboBox.SelectedIndex = SearchMode_Type;
+ searchModeComboBox.SelectedIndex = (int)SearchMode.Type;
e.Handled = true;
} else if (e.Key == Key.M && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
- searchModeComboBox.SelectedIndex = SearchMode_Member;
+ searchModeComboBox.SelectedIndex = (int)SearchMode.Member;
e.Handled = true;
} else if (e.Key == Key.S && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
- searchModeComboBox.SelectedIndex = SearchMode_Literal;
+ searchModeComboBox.SelectedIndex = (int)SearchMode.Literal;
e.Handled = true;
}
}
@@ -183,22 +182,19 @@ namespace ICSharpCode.ILSpy
listBox.SelectedIndex = 0;
}
}
-
+
sealed class RunningSearch
{
readonly Dispatcher dispatcher;
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly LoadedAssembly[] assemblies;
readonly string[] searchTerm;
- readonly int searchMode;
+ readonly SearchMode searchMode;
readonly Language language;
public readonly ObservableCollection Results = new ObservableCollection();
int resultCount;
-
- TypeCode searchTermLiteralType = TypeCode.Empty;
- object searchTermLiteralValue;
-
- public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, int searchMode, Language language)
+
+ public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, SearchMode searchMode, Language language)
{
this.dispatcher = Dispatcher.CurrentDispatcher;
this.assemblies = assemblies;
@@ -217,44 +213,16 @@ namespace ICSharpCode.ILSpy
public void Run()
{
try {
- if (searchMode == SearchMode_Literal) {
- if (1 == searchTerm.Length)
- {
- CSharpParser parser = new CSharpParser();
- PrimitiveExpression pe = parser.ParseExpression(searchTerm[0]) as PrimitiveExpression;
- if (pe != null && pe.Value != null) {
- TypeCode peValueType = Type.GetTypeCode(pe.Value.GetType());
- switch (peValueType) {
- case TypeCode.Byte:
- case TypeCode.SByte:
- case TypeCode.Int16:
- case TypeCode.UInt16:
- case TypeCode.Int32:
- case TypeCode.UInt32:
- case TypeCode.Int64:
- case TypeCode.UInt64:
- searchTermLiteralType = TypeCode.Int64;
- searchTermLiteralValue = CSharpPrimitiveCast.Cast(TypeCode.Int64, pe.Value, false);
- break;
- case TypeCode.Single:
- case TypeCode.Double:
- case TypeCode.String:
- searchTermLiteralType = peValueType;
- searchTermLiteralValue = pe.Value;
- break;
- }
- }
- }
- }
-
+ var searcher = GetSearchStrategy(searchMode, searchTerm);
foreach (var loadedAssembly in assemblies) {
ModuleDefinition module = loadedAssembly.ModuleDefinition;
if (module == null)
continue;
CancellationToken cancellationToken = cts.Token;
+
foreach (TypeDefinition type in module.Types) {
cancellationToken.ThrowIfCancellationRequested();
- PerformSearch(type);
+ searcher.Search(type, language, AddResult);
}
}
} catch (OperationCanceledException) {
@@ -277,265 +245,71 @@ namespace ICSharpCode.ILSpy
new Action(delegate { this.Results.Insert(this.Results.Count - 1, result); }));
cts.Token.ThrowIfCancellationRequested();
}
-
- bool IsMatch(string text)
- {
- for (int i = 0; i < searchTerm.Length; ++i) {
- // How to handle overlapping matches?
- if (text.IndexOf(searchTerm[i], StringComparison.OrdinalIgnoreCase) < 0)
- return false;
- }
- return true;
- }
-
- void PerformSearch(TypeDefinition type)
- {
- if (searchMode == SearchMode_Type && IsMatch(type.Name)) {
- AddResult(new SearchResult {
- Member = type,
- Image = TypeTreeNode.GetIcon(type),
- Name = language.TypeToString(type, includeNamespace: false),
- LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace,
- Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace
- });
- }
-
- foreach (TypeDefinition nestedType in type.NestedTypes) {
- PerformSearch(nestedType);
- }
-
- if (searchMode == SearchMode_Type)
- return;
-
- foreach (FieldDefinition field in type.Fields) {
- if (IsMatch(field)) {
- AddResult(new SearchResult {
- Member = field,
- Image = FieldTreeNode.GetIcon(field),
- Name = field.Name,
- LocationImage = TypeTreeNode.GetIcon(type),
- Location = language.TypeToString(type, includeNamespace: true)
- });
- }
- }
- foreach (PropertyDefinition property in type.Properties) {
- if (IsMatch(property)) {
- AddResult(new SearchResult {
- Member = property,
- Image = PropertyTreeNode.GetIcon(property),
- Name = property.Name,
- LocationImage = TypeTreeNode.GetIcon(type),
- Location = language.TypeToString(type, includeNamespace: true)
- });
- }
- }
- foreach (EventDefinition ev in type.Events) {
- if (IsMatch(ev)) {
- AddResult(new SearchResult {
- Member = ev,
- Image = EventTreeNode.GetIcon(ev),
- Name = ev.Name,
- LocationImage = TypeTreeNode.GetIcon(type),
- Location = language.TypeToString(type, includeNamespace: true)
- });
- }
- }
- foreach (MethodDefinition method in type.Methods) {
- switch (method.SemanticsAttributes) {
- case MethodSemanticsAttributes.Setter:
- case MethodSemanticsAttributes.Getter:
- case MethodSemanticsAttributes.AddOn:
- case MethodSemanticsAttributes.RemoveOn:
- case MethodSemanticsAttributes.Fire:
- continue;
- }
- if (IsMatch(method)) {
- AddResult(new SearchResult {
- Member = method,
- Image = MethodTreeNode.GetIcon(method),
- Name = method.Name,
- LocationImage = TypeTreeNode.GetIcon(type),
- Location = language.TypeToString(type, includeNamespace: true)
- });
- }
- }
- }
-
- bool IsMatch(FieldDefinition field)
- {
- if (searchMode == SearchMode_Literal)
- return IsLiteralMatch(field.Constant);
- else
- return IsMatch(field.Name);
- }
-
- bool IsMatch(PropertyDefinition property)
- {
- if (searchMode == SearchMode_Literal)
- return MethodIsLiteralMatch(property.GetMethod) || MethodIsLiteralMatch(property.SetMethod);
- else
- return IsMatch(property.Name);
- }
-
- bool IsMatch(EventDefinition ev)
- {
- if (searchMode == SearchMode_Literal)
- return MethodIsLiteralMatch(ev.AddMethod) || MethodIsLiteralMatch(ev.RemoveMethod) || MethodIsLiteralMatch(ev.InvokeMethod);
- else
- return IsMatch(ev.Name);
- }
-
- bool IsMatch(MethodDefinition m)
- {
- if (searchMode == SearchMode_Literal)
- return MethodIsLiteralMatch(m);
- else
- return IsMatch(m.Name);
- }
-
- bool IsLiteralMatch(object val)
+
+ AbstractSearchStrategy GetSearchStrategy(SearchMode mode, string[] terms)
{
- if (val == null)
- return false;
- switch (searchTermLiteralType) {
- case TypeCode.Int64:
- TypeCode tc = Type.GetTypeCode(val.GetType());
- if (tc >= TypeCode.SByte && tc <= TypeCode.UInt64)
- return CSharpPrimitiveCast.Cast(TypeCode.Int64, val, false).Equals(searchTermLiteralValue);
- else
- return false;
- case TypeCode.Single:
- case TypeCode.Double:
- case TypeCode.String:
- return searchTermLiteralValue.Equals(val);
- default:
- // substring search with searchTerm
- return IsMatch(val.ToString());
+ if (terms.Length == 1) {
+ if (terms[0].StartsWith("t:"))
+ return new TypeSearchStrategy(terms[0].Substring(2));
+
+ if (terms[0].StartsWith("m:"))
+ return new MemberSearchStrategy(terms[0].Substring(2));
+
+ if (terms[0].StartsWith("c:"))
+ return new LiteralSearchStrategy(terms[0].Substring(2));
}
- }
-
- bool MethodIsLiteralMatch(MethodDefinition m)
- {
- if (m == null)
- return false;
- var body = m.Body;
- if (body == null)
- return false;
- if (searchTermLiteralType == TypeCode.Int64) {
- long val = (long)searchTermLiteralValue;
- foreach (var inst in body.Instructions) {
- switch (inst.OpCode.Code) {
- case Code.Ldc_I8:
- if (val == (long)inst.Operand)
- return true;
- break;
- case Code.Ldc_I4:
- if (val == (int)inst.Operand)
- return true;
- break;
- case Code.Ldc_I4_S:
- if (val == (sbyte)inst.Operand)
- return true;
- break;
- case Code.Ldc_I4_M1:
- if (val == -1)
- return true;
- break;
- case Code.Ldc_I4_0:
- if (val == 0)
- return true;
- break;
- case Code.Ldc_I4_1:
- if (val == 1)
- return true;
- break;
- case Code.Ldc_I4_2:
- if (val == 2)
- return true;
- break;
- case Code.Ldc_I4_3:
- if (val == 3)
- return true;
- break;
- case Code.Ldc_I4_4:
- if (val == 4)
- return true;
- break;
- case Code.Ldc_I4_5:
- if (val == 5)
- return true;
- break;
- case Code.Ldc_I4_6:
- if (val == 6)
- return true;
- break;
- case Code.Ldc_I4_7:
- if (val == 7)
- return true;
- break;
- case Code.Ldc_I4_8:
- if (val == 8)
- return true;
- break;
- }
- }
- } else if (searchTermLiteralType != TypeCode.Empty) {
- Code expectedCode;
- switch (searchTermLiteralType) {
- case TypeCode.Single:
- expectedCode = Code.Ldc_R4;
- break;
- case TypeCode.Double:
- expectedCode = Code.Ldc_R8;
- break;
- case TypeCode.String:
- expectedCode = Code.Ldstr;
- break;
- default:
- throw new InvalidOperationException();
- }
- foreach (var inst in body.Instructions) {
- if (inst.OpCode.Code == expectedCode && searchTermLiteralValue.Equals(inst.Operand))
- return true;
- }
- } else {
- foreach (var inst in body.Instructions) {
- if (inst.OpCode.Code == Code.Ldstr && IsMatch((string)inst.Operand))
- return true;
- }
+
+ switch (mode) {
+ case SearchMode.Type:
+ return new TypeSearchStrategy(terms);
+ case SearchMode.Member:
+ return new MemberSearchStrategy(terms);
+ case SearchMode.Literal:
+ return new LiteralSearchStrategy(terms);
}
- return false;
+
+ return null;
}
}
-
- sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
- {
- event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
- add { }
- remove { }
- }
+ }
+
+ sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
+ {
+ event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
+ add { }
+ remove { }
+ }
- public MemberReference Member { get; set; }
+ public MemberReference Member { get; set; }
- public string Location { get; set; }
- public string Name { get; set; }
- public ImageSource Image { get; set; }
- public ImageSource LocationImage { get; set; }
+ public string Location { get; set; }
+ public string Name { get; set; }
+ public ImageSource Image { get; set; }
+ public ImageSource LocationImage { get; set; }
- public override string ToString()
- {
- return Name;
- }
+ public override string ToString()
+ {
+ return Name;
}
}
- [ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon="Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)]
- [ExportToolbarCommand(ToolTip = "Search (F3)", ToolbarIcon = "Images/Find.png", ToolbarCategory = "View", ToolbarOrder = 100)]
+ [ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon = "Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)]
+ [ExportToolbarCommand(ToolTip = "Search (Ctrl+Shift+F or Ctrl+E)", ToolbarIcon = "Images/Find.png", ToolbarCategory = "View", ToolbarOrder = 100)]
sealed class ShowSearchCommand : CommandWrapper
{
public ShowSearchCommand()
: base(NavigationCommands.Search)
{
+ NavigationCommands.Search.InputGestures.Clear();
+ NavigationCommands.Search.InputGestures.Add(new KeyGesture(Key.F, ModifierKeys.Control | ModifierKeys.Shift));
+ NavigationCommands.Search.InputGestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
}
}
+
+ public enum SearchMode
+ {
+ Type,
+ Member,
+ Literal
+ }
}
\ No newline at end of file
diff --git a/ILSpy/SearchPane.xaml b/ILSpy/SearchPane.xaml
index 481b447a4..37a6ff210 100644
--- a/ILSpy/SearchPane.xaml
+++ b/ILSpy/SearchPane.xaml
@@ -17,7 +17,7 @@
+ WatermarkColor="Gray" WatermarkText="Search for t:TypeName, m:Member or c:Constant; use /reg(ular)?Ex(pressions)?/ or both - t:/Type(Name)?/..." />
Search _for:
2) {
+ var search = terms[0];
+ if (search.StartsWith("/") && search.EndsWith("/") && search.Length > 4)
+ regex = SafeNewRegex(search.Substring(1, search.Length - 2));
+
+ terms[0] = search;
+ }
+
+ searchTerm = terms;
+ }
+
+ protected bool IsMatch(string text)
+ {
+ if (regex != null)
+ return regex.IsMatch(text);
+
+ for (int i = 0; i < searchTerm.Length; ++i) {
+ // How to handle overlapping matches?
+ if (text.IndexOf(searchTerm[i], StringComparison.OrdinalIgnoreCase) < 0)
+ return false;
+ }
+ return true;
+ }
+
+ protected virtual bool IsMatch(FieldDefinition field)
+ {
+ return false;
+ }
+
+ protected virtual bool IsMatch(PropertyDefinition property)
+ {
+ return false;
+ }
+
+ protected virtual bool IsMatch(EventDefinition ev)
+ {
+ return false;
+ }
+
+ protected virtual bool IsMatch(MethodDefinition m)
+ {
+ return false;
+ }
+
+ void Add(IEnumerable items, TypeDefinition type, Language language, Action addResult, Func matcher, Func image) where T : MemberReference
+ {
+ foreach (var item in items) {
+ if (matcher(item)) {
+ addResult(new SearchResult
+ {
+ Member = item,
+ Image = image(item),
+ Name = item.Name,
+ LocationImage = TypeTreeNode.GetIcon(type),
+ Location = language.TypeToString(type, includeNamespace: true)
+ });
+ }
+ }
+ }
+
+ public virtual void Search(TypeDefinition type, Language language, Action addResult)
+ {
+ Add(type.Fields, type, language, addResult, IsMatch, FieldTreeNode.GetIcon);
+ Add(type.Properties, type, language, addResult, IsMatch, p => PropertyTreeNode.GetIcon(p));
+ Add(type.Events, type, language, addResult, IsMatch, EventTreeNode.GetIcon);
+ Add(type.Methods.Where(NotSpecialMethod), type, language, addResult, IsMatch, MethodTreeNode.GetIcon);
+ }
+
+ bool NotSpecialMethod(MethodDefinition arg)
+ {
+ return (arg.SemanticsAttributes & (
+ MethodSemanticsAttributes.Setter
+ | MethodSemanticsAttributes.Getter
+ | MethodSemanticsAttributes.AddOn
+ | MethodSemanticsAttributes.RemoveOn
+ | MethodSemanticsAttributes.Fire)) == 0;
+ }
+
+ Regex SafeNewRegex(string unsafePattern)
+ {
+ try {
+ return new Regex(unsafePattern, RegexOptions.Compiled);
+ } catch (ArgumentException) {
+ return null;
+ }
+ }
+ }
+
+ class LiteralSearchStrategy : AbstractSearchStrategy
+ {
+ readonly TypeCode searchTermLiteralType;
+ readonly object searchTermLiteralValue;
+
+ public LiteralSearchStrategy(params string[] terms)
+ : base(terms)
+ {
+ if (1 == searchTerm.Length) {
+ var parser = new CSharpParser();
+ var pe = parser.ParseExpression(searchTerm[0]) as PrimitiveExpression;
+
+ if (pe != null && pe.Value != null) {
+ TypeCode peValueType = Type.GetTypeCode(pe.Value.GetType());
+ switch (peValueType) {
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Int32:
+ case TypeCode.UInt32:
+ case TypeCode.Int64:
+ case TypeCode.UInt64:
+ searchTermLiteralType = TypeCode.Int64;
+ searchTermLiteralValue = CSharpPrimitiveCast.Cast(TypeCode.Int64, pe.Value, false);
+ break;
+ case TypeCode.Single:
+ case TypeCode.Double:
+ case TypeCode.String:
+ searchTermLiteralType = peValueType;
+ searchTermLiteralValue = pe.Value;
+ break;
+ }
+ }
+ }
+ }
+
+ protected override bool IsMatch(FieldDefinition field)
+ {
+ return IsLiteralMatch(field.Constant);
+ }
+
+ protected override bool IsMatch(PropertyDefinition property)
+ {
+ return MethodIsLiteralMatch(property.GetMethod) || MethodIsLiteralMatch(property.SetMethod);
+ }
+
+ protected override bool IsMatch(EventDefinition ev)
+ {
+ return MethodIsLiteralMatch(ev.AddMethod) || MethodIsLiteralMatch(ev.RemoveMethod) || MethodIsLiteralMatch(ev.InvokeMethod);
+ }
+
+ protected override bool IsMatch(MethodDefinition m)
+ {
+ return MethodIsLiteralMatch(m);
+ }
+
+ bool IsLiteralMatch(object val)
+ {
+ if (val == null)
+ return false;
+ switch (searchTermLiteralType) {
+ case TypeCode.Int64:
+ TypeCode tc = Type.GetTypeCode(val.GetType());
+ if (tc >= TypeCode.SByte && tc <= TypeCode.UInt64)
+ return CSharpPrimitiveCast.Cast(TypeCode.Int64, val, false).Equals(searchTermLiteralValue);
+ else
+ return false;
+ case TypeCode.Single:
+ case TypeCode.Double:
+ case TypeCode.String:
+ return searchTermLiteralValue.Equals(val);
+ default:
+ // substring search with searchTerm
+ return IsMatch(val.ToString());
+ }
+ }
+
+ bool MethodIsLiteralMatch(MethodDefinition m)
+ {
+ if (m == null)
+ return false;
+ var body = m.Body;
+ if (body == null)
+ return false;
+ if (searchTermLiteralType == TypeCode.Int64) {
+ long val = (long)searchTermLiteralValue;
+ foreach (var inst in body.Instructions) {
+ switch (inst.OpCode.Code) {
+ case Code.Ldc_I8:
+ if (val == (long)inst.Operand)
+ return true;
+ break;
+ case Code.Ldc_I4:
+ if (val == (int)inst.Operand)
+ return true;
+ break;
+ case Code.Ldc_I4_S:
+ if (val == (sbyte)inst.Operand)
+ return true;
+ break;
+ case Code.Ldc_I4_M1:
+ if (val == -1)
+ return true;
+ break;
+ case Code.Ldc_I4_0:
+ if (val == 0)
+ return true;
+ break;
+ case Code.Ldc_I4_1:
+ if (val == 1)
+ return true;
+ break;
+ case Code.Ldc_I4_2:
+ if (val == 2)
+ return true;
+ break;
+ case Code.Ldc_I4_3:
+ if (val == 3)
+ return true;
+ break;
+ case Code.Ldc_I4_4:
+ if (val == 4)
+ return true;
+ break;
+ case Code.Ldc_I4_5:
+ if (val == 5)
+ return true;
+ break;
+ case Code.Ldc_I4_6:
+ if (val == 6)
+ return true;
+ break;
+ case Code.Ldc_I4_7:
+ if (val == 7)
+ return true;
+ break;
+ case Code.Ldc_I4_8:
+ if (val == 8)
+ return true;
+ break;
+ }
+ }
+ } else if (searchTermLiteralType != TypeCode.Empty) {
+ Code expectedCode;
+ switch (searchTermLiteralType) {
+ case TypeCode.Single:
+ expectedCode = Code.Ldc_R4;
+ break;
+ case TypeCode.Double:
+ expectedCode = Code.Ldc_R8;
+ break;
+ case TypeCode.String:
+ expectedCode = Code.Ldstr;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ foreach (var inst in body.Instructions) {
+ if (inst.OpCode.Code == expectedCode && searchTermLiteralValue.Equals(inst.Operand))
+ return true;
+ }
+ } else {
+ foreach (var inst in body.Instructions) {
+ if (inst.OpCode.Code == Code.Ldstr && IsMatch((string)inst.Operand))
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ class MemberSearchStrategy : AbstractSearchStrategy
+ {
+ public MemberSearchStrategy(params string[] terms)
+ : base(terms)
+ {
+ }
+
+ protected override bool IsMatch(FieldDefinition field)
+ {
+ return IsMatch(field.Name);
+ }
+
+ protected override bool IsMatch(PropertyDefinition property)
+ {
+ return IsMatch(property.Name);
+ }
+
+ protected override bool IsMatch(EventDefinition ev)
+ {
+ return IsMatch(ev.Name);
+ }
+
+ protected override bool IsMatch(MethodDefinition m)
+ {
+ return IsMatch(m.Name);
+ }
+ }
+
+ class TypeSearchStrategy : AbstractSearchStrategy
+ {
+ public TypeSearchStrategy(params string[] terms)
+ : base(terms)
+ {
+ }
+
+ public override void Search(TypeDefinition type, Language language, Action addResult)
+ {
+ if (IsMatch(type.Name) || IsMatch(type.FullName)) {
+ addResult(new SearchResult {
+ Member = type,
+ Image = TypeTreeNode.GetIcon(type),
+ Name = language.TypeToString(type, includeNamespace: false),
+ LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace,
+ Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace
+ });
+ }
+
+ foreach (TypeDefinition nestedType in type.NestedTypes) {
+ Search(nestedType, language, addResult);
+ }
+ }
+ }
+
+}
diff --git a/ILSpy/SessionSettings.cs b/ILSpy/SessionSettings.cs
index 9c9167114..56a4490dd 100644
--- a/ILSpy/SessionSettings.cs
+++ b/ILSpy/SessionSettings.cs
@@ -48,6 +48,7 @@ namespace ICSharpCode.ILSpy
if (activeTreeViewPath != null) {
this.ActiveTreeViewPath = activeTreeViewPath.Elements().Select(e => Unescape((string)e)).ToArray();
}
+ this.ActiveAutoLoadedAssembly = (string)doc.Element("ActiveAutoLoadedAssembly");
this.WindowState = FromString((string)doc.Element("WindowState"), WindowState.Normal);
this.WindowBounds = FromString((string)doc.Element("WindowBounds"), DefaultWindowBounds);
@@ -67,6 +68,7 @@ namespace ICSharpCode.ILSpy
public FilterSettings FilterSettings { get; private set; }
public string[] ActiveTreeViewPath;
+ public string ActiveAutoLoadedAssembly;
public string ActiveAssemblyList;
@@ -89,6 +91,9 @@ namespace ICSharpCode.ILSpy
if (this.ActiveTreeViewPath != null) {
doc.Add(new XElement("ActiveTreeViewPath", ActiveTreeViewPath.Select(p => new XElement("Node", Escape(p)))));
}
+ if (this.ActiveAutoLoadedAssembly != null) {
+ doc.Add(new XElement("ActiveAutoLoadedAssembly", this.ActiveAutoLoadedAssembly));
+ }
doc.Add(new XElement("WindowState", ToString(this.WindowState)));
doc.Add(new XElement("WindowBounds", ToString(this.WindowBounds)));
doc.Add(new XElement("SplitterPosition", ToString(this.SplitterPosition)));
diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs
index 7f69002cf..66f61c70b 100644
--- a/ILSpy/TextView/DecompilerTextView.cs
+++ b/ILSpy/TextView/DecompilerTextView.cs
@@ -94,6 +94,7 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.Options.RequireControlModifierForHyperlinkClick = false;
textEditor.TextArea.TextView.MouseHover += TextViewMouseHover;
textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped;
+ textEditor.TextArea.TextView.MouseDown += TextViewMouseDown;
textEditor.SetBinding(Control.FontFamilyProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFont") });
textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFontSize") });
@@ -103,7 +104,10 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.ShowLineNumbers = true;
DisplaySettingsPanel.CurrentDisplaySettings.PropertyChanged += CurrentDisplaySettings_PropertyChanged;
- SearchPanel.Install(textEditor);
+ // SearchPanel
+ SearchPanel.Install(textEditor.TextArea);
+ // TODO: re-enable the RegisterCommands call after updating to AvalonEdit 5.0.3
+ // .RegisterCommands(Application.Current.MainWindow.CommandBindings);
ShowLineMargin();
@@ -186,13 +190,17 @@ namespace ICSharpCode.ILSpy.TextView
}
XmlDocRenderer renderer = new XmlDocRenderer();
renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr));
- XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module);
- if (docProvider != null) {
- string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
- if (documentation != null) {
- renderer.AppendText(Environment.NewLine);
- renderer.AddXmlDocumentation(documentation);
+ try {
+ XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module);
+ if (docProvider != null) {
+ string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
+ if (documentation != null) {
+ renderer.AppendText(Environment.NewLine);
+ renderer.AddXmlDocumentation(documentation);
+ }
}
+ } catch (XmlException) {
+ // ignore
}
return renderer.CreateTextBlock();
}
@@ -556,6 +564,12 @@ namespace ICSharpCode.ILSpy.TextView
MainWindow.Instance.JumpToReference(reference);
}
+ void TextViewMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (GetReferenceSegmentAtMousePosition() == null)
+ ClearLocalReferenceMarks();
+ }
+
void ClearLocalReferenceMarks()
{
foreach (var mark in localReferenceMarks) {
diff --git a/ILSpy/TextView/EditorCommands.cs b/ILSpy/TextView/EditorCommands.cs
new file mode 100644
index 000000000..8615ee896
--- /dev/null
+++ b/ILSpy/TextView/EditorCommands.cs
@@ -0,0 +1,44 @@
+// 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;
+
+namespace ICSharpCode.ILSpy.TextView
+{
+ [ExportContextMenuEntryAttribute(Header = "Copy", Category = "Editor")]
+ internal sealed class CopyContextMenuEntry : IContextMenuEntry
+ {
+ public bool IsVisible(TextViewContext context)
+ {
+ return context.TextView != null;
+ }
+
+ public bool IsEnabled(TextViewContext context)
+ {
+ return context.TextView != null && context.TextView.textEditor.SelectionLength > 0;
+ }
+
+ public void Execute(TextViewContext context)
+ {
+ context.TextView.textEditor.Copy();
+ }
+ }
+}
diff --git a/ILSpy/TextView/FoldingCommands.cs b/ILSpy/TextView/FoldingCommands.cs
index 314a1412b..936ff0405 100644
--- a/ILSpy/TextView/FoldingCommands.cs
+++ b/ILSpy/TextView/FoldingCommands.cs
@@ -1,11 +1,21 @@
-/*
- * Created by SharpDevelop.
- * User: Ronny Klier
- * Date: 24.05.2012
- * Time: 23:44
- *
- * To change this template use Tools | Options | Coding | Edit Standard Headers.
- */
+// 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;
@@ -15,76 +25,76 @@ using ICSharpCode.AvalonEdit.Folding;
namespace ICSharpCode.ILSpy.TextView
{
- [ExportContextMenuEntryAttribute(Header = "Toggle All Folding", Category = "Folding")]
- internal sealed class ToggleAllContextMenuEntry : IContextMenuEntry
- {
- public bool IsVisible(TextViewContext context)
- {
- return context.TextView != null;
- }
-
- public bool IsEnabled(TextViewContext context)
- {
- return context.TextView != null && context.TextView.FoldingManager != null;
- }
-
- public void Execute(TextViewContext context)
- {
- if (null == context.TextView)
- return;
- FoldingManager foldingManager = context.TextView.FoldingManager;
- if (null == foldingManager)
- return;
- bool doFold = true;
- foreach (FoldingSection fm in foldingManager.AllFoldings) {
- if (fm.IsFolded) {
- doFold = false;
- break;
- }
- }
- foreach (FoldingSection fm in foldingManager.AllFoldings) {
- fm.IsFolded = doFold;
- }
- }
- }
+ [ExportContextMenuEntryAttribute(Header = "Toggle All Folding", Category = "Folding")]
+ internal sealed class ToggleAllContextMenuEntry : IContextMenuEntry
+ {
+ public bool IsVisible(TextViewContext context)
+ {
+ return context.TextView != null;
+ }
+
+ public bool IsEnabled(TextViewContext context)
+ {
+ return context.TextView != null && context.TextView.FoldingManager != null;
+ }
+
+ public void Execute(TextViewContext context)
+ {
+ if (null == context.TextView)
+ return;
+ FoldingManager foldingManager = context.TextView.FoldingManager;
+ if (null == foldingManager)
+ return;
+ bool doFold = true;
+ foreach (FoldingSection fm in foldingManager.AllFoldings) {
+ if (fm.IsFolded) {
+ doFold = false;
+ break;
+ }
+ }
+ foreach (FoldingSection fm in foldingManager.AllFoldings) {
+ fm.IsFolded = doFold;
+ }
+ }
+ }
- [ExportContextMenuEntryAttribute(Header = "Toggle Folding", Category = "Folding")]
- internal sealed class ToggleContextMenuEntry : IContextMenuEntry
- {
- public bool IsVisible(TextViewContext context)
- {
- return context.TextView != null;
- }
-
- public bool IsEnabled(TextViewContext context)
- {
- return context.TextView != null && context.TextView.FoldingManager != null;
- }
-
- public void Execute(TextViewContext context)
- {
- var textView = context.TextView;
- if (null == textView)
- return;
- var editor = textView.textEditor;
- FoldingManager foldingManager = context.TextView.FoldingManager;
- if (null == foldingManager)
- return;
- // TODO: or use Caret if position is not given?
- var posBox = context.Position;
- if (null == posBox)
- return;
- TextViewPosition pos = posBox.Value;
+ [ExportContextMenuEntryAttribute(Header = "Toggle Folding", Category = "Folding")]
+ internal sealed class ToggleContextMenuEntry : IContextMenuEntry
+ {
+ public bool IsVisible(TextViewContext context)
+ {
+ return context.TextView != null;
+ }
+
+ public bool IsEnabled(TextViewContext context)
+ {
+ return context.TextView != null && context.TextView.FoldingManager != null;
+ }
+
+ public void Execute(TextViewContext context)
+ {
+ var textView = context.TextView;
+ if (null == textView)
+ return;
+ var editor = textView.textEditor;
+ FoldingManager foldingManager = context.TextView.FoldingManager;
+ if (null == foldingManager)
+ return;
+ // TODO: or use Caret if position is not given?
+ var posBox = context.Position;
+ if (null == posBox)
+ return;
+ TextViewPosition pos = posBox.Value;
// look for folding on this line:
FoldingSection folding = foldingManager.GetNextFolding(editor.Document.GetOffset(pos.Line, 1));
if (folding == null || editor.Document.GetLineByOffset(folding.StartOffset).LineNumber != pos.Line) {
- // no folding found on current line: find innermost folding containing the mouse position
- folding = foldingManager.GetFoldingsContaining(editor.Document.GetOffset(pos.Line, pos.Column)).LastOrDefault();
- }
- if (folding != null) {
- folding.IsFolded = !folding.IsFolded;
- }
- }
- }
-
+ // no folding found on current line: find innermost folding containing the mouse position
+ folding = foldingManager.GetFoldingsContaining(editor.Document.GetOffset(pos.Line, pos.Column)).LastOrDefault();
+ }
+ if (folding != null) {
+ folding.IsFolded = !folding.IsFolded;
+ }
+ }
+ }
+
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
index 387998af4..60e8f3b96 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
@@ -87,10 +87,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
public static bool CanShow(TypeDefinition type)
{
- if (type.IsClass && !type.IsEnum) {
- return type.Methods.Where(m => m.Name == ".ctor").Any(m => !m.IsPrivate);
- }
- return false;
+ return (type.IsClass && !(type.IsAbstract && type.IsSealed) && !type.IsEnum);
}
}
}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs
index ab9b8bd5f..2b33c62d2 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs
@@ -54,6 +54,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType));
+ if (AnalyzedTypeUsedByTreeNode.CanShow(analyzedType))
+ this.Children.Add(new AnalyzedTypeUsedByTreeNode(analyzedType));
+
if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeExposedByTreeNode(analyzedType));
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs
new file mode 100644
index 000000000..3a614f97d
--- /dev/null
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs
@@ -0,0 +1,195 @@
+// 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.Threading;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
+{
+ internal sealed class AnalyzedTypeUsedByTreeNode : AnalyzerSearchTreeNode
+ {
+ private readonly TypeDefinition analyzedType;
+
+ public AnalyzedTypeUsedByTreeNode(TypeDefinition analyzedType)
+ {
+ if (analyzedType == null)
+ throw new ArgumentNullException("analyzedType");
+
+ this.analyzedType = analyzedType;
+ }
+
+ public override object Text
+ {
+ get { return "Used By"; }
+ }
+
+ protected override IEnumerable FetchChildren(CancellationToken ct)
+ {
+ var analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindTypeUsage);
+ return analyzer.PerformAnalysis(ct)
+ .Cast()
+ .Where(n => n.Member.DeclaringType != analyzedType)
+ .Distinct(new AnalyzerEntityTreeNodeComparer())
+ .OrderBy(n => n.Text);
+ }
+
+ private IEnumerable FindTypeUsage(TypeDefinition type)
+ {
+ if (type == analyzedType)
+ yield break;
+
+ if (IsUsedInTypeDefinition(type))
+ yield return new AnalyzedTypeTreeNode(type) { Language = Language };
+
+ foreach (var field in type.Fields.Where(IsUsedInFieldReference))
+ yield return new AnalyzedFieldTreeNode(field) { Language = Language };
+
+ foreach (var method in type.Methods.Where(IsUsedInMethodDefinition))
+ yield return HandleSpecialMethodNode(method);
+ }
+
+ private AnalyzerEntityTreeNode HandleSpecialMethodNode(MethodDefinition method)
+ {
+ var property = method.DeclaringType.Properties.FirstOrDefault(p => p.GetMethod == method || p.SetMethod == method);
+ if (property != null)
+ return new AnalyzedPropertyTreeNode(property) { Language = Language };
+
+ return new AnalyzedMethodTreeNode(method) { Language = Language };
+ }
+
+ private bool IsUsedInTypeReferences(IEnumerable types)
+ {
+ return types.Any(IsUsedInTypeReference);
+ }
+
+ private bool IsUsedInTypeReference(TypeReference type)
+ {
+ if (type == null)
+ return false;
+
+ return TypeMatches(type.DeclaringType)
+ || TypeMatches(type);
+ }
+
+ private bool IsUsedInTypeDefinition(TypeDefinition type)
+ {
+ return IsUsedInTypeReference(type)
+ || TypeMatches(type.BaseType)
+ || IsUsedInTypeReferences(type.Interfaces);
+ }
+
+ private bool IsUsedInFieldReference(FieldReference field)
+ {
+ if (field == null)
+ return false;
+
+ return TypeMatches(field.DeclaringType)
+ || TypeMatches(field.FieldType);
+ }
+
+ private bool IsUsedInMethodReference(MethodReference method)
+ {
+ if (method == null)
+ return false;
+
+ return TypeMatches(method.DeclaringType)
+ || TypeMatches(method.ReturnType)
+ || IsUsedInMethodParameters(method.Parameters);
+ }
+
+ private bool IsUsedInMethodDefinition(MethodDefinition method)
+ {
+ return IsUsedInMethodReference(method)
+ || IsUsedInMethodBody(method);
+ }
+
+ private bool IsUsedInMethodBody(MethodDefinition method)
+ {
+ if (method.Body == null)
+ return false;
+
+ bool found = false;
+
+ foreach (var instruction in method.Body.Instructions) {
+ TypeReference tr = instruction.Operand as TypeReference;
+ if (IsUsedInTypeReference(tr)) {
+ found = true;
+ break;
+ }
+ FieldReference fr = instruction.Operand as FieldReference;
+ if (IsUsedInFieldReference(fr)) {
+ found = true;
+ break;
+ }
+ MethodReference mr = instruction.Operand as MethodReference;
+ if (IsUsedInMethodReference(mr)) {
+ found = true;
+ break;
+ }
+ }
+
+ method.Body = null; // discard body to reduce memory pressure & higher GC gen collections
+
+ return found;
+ }
+
+ private bool IsUsedInMethodParameters(IEnumerable parameters)
+ {
+ return parameters.Any(IsUsedInMethodParameter);
+ }
+
+ private bool IsUsedInMethodParameter(ParameterDefinition parameter)
+ {
+ return TypeMatches(parameter.ParameterType);
+ }
+
+ private bool TypeMatches(TypeReference tref)
+ {
+ if (tref != null && tref.Name == analyzedType.Name) {
+ var tdef = tref.Resolve();
+ if (tdef != null) {
+ return (tdef == analyzedType);
+ }
+ }
+ return false;
+ }
+
+ public static bool CanShow(TypeDefinition type)
+ {
+ return type != null;
+ }
+ }
+
+ internal class AnalyzerEntityTreeNodeComparer : IEqualityComparer
+ {
+ public bool Equals(AnalyzerEntityTreeNode x, AnalyzerEntityTreeNode y)
+ {
+ return x.Member == y.Member;
+ }
+
+ public int GetHashCode(AnalyzerEntityTreeNode node)
+ {
+ return node.Member.GetHashCode();
+ }
+ }
+
+}
diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs
index 441c65ee6..a33d5507e 100644
--- a/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs
+++ b/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs
@@ -58,9 +58,17 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
public override bool HandleAssemblyListChanged(ICollection removedAssemblies, ICollection addedAssemblies)
{
- this.LazyLoading = true;
- threading.Cancel();
- this.Children.Clear();
+ // only cancel a running analysis if user has manually added/removed assemblies
+ bool manualAdd = false;
+ foreach (var asm in addedAssemblies) {
+ if (!asm.IsAutoLoaded)
+ manualAdd = true;
+ }
+ if (removedAssemblies.Count > 0 || manualAdd) {
+ this.LazyLoading = true;
+ threading.Cancel();
+ this.Children.Clear();
+ }
return true;
}
}
diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
index e95b6d140..0b59d1f10 100644
--- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
@@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
///
/// Node within assembly reference list.
///
- sealed class AssemblyReferenceTreeNode : ILSpyTreeNode
+ public sealed class AssemblyReferenceTreeNode : ILSpyTreeNode
{
readonly AssemblyNameReference r;
readonly AssemblyTreeNode parentAssembly;
@@ -40,6 +40,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.parentAssembly = parentAssembly;
this.LazyLoading = true;
}
+
+ public AssemblyNameReference AssemblyNameReference
+ {
+ get { return r; }
+ }
public override object Text {
get { return r.Name + r.MetadataToken.ToSuffixString(); }
diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs
index 7913da096..89a17eae6 100644
--- a/ILSpy/TreeNodes/AssemblyTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs
@@ -22,6 +22,8 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.TreeView;
@@ -61,9 +63,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
get { return assembly; }
}
+ public override bool IsAutoLoaded
+ {
+ get {
+ return assembly.IsAutoLoaded;
+ }
+ }
+
public override object Text
{
- get { return HighlightSearchMatch(assembly.ShortName); }
+ get { return HighlightSearchMatch(assembly.Text); }
}
public override object Icon
@@ -78,6 +87,36 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
+ TextBlock tooltip;
+
+ public override object ToolTip
+ {
+ get {
+ if (assembly.HasLoadError)
+ return "Assembly could not be loaded. Click here for details.";
+
+ if (tooltip == null) {
+ tooltip = new TextBlock();
+ tooltip.Inlines.Add(new Bold(new Run("Name: ")));
+ tooltip.Inlines.Add(new Run(assembly.AssemblyDefinition.FullName));
+ tooltip.Inlines.Add(new LineBreak());
+ tooltip.Inlines.Add(new Bold(new Run("Location: ")));
+ tooltip.Inlines.Add(new Run(assembly.FileName));
+ tooltip.Inlines.Add(new LineBreak());
+ tooltip.Inlines.Add(new Bold(new Run("Architecture: ")));
+ tooltip.Inlines.Add(new Run(CSharpLanguage.GetPlatformDisplayName(assembly.AssemblyDefinition.MainModule)));
+ string runtimeName = CSharpLanguage.GetRuntimeDisplayName(assembly.AssemblyDefinition.MainModule);
+ if (runtimeName != null) {
+ tooltip.Inlines.Add(new LineBreak());
+ tooltip.Inlines.Add(new Bold(new Run("Runtime: ")));
+ tooltip.Inlines.Add(new Run(runtimeName));
+ }
+ }
+
+ return tooltip;
+ }
+ }
+
public override bool ShowExpander
{
get { return !assembly.HasLoadError; }
@@ -278,4 +317,65 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
}
+
+ [ExportContextMenuEntryAttribute(Header = "_Load Dependencies")]
+ sealed class LoadDependencies : IContextMenuEntry
+ {
+ public bool IsVisible(TextViewContext context)
+ {
+ if (context.SelectedTreeNodes == null)
+ return false;
+ return context.SelectedTreeNodes.All(n => n is AssemblyTreeNode);
+ }
+
+ public bool IsEnabled(TextViewContext context)
+ {
+ return true;
+ }
+
+ public void Execute(TextViewContext context)
+ {
+ if (context.SelectedTreeNodes == null)
+ return;
+ foreach (var node in context.SelectedTreeNodes) {
+ var la = ((AssemblyTreeNode)node).LoadedAssembly;
+ if (!la.HasLoadError) {
+ foreach (var assyRef in la.ModuleDefinition.AssemblyReferences) {
+ la.LookupReferencedAssembly(assyRef.FullName);
+ }
+ }
+ }
+ MainWindow.Instance.RefreshDecompiledView();
+ }
+ }
+
+ [ExportContextMenuEntryAttribute(Header = "_Add To Main List")]
+ sealed class AddToMainList : IContextMenuEntry
+ {
+ public bool IsVisible(TextViewContext context)
+ {
+ if (context.SelectedTreeNodes == null)
+ return false;
+ return context.SelectedTreeNodes.Where(n => n is AssemblyTreeNode).Any(n=>((AssemblyTreeNode)n).IsAutoLoaded);
+ }
+
+ public bool IsEnabled(TextViewContext context)
+ {
+ return true;
+ }
+
+ public void Execute(TextViewContext context)
+ {
+ if (context.SelectedTreeNodes == null)
+ return;
+ foreach (var node in context.SelectedTreeNodes) {
+ var loadedAssm = ((AssemblyTreeNode)node).LoadedAssembly;
+ if (!loadedAssm.HasLoadError) {
+ loadedAssm.IsAutoLoaded = false;
+ node.RaisePropertyChanged("Foreground");
+ }
+ }
+ MainWindow.Instance.CurrentAssemblyList.RefreshSave();
+ }
+ }
}
diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs
index 0943ccc08..a58906311 100644
--- a/ILSpy/TreeNodes/ILSpyTreeNode.cs
+++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs
@@ -170,11 +170,22 @@ namespace ICSharpCode.ILSpy.TreeNodes
public virtual bool IsPublicAPI {
get { return true; }
}
+
+ public virtual bool IsAutoLoaded
+ {
+ get { return false; }
+ }
public override System.Windows.Media.Brush Foreground {
get {
if (IsPublicAPI)
- return base.Foreground;
+ if (IsAutoLoaded) {
+ // HACK: should not be hard coded?
+ return System.Windows.Media.Brushes.SteelBlue;
+ }
+ else {
+ return base.Foreground;
+ }
else
return System.Windows.SystemColors.GrayTextBrush;
}
diff --git a/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs
index 2bac46449..780399d82 100644
--- a/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs
@@ -26,74 +26,67 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes
{
- [Export(typeof(IResourceNodeFactory))]
- sealed class IconResourceNodeFactory : IResourceNodeFactory
- {
- public ILSpyTreeNode CreateNode(Resource resource)
- {
- EmbeddedResource er = resource as EmbeddedResource;
- if (er != null)
- {
- return CreateNode(er.Name, er.GetResourceStream());
- }
- return null;
- }
+ [Export(typeof(IResourceNodeFactory))]
+ sealed class IconResourceNodeFactory : IResourceNodeFactory
+ {
+ public ILSpyTreeNode CreateNode(Resource resource)
+ {
+ EmbeddedResource er = resource as EmbeddedResource;
+ if (er != null) {
+ return CreateNode(er.Name, er.GetResourceStream());
+ }
+ return null;
+ }
- public ILSpyTreeNode CreateNode(string key, object data)
- {
- if (data is System.Drawing.Icon)
- {
- MemoryStream s = new MemoryStream();
- ((System.Drawing.Icon)data).Save(s);
- return new IconResourceEntryNode(key, s);
- }
- if (data is Stream && key.EndsWith(".ico", StringComparison.OrdinalIgnoreCase))
- return new IconResourceEntryNode(key, (Stream)data);
- return null;
- }
- }
+ public ILSpyTreeNode CreateNode(string key, object data)
+ {
+ if (data is System.Drawing.Icon) {
+ MemoryStream s = new MemoryStream();
+ ((System.Drawing.Icon)data).Save(s);
+ return new IconResourceEntryNode(key, s);
+ }
+ if (data is Stream && key.EndsWith(".ico", StringComparison.OrdinalIgnoreCase))
+ return new IconResourceEntryNode(key, (Stream)data);
+ return null;
+ }
+ }
- sealed class IconResourceEntryNode : ResourceEntryNode
- {
- public IconResourceEntryNode(string key, Stream data)
- : base(key, data)
- {
- }
+ sealed class IconResourceEntryNode : ResourceEntryNode
+ {
+ public IconResourceEntryNode(string key, Stream data)
+ : base(key, data)
+ {
+ }
- public override object Icon
- {
- get { return Images.ResourceImage; }
- }
+ public override object Icon
+ {
+ get { return Images.ResourceImage; }
+ }
- public override bool View(DecompilerTextView textView)
- {
- try
- {
- AvalonEditTextOutput output = new AvalonEditTextOutput();
- Data.Position = 0;
- IconBitmapDecoder decoder = new IconBitmapDecoder(Data, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
- foreach (var frame in decoder.Frames)
- {
- output.Write(String.Format("{0}x{1}, {2} bit: ", frame.PixelHeight, frame.PixelWidth, frame.Thumbnail.Format.BitsPerPixel));
- AddIcon(output, frame);
- output.WriteLine();
- }
- output.AddButton(Images.Save, "Save", delegate
- {
- Save(null);
- });
- textView.ShowNode(output, this);
- return true;
- }
- catch (Exception)
- {
- return false;
- }
- }
+ public override bool View(DecompilerTextView textView)
+ {
+ try {
+ AvalonEditTextOutput output = new AvalonEditTextOutput();
+ Data.Position = 0;
+ IconBitmapDecoder decoder = new IconBitmapDecoder(Data, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
+ foreach (var frame in decoder.Frames) {
+ output.Write(String.Format("{0}x{1}, {2} bit: ", frame.PixelHeight, frame.PixelWidth, frame.Thumbnail.Format.BitsPerPixel));
+ AddIcon(output, frame);
+ output.WriteLine();
+ }
+ output.AddButton(Images.Save, "Save", delegate {
+ Save(null);
+ });
+ textView.ShowNode(output, this);
+ return true;
+ } catch (Exception) {
+ return false;
+ }
+ }
- private static void AddIcon(AvalonEditTextOutput output, BitmapFrame frame)
- {
- output.AddUIElement(() => new Image { Source = frame });
- }
- }
+ private static void AddIcon(AvalonEditTextOutput output, BitmapFrame frame)
+ {
+ output.AddUIElement(() => new Image { Source = frame });
+ }
+ }
}
\ No newline at end of file
diff --git a/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs
new file mode 100644
index 000000000..8d1c0c1c9
--- /dev/null
+++ b/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs
@@ -0,0 +1,90 @@
+// Copyright (c) 2014 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.ComponentModel.Composition;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using ICSharpCode.Decompiler;
+
+namespace ICSharpCode.ILSpy.TreeNodes
+{
+ [Export(typeof(IResourceNodeFactory))]
+ sealed class ImageListResourceEntryNodeFactory : IResourceNodeFactory
+ {
+ #region IResourceNodeFactory Members
+
+ public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource)
+ {
+ return null;
+ }
+
+ public ILSpyTreeNode CreateNode(string key, object data)
+ {
+ if (data is ImageListStreamer)
+ return new ImageListResourceEntryNode(key, (ImageListStreamer)data);
+ return null;
+ }
+
+ #endregion
+ }
+
+ sealed class ImageListResourceEntryNode : ILSpyTreeNode
+ {
+ private readonly string key;
+ private readonly ImageList data;
+
+ public ImageListResourceEntryNode(string key, ImageListStreamer data)
+ {
+ this.LazyLoading = true;
+ this.key = key;
+ this.data = new ImageList();
+ this.data.ImageStream = data;
+ }
+
+ public override object Text
+ {
+ get { return key; }
+ }
+
+ public override object Icon
+ {
+ get { return Images.ResourceImage; }
+ }
+
+ protected override void LoadChildren()
+ {
+ int i = 0;
+ foreach (Image image in this.data.Images) {
+ var node = ResourceEntryNode.Create("Image" + i.ToString(), image);
+ if (node != null)
+ Children.Add(node);
+ ++i;
+ }
+ }
+
+
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ {
+ EnsureLazyChildren();
+ }
+ }
+}
diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
index d96cfb31a..ac474384a 100644
--- a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
@@ -121,9 +121,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (null != smartOutput) {
smartOutput.AddUIElement(
delegate {
- return new ResourceStringTable(stringTableEntries,
- new System.Windows.Size(MainWindow.Instance.mainPane.ActualWidth - 45,
- MainWindow.Instance.mainPane.ActualHeight));
+ return new ResourceStringTable(stringTableEntries, MainWindow.Instance.mainPane);
}
);
}
@@ -135,9 +133,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (null != smartOutput) {
smartOutput.AddUIElement(
delegate {
- return new ResourceObjectTable(otherEntries,
- new System.Windows.Size(MainWindow.Instance.mainPane.ActualWidth - 45,
- MainWindow.Instance.mainPane.ActualHeight));
+ return new ResourceObjectTable(otherEntries, MainWindow.Instance.mainPane);
}
);
}
diff --git a/ILSpy/VB/VBLanguage.cs b/ILSpy/VB/VBLanguage.cs
index ff6339e61..670981ced 100644
--- a/ILSpy/VB/VBLanguage.cs
+++ b/ILSpy/VB/VBLanguage.cs
@@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
+using CSharp = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.VB;
using ICSharpCode.NRefactory.VB.Visitors;
using Mono.Cecil;
@@ -78,6 +79,11 @@ namespace ICSharpCode.ILSpy.VB
base.DecompileAssembly(assembly, output, options);
output.WriteLine();
ModuleDefinition mainModule = assembly.ModuleDefinition;
+ if (mainModule.Types.Count > 0) {
+ output.Write("// Global type: ");
+ output.WriteReference(mainModule.Types[0].FullName, mainModule.Types[0]);
+ output.WriteLine();
+ }
if (mainModule.EntryPoint != null) {
output.Write("' Entry point: ");
output.WriteReference(mainModule.EntryPoint.DeclaringType.FullName + "." + mainModule.EntryPoint.Name, mainModule.EntryPoint);
@@ -125,6 +131,7 @@ namespace ICSharpCode.ILSpy.VB
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = CSharpLanguage.GetPlatformName(module);
+ Guid guid = App.CommandLineArguments.FixedGuid ?? Guid.NewGuid();
using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented;
w.WriteStartDocument();
@@ -133,7 +140,7 @@ namespace ICSharpCode.ILSpy.VB
w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup");
- w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString("B").ToUpperInvariant());
+ w.WriteElementString("ProjectGuid", guid.ToString("B").ToUpperInvariant());
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
@@ -438,8 +445,16 @@ namespace ICSharpCode.ILSpy.VB
void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options, ModuleDefinition module)
{
astBuilder.RunTransformations(transformAbortCondition);
- if (options.DecompilerSettings.ShowXmlDocumentation)
- AddXmlDocTransform.Run(astBuilder.SyntaxTree);
+ if (options.DecompilerSettings.ShowXmlDocumentation) {
+ try {
+ AddXmlDocTransform.Run(astBuilder.SyntaxTree);
+ } catch (XmlException ex) {
+ string[] msg = (" Exception while reading XmlDoc: " + ex.ToString()).Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
+ var insertionPoint = astBuilder.SyntaxTree.FirstChild;
+ for (int i = 0; i < msg.Length; i++)
+ astBuilder.SyntaxTree.InsertChildBefore(insertionPoint, new CSharp.Comment(msg[i], CSharp.CommentType.Documentation), CSharp.Roles.Comment);
+ }
+ }
var csharpUnit = astBuilder.SyntaxTree;
csharpUnit.AcceptVisitor(new NRefactory.CSharp.InsertParenthesesVisitor() { InsertParenthesesForReadability = true });
var unit = csharpUnit.AcceptVisitor(new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider()), null);
diff --git a/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
index cbb54efdf..bdd96727f 100644
--- a/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
+++ b/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
@@ -424,7 +424,7 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- void WriteEmbeddedStatement(Statement embeddedStatement)
+ void WriteEmbeddedStatement(Statement embeddedStatement, bool startOnSameLine = false)
{
if (embeddedStatement.IsNull) {
NewLine();
@@ -433,11 +433,13 @@ namespace ICSharpCode.NRefactory.CSharp
BlockStatement block = embeddedStatement as BlockStatement;
if (block != null) {
VisitBlockStatement(block);
- } else {
+ } else if (!startOnSameLine) {
NewLine();
writer.Indent();
embeddedStatement.AcceptVisitor(this);
writer.Unindent();
+ } else {
+ embeddedStatement.AcceptVisitor(this);
}
}
@@ -1509,7 +1511,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteEmbeddedStatement(ifElseStatement.TrueStatement);
if (!ifElseStatement.FalseStatement.IsNull) {
WriteKeyword(IfElseStatement.ElseKeywordRole);
- WriteEmbeddedStatement(ifElseStatement.FalseStatement);
+ WriteEmbeddedStatement(ifElseStatement.FalseStatement, ifElseStatement.FalseStatement is IfElseStatement);
}
EndNode(ifElseStatement);
}
diff --git a/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs b/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
index 7c29d18a4..963df454f 100644
--- a/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
+++ b/NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
@@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
+using System.Text;
using System.Xml;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
@@ -102,7 +103,8 @@ namespace ICSharpCode.NRefactory.Documentation
XmlDocumentationCache cache = new XmlDocumentationCache();
readonly string fileName;
- volatile IndexEntry[] index; // SORTED array of index entries
+ readonly Encoding encoding;
+ IndexEntry[] index; // SORTED array of index entries
#region Constructor / Redirection support
///
@@ -122,6 +124,7 @@ namespace ICSharpCode.NRefactory.Documentation
xmlReader.MoveToContent();
if (string.IsNullOrEmpty(xmlReader.GetAttribute("redirect"))) {
this.fileName = fileName;
+ this.encoding = xmlReader.Encoding;
ReadXmlDoc(xmlReader);
} else {
string redirectionTarget = GetRedirectionTarget(fileName, xmlReader.GetAttribute("redirect"));
@@ -130,7 +133,9 @@ namespace ICSharpCode.NRefactory.Documentation
using (FileStream redirectedFs = new FileStream(redirectionTarget, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) {
using (XmlTextReader redirectedXmlReader = new XmlTextReader(redirectedFs)) {
redirectedXmlReader.XmlResolver = null; // no DTD resolving
+ redirectedXmlReader.MoveToContent();
this.fileName = redirectionTarget;
+ this.encoding = redirectedXmlReader.Encoding;
ReadXmlDoc(redirectedXmlReader);
}
}
@@ -208,7 +213,7 @@ namespace ICSharpCode.NRefactory.Documentation
//lastWriteDate = File.GetLastWriteTimeUtc(fileName);
// Open up a second file stream for the line<->position mapping
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) {
- LinePositionMapper linePosMapper = new LinePositionMapper(fs);
+ LinePositionMapper linePosMapper = new LinePositionMapper(fs, encoding);
List indexList = new List();
while (reader.Read()) {
if (reader.IsStartElement()) {
@@ -227,21 +232,29 @@ namespace ICSharpCode.NRefactory.Documentation
sealed class LinePositionMapper
{
readonly FileStream fs;
+ readonly Decoder decoder;
int currentLine = 1;
- public LinePositionMapper(FileStream fs)
+ public LinePositionMapper(FileStream fs, Encoding enc)
{
this.fs = fs;
+ this.decoder = enc.GetDecoder();
}
public int GetPositionForLine(int line)
{
Debug.Assert(line >= currentLine);
+ var input = new byte[1];
+ var output = new char[1];
while (line > currentLine) {
int b = fs.ReadByte();
if (b < 0)
throw new EndOfStreamException();
- if (b == '\n') {
+ int bytesUsed, charsUsed;
+ bool completed;
+ input[0] = (byte)b;
+ decoder.Convert(input, 0, 1, output, 0, 1, false, out bytesUsed, out charsUsed, out completed);
+ if (charsUsed == 1 && output[0] == '\n') {
currentLine++;
}
}
@@ -379,7 +392,8 @@ namespace ICSharpCode.NRefactory.Documentation
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) {
fs.Position = positionInFile;
- using (XmlTextReader r = new XmlTextReader(fs, XmlNodeType.Element, null)) {
+ var context = new XmlParserContext(null, null, null, XmlSpace.None) { Encoding = encoding };
+ using (XmlTextReader r = new XmlTextReader(fs, XmlNodeType.Element, context)) {
r.XmlResolver = null; // no DTD resolving
while (r.Read()) {
if (r.NodeType == XmlNodeType.Element) {
diff --git a/README.txt b/README.txt
index b8013ea80..56ef9c3bb 100644
--- a/README.txt
+++ b/README.txt
@@ -9,6 +9,7 @@ Included open-source libraries:
AvalonEdit: LGPL
SharpTreeView: LGPL
ICSharpCode.Decompiler: MIT License (developed as part of ILSpy)
+ Ricciolo.StylesExplorer: MS-PL (part of ILSpy.BamlDecompiler.Plugin)
ILSpy Contributors:
Daniel Grunwald
diff --git a/SharpTreeView/SharpTreeView.cs b/SharpTreeView/SharpTreeView.cs
index 3addc9e03..83b82cc12 100644
--- a/SharpTreeView/SharpTreeView.cs
+++ b/SharpTreeView/SharpTreeView.cs
@@ -120,6 +120,7 @@ namespace ICSharpCode.TreeView
}
TreeFlattener flattener;
+ bool updatesLocked;
void Reload()
{
@@ -148,18 +149,25 @@ namespace ICSharpCode.TreeView
selectedOldItems.Add(node);
}
}
- if (selectedOldItems != null) {
+ if (!updatesLocked && selectedOldItems != null) {
var list = SelectedItems.Cast().Except(selectedOldItems).ToList();
- SetSelectedItems(list);
- if (SelectedItem == null) {
- // if we removed all selected nodes, then move the focus to the node
- // preceding the first of the old selected nodes
- SelectedIndex = Math.Max(0, e.OldStartingIndex - 1);
- FocusNode((SharpTreeNode)SelectedItem);
- }
+ UpdateFocusedNode(list, Math.Max(0, e.OldStartingIndex - 1));
}
}
}
+
+ void UpdateFocusedNode(List newSelection, int topSelectedIndex)
+ {
+ if (updatesLocked) return;
+ SetSelectedItems(newSelection ?? Enumerable.Empty());
+ if (SelectedItem == null) {
+ // if we removed all selected nodes, then move the focus to the node
+ // preceding the first of the old selected nodes
+ SelectedIndex = topSelectedIndex;
+ if (SelectedItem != null)
+ FocusNode((SharpTreeNode)SelectedItem);
+ }
+ }
protected override DependencyObject GetContainerForItemOverride()
{
@@ -631,8 +639,18 @@ namespace ICSharpCode.TreeView
static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e)
{
SharpTreeView treeView = (SharpTreeView)sender;
- foreach (SharpTreeNode node in treeView.GetTopLevelSelection().ToArray())
- node.Delete();
+ treeView.updatesLocked = true;
+ int selectedIndex = -1;
+ try {
+ foreach (SharpTreeNode node in treeView.GetTopLevelSelection().ToArray()) {
+ if (selectedIndex == -1)
+ selectedIndex = treeView.flattener.IndexOf(node);
+ node.Delete();
+ }
+ } finally {
+ treeView.updatesLocked = false;
+ treeView.UpdateFocusedNode(null, Math.Max(0, selectedIndex - 1));
+ }
}
static void HandleCanExecute_Delete(object sender, CanExecuteRoutedEventArgs e)
@@ -652,5 +670,10 @@ namespace ICSharpCode.TreeView
}
#endregion
+
+ public void SetSelectedNodes(IEnumerable nodes)
+ {
+ this.SetSelectedItems(nodes.ToList());
+ }
}
}
diff --git a/doc/Command Line.txt b/doc/Command Line.txt
index c68d6fa51..1cc041d66 100644
--- a/doc/Command Line.txt
+++ b/doc/Command Line.txt
@@ -43,7 +43,7 @@ WM_COPYDATA (SendMessage API):
That is, by sending this message:
ILSpy:
C:\Assembly.dll
- /navigateTo T:Type
+ /navigateTo:T:Type
The target ILSpy instance will open C:\Assembly.dll and navigate to the specified type.
ILSpy will return TRUE (1) if it handles the message, and FALSE (0) otherwise.
diff --git a/doc/copyright.txt b/doc/copyright.txt
index bcc2d6898..57fe86257 100644
--- a/doc/copyright.txt
+++ b/doc/copyright.txt
@@ -1,4 +1,4 @@
-Copyright 2011-2012 for the SharpDevelop team
+Copyright 2011-2014 for the SharpDevelop team
by
AlphaSierraPapa, Christoph Wille
diff --git a/doc/license.txt b/doc/license.txt
index 3aa66eba5..1780d919a 100644
--- a/doc/license.txt
+++ b/doc/license.txt
@@ -1,10 +1,12 @@
The following MIT license applies to ILSpy, NRefactory and ICSharpCode.Decompiler.
Mono.Cecil also uses the MIT license (Copyright JB Evain).
AvalonEdit and SharpTreeView use LGPL, which can be found in the LGPL.txt file.
+ILSpy.BamlDecompiler uses the MS-PL, which can be found in the MS-PL.txt file.
+
MIT license:
-Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop team
+Copyright (c) 2011-2014 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
diff --git a/packages/repositories.config b/packages/repositories.config
index 995ddd17f..857c65c43 100644
--- a/packages/repositories.config
+++ b/packages/repositories.config
@@ -5,4 +5,5 @@
+
\ No newline at end of file