Browse Source

Merge remote-tracking branch 'origin/master' into newdecompiler

pull/728/head
Daniel Grunwald 10 years ago
parent
commit
695b81b78a
  1. 23
      .editorconfig
  2. 4
      .gitignore
  3. 6
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  4. 88
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  5. 24
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  6. 31
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  7. 14
      ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs
  8. 92
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  9. 47
      ICSharpCode.Decompiler/CecilExtensions.cs
  10. 105
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  11. 8
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  12. 2
      ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs
  13. 3
      ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs
  14. 10
      ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
  15. 32
      ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
  16. 2
      ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs
  17. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  18. 38
      ICSharpCode.Decompiler/Tests/Lock.cs
  19. 2
      ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
  20. 17
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs
  21. 17
      ICSharpCode.Decompiler/Tests/ValueTypes.cs
  22. 40
      ICSharpCode.Decompiler/TypeSystem/TypesHierarchyHelpers.cs
  23. 11
      ILSpy.AddIn/GlobalSuppressions.cs
  24. 14
      ILSpy.AddIn/Guids.cs
  25. BIN
      ILSpy.AddIn/ILSpy-Large.ico
  26. 246
      ILSpy.AddIn/ILSpy.AddIn.csproj
  27. 132
      ILSpy.AddIn/ILSpyAddIn.vsct
  28. 167
      ILSpy.AddIn/ILSpyAddInPackage.cs
  29. BIN
      ILSpy.AddIn/Key.snk
  30. 13
      ILSpy.AddIn/PkgCmdID.cs
  31. 36
      ILSpy.AddIn/Properties/AssemblyInfo.cs
  32. 63
      ILSpy.AddIn/Resources.Designer.cs
  33. 129
      ILSpy.AddIn/Resources.resx
  34. BIN
      ILSpy.AddIn/Resources/Images.png
  35. BIN
      ILSpy.AddIn/Resources/Package.ico
  36. 112
      ILSpy.AddIn/Utils.cs
  37. 140
      ILSpy.AddIn/VSPackage.resx
  38. 12
      ILSpy.AddIn/license.txt
  39. 16
      ILSpy.AddIn/packages.config
  40. 32
      ILSpy.AddIn/source.extension.vsixmanifest
  41. 7
      ILSpy.BamlDecompiler/CecilTypeResolver.cs
  42. 3
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs
  43. 48
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
  44. 2
      ILSpy.BamlDecompiler/Tests/Cases/CustomControl.cs
  45. 26
      ILSpy.BamlDecompiler/Tests/Cases/EscapeSequence.xaml
  46. 2
      ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml
  47. 5
      ILSpy.BamlDecompiler/Tests/Cases/NamespacePrefix.xaml
  48. 5
      ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj
  49. 6
      ILSpy.BamlDecompiler/Tests/TestRunner.cs
  50. 20
      ILSpy.sln
  51. 1
      ILSpy/AboutPage.cs
  52. 44
      ILSpy/AssemblyList.cs
  53. 14
      ILSpy/CommandLineArguments.cs
  54. 41
      ILSpy/ContextMenuEntry.cs
  55. 28
      ILSpy/Controls/ResourceObjectTable.xaml.cs
  56. 28
      ILSpy/Controls/ResourceStringTable.xaml.cs
  57. 7
      ILSpy/ILSpy.csproj
  58. 48
      ILSpy/Languages/CSharpLanguage.cs
  59. 42
      ILSpy/LoadedAssembly.cs
  60. 3
      ILSpy/MainWindow.xaml
  61. 87
      ILSpy/MainWindow.xaml.cs
  62. 1
      ILSpy/Options/DecompilerSettingsPanel.xaml
  63. 2
      ILSpy/Options/DecompilerSettingsPanel.xaml.cs
  64. 5
      ILSpy/Properties/AssemblyInfo.template.cs
  65. 356
      ILSpy/SearchPane.cs
  66. 2
      ILSpy/SearchPane.xaml
  67. 335
      ILSpy/SearchStrategies.cs
  68. 5
      ILSpy/SessionSettings.cs
  69. 28
      ILSpy/TextView/DecompilerTextView.cs
  70. 44
      ILSpy/TextView/EditorCommands.cs
  71. 162
      ILSpy/TextView/FoldingCommands.cs
  72. 5
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
  73. 3
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs
  74. 195
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs
  75. 14
      ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs
  76. 7
      ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
  77. 102
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  78. 13
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  79. 123
      ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs
  80. 90
      ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs
  81. 8
      ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
  82. 21
      ILSpy/VB/VBLanguage.cs
  83. 8
      NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
  84. 24
      NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
  85. 1
      README.txt
  86. 43
      SharpTreeView/SharpTreeView.cs
  87. 2
      doc/Command Line.txt
  88. 2
      doc/copyright.txt
  89. 4
      doc/license.txt
  90. 1
      packages/repositories.config

23
.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

4
.gitignore vendored

@ -10,5 +10,5 @@ obj/
_ReSharper*/ _ReSharper*/
*.ReSharper *.ReSharper
*.patch *.patch
/ILSpy.sln.ide /packages
/packages/* *.ide/

6
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -160,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast
RunTransformations(); RunTransformations();
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); 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; var formattingPolicy = context.Settings.CSharpFormattingOptions;
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy)); syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy));
} }
@ -321,11 +321,13 @@ namespace ICSharpCode.Decompiler.Ast
if (typeDef.IsEnum) { if (typeDef.IsEnum) {
long expectedEnumMemberValue = 0; long expectedEnumMemberValue = 0;
bool forcePrintingInitializers = IsFlagsEnum(typeDef); bool forcePrintingInitializers = IsFlagsEnum(typeDef);
TypeCode baseType = TypeCode.Int32;
foreach (FieldDefinition field in typeDef.Fields) { foreach (FieldDefinition field in typeDef.Fields) {
if (!field.IsStatic) { if (!field.IsStatic) {
// the value__ field // the value__ field
if (field.FieldType != typeDef.Module.TypeSystem.Int32) { if (field.FieldType != typeDef.Module.TypeSystem.Int32) {
astType.AddChild(ConvertType(field.FieldType), Roles.BaseType); astType.AddChild(ConvertType(field.FieldType), Roles.BaseType);
baseType = TypeAnalysis.GetTypeCode(field.FieldType);
} }
} else { } else {
EnumMemberDeclaration enumMember = new EnumMemberDeclaration(); EnumMemberDeclaration enumMember = new EnumMemberDeclaration();
@ -333,7 +335,7 @@ namespace ICSharpCode.Decompiler.Ast
enumMember.Name = CleanName(field.Name); enumMember.Name = CleanName(field.Name);
long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false);
if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) { 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; expectedEnumMemberValue = memberValue + 1;
astType.AddChild(enumMember, Roles.TypeMemberRole); astType.AddChild(enumMember, Roles.TypeMemberRole);

88
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.</param> /// These are used to update the parameter names when the decompiler generates names for the parameters.</param>
/// <returns>Block for the method body</returns> /// <returns>Block for the method body</returns>
public static BlockStatement CreateMethodBody(MethodDefinition methodDef, public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
DecompilerContext context, DecompilerContext context,
IEnumerable<ParameterDeclaration> parameters = null) IEnumerable<ParameterDeclaration> parameters = null)
{ {
MethodDefinition oldCurrentMethod = context.CurrentMethod; MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
@ -103,8 +103,8 @@ namespace ICSharpCode.Decompiler.Ast
if (parameters != null) { if (parameters != null) {
foreach (var pair in (from p in parameters foreach (var pair in (from p in parameters
join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter
select new { p, v.Name })) select new { p, v.Name }))
{ {
pair.p.Name = pair.Name; pair.p.Name = pair.Name;
} }
@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock); tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) { foreach (var catchClause in tryCatchNode.CatchBlocks) {
if (catchClause.ExceptionVariable == null 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) }); tryCatchStmt.CatchClauses.Add(new Ast.CatchClause { Body = TransformBlock(catchClause) });
} else { } else {
@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler.Ast
result = node; result = node;
if (result != null) if (result != null)
result = result.WithAnnotation(new TypeInformation(expr.InferredType)); result = result.WithAnnotation(new TypeInformation(expr.InferredType, expr.ExpectedType));
if (result != null) if (result != null)
return result.WithAnnotation(ilRanges); return result.WithAnnotation(ilRanges);
@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast
{ {
BinaryOperatorExpression boe; BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) { if (byteCode.InferredType is PointerType) {
if (byteCode.Arguments[0].ExpectedType is PointerType) { boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType); if (byteCode.Arguments[0].ExpectedType is PointerType ||
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); byteCode.Arguments[1].ExpectedType is PointerType) {
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.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
} }
} else { } else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast
{ {
BinaryOperatorExpression boe; BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) { if (byteCode.InferredType is PointerType) {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
if (byteCode.Arguments[0].ExpectedType is PointerType) { 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); boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
} }
} else { } else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); 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 // can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType; TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne; 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; goto case ILCode.Cgt;
} }
case ILCode.Cle_Un: { case ILCode.Cle_Un: {
// can also mean Equality, when used with object references // can also mean Equality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType; TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq; 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; goto case ILCode.Cle;
} }
case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
@ -706,7 +715,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
return new StackAllocExpression { return new StackAllocExpression {
Type = AstBuilder.ConvertType(type), Type = AstBuilder.ConvertType(type),
CountExpression = DivideBySize(arg1, type) CountExpression = arg1
}; };
} }
case ILCode.Mkrefany: case ILCode.Mkrefany:
@ -902,45 +911,6 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
/// <summary>
/// Divides expr by the size of 'type'.
/// </summary>
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) Expression MakeDefaultValue(TypeReference type)
{ {
TypeDefinition typeDef = type.Resolve(); TypeDefinition typeDef = type.Resolve();

24
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -30,6 +30,7 @@ namespace ICSharpCode.Decompiler.Ast
public class TextOutputFormatter : IOutputFormatter public class TextOutputFormatter : IOutputFormatter
{ {
readonly ITextOutput output; readonly ITextOutput output;
readonly DecompilerContext context;
readonly Stack<AstNode> nodeStack = new Stack<AstNode>(); readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
int braceLevelWithinType = -1; int braceLevelWithinType = -1;
bool inDocumentationComment = false; bool inDocumentationComment = false;
@ -38,11 +39,14 @@ namespace ICSharpCode.Decompiler.Ast
public bool FoldBraces = false; public bool FoldBraces = false;
public TextOutputFormatter(ITextOutput output) public TextOutputFormatter(ITextOutput output, DecompilerContext context)
{ {
if (output == null) if (output == null)
throw new ArgumentNullException("output"); throw new ArgumentNullException("output");
if (context == null)
throw new ArgumentNullException("context");
this.output = output; this.output = output;
this.context = context;
} }
public void WriteIdentifier(string identifier) public void WriteIdentifier(string identifier)
@ -89,6 +93,24 @@ namespace ICSharpCode.Decompiler.Ast
{ {
memberRef = node.Parent.Annotation<MemberReference>(); memberRef = node.Parent.Annotation<MemberReference>();
} }
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; return memberRef;
} }

31
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -144,6 +144,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName)) if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName))
continue; 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) { foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement; BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) { 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) // 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) { for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) {
@ -285,6 +303,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
return true; return true;
} }
static IEnumerable<AstNode> 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) static bool HasNestedBlocks(AstNode node)
{ {

14
ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs

@ -180,8 +180,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
foreach (AstNode node in body.Descendants) { foreach (AstNode node in body.Descendants) {
if (node is ThisReferenceExpression) if (node is ThisReferenceExpression)
node.ReplaceWith(target.Clone()); node.ReplaceWith(target.Clone());
} }
Expression replacement;
if (isLambda) { if (isLambda) {
LambdaExpression lambda = new LambdaExpression(); LambdaExpression lambda = new LambdaExpression();
lambda.CopyAnnotationsFrom(ame); lambda.CopyAnnotationsFrom(ame);
@ -189,11 +189,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression; Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression;
returnExpr.Remove(); returnExpr.Remove();
lambda.Body = returnExpr; lambda.Body = returnExpr;
objectCreateExpression.ReplaceWith(lambda); replacement = lambda;
} else { } else {
ame.Body = body; ame.Body = body;
objectCreateExpression.ReplaceWith(ame); replacement = ame;
}
var expectedType = objectCreateExpression.Annotation<TypeInformation>().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; return true;
} }

92
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -99,6 +99,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (result != null) if (result != null)
return result; return result;
} }
AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement);
if (simplifiedIfElse != null)
return simplifiedIfElse;
return base.VisitIfElseStatement(ifElseStatement, data); return base.VisitIfElseStatement(ifElseStatement, data);
} }
@ -614,6 +617,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
static readonly AstNode lockTryCatchPattern = new TryCatchStatement { static readonly AstNode lockTryCatchPattern = new TryCatchStatement {
TryBlock = new BlockStatement { TryBlock = new BlockStatement {
new OptionalNode(new VariableDeclarationStatement()).ToStatement(),
new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke( new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke(
"Enter", new AnyNode("enter"), "Enter", new AnyNode("enter"),
new DirectionExpression { new DirectionExpression {
@ -626,21 +630,57 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
new IfElseStatement { new IfElseStatement {
Condition = new Backreference("flag"), Condition = new Backreference("flag"),
TrueStatement = new BlockStatement { 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<Expression>("enter").Single();
exit = m2.Get<Expression>("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<Expression>("enter").Single();
exit = m2.Get<Expression>("exit").Single();
return m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("flag").Single().Identifier;
}
public LockStatement TransformLock(ExpressionStatement node) public LockStatement TransformLock(ExpressionStatement node)
{ {
Match m1 = lockFlagInitPattern.Match(node); Expression enter, exit;
if (!m1.Success) return null; bool isV2 = AnalyzeLockV2(node, out enter, out exit);
AstNode tryCatch = node.NextSibling; if (isV2 || AnalyzeLockV4(node, out enter, out exit)) {
Match m2 = lockTryCatchPattern.Match(tryCatch); AstNode tryCatch = node.NextSibling;
if (!m2.Success) return null;
if (m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("flag").Single().Identifier) {
Expression enter = m2.Get<Expression>("enter").Single();
IdentifierExpression exit = m2.Get<IdentifierExpression>("exit").Single();
if (!exit.IsMatch(enter)) { if (!exit.IsMatch(enter)) {
// If exit and enter are not the same, then enter must be "exit = ..." // If exit and enter are not the same, then enter must be "exit = ..."
AssignmentExpression assign = enter as AssignmentExpression; AssignmentExpression assign = enter as AssignmentExpression;
@ -656,7 +696,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
LockStatement l = new LockStatement(); LockStatement l = new LockStatement();
l.Expression = enter.Detach(); l.Expression = enter.Detach();
l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.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); tryCatch.ReplaceWith(l);
node.Remove(); // remove flag variable node.Remove(); // remove flag variable
return l; return l;
@ -1047,5 +1088,36 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null; return null;
} }
#endregion #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<IfElseStatement>("nestedIfStatement").Single();
node.FalseStatement = elseIf.Detach();
}
return null;
}
#endregion
} }
} }

47
ICSharpCode.Decompiler/CecilExtensions.cs

@ -126,6 +126,41 @@ namespace ICSharpCode.Decompiler
return false; return false;
return type.IsValueType || type.IsVoid(); return type.IsValueType || type.IsVoid();
} }
/// <summary>
/// checks if the given TypeReference is one of the following types:
/// [sbyte, short, int, long, IntPtr]
/// </summary>
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;
}
/// <summary>
/// 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]
/// </summary>
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 #endregion
/// <summary> /// <summary>
@ -190,6 +225,7 @@ namespace ICSharpCode.Decompiler
return null; return null;
} }
[Obsolete("throwing exceptions is considered a bug")]
public static TypeDefinition ResolveOrThrow(this TypeReference typeReference) public static TypeDefinition ResolveOrThrow(this TypeReference typeReference)
{ {
var resolved = typeReference.Resolve(); var resolved = typeReference.Resolve();
@ -346,5 +382,16 @@ namespace ICSharpCode.Decompiler
{ {
return new ICSharpCode.NRefactory.TypeSystem.FullTypeName(typeDef.FullName); 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;
}
} }
} }

105
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst
PropertyAccessInstructions, PropertyAccessInstructions,
SplitToMovableBlocks, SplitToMovableBlocks,
TypeInference, TypeInference,
HandlePointerArithmetic,
SimplifyShortCircuit, SimplifyShortCircuit,
SimplifyTernaryOperator, SimplifyTernaryOperator,
SimplifyNullCoalescing, SimplifyNullCoalescing,
@ -125,6 +126,9 @@ namespace ICSharpCode.Decompiler.ILAst
// Types are needed for the ternary operator optimization // Types are needed for the ternary operator optimization
TypeAnalysis.Run(context, method); TypeAnalysis.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.HandlePointerArithmetic) return;
HandlePointerArithmetic(method);
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) { foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
bool modified; bool modified;
do { do {
@ -664,6 +668,107 @@ namespace ICSharpCode.Decompiler.ILAst
return combinedVariable; return combinedVariable;
}); });
} }
static void HandlePointerArithmetic(ILNode method)
{
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
List<ILExpression> 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<ILVariable, ILVariable> variableMapping) public static void ReplaceVariables(ILNode node, Func<ILVariable, ILVariable> variableMapping)
{ {

8
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.ILAst
return (TypeReference)expr.Operand; return (TypeReference)expr.Operand;
case ILCode.Localloc: case ILCode.Localloc:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Int32); InferTypeForExpression(expr.Arguments[0], null);
} }
if (expectedType is PointerType) if (expectedType is PointerType)
return expectedType; return expectedType;
@ -1013,7 +1013,7 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType); TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) { if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred; left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr); InferTypeForExpression(right, null);
return leftPreferred; return leftPreferred;
} }
if (IsEnum(leftPreferred)) { if (IsEnum(leftPreferred)) {
@ -1024,7 +1024,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType); TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) { if (rightPreferred is PointerType) {
InferTypeForExpression(left, typeSystem.IntPtr); InferTypeForExpression(left, null);
right.InferredType = right.ExpectedType = rightPreferred; right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred; return rightPreferred;
} }
@ -1044,7 +1044,7 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType); TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) { if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred; left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr); InferTypeForExpression(right, null);
return leftPreferred; return leftPreferred;
} }
if (IsEnum(leftPreferred)) { if (IsEnum(leftPreferred)) {

2
ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs

@ -12,7 +12,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("IL decompiler engine")] [assembly: AssemblyDescription("IL decompiler engine")]
[assembly: AssemblyCompany("ic#code")] [assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")] [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: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]

3
ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs

@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Tests
{ {
if(String.IsNullOrWhiteSpace(s)) if(String.IsNullOrWhiteSpace(s))
return true; 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<string> lines) public static string ConcatLines(IEnumerable<string> lines)

10
ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs

@ -20,21 +20,19 @@ using System;
public static class CustomShortCircuitOperators 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; return true;
} }
public static bool operator false(CustomShortCircuitOperators.B x) public static bool operator false(CustomShortCircuitOperators.C x)
{ {
return false; return false;
} }
}
private class C : CustomShortCircuitOperators.B
{
public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y) public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
{ {
return null; return null;

32
ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs

@ -35,10 +35,8 @@ namespace ICSharpCode.Decompiler.Tests
{ {
protected static void ValidateFileRoundtrip(string samplesFileName) protected static void ValidateFileRoundtrip(string samplesFileName)
{ {
var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName)); var fullPath = Path.Combine(@"..\..\Tests", samplesFileName);
var testCode = RemoveIgnorableLines(lines); AssertRoundtripCode(fullPath);
var decompiledTestCode = RoundtripCode(testCode);
CodeAssert.AreEqual(testCode, decompiledTestCode);
} }
static string RemoveIgnorableLines(IEnumerable<string> lines) static string RemoveIgnorableLines(IEnumerable<string> lines)
@ -46,29 +44,27 @@ namespace ICSharpCode.Decompiler.Tests
return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l))); return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l)));
} }
/// <summary> protected static void AssertRoundtripCode(string fileName, bool optimize = false, bool useDebug = false, int compilerVersion = 4)
/// Compiles and decompiles a source code.
/// </summary>
/// <param name="code">The source code to copile.</param>
/// <returns>The decompilation result of compiled source code.</returns>
static string RoundtripCode(string code)
{ {
DecompilerSettings settings = new DecompilerSettings(); var code = RemoveIgnorableLines(File.ReadLines(fileName));
settings.FullyQualifyAmbiguousTypeNames = false; AssemblyDefinition assembly = CompileLegacy(code, optimize, useDebug, compilerVersion);
AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule) { Settings = settings }); AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly); decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree); new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree);
StringWriter output = new StringWriter(); StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output)); 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<string, string> { { "CompilerVersion", "v4.0" } }); CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v" + new Version(compilerVersion, 0) } });
CompilerParameters options = new CompilerParameters(); 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); CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try try
{ {

2
ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs

@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
private static IEnumerable<string> NormalizeAndSplitCode(string input) private static IEnumerable<string> 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);
} }
} }
} }

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

@ -107,7 +107,6 @@
<Compile Include="TestCases\HelloWorld.cs" /> <Compile Include="TestCases\HelloWorld.cs" />
<Compile Include="TestCases\PropertiesAndEvents.cs" /> <Compile Include="TestCases\PropertiesAndEvents.cs" />
<Compile Include="TestRunner.cs" /> <Compile Include="TestRunner.cs" />
<Compile Include="Util\IntervalTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

38
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();
}
}
}

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

@ -664,7 +664,9 @@ namespace HideMembers3
} }
public class J2 : J public class J2 : J
{ {
#pragma warning disable 0108 // Deliberate bad code for test case
public int get_P; public int get_P;
#pragma warning restore 0108
} }
} }
//$$ HideMembers4 //$$ HideMembers4

17
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -122,7 +122,22 @@ public class UnsafeCode
} }
return this.PointerReferenceExpression((double*)ptr); 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() unsafe ~UnsafeCode()
{ {
this.PassPointerAsRefParameter(this.NullPointer); this.PassPointerAsRefParameter(this.NullPointer);

17
ICSharpCode.Decompiler/Tests/ValueTypes.cs

@ -168,4 +168,21 @@ public static class ValueTypes
Console.WriteLine("true"); Console.WriteLine("true");
} }
} }
public static void CompareNotEqual0IsReallyNotEqual(IComparable<int> a)
{
if (a.CompareTo(0) != 0)
{
Console.WriteLine("true");
}
}
public static void CompareEqual0IsReallyEqual(IComparable<int> a)
{
if (a.CompareTo(0) == 0)
{
Console.WriteLine("true");
}
}
} }

40
ICSharpCode.Decompiler/TypeSystem/TypesHierarchyHelpers.cs

@ -32,9 +32,11 @@ namespace ICSharpCode.Decompiler.Ast
if (resolveTypeArguments) if (resolveTypeArguments)
return BaseTypes(derivedType).Any(t => t.Item == baseType); return BaseTypes(derivedType).Any(t => t.Item == baseType);
else { else {
var comparableBaseType = baseType.ResolveOrThrow(); var comparableBaseType = baseType.Resolve();
if (comparableBaseType == null)
return false;
while (derivedType.BaseType != null) { while (derivedType.BaseType != null) {
var resolvedBaseType = derivedType.BaseType.ResolveOrThrow(); var resolvedBaseType = derivedType.BaseType.Resolve();
if (resolvedBaseType == null) if (resolvedBaseType == null)
return false; return false;
if (comparableBaseType == resolvedBaseType) if (comparableBaseType == resolvedBaseType)
@ -185,24 +187,32 @@ namespace ICSharpCode.Decompiler.Ast
if (derivedType == null) if (derivedType == null)
throw new ArgumentNullException("derivedType"); throw new ArgumentNullException("derivedType");
var visibility = IsVisibleFromDerived(baseMember); MethodAttributes attrs = GetAccessAttributes(baseMember) & MethodAttributes.MemberAccessMask;
if (visibility.HasValue) if (attrs == MethodAttributes.Private)
return visibility.Value; return false;
if (baseMember.DeclaringType.Module == derivedType.Module) if (baseMember.DeclaringType.Module == derivedType.Module)
return true; return true;
// TODO: Check also InternalsVisibleToAttribute.
return false;
}
private static bool? IsVisibleFromDerived(IMemberDefinition member) if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem) {
{ var derivedTypeAsm = derivedType.Module.Assembly;
MethodAttributes attrs = GetAccessAttributes(member) & MethodAttributes.MemberAccessMask; var asm = baseMember.DeclaringType.Module.Assembly;
if (attrs == MethodAttributes.Private)
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; return false;
if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem) }
return null;
return true; return true;
} }
private static MethodAttributes GetAccessAttributes(IMemberDefinition member) private static MethodAttributes GetAccessAttributes(IMemberDefinition member)

11
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")]

14
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);
};
}

BIN
ILSpy.AddIn/ILSpy-Large.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

246
ILSpy.AddIn/ILSpy.AddIn.csproj

@ -0,0 +1,246 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<!-- Use the SDK for the current version of Visual Studio -->
<VsSdkTargets Condition="'$(VisualStudioVersion)'!=''">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\VSSDK\Microsoft.VsSDK.targets</VsSdkTargets>
<VsSdkTargets Condition="'$(VisualStudioVersion)'==''">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\VSSDK\Microsoft.VsSDK.targets</VsSdkTargets>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' != ''">
<!-- This is added to prevent forced migrations in Visual Studio 2012 and newer -->
<MinimumVisualStudioVersion>$(VisualStudioVersion)</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}</ProjectGuid>
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ICSharpCode.ILSpy.AddIn</RootNamespace>
<AssemblyName>ILSpy.AddIn</AssemblyName>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<!-- Common debugging support -->
<StartAction>Program</StartAction>
<StartProgram>$(DevEnvDir)\devenv.exe</StartProgram>
<StartArguments>/rootSuffix Exp</StartArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>true</RunCodeAnalysis>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="EnvDTE">
<HintPath>..\packages\VSSDK.DTE.7.0.3\lib\net20\envdte.dll</HintPath>
<EmbedInteropTypes>False</EmbedInteropTypes>
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualStudio.OLE.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
<HintPath>..\packages\VSSDK.OLE.Interop.7.0.3\lib\net20\Microsoft.VisualStudio.OLE.Interop.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
<HintPath>..\packages\VSSDK.Shell.10.10.0.3\lib\net40\Microsoft.VisualStudio.Shell.10.0.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
<HintPath>..\packages\VSSDK.Shell.Immutable.10.10.0.3\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
<HintPath>..\packages\VSSDK.Shell.Interop.7.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
<HintPath>..\packages\VSSDK.Shell.Interop.8.8.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.8.0.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Interop.10.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
<HintPath>..\packages\VSSDK.Shell.Interop.9.9.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.9.0.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TextManager.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
<HintPath>..\packages\VSSDK.TextManager.Interop.7.0.3\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TextManager.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
<HintPath>..\packages\VSSDK.TextManager.Interop.8.8.0.3\lib\net20\Microsoft.VisualStudio.TextManager.Interop.8.0.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="stdole">
<HintPath>..\packages\VSSDK.DTE.7.0.3\lib\net20\stdole.dll</HintPath>
<EmbedInteropTypes>False</EmbedInteropTypes>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Design" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<COMReference Include="EnvDTE100">
<Guid>{26AD1324-4B7C-44BC-84F8-B86AED45729F}</Guid>
<VersionMajor>10</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="EnvDTE80">
<Guid>{1A31287A-4D7D-413E-8E32-3B374931BD89}</Guid>
<VersionMajor>8</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="EnvDTE90">
<Guid>{2CE2370E-D744-4936-A090-3FFFE667B0E1}</Guid>
<VersionMajor>9</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Guids.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="ILSpyAddInPackage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PkgCmdID.cs" />
<Compile Include="Utils.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="VSPackage.resx">
<MergeWithCTO>true</MergeWithCTO>
<ManifestResourceName>VSPackage</ManifestResourceName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="Key.snk" />
</ItemGroup>
<ItemGroup>
<VSCTCompile Include="ILSpyAddIn.vsct">
<ResourceName>Menus.ctmenu</ResourceName>
<SubType>Designer</SubType>
</VSCTCompile>
</ItemGroup>
<ItemGroup>
<None Include="Resources\Images.png" />
</ItemGroup>
<ItemGroup>
<Content Include="ILSpy-Large.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<Content Include="license.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<Content Include="Resources\Package.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj">
<Project>{6c55b776-26d4-4db3-a6ab-87e783b2f3d1}</Project>
<Name>ICSharpCode.AvalonEdit</Name>
</ProjectReference>
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj">
<Project>{984cc812-9470-4a13-aff9-cc44068d666c}</Project>
<Name>ICSharpCode.Decompiler</Name>
</ProjectReference>
<ProjectReference Include="..\ILSpy.BamlDecompiler\ILSpy.BamlDecompiler.csproj">
<Project>{a6bad2ba-76ba-461c-8b6d-418607591247}</Project>
<Name>ILSpy.BamlDecompiler</Name>
</ProjectReference>
<ProjectReference Include="..\ILSpy\ILSpy.csproj">
<Project>{1e85eff9-e370-4683-83e4-8a3d063ff791}</Project>
<Name>ILSpy</Name>
</ProjectReference>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{d68133bd-1e63-496e-9ede-4fbdbf77b486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\Mono.Cecil\symbols\pdb\Mono.Cecil.Pdb.csproj">
<Project>{63e6915c-7ea4-4d76-ab28-0d7191eea626}</Project>
<Name>Mono.Cecil.Pdb</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53dca265-3c3c-42f9-b647-f72ba678122b}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory.VB\ICSharpCode.NRefactory.VB.csproj">
<Project>{7b82b671-419f-45f4-b778-d9286f996efa}</Project>
<Name>ICSharpCode.NRefactory.VB</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3b2a5653-ec97-4001-bb9b-d90f1af2c371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
<ProjectReference Include="..\SharpTreeView\ICSharpCode.TreeView.csproj">
<Project>{dde2a481-8271-4eac-a330-8fa6a38d13d1}</Project>
<Name>ICSharpCode.TreeView</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup>
<UseCodebase>true</UseCodebase>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Condition="Exists($(VsSdkTargets))" Project="$(VsSdkTargets)" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

132
ILSpy.AddIn/ILSpyAddIn.vsct

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This is the file that defines the actual layout and type of the commands.
It is divided in different sections (e.g. command definition, command
placement, ...), with each defining a specific set of properties.
See the comment before each section for more details about how to
use it. -->
<!-- The VSCT compiler (the tool that translates this file into the binary
format that VisualStudio will consume) has the ability to run a preprocessor
on the vsct file; this preprocessor is (usually) the C++ preprocessor, so
it is possible to define includes and macros with the same syntax used
in C++ files. Using this ability of the compiler here, we include some files
defining some of the constants that we will use inside the file. -->
<!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
<Extern href="stdidcmd.h"/>
<!--This header contains the command ids for the menus provided by the shell. -->
<Extern href="vsshlids.h"/>
<!--The Commands section is where we the commands, menus and menu groups are defined.
This section uses a Guid to identify the package that provides the command defined inside it. -->
<Commands package="guidILSpyAddInPkg">
<!-- Inside this section we have different sub-sections: one for the menus, another
for the menu groups, one for the buttons (the actual commands), one for the combos
and the last one for the bitmaps used. Each element is identified by a command id that
is a unique pair of guid and numeric identifier; the guid part of the identifier is usually
called "command set" and is used to group different command inside a logically related
group; your package should define its own command set in order to avoid collisions
with command ids defined by other packages. -->
<!-- In this section you can define new menu groups. A menu group is a container for
other menus or buttons (commands); from a visual point of view you can see the
group as the part of a menu contained between two lines. The parent of a group
must be a menu. -->
<Groups>
<Group guid="guidILSpyAddInCmdSet" id="OpenILSpyGroup" priority="0x0200">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
</Group>
<Group guid="guidILSpyAddInCmdSet" id="OpenILSpyProjGroup" priority="0x0200">
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/>
</Group>
</Groups>
<!--Buttons section. -->
<!--This section defines the elements the user can interact with, like a menu command or a button
or combo box in a toolbar. -->
<Buttons>
<!--To define a menu group you have to specify its ID, the parent menu and its display priority.
The command is visible and enabled by default. If you need to change the visibility, status, etc, you can use
the CommandFlag node.
You can add more than one CommandFlag node e.g.:
<CommandFlag>DefaultInvisible</CommandFlag>
<CommandFlag>DynamicVisibility</CommandFlag>
If you do not want an image next to your command, remove the Icon node /> -->
<Button guid="guidILSpyAddInCmdSet" id="cmdidOpenReferenceInILSpy" priority="0x0600" type="Button">
<Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyRefGroup" />
<Icon guid="guidImages" id="bmpLogo" />
<Strings>
<ButtonText>Open in ILSpy</ButtonText>
</Strings>
</Button>
<Button guid="guidILSpyAddInCmdSet" id="cmdidOpenProjectOutputInILSpy" priority="0x0600" type="Button">
<Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyProjGroup" />
<Icon guid="guidImages" id="bmpLogo" />
<Strings>
<ButtonText>Open output in ILSpy</ButtonText>
</Strings>
</Button>
<Button guid="guidILSpyAddInCmdSet" id="cmdidOpenILSpy" priority="0x0600" type="Button">
<Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyGroup" />
<Icon guid="guidImages" id="bmpLogo" />
<Strings>
<ButtonText>ILSpy</ButtonText>
</Strings>
</Button>
</Buttons>
<!--The bitmaps section is used to define the bitmaps that are used for the commands.-->
<Bitmaps>
<!-- The bitmap id is defined in a way that is a little bit different from the others:
the declaration starts with a guid for the bitmap strip, then there is the resource id of the
bitmap strip containing the bitmaps and then there are the numeric ids of the elements used
inside a button definition. An important aspect of this declaration is that the element id
must be the actual index (1-based) of the bitmap inside the bitmap strip. -->
<Bitmap guid="guidImages" href="Resources\Images.png" usedList="bmpLogo, bmpPic1, bmpPic2, bmpPicX, bmpPicArrows"/>
</Bitmaps>
</Commands>
<CommandPlacements>
<CommandPlacement guid="guidILSpyAddInCmdSet" id="cmdidOpenReferenceInILSpy" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDG_VS_CTXT_REFERENCE"/>
</CommandPlacement>
</CommandPlacements>
<Symbols>
<!-- This is the package guid. -->
<GuidSymbol name="guidILSpyAddInPkg" value="{a9120dbe-164a-4891-842f-fb7829273838}" />
<!-- This is the guid used to group the menu commands together -->
<GuidSymbol name="guidILSpyAddInCmdSet" value="{85ddb8ca-a842-4b1c-ba1a-94141fdf19d0}">
<IDSymbol name="OpenILSpyGroup" value="0x1010" />
<IDSymbol name="OpenILSpyRefGroup" value="0x1020" />
<IDSymbol name="OpenILSpyProjGroup" value="0x1030" />
<IDSymbol name="cmdidOpenILSpy" value="0x0100" />
<IDSymbol name="cmdidOpenReferenceInILSpy" value="0x0200" />
<IDSymbol name="cmdidOpenProjectOutputInILSpy" value="0x0300" />
</GuidSymbol>
<GuidSymbol name="guidImages" value="{2f654db9-4641-4638-9937-27c6202b2a6a}" >
<IDSymbol name="bmpLogo" value="1" />
<IDSymbol name="bmpPic1" value="2" />
<IDSymbol name="bmpPic2" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
<IDSymbol name="bmpPicStrikethrough" value="6" />
</GuidSymbol>
</Symbols>
</CommandTable>

167
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
{
/// <summary>
/// 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.
/// </summary>
// 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
{
/// <summary>
/// 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.
/// </summary>
public ILSpyAddInPackage()
{
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
}
/////////////////////////////////////////////////////////////////////////////
// Overridden Package Implementation
#region Package Members
/// <summary>
/// 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.
/// </summary>
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
/// <summary>
/// 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.
/// </summary>
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
)
);
}
}
}

BIN
ILSpy.AddIn/Key.snk

Binary file not shown.

13
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;
};
}

36
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")]

63
ILSpy.AddIn/Resources.Designer.cs generated

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ICSharpCode.ILSpy.AddIn {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

129
ILSpy.AddIn/Resources.resx

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
VS SDK Notes: This resx file contains the resources that will be consumed directly by your package.
For example, if you chose to create a tool window, there is a resource with ID 'CanNotCreateWindow'. This
is used in VsPkg.cs to determine the string to show the user if there is an error when attempting to create
the tool window.
Resources that are accessed directly from your package *by Visual Studio* are stored in the VSPackage.resx
file.
-->
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

BIN
ILSpy.AddIn/Resources/Images.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
ILSpy.AddIn/Resources/Package.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

112
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
/// <summary>
/// Decodes a command line into an array of arguments according to the CommandLineToArgvW rules.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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', '"' };
/// <summary>
/// Escapes a set of arguments according to the CommandLineToArgvW rules.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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;
}
}
}

140
ILSpy.AddIn/VSPackage.resx

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
VS SDK Notes: This resx file contains the resources that will be consumed from your package by Visual Studio.
For example, Visual Studio will attempt to load resource '400' from this resource stream when it needs to
load your package's icon. Because Visual Studio will always look in the VSPackage.resources stream first for
resources it needs, you should put additional resources that Visual Studio will load directly into this resx
file.
Resources that you would like to access directly from your package in a strong-typed fashion should be stored
in Resources.resx or another resx file.
-->
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="110" xml:space="preserve">
<value>ILSpy.AddIn</value>
</data>
<data name="112" xml:space="preserve">
<value>Integration of the ILSpy Decompiler into Visual Studio.</value>
</data>
<data name="400" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

12
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.

16
ILSpy.AddIn/packages.config

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="VSSDK.DTE" version="7.0.3" targetFramework="net45" />
<package id="VSSDK.IDE" version="7.0.3" targetFramework="net45" />
<package id="VSSDK.IDE.10" version="10.0.3" targetFramework="net45" />
<package id="VSSDK.IDE.8" version="8.0.3" targetFramework="net45" />
<package id="VSSDK.IDE.9" version="9.0.3" targetFramework="net45" />
<package id="VSSDK.OLE.Interop" version="7.0.3" targetFramework="net45" />
<package id="VSSDK.Shell.10" version="10.0.3" targetFramework="net45" />
<package id="VSSDK.Shell.Immutable.10" version="10.0.3" targetFramework="net45" />
<package id="VSSDK.Shell.Interop" version="7.0.3" targetFramework="net45" />
<package id="VSSDK.Shell.Interop.8" version="8.0.3" targetFramework="net45" />
<package id="VSSDK.Shell.Interop.9" version="9.0.3" targetFramework="net45" />
<package id="VSSDK.TextManager.Interop" version="7.0.3" targetFramework="net45" />
<package id="VSSDK.TextManager.Interop.8" version="8.0.3" targetFramework="net45" />
</packages>

32
ILSpy.AddIn/source.extension.vsixmanifest

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Vsix Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
<Identifier Id="a9120dbe-164a-4891-842f-fb7829273838">
<Name>ILSpy</Name>
<Author>IC#Code</Author>
<Version>1.2</Version>
<Description xml:space="preserve">Integrates the ILSpy decompiler into Visual Studio.</Description>
<Icon>ILSpy-Large.ico</Icon>
<License>license.txt</License>
<!--TODO: <PreviewImage>~200px image</PreviewImage>-->
<MoreInfoUrl>http://ilspy.net</MoreInfoUrl>
<Locale>1033</Locale>
<SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="6.0"/>
<SupportedProducts>
<VisualStudio Version="10.0">
<Edition>Pro</Edition>
</VisualStudio>
<VisualStudio Version="11.0">
<Edition>Pro</Edition>
</VisualStudio>
<VisualStudio Version="12.0">
<Edition>Pro</Edition>
</VisualStudio>
<VisualStudio Version="14.0">
<Edition>Pro</Edition>
</VisualStudio>
</SupportedProducts>
</Identifier>
<Content>
<VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
</Content>
</Vsix>

7
ILSpy.BamlDecompiler/CecilTypeResolver.cs

@ -39,12 +39,13 @@ namespace ILSpy.BamlDecompiler
public IType GetTypeByAssemblyQualifiedName(string name) 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) if (comma == -1)
throw new ArgumentException("invalid name"); 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(); string assemblyName = name.Substring(comma + 1).Trim();
var type = thisAssembly.MainModule.GetType(fullName); var type = thisAssembly.MainModule.GetType(fullName);

3
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) 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 = ""; assembly = "";
if (commaSeparator >= 0) { if (commaSeparator >= 0) {
assembly = assemblyQualifiedName.Substring(commaSeparator + 2); assembly = assemblyQualifiedName.Substring(commaSeparator + 2);

48
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs

@ -868,11 +868,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
switch (x) { switch (x) {
case 0x25a: case 0x25a:
// StaticExtension // StaticExtension
object resource = this.GetResourceName(valueIdentifier); value = this.GetStaticExtension(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));
break; break;
case 0x25b: // StaticResource case 0x25b: // StaticResource
case 0xbd: // DynamicResource case 0xbd: // DynamicResource
@ -883,7 +879,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
else if (isStaticType) else if (isStaticType)
{ {
TypeDeclaration extensionDeclaration = this.GetTypeDeclaration(extensionIdentifier); TypeDeclaration extensionDeclaration = this.GetTypeDeclaration(extensionIdentifier);
value = GetExtension(extensionDeclaration, GetStaticExtension(GetResourceName(valueIdentifier).ToString())); value = GetExtension(extensionDeclaration, GetStaticExtension(GetResourceName(valueIdentifier)));
} }
else else
{ {
@ -912,7 +908,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
short identifier = reader.ReadInt16(); short identifier = reader.ReadInt16();
string text = reader.ReadString(); string text = reader.ReadString();
EnqueueProperty(identifier, text); EnqueueProperty(identifier, EscapeCurlyBraces(text));
} }
void ReadPropertyWithConverter() void ReadPropertyWithConverter()
@ -921,7 +917,16 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
string text = reader.ReadString(); string text = reader.ReadString();
reader.ReadInt16(); 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() bool HaveSeenNestedElement()
@ -1316,7 +1321,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
{ {
reader.ReadInt16(); reader.ReadInt16();
// Non serve aprire niente, è il default // Non serve aprire niente, ?il default
} }
static void ReadConstructorParametersStart() static void ReadConstructorParametersStart()
@ -1449,15 +1454,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
if (isValueType) if (isValueType)
resource = GetTypeExtension(typeIdentifier); resource = GetTypeExtension(typeIdentifier);
else if (isStaticType) { else if (isStaticType) {
object name = GetResourceName(typeIdentifier); resource = GetStaticExtension(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());
} else { } else {
resource = this.stringTable[typeIdentifier]; resource = this.stringTable[typeIdentifier];
} }
@ -1473,8 +1470,18 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return String.Format("{{TemplateBinding {0}}}", FormatPropertyDeclaration(propertyDeclaration, true, false, false)); 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); string prefix = this.LookupPrefix(XmlPIMapping.XamlNamespace, false);
if (String.IsNullOrEmpty(prefix)) if (String.IsNullOrEmpty(prefix))
return String.Format("{{Static {0}}}", name); return String.Format("{{Static {0}}}", name);
@ -1588,7 +1595,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
string fullName = reader.ReadString(); string fullName = reader.ReadString();
assemblyId = (short)(assemblyId & 0xfff); assemblyId = (short)(assemblyId & 0xfff);
TypeDeclaration declaration; TypeDeclaration declaration;
int length = fullName.LastIndexOf('.'); int bracket = fullName.IndexOf('[');
int length = bracket > -1 ? fullName.LastIndexOf('.', bracket) : fullName.LastIndexOf('.');
if (length != -1) if (length != -1)
{ {
string name = fullName.Substring(length + 1); string name = fullName.Substring(length + 1);

2
ILSpy.BamlDecompiler/Tests/Cases/CustomControl.cs

@ -10,6 +10,8 @@ namespace ILSpy.BamlDecompiler.Tests.Cases
{ {
public class CustomControl : ContentControl public class CustomControl : ContentControl
{ {
public static string SimpleProperty = "Hi!";
public static readonly DependencyProperty CustomNameProperty = DependencyProperty.RegisterAttached("CustomName", typeof(string), typeof(CustomControl)); public static readonly DependencyProperty CustomNameProperty = DependencyProperty.RegisterAttached("CustomName", typeof(string), typeof(CustomControl));
public static string GetCustomName(DependencyObject target) public static string GetCustomName(DependencyObject target)

26
ILSpy.BamlDecompiler/Tests/Cases/EscapeSequence.xaml

@ -0,0 +1,26 @@
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<StackPanel>
<StackPanel.Resources>
<DataTemplate x:Key="key" DataType="{}{http://planetsNS}Planet">
<StackPanel Orientation="Horizontal">
<TextBlock Width="100" Text="{Binding Path=Element[{http://planetsNS}DiameterKM].Value}" />
<TextBlock Width="100" Text="{Binding Path=Attribute[Name].Value}" />
<TextBlock Text="{Binding Path=Element[{http://planetsNS}Details].Value}" />
<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, StringFormat=Date: {0:dddd, MMMM dd}}" />
<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, StringFormat=Time: {0:HH:mm}}" />
</StackPanel>
</DataTemplate>
</StackPanel.Resources>
<TextBlock Text="{Binding Path=ActualWidth, StringFormat=Window width: {0:#,#.0}}" />
<TextBlock Text="{Binding Path=ActualHeight, StringFormat=Window height: {0:C}}" />
<WrapPanel Margin="10">
<TextBlock Text="Width: " />
<TextBlock Text="{Binding ActualWidth, StringFormat={}{0:#,#.0}}" />
<StackPanel Margin="10">
<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, ConverterCulture=de-DE, StringFormat=German date: {0:D}}" />
<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, ConverterCulture=en-US, StringFormat=American date: {0:D}}" />
<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, ConverterCulture=ja-JP, StringFormat=Japanese date: {0:D}}" />
</StackPanel>
</WrapPanel>
</StackPanel>
</UserControl>

2
ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml

@ -3,6 +3,6 @@
<Style /> <Style />
</Label.Style> </Label.Style>
<Label.Content> <Label.Content>
<Binding Path="Blah" /> <Binding Path="Blah" StringFormat="{}{0} items" />
</Label.Content> </Label.Content>
</Label> </Label>

5
ILSpy.BamlDecompiler/Tests/Cases/NamespacePrefix.xaml

@ -1,12 +1,13 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:cc="clr-namespace:ILSpy.BamlDecompiler.Tests.Cases"> <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:cc="clr-namespace:ILSpy.BamlDecompiler.Tests.Cases">
<cc:CustomControl> <cc:CustomControl>
<cc:CustomControl.Style> <cc:CustomControl.Style>
<Style /> <Style />
</cc:CustomControl.Style> </cc:CustomControl.Style>
<Grid.Row>0</Grid.Row> <Grid.Row>0</Grid.Row>
<cc:CustomControl.Tag>{}{Test}</cc:CustomControl.Tag>
<cc:CustomControl.CustomName>Custom1</cc:CustomControl.CustomName> <cc:CustomControl.CustomName>Custom1</cc:CustomControl.CustomName>
</cc:CustomControl> </cc:CustomControl>
<Label> <Label ToolTip="{DynamicResource {x:Static cc:CustomControl.SimpleProperty}}">
<Label.Style> <Label.Style>
<Style /> <Style />
</Label.Style> </Label.Style>

5
ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -117,6 +117,7 @@
<Name>ILSpy.BamlDecompiler</Name> <Name>ILSpy.BamlDecompiler</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup />
<ItemGroup> <ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup> </ItemGroup>
@ -124,6 +125,10 @@
<Page Include="Cases\AttachedEvent.xaml" /> <Page Include="Cases\AttachedEvent.xaml" />
<Page Include="Cases\AvalonDockBrushes.xaml" /> <Page Include="Cases\AvalonDockBrushes.xaml" />
<Page Include="Cases\AvalonDockCommon.xaml" /> <Page Include="Cases\AvalonDockCommon.xaml" />
<Page Include="Cases\EscapeSequence.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Cases\MarkupExtension.xaml" /> <Page Include="Cases\MarkupExtension.xaml" />
<Page Include="Cases\MyControl.xaml" /> <Page Include="Cases\MyControl.xaml" />
<Page Include="Cases\NamespacePrefix.xaml" /> <Page Include="Cases\NamespacePrefix.xaml" />

6
ILSpy.BamlDecompiler/Tests/TestRunner.cs

@ -91,6 +91,12 @@ namespace ILSpy.BamlDecompiler.Tests
{ {
RunTest("cases/namespaceprefix"); RunTest("cases/namespaceprefix");
} }
[Test]
public void EscapeSequence()
{
RunTest("cases/escapesequence");
}
#region RunTest #region RunTest
void RunTest(string name) void RunTest(string name)

20
ILSpy.sln

@ -2,7 +2,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012 # Visual Studio 2012
# SharpDevelop 5.1 # SharpDevelop 5.1
VisualStudioVersion = 14.0.21730.1 VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
@ -34,7 +34,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSha
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.Cecil", "NRefactory\ICSharpCode.NRefactory.Cecil\ICSharpCode.NRefactory.Cecil.csproj", "{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.Cecil", "NRefactory\ICSharpCode.NRefactory.Cecil\ICSharpCode.NRefactory.Cecil.csproj", "{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}"
EndProject 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 ProjectSection(SolutionItems) = preProject
Rebracer.xml = Rebracer.xml Rebracer.xml = Rebracer.xml
EndProjectSection 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.ActiveCfg = Release|Any CPU
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|Any CPU.Build.0 = 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 {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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

1
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("SharpDevelop", "http://www.icsharpcode.net/opensource/sd/"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt")); output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("LGPL", "resource:LGPL.txt")); output.AddVisualLineElementGenerator(new MyLinkElementGenerator("LGPL", "resource:LGPL.txt"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MS-PL", "resource:MS-PL.txt"));
textView.ShowText(output); textView.ShowText(output);
} }

44
ILSpy/AssemblyList.cs

@ -88,7 +88,7 @@ namespace ICSharpCode.ILSpy
return new XElement( return new XElement(
"List", "List",
new XAttribute("name", this.ListName), 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() internal void ClearCache()
{ {
@ -128,7 +143,7 @@ namespace ICSharpCode.ILSpy
/// Opens an assembly from disk. /// Opens an assembly from disk.
/// Returns the existing assembly node if it is already loaded. /// Returns the existing assembly node if it is already loaded.
/// </summary> /// </summary>
public LoadedAssembly OpenAssembly(string file) public LoadedAssembly OpenAssembly(string file, bool isAutoLoaded=false)
{ {
App.Current.Dispatcher.VerifyAccess(); App.Current.Dispatcher.VerifyAccess();
@ -140,11 +155,36 @@ namespace ICSharpCode.ILSpy
} }
var newAsm = new LoadedAssembly(this, file); var newAsm = new LoadedAssembly(this, file);
newAsm.IsAutoLoaded = isAutoLoaded;
lock (assemblies) { lock (assemblies) {
this.assemblies.Add(newAsm); this.assemblies.Add(newAsm);
} }
return newAsm; return newAsm;
} }
/// <summary>
/// Replace the assembly object model from a crafted stream, without disk I/O
/// Returns null if it is not already loaded.
/// </summary>
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) public void Unload(LoadedAssembly assembly)
{ {

14
ILSpy/CommandLineArguments.cs

@ -27,8 +27,11 @@ namespace ICSharpCode.ILSpy
public List<string> AssembliesToLoad = new List<string>(); public List<string> AssembliesToLoad = new List<string>();
public bool? SingleInstance; public bool? SingleInstance;
public string NavigateTo; public string NavigateTo;
public string Search;
public string Language; public string Language;
public bool NoActivate; public bool NoActivate;
public Guid? FixedGuid;
public string SaveDirectory;
public CommandLineArguments(IEnumerable<string> arguments) public CommandLineArguments(IEnumerable<string> arguments)
{ {
@ -42,10 +45,21 @@ namespace ICSharpCode.ILSpy
this.SingleInstance = false; this.SingleInstance = false;
else if (arg.StartsWith("/navigateTo:", StringComparison.OrdinalIgnoreCase)) else if (arg.StartsWith("/navigateTo:", StringComparison.OrdinalIgnoreCase))
this.NavigateTo = arg.Substring("/navigateTo:".Length); 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)) else if (arg.StartsWith("/language:", StringComparison.OrdinalIgnoreCase))
this.Language = arg.Substring("/language:".Length); this.Language = arg.Substring("/language:".Length);
else if (arg.Equals("/noActivate", StringComparison.OrdinalIgnoreCase)) else if (arg.Equals("/noActivate", StringComparison.OrdinalIgnoreCase))
this.NoActivate = true; 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 { } else {
this.AssembliesToLoad.Add(arg); this.AssembliesToLoad.Add(arg);
} }

41
ILSpy/ContextMenuEntry.cs

@ -55,6 +55,12 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public DecompilerTextView TextView { get; private set; } public DecompilerTextView TextView { get; private set; }
/// <summary>
/// Returns the list box the context menu is assigned to.
/// Returns null, if context menu is not assigned to a list box.
/// </summary>
public ListBox ListBox { get; private set; }
/// <summary> /// <summary>
/// Returns the reference the mouse cursor is currently hovering above. /// Returns the reference the mouse cursor is currently hovering above.
/// Returns null, if there was no reference found. /// Returns null, if there was no reference found.
@ -67,9 +73,15 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public TextViewPosition? Position { get; private set; } 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 position = textView != null ? textView.GetPositionFromMousePosition() : null;
var selectedTreeNodes = treeView != null ? treeView.GetTopLevelSelection().ToArray() : null; var selectedTreeNodes = treeView != null ? treeView.GetTopLevelSelection().ToArray() : null;
return new TextViewContext { 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 SharpTreeView treeView;
readonly DecompilerTextView textView; readonly DecompilerTextView textView;
readonly ListBox listBox;
[ImportMany(typeof(IContextMenuEntry))] [ImportMany(typeof(IContextMenuEntry))]
Lazy<IContextMenuEntry, IContextMenuEntryMetadata>[] entries = null; Lazy<IContextMenuEntry, IContextMenuEntryMetadata>[] entries = null;
@ -139,6 +159,12 @@ namespace ICSharpCode.ILSpy
App.CompositionContainer.ComposeParts(this); App.CompositionContainer.ComposeParts(this);
} }
ContextMenuProvider(ListBox listBox)
{
this.listBox = listBox;
App.CompositionContainer.ComposeParts(this);
}
void treeView_ContextMenuOpening(object sender, ContextMenuEventArgs e) void treeView_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{ {
TextViewContext context = TextViewContext.Create(treeView); TextViewContext context = TextViewContext.Create(treeView);
@ -165,6 +191,17 @@ namespace ICSharpCode.ILSpy
e.Handled = true; 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) bool ShowContextMenu(TextViewContext context, out ContextMenu menu)
{ {
menu = new ContextMenu(); menu = new ContextMenu();

28
ILSpy/Controls/ResourceObjectTable.xaml.cs

@ -30,24 +30,32 @@ namespace ICSharpCode.ILSpy.Controls
/// </summary> /// </summary>
public partial class ResourceObjectTable : UserControl public partial class ResourceObjectTable : UserControl
{ {
public ResourceObjectTable(IEnumerable resources,Size maxSize) public ResourceObjectTable(IEnumerable resources, ContentPresenter contentPresenter)
{ {
InitializeComponent(); InitializeComponent();
// set size to fit decompiler window // set size to fit decompiler window
// TODO: there should be a more transparent way to do this contentPresenter.SizeChanged += OnParentSizeChanged;
Width = maxSize.Width; Width = contentPresenter.ActualWidth - 45;
MaxHeight = maxSize.Height; MaxHeight = contentPresenter.ActualHeight;
resourceListView.ItemsSource = resources; 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) void ExecuteCopy(object sender, ExecutedRoutedEventArgs args)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
foreach (var item in resourceListView.SelectedItems) foreach (var item in resourceListView.SelectedItems)
{ {
sb.AppendLine(item.ToString()); sb.AppendLine(item.ToString());
} }
Clipboard.SetText(sb.ToString()); Clipboard.SetText(sb.ToString());
} }
void CanExecuteCopy(object sender, CanExecuteRoutedEventArgs args) void CanExecuteCopy(object sender, CanExecuteRoutedEventArgs args)

28
ILSpy/Controls/ResourceStringTable.xaml.cs

@ -30,24 +30,32 @@ namespace ICSharpCode.ILSpy.Controls
/// </summary> /// </summary>
public partial class ResourceStringTable : UserControl public partial class ResourceStringTable : UserControl
{ {
public ResourceStringTable(IEnumerable strings,Size maxSize) public ResourceStringTable(IEnumerable strings, ContentPresenter contentPresenter)
{ {
InitializeComponent(); InitializeComponent();
// set size to fit decompiler window // set size to fit decompiler window
// TODO: there should be a more transparent way to do this contentPresenter.SizeChanged += OnParentSizeChanged;
Width = maxSize.Width; Width = contentPresenter.ActualWidth - 45;
MaxHeight = maxSize.Height; MaxHeight = contentPresenter.ActualHeight;
resourceListView.ItemsSource = strings; 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) void ExecuteCopy(object sender, ExecutedRoutedEventArgs args)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
foreach (var item in resourceListView.SelectedItems) foreach (var item in resourceListView.SelectedItems)
{ {
sb.AppendLine(item.ToString()); sb.AppendLine(item.ToString());
} }
Clipboard.SetText(sb.ToString()); Clipboard.SetText(sb.ToString());
} }
void CanExecuteCopy(object sender, CanExecuteRoutedEventArgs args) void CanExecuteCopy(object sender, CanExecuteRoutedEventArgs args)

7
ILSpy/ILSpy.csproj

@ -199,7 +199,9 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Commands\SimpleCommand.cs" /> <Compile Include="Commands\SimpleCommand.cs" />
<Compile Include="SearchStrategies.cs" />
<Compile Include="TaskHelper.cs" /> <Compile Include="TaskHelper.cs" />
<Compile Include="TextView\EditorCommands.cs" />
<Compile Include="TextView\FoldingCommands.cs" /> <Compile Include="TextView\FoldingCommands.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedAssemblyTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedAssemblyTreeNode.cs" />
@ -216,6 +218,7 @@
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedVirtualMethodUsedByTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedVirtualMethodUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerEntityTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzerEntityTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerSearchTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzerSearchTreeNode.cs" />
@ -228,6 +231,7 @@
<Compile Include="TreeNodes\IMemberTreeNode.cs" /> <Compile Include="TreeNodes\IMemberTreeNode.cs" />
<Compile Include="TreeNodes\ResourceNodes\CursorResourceEntryNode.cs" /> <Compile Include="TreeNodes\ResourceNodes\CursorResourceEntryNode.cs" />
<Compile Include="TreeNodes\ResourceNodes\IconResourceEntryNode.cs" /> <Compile Include="TreeNodes\ResourceNodes\IconResourceEntryNode.cs" />
<Compile Include="TreeNodes\ResourceNodes\ImageListResourceEntryNode.cs" />
<Compile Include="TreeNodes\ResourceNodes\ImageResourceEntryNode.cs" /> <Compile Include="TreeNodes\ResourceNodes\ImageResourceEntryNode.cs" />
<Compile Include="TreeNodes\ResourceNodes\XmlResourceNode.cs" /> <Compile Include="TreeNodes\ResourceNodes\XmlResourceNode.cs" />
<Compile Include="TreeNodes\ResourceNodes\IResourceNodeFactory.cs" /> <Compile Include="TreeNodes\ResourceNodes\IResourceNodeFactory.cs" />
@ -249,6 +253,9 @@
<EmbeddedResource Include="..\doc\license.txt"> <EmbeddedResource Include="..\doc\license.txt">
<Link>license.txt</Link> <Link>license.txt</Link>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="..\doc\MS-PL.txt">
<Link>MS-PL.txt</Link>
</EmbeddedResource>
<Resource Include="Images\AssemblyList.png" /> <Resource Include="Images\AssemblyList.png" />
<Resource Include="Images\AssemblyListGAC.png" /> <Resource Include="Images\AssemblyListGAC.png" />
<Resource Include="Images\AssemblyWarning.png" /> <Resource Include="Images\AssemblyWarning.png" />

48
ILSpy/Languages/CSharpLanguage.cs

@ -225,7 +225,14 @@ namespace ICSharpCode.ILSpy
additionalTransform.Run(astBuilder.SyntaxTree); additionalTransform.Run(astBuilder.SyntaxTree);
} }
if (options.DecompilerSettings.ShowXmlDocumentation) { 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); astBuilder.GenerateCode(output);
}*/ }*/
@ -267,6 +274,21 @@ namespace ICSharpCode.ILSpy
return module.Architecture.ToString(); 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) public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{ {
@ -279,6 +301,11 @@ namespace ICSharpCode.ILSpy
base.DecompileAssembly(assembly, output, options); base.DecompileAssembly(assembly, output, options);
output.WriteLine(); output.WriteLine();
ModuleDefinition mainModule = assembly.ModuleDefinition; 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) { if (mainModule.EntryPoint != null) {
output.Write("// Entry point: "); output.Write("// Entry point: ");
output.WriteReference(mainModule.EntryPoint.DeclaringType.FullName + "." + mainModule.EntryPoint.Name, mainModule.EntryPoint); output.WriteReference(mainModule.EntryPoint.DeclaringType.FullName + "." + mainModule.EntryPoint.Name, mainModule.EntryPoint);
@ -288,19 +315,9 @@ namespace ICSharpCode.ILSpy
if ((mainModule.Attributes & ModuleAttributes.ILOnly) == 0) { if ((mainModule.Attributes & ModuleAttributes.ILOnly) == 0) {
output.WriteLine("// This assembly contains unmanaged code."); output.WriteLine("// This assembly contains unmanaged code.");
} }
switch (mainModule.Runtime) { string runtimeName = GetRuntimeDisplayName(mainModule);
case TargetRuntime.Net_1_0: if (runtimeName != null) {
output.WriteLine("// Runtime: .NET 1.0"); output.WriteLine("// Runtime: " + runtimeName);
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;
} }
output.WriteLine(); output.WriteLine();
@ -319,6 +336,7 @@ namespace ICSharpCode.ILSpy
{ {
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003"; const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = GetPlatformName(module); string platformName = GetPlatformName(module);
Guid guid = App.CommandLineArguments.FixedGuid ?? Guid.NewGuid();
using (XmlTextWriter w = new XmlTextWriter(writer)) { using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented; w.Formatting = Formatting.Indented;
w.WriteStartDocument(); w.WriteStartDocument();
@ -327,7 +345,7 @@ namespace ICSharpCode.ILSpy
w.WriteAttributeString("DefaultTargets", "Build"); w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup"); w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString("B").ToUpperInvariant()); w.WriteElementString("ProjectGuid", guid.ToString("B").ToUpperInvariant());
w.WriteStartElement("Configuration"); w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' "); w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");

42
ILSpy/LoadedAssembly.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy
readonly string fileName; readonly string fileName;
readonly string shortName; readonly string shortName;
public LoadedAssembly(AssemblyList assemblyList, string fileName) public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null)
{ {
if (assemblyList == null) if (assemblyList == null)
throw new ArgumentNullException("assemblyList"); throw new ArgumentNullException("assemblyList");
@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy
this.assemblyList = assemblyList; this.assemblyList = assemblyList;
this.fileName = fileName; this.fileName = fileName;
this.assemblyTask = Task.Factory.StartNew<ModuleDefinition>(LoadAssembly); // requires that this.fileName is set this.assemblyTask = Task.Factory.StartNew<ModuleDefinition>(LoadAssembly, stream); // requires that this.fileName is set
this.shortName = Path.GetFileNameWithoutExtension(fileName); this.shortName = Path.GetFileNameWithoutExtension(fileName);
} }
@ -84,6 +84,16 @@ namespace ICSharpCode.ILSpy
public string ShortName { public string ShortName {
get { return 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 { public bool IsLoaded {
get { return assemblyTask.IsCompleted; } get { return assemblyTask.IsCompleted; }
@ -92,13 +102,29 @@ namespace ICSharpCode.ILSpy
public bool HasLoadError { public bool HasLoadError {
get { return assemblyTask.IsFaulted; } 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 // runs on background thread
ReaderParameters p = new ReaderParameters(); ReaderParameters p = new ReaderParameters();
p.AssemblyResolver = new MyAssemblyResolver(this); 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) { if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) {
try { try {
LoadSymbols(module); LoadSymbols(module);
@ -228,7 +254,8 @@ namespace ICSharpCode.ILSpy
file = Path.Combine(dir, name.Name + ".exe"); file = Path.Combine(dir, name.Name + ".exe");
} }
if (file != null) { if (file != null) {
return assemblyList.OpenAssembly(file); var loaded = assemblyList.OpenAssembly(file, true);
return loaded;
} else { } else {
return null; return null;
} }
@ -249,7 +276,7 @@ namespace ICSharpCode.ILSpy
string file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name + ".winmd"); string file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name + ".winmd");
if (File.Exists(file)) { if (File.Exists(file)) {
return assemblyList.OpenAssembly(file); return assemblyList.OpenAssembly(file, true);
} else { } else {
return null; return null;
} }
@ -268,5 +295,6 @@ namespace ICSharpCode.ILSpy
{ {
assemblyTask.Wait(); assemblyTask.Wait();
} }
} }
} }

3
ILSpy/MainWindow.xaml

@ -125,6 +125,7 @@
BorderThickness="5,0" BorderThickness="5,0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Focusable="False"
BorderBrush="Transparent" /> BorderBrush="Transparent" />
<!-- Right pane: Text Editor --> <!-- Right pane: Text Editor -->
<Grid Grid.Column="2"> <Grid Grid.Column="2">
@ -162,6 +163,7 @@
BorderBrush="Transparent" BorderBrush="Transparent"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center" VerticalAlignment="Center"
Focusable="False"
Visibility="{Binding Visibility, ElementName=topPane}" /> Visibility="{Binding Visibility, ElementName=topPane}" />
<!-- decompilerTextView is into the mainPane by code --> <!-- decompilerTextView is into the mainPane by code -->
@ -175,6 +177,7 @@
BorderBrush="Transparent" BorderBrush="Transparent"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center" VerticalAlignment="Center"
Focusable="False"
Visibility="{Binding Visibility, ElementName=bottomPane}" /> Visibility="{Binding Visibility, ElementName=bottomPane}" />
<controls:DockedPane x:Name="bottomPane" Grid.Row="5" Title="Bottom" Visibility="Collapsed" <controls:DockedPane x:Name="bottomPane" Grid.Row="5" Title="Bottom" Visibility="Collapsed"

87
ILSpy/MainWindow.xaml.cs

@ -295,9 +295,38 @@ namespace ICSharpCode.ILSpy
// Select the newly loaded assembly // Select the newly loaded assembly
JumpToReference(commandLineLoadedAssemblies[0].ModuleDefinition); JumpToReference(commandLineLoadedAssemblies[0].ModuleDefinition);
} }
if (args.Search != null)
{
SearchPane.Instance.SearchTerm = args.Search;
SearchPane.Instance.Show();
}
if (!string.IsNullOrEmpty(args.SaveDirectory)) {
foreach (var x in commandLineLoadedAssemblies) {
x.ContinueWhenLoaded( (Task<ModuleDefinition> moduleTask) => {
OnExportAssembly(moduleTask, args.SaveDirectory);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
} }
void OnExportAssembly(Task<ModuleDefinition> 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) void MainWindow_Loaded(object sender, RoutedEventArgs e)
{ {
ILSpySettings spySettings = this.spySettings; ILSpySettings spySettings = this.spySettings;
@ -319,7 +348,14 @@ namespace ICSharpCode.ILSpy
HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments); HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments);
if (App.CommandLineArguments.NavigateTo == null && App.CommandLineArguments.AssembliesToLoad.Count != 1) { 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) { if (node != null) {
SelectNode(node); SelectNode(node);
@ -330,8 +366,6 @@ namespace ICSharpCode.ILSpy
} }
} }
NavigationCommands.Search.InputGestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
if (FormatExceptions(App.StartupExceptions.ToArray(), output)) if (FormatExceptions(App.StartupExceptions.ToArray(), output))
decompilerTextView.ShowText(output); decompilerTextView.ShowText(output);
@ -458,7 +492,7 @@ namespace ICSharpCode.ILSpy
{ {
RefreshTreeViewFilter(); RefreshTreeViewFilter();
if (e.PropertyName == "Language") { if (e.PropertyName == "Language") {
DecompileSelectedNodes(); DecompileSelectedNodes(recordHistory: false);
} }
} }
@ -476,7 +510,8 @@ namespace ICSharpCode.ILSpy
} }
#region Node Selection #region Node Selection
internal void SelectNode(SharpTreeNode obj)
public void SelectNode(SharpTreeNode obj)
{ {
if (obj != null) { if (obj != null) {
if (!obj.AncestorsAndSelf().Any(node => node.IsHidden)) { if (!obj.AncestorsAndSelf().Any(node => node.IsHidden)) {
@ -495,7 +530,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Retrieves a node using the .ToString() representations of its ancestors. /// Retrieves a node using the .ToString() representations of its ancestors.
/// </summary> /// </summary>
SharpTreeNode FindNodeByPath(string[] path, bool returnBestMatch) public SharpTreeNode FindNodeByPath(string[] path, bool returnBestMatch)
{ {
if (path == null) if (path == null)
return null; return null;
@ -517,7 +552,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Gets the .ToString() representation of the node's ancestors. /// Gets the .ToString() representation of the node's ancestors.
/// </summary> /// </summary>
string[] GetPathForNode(SharpTreeNode node) public string[] GetPathForNode(SharpTreeNode node)
{ {
if (node == null) if (node == null)
return null; return null;
@ -634,6 +669,9 @@ namespace ICSharpCode.ILSpy
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e) void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
DecompileSelectedNodes(); DecompileSelectedNodes();
if (SelectionChanged != null)
SelectionChanged(sender, e);
} }
Task decompilationTask; Task decompilationTask;
@ -684,7 +722,9 @@ namespace ICSharpCode.ILSpy
return sessionSettings.FilterSettings.Language; return sessionSettings.FilterSettings.Language;
} }
} }
public event SelectionChangedEventHandler SelectionChanged;
public IEnumerable<ILSpyTreeNode> SelectedNodes { public IEnumerable<ILSpyTreeNode> SelectedNodes {
get { get {
return treeView.GetTopLevelSelection().OfType<ILSpyTreeNode>(); return treeView.GetTopLevelSelection().OfType<ILSpyTreeNode>();
@ -755,6 +795,7 @@ namespace ICSharpCode.ILSpy
base.OnClosing(e); base.OnClosing(e);
sessionSettings.ActiveAssemblyList = assemblyList.ListName; sessionSettings.ActiveAssemblyList = assemblyList.ListName;
sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode); sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(treeView.SelectedItem as SharpTreeNode);
sessionSettings.WindowBounds = this.RestoreBounds; sessionSettings.WindowBounds = this.RestoreBounds;
sessionSettings.SplitterPosition = leftColumn.Width.Value / (leftColumn.Width.Value + rightColumn.Width.Value); sessionSettings.SplitterPosition = leftColumn.Width.Value / (leftColumn.Width.Value + rightColumn.Width.Value);
if (topPane.Visibility == Visibility.Visible) if (topPane.Visibility == Visibility.Visible)
@ -763,6 +804,22 @@ namespace ICSharpCode.ILSpy
sessionSettings.BottomPaneSplitterPosition = bottomPaneRow.Height.Value / (bottomPaneRow.Height.Value + textViewRow.Height.Value); sessionSettings.BottomPaneSplitterPosition = bottomPaneRow.Height.Value / (bottomPaneRow.Height.Value + textViewRow.Height.Value);
sessionSettings.Save(); 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 #region Top/Bottom Pane management
public void ShowInTopPane(string title, object content) public void ShowInTopPane(string title, object content)
@ -773,7 +830,12 @@ namespace ICSharpCode.ILSpy
topPaneRow.Height = new GridLength(sessionSettings.TopPaneSplitterPosition, GridUnitType.Star); topPaneRow.Height = new GridLength(sessionSettings.TopPaneSplitterPosition, GridUnitType.Star);
} }
topPane.Title = title; 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; topPane.Visibility = Visibility.Visible;
} }
@ -798,7 +860,12 @@ namespace ICSharpCode.ILSpy
bottomPaneRow.Height = new GridLength(sessionSettings.BottomPaneSplitterPosition, GridUnitType.Star); bottomPaneRow.Height = new GridLength(sessionSettings.BottomPaneSplitterPosition, GridUnitType.Star);
} }
bottomPane.Title = title; 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; bottomPane.Visibility = Visibility.Visible;
} }

1
ILSpy/Options/DecompilerSettingsPanel.xaml

@ -7,6 +7,7 @@
<CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox> <CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox>
<CheckBox IsChecked="{Binding AsyncAwait}">Decompile async methods (async/await)</CheckBox> <CheckBox IsChecked="{Binding AsyncAwait}">Decompile async methods (async/await)</CheckBox>
<CheckBox IsChecked="{Binding QueryExpressions}" IsEnabled="{Binding AnonymousMethods}">Decompile query expressions</CheckBox> <CheckBox IsChecked="{Binding QueryExpressions}" IsEnabled="{Binding AnonymousMethods}">Decompile query expressions</CheckBox>
<CheckBox IsChecked="{Binding ExpressionTrees}">Decompile expression trees</CheckBox>
<CheckBox IsChecked="{Binding UseDebugSymbols}">Use variable names from debug symbols, if available</CheckBox> <CheckBox IsChecked="{Binding UseDebugSymbols}">Use variable names from debug symbols, if available</CheckBox>
<CheckBox IsChecked="{Binding ShowXmlDocumentation}">Show XML documentation in decompiled code</CheckBox> <CheckBox IsChecked="{Binding ShowXmlDocumentation}">Show XML documentation in decompiled code</CheckBox>
<CheckBox IsChecked="{Binding FoldBraces}">Enable folding on all blocks in braces</CheckBox> <CheckBox IsChecked="{Binding FoldBraces}">Enable folding on all blocks in braces</CheckBox>

2
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.ILSpy.Options
s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn; s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn;
s.AsyncAwait = (bool?)e.Attribute("asyncAwait") ?? s.AsyncAwait; s.AsyncAwait = (bool?)e.Attribute("asyncAwait") ?? s.AsyncAwait;
s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions; 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.UseDebugSymbols = (bool?)e.Attribute("useDebugSymbols") ?? s.UseDebugSymbols;
s.ShowXmlDocumentation = (bool?)e.Attribute("xmlDoc") ?? s.ShowXmlDocumentation; s.ShowXmlDocumentation = (bool?)e.Attribute("xmlDoc") ?? s.ShowXmlDocumentation;
s.FoldBraces = (bool?)e.Attribute("foldBraces") ?? s.FoldBraces; s.FoldBraces = (bool?)e.Attribute("foldBraces") ?? s.FoldBraces;
@ -69,6 +70,7 @@ namespace ICSharpCode.ILSpy.Options
section.SetAttributeValue("yieldReturn", s.YieldReturn); section.SetAttributeValue("yieldReturn", s.YieldReturn);
section.SetAttributeValue("asyncAwait", s.AsyncAwait); section.SetAttributeValue("asyncAwait", s.AsyncAwait);
section.SetAttributeValue("queryExpressions", s.QueryExpressions); section.SetAttributeValue("queryExpressions", s.QueryExpressions);
section.SetAttributeValue("expressionTrees", s.ExpressionTrees);
section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols); section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols);
section.SetAttributeValue("xmlDoc", s.ShowXmlDocumentation); section.SetAttributeValue("xmlDoc", s.ShowXmlDocumentation);
section.SetAttributeValue("foldBraces", s.FoldBraces); section.SetAttributeValue("foldBraces", s.FoldBraces);

5
ILSpy/Properties/AssemblyInfo.template.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Resources; using System.Resources;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#endregion #endregion
@ -14,7 +15,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription(".NET assembly inspector and decompiler")] [assembly: AssemblyDescription(".NET assembly inspector and decompiler")]
[assembly: AssemblyCompany("ic#code")] [assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")] [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: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@ -29,6 +30,8 @@ using System.Runtime.InteropServices;
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly", [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly",
Justification = "AssemblyInformationalVersion does not need to be a parsable version")] Justification = "AssemblyInformationalVersion does not need to be a parsable version")]
[assembly: InternalsVisibleTo("ILSpy.AddIn, PublicKey=0024000004800000940000000602000000240000525341310004000001000100653c4a319be4f524972c3c5bba5fd243330f8e900287d9022d7821a63fd0086fd3801e3683dbe9897f2ecc44727023e9b40adcf180730af70c81c54476b3e5ba8b0f07f5132b2c3cc54347a2c1a9d64ebaaaf3cbffc1a18c427981e2a51d53d5ab02536b7550e732f795121c38a0abfdb38596353525d034baf9e6f1fd8ac4ac")]
internal static class RevisionClass internal static class RevisionClass
{ {
public const string Major = "3"; public const string Major = "3";

356
ILSpy/SearchPane.cs

@ -17,10 +17,12 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.Linq;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; 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() private SearchPane()
{ {
InitializeComponent(); InitializeComponent();
searchModeComboBox.Items.Add(new { Image = Images.Class, Name = "Type" }); searchModeComboBox.Items.Add(new { Image = Images.Class, Name = "Type" });
searchModeComboBox.Items.Add(new { Image = Images.Property, Name = "Member" }); searchModeComboBox.Items.Add(new { Image = Images.Property, Name = "Member" });
searchModeComboBox.Items.Add(new { Image = Images.Literal, Name = "Constant" }); 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; MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged;
} }
@ -127,7 +126,7 @@ namespace ICSharpCode.ILSpy
listBox.ItemsSource = null; listBox.ItemsSource = null;
} else { } else {
MainWindow mainWindow = MainWindow.Instance; 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; listBox.ItemsSource = currentSearch.Results;
new Thread(currentSearch.Run).Start(); new Thread(currentSearch.Run).Start();
} }
@ -164,13 +163,13 @@ namespace ICSharpCode.ILSpy
{ {
base.OnKeyDown(e); base.OnKeyDown(e);
if (e.Key == Key.T && e.KeyboardDevice.Modifiers == ModifierKeys.Control) { if (e.Key == Key.T && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
searchModeComboBox.SelectedIndex = SearchMode_Type; searchModeComboBox.SelectedIndex = (int)SearchMode.Type;
e.Handled = true; e.Handled = true;
} else if (e.Key == Key.M && e.KeyboardDevice.Modifiers == ModifierKeys.Control) { } else if (e.Key == Key.M && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
searchModeComboBox.SelectedIndex = SearchMode_Member; searchModeComboBox.SelectedIndex = (int)SearchMode.Member;
e.Handled = true; e.Handled = true;
} else if (e.Key == Key.S && e.KeyboardDevice.Modifiers == ModifierKeys.Control) { } else if (e.Key == Key.S && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
searchModeComboBox.SelectedIndex = SearchMode_Literal; searchModeComboBox.SelectedIndex = (int)SearchMode.Literal;
e.Handled = true; e.Handled = true;
} }
} }
@ -183,22 +182,19 @@ namespace ICSharpCode.ILSpy
listBox.SelectedIndex = 0; listBox.SelectedIndex = 0;
} }
} }
sealed class RunningSearch sealed class RunningSearch
{ {
readonly Dispatcher dispatcher; readonly Dispatcher dispatcher;
readonly CancellationTokenSource cts = new CancellationTokenSource(); readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly LoadedAssembly[] assemblies; readonly LoadedAssembly[] assemblies;
readonly string[] searchTerm; readonly string[] searchTerm;
readonly int searchMode; readonly SearchMode searchMode;
readonly Language language; readonly Language language;
public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>(); public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>();
int resultCount; int resultCount;
TypeCode searchTermLiteralType = TypeCode.Empty; public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, SearchMode searchMode, Language language)
object searchTermLiteralValue;
public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, int searchMode, Language language)
{ {
this.dispatcher = Dispatcher.CurrentDispatcher; this.dispatcher = Dispatcher.CurrentDispatcher;
this.assemblies = assemblies; this.assemblies = assemblies;
@ -217,44 +213,16 @@ namespace ICSharpCode.ILSpy
public void Run() public void Run()
{ {
try { try {
if (searchMode == SearchMode_Literal) { var searcher = GetSearchStrategy(searchMode, searchTerm);
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;
}
}
}
}
foreach (var loadedAssembly in assemblies) { foreach (var loadedAssembly in assemblies) {
ModuleDefinition module = loadedAssembly.ModuleDefinition; ModuleDefinition module = loadedAssembly.ModuleDefinition;
if (module == null) if (module == null)
continue; continue;
CancellationToken cancellationToken = cts.Token; CancellationToken cancellationToken = cts.Token;
foreach (TypeDefinition type in module.Types) { foreach (TypeDefinition type in module.Types) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
PerformSearch(type); searcher.Search(type, language, AddResult);
} }
} }
} catch (OperationCanceledException) { } catch (OperationCanceledException) {
@ -277,265 +245,71 @@ namespace ICSharpCode.ILSpy
new Action(delegate { this.Results.Insert(this.Results.Count - 1, result); })); new Action(delegate { this.Results.Insert(this.Results.Count - 1, result); }));
cts.Token.ThrowIfCancellationRequested(); cts.Token.ThrowIfCancellationRequested();
} }
bool IsMatch(string text) AbstractSearchStrategy GetSearchStrategy(SearchMode mode, string[] terms)
{
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)
{ {
if (val == null) if (terms.Length == 1) {
return false; if (terms[0].StartsWith("t:"))
switch (searchTermLiteralType) { return new TypeSearchStrategy(terms[0].Substring(2));
case TypeCode.Int64:
TypeCode tc = Type.GetTypeCode(val.GetType()); if (terms[0].StartsWith("m:"))
if (tc >= TypeCode.SByte && tc <= TypeCode.UInt64) return new MemberSearchStrategy(terms[0].Substring(2));
return CSharpPrimitiveCast.Cast(TypeCode.Int64, val, false).Equals(searchTermLiteralValue);
else if (terms[0].StartsWith("c:"))
return false; return new LiteralSearchStrategy(terms[0].Substring(2));
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.String:
return searchTermLiteralValue.Equals(val);
default:
// substring search with searchTerm
return IsMatch(val.ToString());
} }
}
switch (mode) {
bool MethodIsLiteralMatch(MethodDefinition m) case SearchMode.Type:
{ return new TypeSearchStrategy(terms);
if (m == null) case SearchMode.Member:
return false; return new MemberSearchStrategy(terms);
var body = m.Body; case SearchMode.Literal:
if (body == null) return new LiteralSearchStrategy(terms);
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;
return null;
} }
} }
}
sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
{ sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { {
add { } event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
remove { } add { }
} remove { }
}
public MemberReference Member { get; set; } public MemberReference Member { get; set; }
public string Location { get; set; } public string Location { get; set; }
public string Name { get; set; } public string Name { get; set; }
public ImageSource Image { get; set; } public ImageSource Image { get; set; }
public ImageSource LocationImage { get; set; } public ImageSource LocationImage { get; set; }
public override string ToString() public override string ToString()
{ {
return Name; return Name;
}
} }
} }
[ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon="Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)] [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)] [ExportToolbarCommand(ToolTip = "Search (Ctrl+Shift+F or Ctrl+E)", ToolbarIcon = "Images/Find.png", ToolbarCategory = "View", ToolbarOrder = 100)]
sealed class ShowSearchCommand : CommandWrapper sealed class ShowSearchCommand : CommandWrapper
{ {
public ShowSearchCommand() public ShowSearchCommand()
: base(NavigationCommands.Search) : 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
}
} }

2
ILSpy/SearchPane.xaml

@ -17,7 +17,7 @@
<controls:SearchBox x:Name="searchBox" DockPanel.Dock="Top" Grid.Column="0" Grid.Row="0" Margin="1" <controls:SearchBox x:Name="searchBox" DockPanel.Dock="Top" Grid.Column="0" Grid.Row="0" Margin="1"
PreviewKeyDown="SearchBox_PreviewKeyDown" PreviewKeyDown="SearchBox_PreviewKeyDown"
Text="{Binding SearchTerm, ElementName=self}" ToolTip="Search" UpdateDelay="0:0:0.1" Text="{Binding SearchTerm, ElementName=self}" ToolTip="Search" UpdateDelay="0:0:0.1"
WatermarkColor="Gray" WatermarkText="Search" /> WatermarkColor="Gray" WatermarkText="Search for t:TypeName, m:Member or c:Constant; use /reg(ular)?Ex(pressions)?/ or both - t:/Type(Name)?/..." />
<StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal"> <StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal">
<Label Margin="0,-1">Search _for:</Label> <Label Margin="0,-1">Search _for:</Label>
<ComboBox Width="100" Name="searchModeComboBox" Margin="1" <ComboBox Width="100" Name="searchModeComboBox" Margin="1"

335
ILSpy/SearchStrategies.cs

@ -0,0 +1,335 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Media;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy
{
abstract class AbstractSearchStrategy
{
protected string[] searchTerm;
protected Regex regex;
protected AbstractSearchStrategy(params string[] terms)
{
if (terms.Length == 1 && terms[0].Length > 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<T>(IEnumerable<T> items, TypeDefinition type, Language language, Action<SearchResult> addResult, Func<T, bool> matcher, Func<T, ImageSource> 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<SearchResult> 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<SearchResult> 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);
}
}
}
}

5
ILSpy/SessionSettings.cs

@ -48,6 +48,7 @@ namespace ICSharpCode.ILSpy
if (activeTreeViewPath != null) { if (activeTreeViewPath != null) {
this.ActiveTreeViewPath = activeTreeViewPath.Elements().Select(e => Unescape((string)e)).ToArray(); 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.WindowState = FromString((string)doc.Element("WindowState"), WindowState.Normal);
this.WindowBounds = FromString((string)doc.Element("WindowBounds"), DefaultWindowBounds); this.WindowBounds = FromString((string)doc.Element("WindowBounds"), DefaultWindowBounds);
@ -67,6 +68,7 @@ namespace ICSharpCode.ILSpy
public FilterSettings FilterSettings { get; private set; } public FilterSettings FilterSettings { get; private set; }
public string[] ActiveTreeViewPath; public string[] ActiveTreeViewPath;
public string ActiveAutoLoadedAssembly;
public string ActiveAssemblyList; public string ActiveAssemblyList;
@ -89,6 +91,9 @@ namespace ICSharpCode.ILSpy
if (this.ActiveTreeViewPath != null) { if (this.ActiveTreeViewPath != null) {
doc.Add(new XElement("ActiveTreeViewPath", ActiveTreeViewPath.Select(p => new XElement("Node", Escape(p))))); 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("WindowState", ToString(this.WindowState)));
doc.Add(new XElement("WindowBounds", ToString(this.WindowBounds))); doc.Add(new XElement("WindowBounds", ToString(this.WindowBounds)));
doc.Add(new XElement("SplitterPosition", ToString(this.SplitterPosition))); doc.Add(new XElement("SplitterPosition", ToString(this.SplitterPosition)));

28
ILSpy/TextView/DecompilerTextView.cs

@ -94,6 +94,7 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.Options.RequireControlModifierForHyperlinkClick = false; textEditor.Options.RequireControlModifierForHyperlinkClick = false;
textEditor.TextArea.TextView.MouseHover += TextViewMouseHover; textEditor.TextArea.TextView.MouseHover += TextViewMouseHover;
textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped; 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.FontFamilyProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFont") });
textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFontSize") }); textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFontSize") });
@ -103,7 +104,10 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.ShowLineNumbers = true; textEditor.ShowLineNumbers = true;
DisplaySettingsPanel.CurrentDisplaySettings.PropertyChanged += CurrentDisplaySettings_PropertyChanged; 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(); ShowLineMargin();
@ -186,13 +190,17 @@ namespace ICSharpCode.ILSpy.TextView
} }
XmlDocRenderer renderer = new XmlDocRenderer(); XmlDocRenderer renderer = new XmlDocRenderer();
renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr)); renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr));
XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module); try {
if (docProvider != null) { XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module);
string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr)); if (docProvider != null) {
if (documentation != null) { string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
renderer.AppendText(Environment.NewLine); if (documentation != null) {
renderer.AddXmlDocumentation(documentation); renderer.AppendText(Environment.NewLine);
renderer.AddXmlDocumentation(documentation);
}
} }
} catch (XmlException) {
// ignore
} }
return renderer.CreateTextBlock(); return renderer.CreateTextBlock();
} }
@ -556,6 +564,12 @@ namespace ICSharpCode.ILSpy.TextView
MainWindow.Instance.JumpToReference(reference); MainWindow.Instance.JumpToReference(reference);
} }
void TextViewMouseDown(object sender, MouseButtonEventArgs e)
{
if (GetReferenceSegmentAtMousePosition() == null)
ClearLocalReferenceMarks();
}
void ClearLocalReferenceMarks() void ClearLocalReferenceMarks()
{ {
foreach (var mark in localReferenceMarks) { foreach (var mark in localReferenceMarks) {

44
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();
}
}
}

162
ILSpy/TextView/FoldingCommands.cs

@ -1,11 +1,21 @@
/* // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
* Created by SharpDevelop. //
* User: Ronny Klier // Permission is hereby granted, free of charge, to any person obtaining a copy of this
* Date: 24.05.2012 // software and associated documentation files (the "Software"), to deal in the Software
* Time: 23:44 // 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 change this template use Tools | Options | Coding | Edit Standard Headers. // 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -15,76 +25,76 @@ using ICSharpCode.AvalonEdit.Folding;
namespace ICSharpCode.ILSpy.TextView namespace ICSharpCode.ILSpy.TextView
{ {
[ExportContextMenuEntryAttribute(Header = "Toggle All Folding", Category = "Folding")] [ExportContextMenuEntryAttribute(Header = "Toggle All Folding", Category = "Folding")]
internal sealed class ToggleAllContextMenuEntry : IContextMenuEntry internal sealed class ToggleAllContextMenuEntry : IContextMenuEntry
{ {
public bool IsVisible(TextViewContext context) public bool IsVisible(TextViewContext context)
{ {
return context.TextView != null; return context.TextView != null;
} }
public bool IsEnabled(TextViewContext context) public bool IsEnabled(TextViewContext context)
{ {
return context.TextView != null && context.TextView.FoldingManager != null; return context.TextView != null && context.TextView.FoldingManager != null;
} }
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
if (null == context.TextView) if (null == context.TextView)
return; return;
FoldingManager foldingManager = context.TextView.FoldingManager; FoldingManager foldingManager = context.TextView.FoldingManager;
if (null == foldingManager) if (null == foldingManager)
return; return;
bool doFold = true; bool doFold = true;
foreach (FoldingSection fm in foldingManager.AllFoldings) { foreach (FoldingSection fm in foldingManager.AllFoldings) {
if (fm.IsFolded) { if (fm.IsFolded) {
doFold = false; doFold = false;
break; break;
} }
} }
foreach (FoldingSection fm in foldingManager.AllFoldings) { foreach (FoldingSection fm in foldingManager.AllFoldings) {
fm.IsFolded = doFold; fm.IsFolded = doFold;
} }
} }
} }
[ExportContextMenuEntryAttribute(Header = "Toggle Folding", Category = "Folding")] [ExportContextMenuEntryAttribute(Header = "Toggle Folding", Category = "Folding")]
internal sealed class ToggleContextMenuEntry : IContextMenuEntry internal sealed class ToggleContextMenuEntry : IContextMenuEntry
{ {
public bool IsVisible(TextViewContext context) public bool IsVisible(TextViewContext context)
{ {
return context.TextView != null; return context.TextView != null;
} }
public bool IsEnabled(TextViewContext context) public bool IsEnabled(TextViewContext context)
{ {
return context.TextView != null && context.TextView.FoldingManager != null; return context.TextView != null && context.TextView.FoldingManager != null;
} }
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
var textView = context.TextView; var textView = context.TextView;
if (null == textView) if (null == textView)
return; return;
var editor = textView.textEditor; var editor = textView.textEditor;
FoldingManager foldingManager = context.TextView.FoldingManager; FoldingManager foldingManager = context.TextView.FoldingManager;
if (null == foldingManager) if (null == foldingManager)
return; return;
// TODO: or use Caret if position is not given? // TODO: or use Caret if position is not given?
var posBox = context.Position; var posBox = context.Position;
if (null == posBox) if (null == posBox)
return; return;
TextViewPosition pos = posBox.Value; TextViewPosition pos = posBox.Value;
// look for folding on this line: // look for folding on this line:
FoldingSection folding = foldingManager.GetNextFolding(editor.Document.GetOffset(pos.Line, 1)); FoldingSection folding = foldingManager.GetNextFolding(editor.Document.GetOffset(pos.Line, 1));
if (folding == null || editor.Document.GetLineByOffset(folding.StartOffset).LineNumber != pos.Line) { if (folding == null || editor.Document.GetLineByOffset(folding.StartOffset).LineNumber != pos.Line) {
// no folding found on current line: find innermost folding containing the mouse position // no folding found on current line: find innermost folding containing the mouse position
folding = foldingManager.GetFoldingsContaining(editor.Document.GetOffset(pos.Line, pos.Column)).LastOrDefault(); folding = foldingManager.GetFoldingsContaining(editor.Document.GetOffset(pos.Line, pos.Column)).LastOrDefault();
} }
if (folding != null) { if (folding != null) {
folding.IsFolded = !folding.IsFolded; folding.IsFolded = !folding.IsFolded;
} }
} }
} }
} }

5
ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs

@ -87,10 +87,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
public static bool CanShow(TypeDefinition type) public static bool CanShow(TypeDefinition type)
{ {
if (type.IsClass && !type.IsEnum) { return (type.IsClass && !(type.IsAbstract && type.IsSealed) && !type.IsEnum);
return type.Methods.Where(m => m.Name == ".ctor").Any(m => !m.IsPrivate);
}
return false;
} }
} }
} }

3
ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs

@ -54,6 +54,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType)) if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType)); this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType));
if (AnalyzedTypeUsedByTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeUsedByTreeNode(analyzedType));
if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType)) if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeExposedByTreeNode(analyzedType)); this.Children.Add(new AnalyzedTypeExposedByTreeNode(analyzedType));

195
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<AnalyzerTreeNode> FetchChildren(CancellationToken ct)
{
var analyzer = new ScopedWhereUsedAnalyzer<AnalyzerTreeNode>(analyzedType, FindTypeUsage);
return analyzer.PerformAnalysis(ct)
.Cast<AnalyzerEntityTreeNode>()
.Where(n => n.Member.DeclaringType != analyzedType)
.Distinct(new AnalyzerEntityTreeNodeComparer())
.OrderBy(n => n.Text);
}
private IEnumerable<AnalyzerEntityTreeNode> 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<TypeReference> 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<ParameterDefinition> 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<AnalyzerEntityTreeNode>
{
public bool Equals(AnalyzerEntityTreeNode x, AnalyzerEntityTreeNode y)
{
return x.Member == y.Member;
}
public int GetHashCode(AnalyzerEntityTreeNode node)
{
return node.Member.GetHashCode();
}
}
}

14
ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs

@ -58,9 +58,17 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
public override bool HandleAssemblyListChanged(ICollection<LoadedAssembly> removedAssemblies, ICollection<LoadedAssembly> addedAssemblies) public override bool HandleAssemblyListChanged(ICollection<LoadedAssembly> removedAssemblies, ICollection<LoadedAssembly> addedAssemblies)
{ {
this.LazyLoading = true; // only cancel a running analysis if user has manually added/removed assemblies
threading.Cancel(); bool manualAdd = false;
this.Children.Clear(); 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; return true;
} }
} }

7
ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary> /// <summary>
/// Node within assembly reference list. /// Node within assembly reference list.
/// </summary> /// </summary>
sealed class AssemblyReferenceTreeNode : ILSpyTreeNode public sealed class AssemblyReferenceTreeNode : ILSpyTreeNode
{ {
readonly AssemblyNameReference r; readonly AssemblyNameReference r;
readonly AssemblyTreeNode parentAssembly; readonly AssemblyTreeNode parentAssembly;
@ -40,6 +40,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.parentAssembly = parentAssembly; this.parentAssembly = parentAssembly;
this.LazyLoading = true; this.LazyLoading = true;
} }
public AssemblyNameReference AssemblyNameReference
{
get { return r; }
}
public override object Text { public override object Text {
get { return r.Name + r.MetadataToken.ToSuffixString(); } get { return r.Name + r.MetadataToken.ToSuffixString(); }

102
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -22,6 +22,8 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
@ -61,9 +63,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
get { return assembly; } get { return assembly; }
} }
public override bool IsAutoLoaded
{
get {
return assembly.IsAutoLoaded;
}
}
public override object Text public override object Text
{ {
get { return HighlightSearchMatch(assembly.ShortName); } get { return HighlightSearchMatch(assembly.Text); }
} }
public override object Icon 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 public override bool ShowExpander
{ {
get { return !assembly.HasLoadError; } 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();
}
}
} }

13
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -170,11 +170,22 @@ namespace ICSharpCode.ILSpy.TreeNodes
public virtual bool IsPublicAPI { public virtual bool IsPublicAPI {
get { return true; } get { return true; }
} }
public virtual bool IsAutoLoaded
{
get { return false; }
}
public override System.Windows.Media.Brush Foreground { public override System.Windows.Media.Brush Foreground {
get { get {
if (IsPublicAPI) if (IsPublicAPI)
return base.Foreground; if (IsAutoLoaded) {
// HACK: should not be hard coded?
return System.Windows.Media.Brushes.SteelBlue;
}
else {
return base.Foreground;
}
else else
return System.Windows.SystemColors.GrayTextBrush; return System.Windows.SystemColors.GrayTextBrush;
} }

123
ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs

@ -26,74 +26,67 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes namespace ICSharpCode.ILSpy.TreeNodes
{ {
[Export(typeof(IResourceNodeFactory))] [Export(typeof(IResourceNodeFactory))]
sealed class IconResourceNodeFactory : IResourceNodeFactory sealed class IconResourceNodeFactory : IResourceNodeFactory
{ {
public ILSpyTreeNode CreateNode(Resource resource) public ILSpyTreeNode CreateNode(Resource resource)
{ {
EmbeddedResource er = resource as EmbeddedResource; EmbeddedResource er = resource as EmbeddedResource;
if (er != null) if (er != null) {
{ return CreateNode(er.Name, er.GetResourceStream());
return CreateNode(er.Name, er.GetResourceStream()); }
} return null;
return null; }
}
public ILSpyTreeNode CreateNode(string key, object data) public ILSpyTreeNode CreateNode(string key, object data)
{ {
if (data is System.Drawing.Icon) if (data is System.Drawing.Icon) {
{ MemoryStream s = new MemoryStream();
MemoryStream s = new MemoryStream(); ((System.Drawing.Icon)data).Save(s);
((System.Drawing.Icon)data).Save(s); return new IconResourceEntryNode(key, s);
return new IconResourceEntryNode(key, s); }
} if (data is Stream && key.EndsWith(".ico", StringComparison.OrdinalIgnoreCase))
if (data is Stream && key.EndsWith(".ico", StringComparison.OrdinalIgnoreCase)) return new IconResourceEntryNode(key, (Stream)data);
return new IconResourceEntryNode(key, (Stream)data); return null;
return null; }
} }
}
sealed class IconResourceEntryNode : ResourceEntryNode sealed class IconResourceEntryNode : ResourceEntryNode
{ {
public IconResourceEntryNode(string key, Stream data) public IconResourceEntryNode(string key, Stream data)
: base(key, data) : base(key, data)
{ {
} }
public override object Icon public override object Icon
{ {
get { return Images.ResourceImage; } get { return Images.ResourceImage; }
} }
public override bool View(DecompilerTextView textView) public override bool View(DecompilerTextView textView)
{ {
try try {
{ AvalonEditTextOutput output = new AvalonEditTextOutput();
AvalonEditTextOutput output = new AvalonEditTextOutput(); Data.Position = 0;
Data.Position = 0; IconBitmapDecoder decoder = new IconBitmapDecoder(Data, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
IconBitmapDecoder decoder = new IconBitmapDecoder(Data, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None); foreach (var frame in decoder.Frames) {
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.Write(String.Format("{0}x{1}, {2} bit: ", frame.PixelHeight, frame.PixelWidth, frame.Thumbnail.Format.BitsPerPixel)); output.WriteLine();
AddIcon(output, frame); }
output.WriteLine(); output.AddButton(Images.Save, "Save", delegate {
} Save(null);
output.AddButton(Images.Save, "Save", delegate });
{ textView.ShowNode(output, this);
Save(null); return true;
}); } catch (Exception) {
textView.ShowNode(output, this); return false;
return true; }
} }
catch (Exception)
{
return false;
}
}
private static void AddIcon(AvalonEditTextOutput output, BitmapFrame frame) private static void AddIcon(AvalonEditTextOutput output, BitmapFrame frame)
{ {
output.AddUIElement(() => new Image { Source = frame }); output.AddUIElement(() => new Image { Source = frame });
} }
} }
} }

90
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();
}
}
}

8
ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs

@ -121,9 +121,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (null != smartOutput) { if (null != smartOutput) {
smartOutput.AddUIElement( smartOutput.AddUIElement(
delegate { delegate {
return new ResourceStringTable(stringTableEntries, return new ResourceStringTable(stringTableEntries, MainWindow.Instance.mainPane);
new System.Windows.Size(MainWindow.Instance.mainPane.ActualWidth - 45,
MainWindow.Instance.mainPane.ActualHeight));
} }
); );
} }
@ -135,9 +133,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (null != smartOutput) { if (null != smartOutput) {
smartOutput.AddUIElement( smartOutput.AddUIElement(
delegate { delegate {
return new ResourceObjectTable(otherEntries, return new ResourceObjectTable(otherEntries, MainWindow.Instance.mainPane);
new System.Windows.Size(MainWindow.Instance.mainPane.ActualWidth - 45,
MainWindow.Instance.mainPane.ActualHeight));
} }
); );
} }

21
ILSpy/VB/VBLanguage.cs

@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.ILSpy.XmlDoc; using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using CSharp = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.VB; using ICSharpCode.NRefactory.VB;
using ICSharpCode.NRefactory.VB.Visitors; using ICSharpCode.NRefactory.VB.Visitors;
using Mono.Cecil; using Mono.Cecil;
@ -78,6 +79,11 @@ namespace ICSharpCode.ILSpy.VB
base.DecompileAssembly(assembly, output, options); base.DecompileAssembly(assembly, output, options);
output.WriteLine(); output.WriteLine();
ModuleDefinition mainModule = assembly.ModuleDefinition; 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) { if (mainModule.EntryPoint != null) {
output.Write("' Entry point: "); output.Write("' Entry point: ");
output.WriteReference(mainModule.EntryPoint.DeclaringType.FullName + "." + mainModule.EntryPoint.Name, mainModule.EntryPoint); 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"; const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = CSharpLanguage.GetPlatformName(module); string platformName = CSharpLanguage.GetPlatformName(module);
Guid guid = App.CommandLineArguments.FixedGuid ?? Guid.NewGuid();
using (XmlTextWriter w = new XmlTextWriter(writer)) { using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented; w.Formatting = Formatting.Indented;
w.WriteStartDocument(); w.WriteStartDocument();
@ -133,7 +140,7 @@ namespace ICSharpCode.ILSpy.VB
w.WriteAttributeString("DefaultTargets", "Build"); w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup"); w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString("B").ToUpperInvariant()); w.WriteElementString("ProjectGuid", guid.ToString("B").ToUpperInvariant());
w.WriteStartElement("Configuration"); w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' "); w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
@ -438,8 +445,16 @@ namespace ICSharpCode.ILSpy.VB
void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options, ModuleDefinition module) void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options, ModuleDefinition module)
{ {
astBuilder.RunTransformations(transformAbortCondition); astBuilder.RunTransformations(transformAbortCondition);
if (options.DecompilerSettings.ShowXmlDocumentation) 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 CSharp.Comment(msg[i], CSharp.CommentType.Documentation), CSharp.Roles.Comment);
}
}
var csharpUnit = astBuilder.SyntaxTree; var csharpUnit = astBuilder.SyntaxTree;
csharpUnit.AcceptVisitor(new NRefactory.CSharp.InsertParenthesesVisitor() { InsertParenthesesForReadability = true }); csharpUnit.AcceptVisitor(new NRefactory.CSharp.InsertParenthesesVisitor() { InsertParenthesesForReadability = true });
var unit = csharpUnit.AcceptVisitor(new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider()), null); var unit = csharpUnit.AcceptVisitor(new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider()), null);

8
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) { if (embeddedStatement.IsNull) {
NewLine(); NewLine();
@ -433,11 +433,13 @@ namespace ICSharpCode.NRefactory.CSharp
BlockStatement block = embeddedStatement as BlockStatement; BlockStatement block = embeddedStatement as BlockStatement;
if (block != null) { if (block != null) {
VisitBlockStatement(block); VisitBlockStatement(block);
} else { } else if (!startOnSameLine) {
NewLine(); NewLine();
writer.Indent(); writer.Indent();
embeddedStatement.AcceptVisitor(this); embeddedStatement.AcceptVisitor(this);
writer.Unindent(); writer.Unindent();
} else {
embeddedStatement.AcceptVisitor(this);
} }
} }
@ -1509,7 +1511,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteEmbeddedStatement(ifElseStatement.TrueStatement); WriteEmbeddedStatement(ifElseStatement.TrueStatement);
if (!ifElseStatement.FalseStatement.IsNull) { if (!ifElseStatement.FalseStatement.IsNull) {
WriteKeyword(IfElseStatement.ElseKeywordRole); WriteKeyword(IfElseStatement.ElseKeywordRole);
WriteEmbeddedStatement(ifElseStatement.FalseStatement); WriteEmbeddedStatement(ifElseStatement.FalseStatement, ifElseStatement.FalseStatement is IfElseStatement);
} }
EndNode(ifElseStatement); EndNode(ifElseStatement);
} }

24
NRefactory/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs

@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text;
using System.Xml; using System.Xml;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -102,7 +103,8 @@ namespace ICSharpCode.NRefactory.Documentation
XmlDocumentationCache cache = new XmlDocumentationCache(); XmlDocumentationCache cache = new XmlDocumentationCache();
readonly string fileName; 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 #region Constructor / Redirection support
/// <summary> /// <summary>
@ -122,6 +124,7 @@ namespace ICSharpCode.NRefactory.Documentation
xmlReader.MoveToContent(); xmlReader.MoveToContent();
if (string.IsNullOrEmpty(xmlReader.GetAttribute("redirect"))) { if (string.IsNullOrEmpty(xmlReader.GetAttribute("redirect"))) {
this.fileName = fileName; this.fileName = fileName;
this.encoding = xmlReader.Encoding;
ReadXmlDoc(xmlReader); ReadXmlDoc(xmlReader);
} else { } else {
string redirectionTarget = GetRedirectionTarget(fileName, xmlReader.GetAttribute("redirect")); 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 (FileStream redirectedFs = new FileStream(redirectionTarget, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) {
using (XmlTextReader redirectedXmlReader = new XmlTextReader(redirectedFs)) { using (XmlTextReader redirectedXmlReader = new XmlTextReader(redirectedFs)) {
redirectedXmlReader.XmlResolver = null; // no DTD resolving redirectedXmlReader.XmlResolver = null; // no DTD resolving
redirectedXmlReader.MoveToContent();
this.fileName = redirectionTarget; this.fileName = redirectionTarget;
this.encoding = redirectedXmlReader.Encoding;
ReadXmlDoc(redirectedXmlReader); ReadXmlDoc(redirectedXmlReader);
} }
} }
@ -208,7 +213,7 @@ namespace ICSharpCode.NRefactory.Documentation
//lastWriteDate = File.GetLastWriteTimeUtc(fileName); //lastWriteDate = File.GetLastWriteTimeUtc(fileName);
// Open up a second file stream for the line<->position mapping // 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)) { 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<IndexEntry> indexList = new List<IndexEntry>(); List<IndexEntry> indexList = new List<IndexEntry>();
while (reader.Read()) { while (reader.Read()) {
if (reader.IsStartElement()) { if (reader.IsStartElement()) {
@ -227,21 +232,29 @@ namespace ICSharpCode.NRefactory.Documentation
sealed class LinePositionMapper sealed class LinePositionMapper
{ {
readonly FileStream fs; readonly FileStream fs;
readonly Decoder decoder;
int currentLine = 1; int currentLine = 1;
public LinePositionMapper(FileStream fs) public LinePositionMapper(FileStream fs, Encoding enc)
{ {
this.fs = fs; this.fs = fs;
this.decoder = enc.GetDecoder();
} }
public int GetPositionForLine(int line) public int GetPositionForLine(int line)
{ {
Debug.Assert(line >= currentLine); Debug.Assert(line >= currentLine);
var input = new byte[1];
var output = new char[1];
while (line > currentLine) { while (line > currentLine) {
int b = fs.ReadByte(); int b = fs.ReadByte();
if (b < 0) if (b < 0)
throw new EndOfStreamException(); 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++; currentLine++;
} }
} }
@ -379,7 +392,8 @@ namespace ICSharpCode.NRefactory.Documentation
{ {
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) { using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) {
fs.Position = positionInFile; 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 r.XmlResolver = null; // no DTD resolving
while (r.Read()) { while (r.Read()) {
if (r.NodeType == XmlNodeType.Element) { if (r.NodeType == XmlNodeType.Element) {

1
README.txt

@ -9,6 +9,7 @@ Included open-source libraries:
AvalonEdit: LGPL AvalonEdit: LGPL
SharpTreeView: LGPL SharpTreeView: LGPL
ICSharpCode.Decompiler: MIT License (developed as part of ILSpy) ICSharpCode.Decompiler: MIT License (developed as part of ILSpy)
Ricciolo.StylesExplorer: MS-PL (part of ILSpy.BamlDecompiler.Plugin)
ILSpy Contributors: ILSpy Contributors:
Daniel Grunwald Daniel Grunwald

43
SharpTreeView/SharpTreeView.cs

@ -120,6 +120,7 @@ namespace ICSharpCode.TreeView
} }
TreeFlattener flattener; TreeFlattener flattener;
bool updatesLocked;
void Reload() void Reload()
{ {
@ -148,18 +149,25 @@ namespace ICSharpCode.TreeView
selectedOldItems.Add(node); selectedOldItems.Add(node);
} }
} }
if (selectedOldItems != null) { if (!updatesLocked && selectedOldItems != null) {
var list = SelectedItems.Cast<SharpTreeNode>().Except(selectedOldItems).ToList(); var list = SelectedItems.Cast<SharpTreeNode>().Except(selectedOldItems).ToList();
SetSelectedItems(list); UpdateFocusedNode(list, Math.Max(0, e.OldStartingIndex - 1));
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);
}
} }
} }
} }
void UpdateFocusedNode(List<SharpTreeNode> newSelection, int topSelectedIndex)
{
if (updatesLocked) return;
SetSelectedItems(newSelection ?? Enumerable.Empty<SharpTreeNode>());
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() protected override DependencyObject GetContainerForItemOverride()
{ {
@ -631,8 +639,18 @@ namespace ICSharpCode.TreeView
static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e) static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e)
{ {
SharpTreeView treeView = (SharpTreeView)sender; SharpTreeView treeView = (SharpTreeView)sender;
foreach (SharpTreeNode node in treeView.GetTopLevelSelection().ToArray()) treeView.updatesLocked = true;
node.Delete(); 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) static void HandleCanExecute_Delete(object sender, CanExecuteRoutedEventArgs e)
@ -652,5 +670,10 @@ namespace ICSharpCode.TreeView
} }
#endregion #endregion
public void SetSelectedNodes(IEnumerable<SharpTreeNode> nodes)
{
this.SetSelectedItems(nodes.ToList());
}
} }
} }

2
doc/Command Line.txt

@ -43,7 +43,7 @@ WM_COPYDATA (SendMessage API):
That is, by sending this message: That is, by sending this message:
ILSpy: ILSpy:
C:\Assembly.dll C:\Assembly.dll
/navigateTo T:Type /navigateTo:T:Type
The target ILSpy instance will open C:\Assembly.dll and navigate to the specified 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. ILSpy will return TRUE (1) if it handles the message, and FALSE (0) otherwise.

2
doc/copyright.txt

@ -1,4 +1,4 @@
Copyright 2011-2012 for the SharpDevelop team Copyright 2011-2014 for the SharpDevelop team
by by
AlphaSierraPapa, Christoph Wille AlphaSierraPapa, Christoph Wille

4
doc/license.txt

@ -1,10 +1,12 @@
The following MIT license applies to ILSpy, NRefactory and ICSharpCode.Decompiler. The following MIT license applies to ILSpy, NRefactory and ICSharpCode.Decompiler.
Mono.Cecil also uses the MIT license (Copyright JB Evain). Mono.Cecil also uses the MIT license (Copyright JB Evain).
AvalonEdit and SharpTreeView use LGPL, which can be found in the LGPL.txt file. 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: 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 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 software and associated documentation files (the "Software"), to deal in the Software

1
packages/repositories.config

@ -5,4 +5,5 @@
<repository path="..\ILSpy.BamlDecompiler\packages.config" /> <repository path="..\ILSpy.BamlDecompiler\packages.config" />
<repository path="..\ILSpy.BamlDecompiler\Tests\packages.config" /> <repository path="..\ILSpy.BamlDecompiler\Tests\packages.config" />
<repository path="..\ILSpy\packages.config" /> <repository path="..\ILSpy\packages.config" />
<repository path="..\ILSpy.AddIn\packages.config" />
</repositories> </repositories>
Loading…
Cancel
Save