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. 15
      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. 5
      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. 40
      ILSpy/LoadedAssembly.cs
  60. 3
      ILSpy/MainWindow.xaml
  61. 85
      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. 340
      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. 152
      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 @@ @@ -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/ @@ -10,5 +10,5 @@ obj/
_ReSharper*/
*.ReSharper
*.patch
/ILSpy.sln.ide
/packages/*
/packages
*.ide/

6
ICSharpCode.Decompiler/Ast/AstBuilder.cs

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

88
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -52,8 +52,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -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>
/// <returns>Block for the method body</returns>
public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
DecompilerContext context,
IEnumerable<ParameterDeclaration> parameters = null)
DecompilerContext context,
IEnumerable<ParameterDeclaration> parameters = null)
{
MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
@ -103,8 +103,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -103,8 +103,8 @@ namespace ICSharpCode.Decompiler.Ast
if (parameters != null) {
foreach (var pair in (from p in parameters
join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter
select new { p, v.Name }))
join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter
select new { p, v.Name }))
{
pair.p.Name = pair.Name;
}
@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) {
if (catchClause.ExceptionVariable == null
&& (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
&& (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
{
tryCatchStmt.CatchClauses.Add(new Ast.CatchClause { Body = TransformBlock(catchClause) });
} else {
@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler.Ast
result = node;
if (result != null)
result = result.WithAnnotation(new TypeInformation(expr.InferredType));
result = result.WithAnnotation(new TypeInformation(expr.InferredType, expr.ExpectedType));
if (result != null)
return result.WithAnnotation(ilRanges);
@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
if (byteCode.Arguments[0].ExpectedType is PointerType) {
arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else if (byteCode.Arguments[1].ExpectedType is PointerType) {
arg1 = DivideBySize(arg1, ((PointerType)byteCode.InferredType).ElementType);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
if (byteCode.Arguments[0].ExpectedType is PointerType ||
byteCode.Arguments[1].ExpectedType is PointerType) {
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
if (byteCode.Arguments[0].ExpectedType is PointerType) {
arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
@ -460,12 +451,30 @@ namespace ICSharpCode.Decompiler.Ast @@ -460,12 +451,30 @@ namespace ICSharpCode.Decompiler.Ast
// can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne;
// when comparing signed integral values using Cgt_Un with 0
// the Ast should actually contain InEquality since "(uint)a > 0u" is identical to "a != 0"
if (arg1Type.IsSignedIntegralType())
{
var p = arg2 as Ast.PrimitiveExpression;
if (p != null && p.Value.IsZero()) goto case ILCode.Cne;
}
goto case ILCode.Cgt;
}
case ILCode.Cle_Un: {
// can also mean Equality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq;
// when comparing signed integral values using Cle_Un with 0
// the Ast should actually contain Equality since "(uint)a <= 0u" is identical to "a == 0"
if (arg1Type.IsSignedIntegralType())
{
var p = arg2 as Ast.PrimitiveExpression;
if (p != null && p.Value.IsZero()) goto case ILCode.Ceq;
}
goto case ILCode.Cle;
}
case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
@ -706,7 +715,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -706,7 +715,7 @@ namespace ICSharpCode.Decompiler.Ast
}
return new StackAllocExpression {
Type = AstBuilder.ConvertType(type),
CountExpression = DivideBySize(arg1, type)
CountExpression = arg1
};
}
case ILCode.Mkrefany:
@ -902,45 +911,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -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)
{
TypeDefinition typeDef = type.Resolve();

24
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

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

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

@ -144,6 +144,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -144,6 +144,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName))
continue;
}
IfElseStatement ies = stmt as IfElseStatement;
if (ies != null) {
foreach (var child in IfElseChainChildren(ies)) {
BlockStatement subBlock = child as BlockStatement;
if (subBlock != null)
DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops);
}
continue;
}
foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) {
@ -269,6 +278,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -269,6 +278,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
IfElseStatement ies = stmt as IfElseStatement;
if (ies != null) {
foreach (var child in IfElseChainChildren(ies)) {
if (!(child is BlockStatement) && UsesVariable(child, variableName))
return false;
}
return true;
}
// We can move the variable into a sub-block only if the variable is used in only that sub-block (and not in expressions such as the loop condition)
for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) {
if (!(child is BlockStatement) && UsesVariable(child, variableName)) {
@ -286,6 +304,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -286,6 +304,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
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)
{
return node is CatchClause || node is SwitchSection;

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

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

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

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

47
ICSharpCode.Decompiler/CecilExtensions.cs

@ -126,6 +126,41 @@ namespace ICSharpCode.Decompiler @@ -126,6 +126,41 @@ namespace ICSharpCode.Decompiler
return false;
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
/// <summary>
@ -190,6 +225,7 @@ namespace ICSharpCode.Decompiler @@ -190,6 +225,7 @@ namespace ICSharpCode.Decompiler
return null;
}
[Obsolete("throwing exceptions is considered a bug")]
public static TypeDefinition ResolveOrThrow(this TypeReference typeReference)
{
var resolved = typeReference.Resolve();
@ -346,5 +382,16 @@ namespace ICSharpCode.Decompiler @@ -346,5 +382,16 @@ namespace ICSharpCode.Decompiler
{
return new ICSharpCode.NRefactory.TypeSystem.FullTypeName(typeDef.FullName);
}
public static bool IsDelegate(this TypeDefinition type)
{
if (type.BaseType != null && type.BaseType.Namespace == "System") {
if (type.BaseType.Name == "MulticastDelegate")
return true;
if (type.BaseType.Name == "Delegate" && type.Name != "MulticastDelegate")
return true;
}
return false;
}
}
}

105
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

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

8
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

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

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

@ -12,7 +12,7 @@ using System.Runtime.InteropServices; @@ -12,7 +12,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("IL decompiler engine")]
[assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")]
[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyCopyright("Copyright 2011-2015 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

3
ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs

@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Tests @@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Tests
{
if(String.IsNullOrWhiteSpace(s))
return true;
return s.Trim().StartsWith("//");
s = s.Trim();
return s.StartsWith("//") || s.StartsWith("#"); // Also ignore #pragmas for warning suppression
}
public static string ConcatLines(IEnumerable<string> lines)

10
ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs

@ -20,21 +20,19 @@ using System; @@ -20,21 +20,19 @@ using System;
public static class CustomShortCircuitOperators
{
private class B
// TODO: Restore base class after https://roslyn.codeplex.com/workitem/358 is fixed.
private class C
{
public static bool operator true(CustomShortCircuitOperators.B x)
public static bool operator true(CustomShortCircuitOperators.C x)
{
return true;
}
public static bool operator false(CustomShortCircuitOperators.B x)
public static bool operator false(CustomShortCircuitOperators.C x)
{
return false;
}
}
private class C : CustomShortCircuitOperators.B
{
public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
{
return null;

32
ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs

@ -35,10 +35,8 @@ namespace ICSharpCode.Decompiler.Tests @@ -35,10 +35,8 @@ namespace ICSharpCode.Decompiler.Tests
{
protected static void ValidateFileRoundtrip(string samplesFileName)
{
var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName));
var testCode = RemoveIgnorableLines(lines);
var decompiledTestCode = RoundtripCode(testCode);
CodeAssert.AreEqual(testCode, decompiledTestCode);
var fullPath = Path.Combine(@"..\..\Tests", samplesFileName);
AssertRoundtripCode(fullPath);
}
static string RemoveIgnorableLines(IEnumerable<string> lines)
@ -46,29 +44,27 @@ namespace ICSharpCode.Decompiler.Tests @@ -46,29 +44,27 @@ namespace ICSharpCode.Decompiler.Tests
return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l)));
}
/// <summary>
/// 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)
protected static void AssertRoundtripCode(string fileName, bool optimize = false, bool useDebug = false, int compilerVersion = 4)
{
DecompilerSettings settings = new DecompilerSettings();
settings.FullyQualifyAmbiguousTypeNames = false;
AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule) { Settings = settings });
var code = RemoveIgnorableLines(File.ReadLines(fileName));
AssemblyDefinition assembly = CompileLegacy(code, optimize, useDebug, compilerVersion);
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree);
StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output));
return output.ToString();
CodeAssert.AreEqual(code, output.ToString());
}
static AssemblyDefinition Compile(string code)
protected static AssemblyDefinition CompileLegacy(string code, bool optimize, bool useDebug, int compilerVersion)
{
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v" + new Version(compilerVersion, 0) } });
CompilerParameters options = new CompilerParameters();
options.ReferencedAssemblies.Add("System.Core.dll");
options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-") + (useDebug ? " /debug" : "");
if (compilerVersion >= 4)
options.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try
{

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

@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
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 @@ @@ -107,7 +107,6 @@
<Compile Include="TestCases\HelloWorld.cs" />
<Compile Include="TestCases\PropertiesAndEvents.cs" />
<Compile Include="TestRunner.cs" />
<Compile Include="Util\IntervalTests.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

38
ICSharpCode.Decompiler/Tests/Lock.cs

@ -0,0 +1,38 @@ @@ -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 @@ -664,7 +664,9 @@ namespace HideMembers3
}
public class J2 : J
{
#pragma warning disable 0108 // Deliberate bad code for test case
public int get_P;
#pragma warning restore 0108
}
}
//$$ HideMembers4

15
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -123,6 +123,21 @@ public class UnsafeCode @@ -123,6 +123,21 @@ public class UnsafeCode
return this.PointerReferenceExpression((double*)ptr);
}
public unsafe int* PointerArithmetic(int* p)
{
return p + 2;
}
public unsafe byte* PointerArithmetic2(long* p, int y, int x)
{
return (byte*)p + (y * x);
}
public unsafe long* PointerArithmetic3(long* p)
{
return (long*)((byte*)p + 3);
}
unsafe ~UnsafeCode()
{
this.PassPointerAsRefParameter(this.NullPointer);

17
ICSharpCode.Decompiler/Tests/ValueTypes.cs

@ -168,4 +168,21 @@ public static class ValueTypes @@ -168,4 +168,21 @@ public static class ValueTypes
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 @@ -32,9 +32,11 @@ namespace ICSharpCode.Decompiler.Ast
if (resolveTypeArguments)
return BaseTypes(derivedType).Any(t => t.Item == baseType);
else {
var comparableBaseType = baseType.ResolveOrThrow();
var comparableBaseType = baseType.Resolve();
if (comparableBaseType == null)
return false;
while (derivedType.BaseType != null) {
var resolvedBaseType = derivedType.BaseType.ResolveOrThrow();
var resolvedBaseType = derivedType.BaseType.Resolve();
if (resolvedBaseType == null)
return false;
if (comparableBaseType == resolvedBaseType)
@ -185,24 +187,32 @@ namespace ICSharpCode.Decompiler.Ast @@ -185,24 +187,32 @@ namespace ICSharpCode.Decompiler.Ast
if (derivedType == null)
throw new ArgumentNullException("derivedType");
var visibility = IsVisibleFromDerived(baseMember);
if (visibility.HasValue)
return visibility.Value;
MethodAttributes attrs = GetAccessAttributes(baseMember) & MethodAttributes.MemberAccessMask;
if (attrs == MethodAttributes.Private)
return false;
if (baseMember.DeclaringType.Module == derivedType.Module)
return true;
// TODO: Check also InternalsVisibleToAttribute.
return false;
}
private static bool? IsVisibleFromDerived(IMemberDefinition member)
{
MethodAttributes attrs = GetAccessAttributes(member) & MethodAttributes.MemberAccessMask;
if (attrs == MethodAttributes.Private)
if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem) {
var derivedTypeAsm = derivedType.Module.Assembly;
var asm = baseMember.DeclaringType.Module.Assembly;
if (asm.HasCustomAttributes) {
var attributes = asm.CustomAttributes
.Where(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.InternalsVisibleToAttribute");
foreach (var attribute in attributes) {
string assemblyName = attribute.ConstructorArguments[0].Value as string;
assemblyName = assemblyName.Split(',')[0]; // strip off any public key info
if (assemblyName == derivedTypeAsm.Name.Name)
return true;
}
}
return false;
if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem)
return null;
return true;
}
return true;
}
private static MethodAttributes GetAccessAttributes(IMemberDefinition member)

11
ILSpy.AddIn/GlobalSuppressions.cs

@ -0,0 +1,11 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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>

5
ILSpy.BamlDecompiler/CecilTypeResolver.cs

@ -39,12 +39,13 @@ namespace ILSpy.BamlDecompiler @@ -39,12 +39,13 @@ namespace ILSpy.BamlDecompiler
public IType GetTypeByAssemblyQualifiedName(string name)
{
int comma = name.IndexOf(',');
int bracket = name.LastIndexOf(']');
int comma = bracket > -1 ? name.IndexOf(',', bracket) : name.IndexOf(',');
if (comma == -1)
throw new ArgumentException("invalid name");
string fullName = name.Substring(0, comma);
string fullName = bracket > -1 ? name.Substring(0, name.IndexOf('[')) : name.Substring(0, comma);
string assemblyName = name.Substring(comma + 1).Trim();
var type = thisAssembly.MainModule.GetType(fullName);

3
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs

@ -131,7 +131,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -131,7 +131,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ParseName(string assemblyQualifiedName, out string name, out string @namespace, out string assembly)
{
int commaSeparator = assemblyQualifiedName.IndexOf(", ");
int bracket = assemblyQualifiedName.LastIndexOf(']');
int commaSeparator = bracket > -1 ? assemblyQualifiedName.IndexOf(", ", bracket) : assemblyQualifiedName.IndexOf(", ");
assembly = "";
if (commaSeparator >= 0) {
assembly = assemblyQualifiedName.Substring(commaSeparator + 2);

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

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

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

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

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

@ -0,0 +1,26 @@ @@ -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 @@ @@ -3,6 +3,6 @@
<Style />
</Label.Style>
<Label.Content>
<Binding Path="Blah" />
<Binding Path="Blah" StringFormat="{}{0} items" />
</Label.Content>
</Label>

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

@ -1,12 +1,13 @@ @@ -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.Style>
<Style />
</cc:CustomControl.Style>
<Grid.Row>0</Grid.Row>
<cc:CustomControl.Tag>{}{Test}</cc:CustomControl.Tag>
<cc:CustomControl.CustomName>Custom1</cc:CustomControl.CustomName>
</cc:CustomControl>
<Label>
<Label ToolTip="{DynamicResource {x:Static cc:CustomControl.SimpleProperty}}">
<Label.Style>
<Style />
</Label.Style>

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

@ -117,6 +117,7 @@ @@ -117,6 +117,7 @@
<Name>ILSpy.BamlDecompiler</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
@ -124,6 +125,10 @@ @@ -124,6 +125,10 @@
<Page Include="Cases\AttachedEvent.xaml" />
<Page Include="Cases\AvalonDockBrushes.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\MyControl.xaml" />
<Page Include="Cases\NamespacePrefix.xaml" />

6
ILSpy.BamlDecompiler/Tests/TestRunner.cs

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

20
ILSpy.sln

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
# SharpDevelop 5.1
VisualStudioVersion = 14.0.21730.1
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}"
ProjectSection(SolutionItems) = preProject
@ -34,7 +34,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSha @@ -34,7 +34,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSha
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.Cecil", "NRefactory\ICSharpCode.NRefactory.Cecil\ICSharpCode.NRefactory.Cecil.csproj", "{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7BB4F277-CB4E-432D-B503-841CE1918294}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.AddIn", "ILSpy.AddIn\ILSpy.AddIn.csproj", "{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0A344E19-D1FC-4F4C-8883-0844AC669113}"
ProjectSection(SolutionItems) = preProject
Rebracer.xml = Rebracer.xml
EndProjectSection
@ -225,6 +227,20 @@ Global @@ -225,6 +227,20 @@ Global
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|Any CPU.Build.0 = Release|Any CPU
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|x86.ActiveCfg = Release|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Debug|x86.ActiveCfg = Debug|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|Any CPU.ActiveCfg = net_4_5_Debug|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|Any CPU.Build.0 = net_4_5_Debug|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|x86.ActiveCfg = net_4_5_Debug|x86
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Debug|x86.Build.0 = net_4_5_Debug|x86
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|Any CPU.ActiveCfg = net_4_5_Release|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|Any CPU.Build.0 = net_4_5_Release|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|x86.ActiveCfg = net_4_5_Release|x86
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.net_4_5_Release|x86.Build.0 = net_4_5_Release|x86
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Release|Any CPU.Build.0 = Release|Any CPU
{9D7BE6C0-B7B3-4A50-A54E-18A2D84A3384}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

1
ILSpy/AboutPage.cs

@ -95,6 +95,7 @@ namespace ICSharpCode.ILSpy @@ -95,6 +95,7 @@ namespace ICSharpCode.ILSpy
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("SharpDevelop", "http://www.icsharpcode.net/opensource/sd/"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("LGPL", "resource:LGPL.txt"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MS-PL", "resource:MS-PL.txt"));
textView.ShowText(output);
}

44
ILSpy/AssemblyList.cs

@ -88,7 +88,7 @@ namespace ICSharpCode.ILSpy @@ -88,7 +88,7 @@ namespace ICSharpCode.ILSpy
return new XElement(
"List",
new XAttribute("name", this.ListName),
assemblies.Select(asm => new XElement("Assembly", asm.FileName))
assemblies.Where(asm => !asm.IsAutoLoaded).Select(asm => new XElement("Assembly", asm.FileName))
);
}
@ -118,6 +118,21 @@ namespace ICSharpCode.ILSpy @@ -118,6 +118,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()
{
assemblyLookupCache.Clear();
@ -128,7 +143,7 @@ namespace ICSharpCode.ILSpy @@ -128,7 +143,7 @@ namespace ICSharpCode.ILSpy
/// Opens an assembly from disk.
/// Returns the existing assembly node if it is already loaded.
/// </summary>
public LoadedAssembly OpenAssembly(string file)
public LoadedAssembly OpenAssembly(string file, bool isAutoLoaded=false)
{
App.Current.Dispatcher.VerifyAccess();
@ -140,12 +155,37 @@ namespace ICSharpCode.ILSpy @@ -140,12 +155,37 @@ namespace ICSharpCode.ILSpy
}
var newAsm = new LoadedAssembly(this, file);
newAsm.IsAutoLoaded = isAutoLoaded;
lock (assemblies) {
this.assemblies.Add(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)
{
App.Current.Dispatcher.VerifyAccess();

14
ILSpy/CommandLineArguments.cs

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

41
ILSpy/ContextMenuEntry.cs

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

28
ILSpy/Controls/ResourceObjectTable.xaml.cs

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

28
ILSpy/Controls/ResourceStringTable.xaml.cs

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

7
ILSpy/ILSpy.csproj

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

48
ILSpy/Languages/CSharpLanguage.cs

@ -225,7 +225,14 @@ namespace ICSharpCode.ILSpy @@ -225,7 +225,14 @@ namespace ICSharpCode.ILSpy
additionalTransform.Run(astBuilder.SyntaxTree);
}
if (options.DecompilerSettings.ShowXmlDocumentation) {
AddXmlDocTransform.Run(astBuilder.SyntaxTree);
try {
AddXmlDocTransform.Run(astBuilder.SyntaxTree);
} catch (XmlException ex) {
string[] msg = (" Exception while reading XmlDoc: " + ex.ToString()).Split(new[]{'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries);
var insertionPoint = astBuilder.SyntaxTree.FirstChild;
for (int i = 0; i < msg.Length; i++)
astBuilder.SyntaxTree.InsertChildBefore(insertionPoint, new Comment(msg[i], CommentType.Documentation), Roles.Comment);
}
}
astBuilder.GenerateCode(output);
}*/
@ -267,6 +274,21 @@ namespace ICSharpCode.ILSpy @@ -267,6 +274,21 @@ namespace ICSharpCode.ILSpy
return module.Architecture.ToString();
}
}
public static string GetRuntimeDisplayName(ModuleDefinition module)
{
switch (module.Runtime) {
case TargetRuntime.Net_1_0:
return ".NET 1.0";
case TargetRuntime.Net_1_1:
return ".NET 1.1";
case TargetRuntime.Net_2_0:
return ".NET 2.0";
case TargetRuntime.Net_4_0:
return ".NET 4.0";
}
return null;
}
/*
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
@ -279,6 +301,11 @@ namespace ICSharpCode.ILSpy @@ -279,6 +301,11 @@ namespace ICSharpCode.ILSpy
base.DecompileAssembly(assembly, output, options);
output.WriteLine();
ModuleDefinition mainModule = assembly.ModuleDefinition;
if (mainModule.Types.Count > 0) {
output.Write("// Global type: ");
output.WriteReference(mainModule.Types[0].FullName, mainModule.Types[0]);
output.WriteLine();
}
if (mainModule.EntryPoint != null) {
output.Write("// Entry point: ");
output.WriteReference(mainModule.EntryPoint.DeclaringType.FullName + "." + mainModule.EntryPoint.Name, mainModule.EntryPoint);
@ -288,19 +315,9 @@ namespace ICSharpCode.ILSpy @@ -288,19 +315,9 @@ namespace ICSharpCode.ILSpy
if ((mainModule.Attributes & ModuleAttributes.ILOnly) == 0) {
output.WriteLine("// This assembly contains unmanaged code.");
}
switch (mainModule.Runtime) {
case TargetRuntime.Net_1_0:
output.WriteLine("// Runtime: .NET 1.0");
break;
case TargetRuntime.Net_1_1:
output.WriteLine("// Runtime: .NET 1.1");
break;
case TargetRuntime.Net_2_0:
output.WriteLine("// Runtime: .NET 2.0");
break;
case TargetRuntime.Net_4_0:
output.WriteLine("// Runtime: .NET 4.0");
break;
string runtimeName = GetRuntimeDisplayName(mainModule);
if (runtimeName != null) {
output.WriteLine("// Runtime: " + runtimeName);
}
output.WriteLine();
@ -319,6 +336,7 @@ namespace ICSharpCode.ILSpy @@ -319,6 +336,7 @@ namespace ICSharpCode.ILSpy
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = GetPlatformName(module);
Guid guid = App.CommandLineArguments.FixedGuid ?? Guid.NewGuid();
using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented;
w.WriteStartDocument();
@ -327,7 +345,7 @@ namespace ICSharpCode.ILSpy @@ -327,7 +345,7 @@ namespace ICSharpCode.ILSpy
w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString("B").ToUpperInvariant());
w.WriteElementString("ProjectGuid", guid.ToString("B").ToUpperInvariant());
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");

40
ILSpy/LoadedAssembly.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy @@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy
readonly string fileName;
readonly string shortName;
public LoadedAssembly(AssemblyList assemblyList, string fileName)
public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null)
{
if (assemblyList == null)
throw new ArgumentNullException("assemblyList");
@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy @@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy
this.assemblyList = assemblyList;
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);
}
@ -85,6 +85,16 @@ namespace ICSharpCode.ILSpy @@ -85,6 +85,16 @@ namespace ICSharpCode.ILSpy
get { return shortName; }
}
public string Text {
get {
if (AssemblyDefinition != null) {
return String.Format("{0} ({1})", ShortName, AssemblyDefinition.Name.Version);
} else {
return ShortName;
}
}
}
public bool IsLoaded {
get { return assemblyTask.IsCompleted; }
}
@ -93,12 +103,28 @@ namespace ICSharpCode.ILSpy @@ -93,12 +103,28 @@ namespace ICSharpCode.ILSpy
get { return assemblyTask.IsFaulted; }
}
ModuleDefinition LoadAssembly()
public bool IsAutoLoaded { get; set; }
ModuleDefinition LoadAssembly(object state)
{
var stream = state as Stream;
ModuleDefinition module;
// runs on background thread
ReaderParameters p = new ReaderParameters();
p.AssemblyResolver = new MyAssemblyResolver(this);
ModuleDefinition module = ModuleDefinition.ReadModule(fileName, p);
if (stream != null)
{
// Read the module from a precrafted stream
module = ModuleDefinition.ReadModule(stream, p);
}
else
{
// Read the module from disk (by default)
module = ModuleDefinition.ReadModule(fileName, p);
}
if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) {
try {
LoadSymbols(module);
@ -228,7 +254,8 @@ namespace ICSharpCode.ILSpy @@ -228,7 +254,8 @@ namespace ICSharpCode.ILSpy
file = Path.Combine(dir, name.Name + ".exe");
}
if (file != null) {
return assemblyList.OpenAssembly(file);
var loaded = assemblyList.OpenAssembly(file, true);
return loaded;
} else {
return null;
}
@ -249,7 +276,7 @@ namespace ICSharpCode.ILSpy @@ -249,7 +276,7 @@ namespace ICSharpCode.ILSpy
string file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name + ".winmd");
if (File.Exists(file)) {
return assemblyList.OpenAssembly(file);
return assemblyList.OpenAssembly(file, true);
} else {
return null;
}
@ -268,5 +295,6 @@ namespace ICSharpCode.ILSpy @@ -268,5 +295,6 @@ namespace ICSharpCode.ILSpy
{
assemblyTask.Wait();
}
}
}

3
ILSpy/MainWindow.xaml

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

85
ILSpy/MainWindow.xaml.cs

@ -295,9 +295,38 @@ namespace ICSharpCode.ILSpy @@ -295,9 +295,38 @@ namespace ICSharpCode.ILSpy
// Select the newly loaded assembly
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
}
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)
{
ILSpySettings spySettings = this.spySettings;
@ -319,7 +348,14 @@ namespace ICSharpCode.ILSpy @@ -319,7 +348,14 @@ namespace ICSharpCode.ILSpy
HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments);
if (App.CommandLineArguments.NavigateTo == null && App.CommandLineArguments.AssembliesToLoad.Count != 1) {
SharpTreeNode node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
SharpTreeNode node = null;
if (sessionSettings.ActiveTreeViewPath != null) {
node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
if (node == this.assemblyListTreeNode & sessionSettings.ActiveAutoLoadedAssembly != null) {
this.assemblyList.OpenAssembly(sessionSettings.ActiveAutoLoadedAssembly, true);
node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
}
}
if (node != null) {
SelectNode(node);
@ -330,8 +366,6 @@ namespace ICSharpCode.ILSpy @@ -330,8 +366,6 @@ namespace ICSharpCode.ILSpy
}
}
NavigationCommands.Search.InputGestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
AvalonEditTextOutput output = new AvalonEditTextOutput();
if (FormatExceptions(App.StartupExceptions.ToArray(), output))
decompilerTextView.ShowText(output);
@ -458,7 +492,7 @@ namespace ICSharpCode.ILSpy @@ -458,7 +492,7 @@ namespace ICSharpCode.ILSpy
{
RefreshTreeViewFilter();
if (e.PropertyName == "Language") {
DecompileSelectedNodes();
DecompileSelectedNodes(recordHistory: false);
}
}
@ -476,7 +510,8 @@ namespace ICSharpCode.ILSpy @@ -476,7 +510,8 @@ namespace ICSharpCode.ILSpy
}
#region Node Selection
internal void SelectNode(SharpTreeNode obj)
public void SelectNode(SharpTreeNode obj)
{
if (obj != null) {
if (!obj.AncestorsAndSelf().Any(node => node.IsHidden)) {
@ -495,7 +530,7 @@ namespace ICSharpCode.ILSpy @@ -495,7 +530,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Retrieves a node using the .ToString() representations of its ancestors.
/// </summary>
SharpTreeNode FindNodeByPath(string[] path, bool returnBestMatch)
public SharpTreeNode FindNodeByPath(string[] path, bool returnBestMatch)
{
if (path == null)
return null;
@ -517,7 +552,7 @@ namespace ICSharpCode.ILSpy @@ -517,7 +552,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Gets the .ToString() representation of the node's ancestors.
/// </summary>
string[] GetPathForNode(SharpTreeNode node)
public string[] GetPathForNode(SharpTreeNode node)
{
if (node == null)
return null;
@ -634,6 +669,9 @@ namespace ICSharpCode.ILSpy @@ -634,6 +669,9 @@ namespace ICSharpCode.ILSpy
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DecompileSelectedNodes();
if (SelectionChanged != null)
SelectionChanged(sender, e);
}
Task decompilationTask;
@ -685,6 +723,8 @@ namespace ICSharpCode.ILSpy @@ -685,6 +723,8 @@ namespace ICSharpCode.ILSpy
}
}
public event SelectionChangedEventHandler SelectionChanged;
public IEnumerable<ILSpyTreeNode> SelectedNodes {
get {
return treeView.GetTopLevelSelection().OfType<ILSpyTreeNode>();
@ -755,6 +795,7 @@ namespace ICSharpCode.ILSpy @@ -755,6 +795,7 @@ namespace ICSharpCode.ILSpy
base.OnClosing(e);
sessionSettings.ActiveAssemblyList = assemblyList.ListName;
sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(treeView.SelectedItem as SharpTreeNode);
sessionSettings.WindowBounds = this.RestoreBounds;
sessionSettings.SplitterPosition = leftColumn.Width.Value / (leftColumn.Width.Value + rightColumn.Width.Value);
if (topPane.Visibility == Visibility.Visible)
@ -764,6 +805,22 @@ namespace ICSharpCode.ILSpy @@ -764,6 +805,22 @@ namespace ICSharpCode.ILSpy
sessionSettings.Save();
}
private string GetAutoLoadedAssemblyNode(SharpTreeNode node)
{
if (node == null)
return null;
while (!(node is TreeNodes.AssemblyTreeNode) && node.Parent != null) {
node = node.Parent;
}
//this should be an assembly node
var assyNode = node as TreeNodes.AssemblyTreeNode;
var loadedAssy = assyNode.LoadedAssembly;
if (!(loadedAssy.IsLoaded && loadedAssy.IsAutoLoaded))
return null;
return loadedAssy.FileName;
}
#region Top/Bottom Pane management
public void ShowInTopPane(string title, object content)
{
@ -773,7 +830,12 @@ namespace ICSharpCode.ILSpy @@ -773,7 +830,12 @@ namespace ICSharpCode.ILSpy
topPaneRow.Height = new GridLength(sessionSettings.TopPaneSplitterPosition, GridUnitType.Star);
}
topPane.Title = title;
topPane.Content = content;
if (topPane.Content != content) {
IPane pane = topPane.Content as IPane;
if (pane != null)
pane.Closed();
topPane.Content = content;
}
topPane.Visibility = Visibility.Visible;
}
@ -798,7 +860,12 @@ namespace ICSharpCode.ILSpy @@ -798,7 +860,12 @@ namespace ICSharpCode.ILSpy
bottomPaneRow.Height = new GridLength(sessionSettings.BottomPaneSplitterPosition, GridUnitType.Star);
}
bottomPane.Title = title;
bottomPane.Content = content;
if (bottomPane.Content != content) {
IPane pane = bottomPane.Content as IPane;
if (pane != null)
pane.Closed();
bottomPane.Content = content;
}
bottomPane.Visibility = Visibility.Visible;
}

1
ILSpy/Options/DecompilerSettingsPanel.xaml

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
<CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</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 ExpressionTrees}">Decompile expression trees</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 FoldBraces}">Enable folding on all blocks in braces</CheckBox>

2
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

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

5
ILSpy/Properties/AssemblyInfo.template.cs

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

340
ILSpy/SearchPane.cs

@ -17,10 +17,12 @@ @@ -17,10 +17,12 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
@ -53,17 +55,14 @@ namespace ICSharpCode.ILSpy @@ -53,17 +55,14 @@ namespace ICSharpCode.ILSpy
}
}
const int SearchMode_Type = 0;
const int SearchMode_Member = 1;
const int SearchMode_Literal = 2;
private SearchPane()
{
InitializeComponent();
searchModeComboBox.Items.Add(new { Image = Images.Class, Name = "Type" });
searchModeComboBox.Items.Add(new { Image = Images.Property, Name = "Member" });
searchModeComboBox.Items.Add(new { Image = Images.Literal, Name = "Constant" });
searchModeComboBox.SelectedIndex = SearchMode_Type;
searchModeComboBox.SelectedIndex = (int)SearchMode.Type;
ContextMenuProvider.Add(listBox);
MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged;
}
@ -127,7 +126,7 @@ namespace ICSharpCode.ILSpy @@ -127,7 +126,7 @@ namespace ICSharpCode.ILSpy
listBox.ItemsSource = null;
} else {
MainWindow mainWindow = MainWindow.Instance;
currentSearch = new RunningSearch(mainWindow.CurrentAssemblyList.GetAssemblies(), searchTerm, searchModeComboBox.SelectedIndex, mainWindow.CurrentLanguage);
currentSearch = new RunningSearch(mainWindow.CurrentAssemblyList.GetAssemblies(), searchTerm, (SearchMode)searchModeComboBox.SelectedIndex, mainWindow.CurrentLanguage);
listBox.ItemsSource = currentSearch.Results;
new Thread(currentSearch.Run).Start();
}
@ -164,13 +163,13 @@ namespace ICSharpCode.ILSpy @@ -164,13 +163,13 @@ namespace ICSharpCode.ILSpy
{
base.OnKeyDown(e);
if (e.Key == Key.T && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
searchModeComboBox.SelectedIndex = SearchMode_Type;
searchModeComboBox.SelectedIndex = (int)SearchMode.Type;
e.Handled = true;
} else if (e.Key == Key.M && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
searchModeComboBox.SelectedIndex = SearchMode_Member;
searchModeComboBox.SelectedIndex = (int)SearchMode.Member;
e.Handled = true;
} else if (e.Key == Key.S && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
searchModeComboBox.SelectedIndex = SearchMode_Literal;
searchModeComboBox.SelectedIndex = (int)SearchMode.Literal;
e.Handled = true;
}
}
@ -190,15 +189,12 @@ namespace ICSharpCode.ILSpy @@ -190,15 +189,12 @@ namespace ICSharpCode.ILSpy
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly LoadedAssembly[] assemblies;
readonly string[] searchTerm;
readonly int searchMode;
readonly SearchMode searchMode;
readonly Language language;
public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>();
int resultCount;
TypeCode searchTermLiteralType = TypeCode.Empty;
object searchTermLiteralValue;
public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, int searchMode, Language language)
public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, SearchMode searchMode, Language language)
{
this.dispatcher = Dispatcher.CurrentDispatcher;
this.assemblies = assemblies;
@ -217,44 +213,16 @@ namespace ICSharpCode.ILSpy @@ -217,44 +213,16 @@ namespace ICSharpCode.ILSpy
public void Run()
{
try {
if (searchMode == SearchMode_Literal) {
if (1 == searchTerm.Length)
{
CSharpParser parser = new CSharpParser();
PrimitiveExpression pe = parser.ParseExpression(searchTerm[0]) as PrimitiveExpression;
if (pe != null && pe.Value != null) {
TypeCode peValueType = Type.GetTypeCode(pe.Value.GetType());
switch (peValueType) {
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
searchTermLiteralType = TypeCode.Int64;
searchTermLiteralValue = CSharpPrimitiveCast.Cast(TypeCode.Int64, pe.Value, false);
break;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.String:
searchTermLiteralType = peValueType;
searchTermLiteralValue = pe.Value;
break;
}
}
}
}
var searcher = GetSearchStrategy(searchMode, searchTerm);
foreach (var loadedAssembly in assemblies) {
ModuleDefinition module = loadedAssembly.ModuleDefinition;
if (module == null)
continue;
CancellationToken cancellationToken = cts.Token;
foreach (TypeDefinition type in module.Types) {
cancellationToken.ThrowIfCancellationRequested();
PerformSearch(type);
searcher.Search(type, language, AddResult);
}
}
} catch (OperationCanceledException) {
@ -278,264 +246,70 @@ namespace ICSharpCode.ILSpy @@ -278,264 +246,70 @@ namespace ICSharpCode.ILSpy
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;
}
if (terms.Length == 1) {
if (terms[0].StartsWith("t:"))
return new TypeSearchStrategy(terms[0].Substring(2));
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
});
}
if (terms[0].StartsWith("m:"))
return new MemberSearchStrategy(terms[0].Substring(2));
foreach (TypeDefinition nestedType in type.NestedTypes) {
PerformSearch(nestedType);
if (terms[0].StartsWith("c:"))
return new LiteralSearchStrategy(terms[0].Substring(2));
}
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)
});
}
switch (mode) {
case SearchMode.Type:
return new TypeSearchStrategy(terms);
case SearchMode.Member:
return new MemberSearchStrategy(terms);
case SearchMode.Literal:
return new LiteralSearchStrategy(terms);
}
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)
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;
return null;
}
}
}
sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
{
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
add { }
remove { }
}
sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode
{
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
add { }
remove { }
}
public MemberReference Member { get; set; }
public MemberReference Member { get; set; }
public string Location { get; set; }
public string Name { get; set; }
public ImageSource Image { get; set; }
public ImageSource LocationImage { get; set; }
public string Location { get; set; }
public string Name { get; set; }
public ImageSource Image { get; set; }
public ImageSource LocationImage { get; set; }
public override string ToString()
{
return Name;
}
public override string ToString()
{
return Name;
}
}
[ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon="Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)]
[ExportToolbarCommand(ToolTip = "Search (F3)", ToolbarIcon = "Images/Find.png", ToolbarCategory = "View", ToolbarOrder = 100)]
[ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon = "Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)]
[ExportToolbarCommand(ToolTip = "Search (Ctrl+Shift+F or Ctrl+E)", ToolbarIcon = "Images/Find.png", ToolbarCategory = "View", ToolbarOrder = 100)]
sealed class ShowSearchCommand : CommandWrapper
{
public ShowSearchCommand()
: base(NavigationCommands.Search)
{
NavigationCommands.Search.InputGestures.Clear();
NavigationCommands.Search.InputGestures.Add(new KeyGesture(Key.F, ModifierKeys.Control | ModifierKeys.Shift));
NavigationCommands.Search.InputGestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
}
}
public enum SearchMode
{
Type,
Member,
Literal
}
}

2
ILSpy/SearchPane.xaml

@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
<controls:SearchBox x:Name="searchBox" DockPanel.Dock="Top" Grid.Column="0" Grid.Row="0" Margin="1"
PreviewKeyDown="SearchBox_PreviewKeyDown"
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">
<Label Margin="0,-1">Search _for:</Label>
<ComboBox Width="100" Name="searchModeComboBox" Margin="1"

335
ILSpy/SearchStrategies.cs

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

28
ILSpy/TextView/DecompilerTextView.cs

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

44
ILSpy/TextView/EditorCommands.cs

@ -0,0 +1,44 @@ @@ -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();
}
}
}

152
ILSpy/TextView/FoldingCommands.cs

@ -1,11 +1,21 @@ @@ -1,11 +1,21 @@
/*
* Created by SharpDevelop.
* User: Ronny Klier
* Date: 24.05.2012
* Time: 23:44
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
@ -15,76 +25,76 @@ using ICSharpCode.AvalonEdit.Folding; @@ -15,76 +25,76 @@ using ICSharpCode.AvalonEdit.Folding;
namespace ICSharpCode.ILSpy.TextView
{
[ExportContextMenuEntryAttribute(Header = "Toggle All Folding", Category = "Folding")]
internal sealed class ToggleAllContextMenuEntry : IContextMenuEntry
{
public bool IsVisible(TextViewContext context)
{
return context.TextView != null;
}
[ExportContextMenuEntryAttribute(Header = "Toggle All Folding", Category = "Folding")]
internal sealed class ToggleAllContextMenuEntry : IContextMenuEntry
{
public bool IsVisible(TextViewContext context)
{
return context.TextView != null;
}
public bool IsEnabled(TextViewContext context)
{
return context.TextView != null && context.TextView.FoldingManager != null;
}
public bool IsEnabled(TextViewContext context)
{
return context.TextView != null && context.TextView.FoldingManager != null;
}
public void Execute(TextViewContext context)
{
if (null == context.TextView)
return;
FoldingManager foldingManager = context.TextView.FoldingManager;
if (null == foldingManager)
return;
bool doFold = true;
foreach (FoldingSection fm in foldingManager.AllFoldings) {
if (fm.IsFolded) {
doFold = false;
break;
}
}
foreach (FoldingSection fm in foldingManager.AllFoldings) {
fm.IsFolded = doFold;
}
}
}
public void Execute(TextViewContext context)
{
if (null == context.TextView)
return;
FoldingManager foldingManager = context.TextView.FoldingManager;
if (null == foldingManager)
return;
bool doFold = true;
foreach (FoldingSection fm in foldingManager.AllFoldings) {
if (fm.IsFolded) {
doFold = false;
break;
}
}
foreach (FoldingSection fm in foldingManager.AllFoldings) {
fm.IsFolded = doFold;
}
}
}
[ExportContextMenuEntryAttribute(Header = "Toggle Folding", Category = "Folding")]
internal sealed class ToggleContextMenuEntry : IContextMenuEntry
{
public bool IsVisible(TextViewContext context)
{
return context.TextView != null;
}
[ExportContextMenuEntryAttribute(Header = "Toggle Folding", Category = "Folding")]
internal sealed class ToggleContextMenuEntry : IContextMenuEntry
{
public bool IsVisible(TextViewContext context)
{
return context.TextView != null;
}
public bool IsEnabled(TextViewContext context)
{
return context.TextView != null && context.TextView.FoldingManager != null;
}
public bool IsEnabled(TextViewContext context)
{
return context.TextView != null && context.TextView.FoldingManager != null;
}
public void Execute(TextViewContext context)
{
var textView = context.TextView;
if (null == textView)
return;
var editor = textView.textEditor;
FoldingManager foldingManager = context.TextView.FoldingManager;
if (null == foldingManager)
return;
// TODO: or use Caret if position is not given?
var posBox = context.Position;
if (null == posBox)
return;
TextViewPosition pos = posBox.Value;
public void Execute(TextViewContext context)
{
var textView = context.TextView;
if (null == textView)
return;
var editor = textView.textEditor;
FoldingManager foldingManager = context.TextView.FoldingManager;
if (null == foldingManager)
return;
// TODO: or use Caret if position is not given?
var posBox = context.Position;
if (null == posBox)
return;
TextViewPosition pos = posBox.Value;
// look for folding on this line:
FoldingSection folding = foldingManager.GetNextFolding(editor.Document.GetOffset(pos.Line, 1));
if (folding == null || editor.Document.GetLineByOffset(folding.StartOffset).LineNumber != pos.Line) {
// no folding found on current line: find innermost folding containing the mouse position
folding = foldingManager.GetFoldingsContaining(editor.Document.GetOffset(pos.Line, pos.Column)).LastOrDefault();
}
if (folding != null) {
folding.IsFolded = !folding.IsFolded;
}
}
}
// no folding found on current line: find innermost folding containing the mouse position
folding = foldingManager.GetFoldingsContaining(editor.Document.GetOffset(pos.Line, pos.Column)).LastOrDefault();
}
if (folding != null) {
folding.IsFolded = !folding.IsFolded;
}
}
}
}

5
ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs

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

3
ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs

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

195
ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs

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

7
ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs

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

102
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -22,6 +22,8 @@ using System.IO; @@ -22,6 +22,8 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.TreeView;
@ -61,9 +63,16 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -61,9 +63,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
get { return assembly; }
}
public override bool IsAutoLoaded
{
get {
return assembly.IsAutoLoaded;
}
}
public override object Text
{
get { return HighlightSearchMatch(assembly.ShortName); }
get { return HighlightSearchMatch(assembly.Text); }
}
public override object Icon
@ -78,6 +87,36 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -78,6 +87,36 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
TextBlock tooltip;
public override object ToolTip
{
get {
if (assembly.HasLoadError)
return "Assembly could not be loaded. Click here for details.";
if (tooltip == null) {
tooltip = new TextBlock();
tooltip.Inlines.Add(new Bold(new Run("Name: ")));
tooltip.Inlines.Add(new Run(assembly.AssemblyDefinition.FullName));
tooltip.Inlines.Add(new LineBreak());
tooltip.Inlines.Add(new Bold(new Run("Location: ")));
tooltip.Inlines.Add(new Run(assembly.FileName));
tooltip.Inlines.Add(new LineBreak());
tooltip.Inlines.Add(new Bold(new Run("Architecture: ")));
tooltip.Inlines.Add(new Run(CSharpLanguage.GetPlatformDisplayName(assembly.AssemblyDefinition.MainModule)));
string runtimeName = CSharpLanguage.GetRuntimeDisplayName(assembly.AssemblyDefinition.MainModule);
if (runtimeName != null) {
tooltip.Inlines.Add(new LineBreak());
tooltip.Inlines.Add(new Bold(new Run("Runtime: ")));
tooltip.Inlines.Add(new Run(runtimeName));
}
}
return tooltip;
}
}
public override bool ShowExpander
{
get { return !assembly.HasLoadError; }
@ -278,4 +317,65 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -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

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

123
ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs

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

90
ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs

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

21
ILSpy/VB/VBLanguage.cs

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

8
NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -424,7 +424,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -424,7 +424,7 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
void WriteEmbeddedStatement(Statement embeddedStatement)
void WriteEmbeddedStatement(Statement embeddedStatement, bool startOnSameLine = false)
{
if (embeddedStatement.IsNull) {
NewLine();
@ -433,11 +433,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -433,11 +433,13 @@ namespace ICSharpCode.NRefactory.CSharp
BlockStatement block = embeddedStatement as BlockStatement;
if (block != null) {
VisitBlockStatement(block);
} else {
} else if (!startOnSameLine) {
NewLine();
writer.Indent();
embeddedStatement.AcceptVisitor(this);
writer.Unindent();
} else {
embeddedStatement.AcceptVisitor(this);
}
}
@ -1509,7 +1511,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1509,7 +1511,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteEmbeddedStatement(ifElseStatement.TrueStatement);
if (!ifElseStatement.FalseStatement.IsNull) {
WriteKeyword(IfElseStatement.ElseKeywordRole);
WriteEmbeddedStatement(ifElseStatement.FalseStatement);
WriteEmbeddedStatement(ifElseStatement.FalseStatement, ifElseStatement.FalseStatement is IfElseStatement);
}
EndNode(ifElseStatement);
}

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

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

1
README.txt

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

43
SharpTreeView/SharpTreeView.cs

@ -120,6 +120,7 @@ namespace ICSharpCode.TreeView @@ -120,6 +120,7 @@ namespace ICSharpCode.TreeView
}
TreeFlattener flattener;
bool updatesLocked;
void Reload()
{
@ -148,19 +149,26 @@ namespace ICSharpCode.TreeView @@ -148,19 +149,26 @@ namespace ICSharpCode.TreeView
selectedOldItems.Add(node);
}
}
if (selectedOldItems != null) {
if (!updatesLocked && selectedOldItems != null) {
var list = SelectedItems.Cast<SharpTreeNode>().Except(selectedOldItems).ToList();
SetSelectedItems(list);
if (SelectedItem == null) {
// if we removed all selected nodes, then move the focus to the node
// preceding the first of the old selected nodes
SelectedIndex = Math.Max(0, e.OldStartingIndex - 1);
FocusNode((SharpTreeNode)SelectedItem);
}
UpdateFocusedNode(list, Math.Max(0, e.OldStartingIndex - 1));
}
}
}
void UpdateFocusedNode(List<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()
{
return new SharpTreeViewItem();
@ -631,8 +639,18 @@ namespace ICSharpCode.TreeView @@ -631,8 +639,18 @@ namespace ICSharpCode.TreeView
static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e)
{
SharpTreeView treeView = (SharpTreeView)sender;
foreach (SharpTreeNode node in treeView.GetTopLevelSelection().ToArray())
node.Delete();
treeView.updatesLocked = true;
int selectedIndex = -1;
try {
foreach (SharpTreeNode node in treeView.GetTopLevelSelection().ToArray()) {
if (selectedIndex == -1)
selectedIndex = treeView.flattener.IndexOf(node);
node.Delete();
}
} finally {
treeView.updatesLocked = false;
treeView.UpdateFocusedNode(null, Math.Max(0, selectedIndex - 1));
}
}
static void HandleCanExecute_Delete(object sender, CanExecuteRoutedEventArgs e)
@ -652,5 +670,10 @@ namespace ICSharpCode.TreeView @@ -652,5 +670,10 @@ namespace ICSharpCode.TreeView
}
#endregion
public void SetSelectedNodes(IEnumerable<SharpTreeNode> nodes)
{
this.SetSelectedItems(nodes.ToList());
}
}
}

2
doc/Command Line.txt

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

2
doc/copyright.txt

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

4
doc/license.txt

@ -1,10 +1,12 @@ @@ -1,10 +1,12 @@
The following MIT license applies to ILSpy, NRefactory and ICSharpCode.Decompiler.
Mono.Cecil also uses the MIT license (Copyright JB Evain).
AvalonEdit and SharpTreeView use LGPL, which can be found in the LGPL.txt file.
ILSpy.BamlDecompiler uses the MS-PL, which can be found in the MS-PL.txt file.
MIT license:
Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop team
Copyright (c) 2011-2014 AlphaSierraPapa for the SharpDevelop team
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software

1
packages/repositories.config

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