From 207af4eced2d2e6449944626b007221f787c3a3e Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Mon, 16 May 2011 10:53:21 +0300 Subject: [PATCH 01/57] update to latest code mappings --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 35 ++--- ICSharpCode.Decompiler/CodeMappings.cs | 133 +++++++++--------- .../Disassembler/ReflectionDisassembler.cs | 34 +++-- ICSharpCode.Decompiler/PlainTextOutput.cs | 9 +- 4 files changed, 110 insertions(+), 101 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index b4860eb7d..21c5d73a4 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.Ast IncludeTypeParameterDefinitions = 2 } - public class AstBuilder : ICodeMappings + public class AstBuilder : BaseCodeMappings { DecompilerContext context; CompilationUnit astCompileUnit = new CompilationUnit(); @@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.Ast this.DecompileMethodBodies = true; this.LocalVariables = new ConcurrentDictionary>(); + this.CodeMappings = new Dictionary>(); + this.DecompiledMemberReferences = new Dictionary(); } public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings) @@ -196,10 +198,6 @@ namespace ICSharpCode.Decompiler.Ast /// TypeDeclaration or DelegateDeclaration. public AttributedNode CreateType(TypeDefinition typeDef) { - // create CSharp code mappings - used for debugger - if (this.CodeMappings == null) - this.CodeMappings = new Tuple>(typeDef.FullName, new List()); - // create type TypeDefinition oldCurrentType = context.CurrentType; context.CurrentType = typeDef; @@ -627,7 +625,8 @@ namespace ICSharpCode.Decompiler.Ast AttributedNode CreateMethod(MethodDefinition methodDef) { // Create mapping - used in debugger - MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings); + CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef); + MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]); MethodDeclaration astMethod = new MethodDeclaration().WithAnnotation(methodMapping); astMethod.AddAnnotation(methodDef); @@ -715,7 +714,8 @@ namespace ICSharpCode.Decompiler.Ast ConstructorDeclaration CreateConstructor(MethodDefinition methodDef) { // Create mapping - used in debugger - MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings); + CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef); + MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]); ConstructorDeclaration astMethod = new ConstructorDeclaration(); astMethod.AddAnnotation(methodDef); @@ -776,9 +776,11 @@ namespace ICSharpCode.Decompiler.Ast } astProp.Name = CleanName(propDef.Name); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); + if (propDef.GetMethod != null) { // Create mapping - used in debugger - MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings); + CreateCodeMappings(propDef.GetMethod.MetadataToken.ToInt32(), propDef); + MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[propDef.GetMethod.MetadataToken.ToInt32()], propDef); astProp.Getter = new Accessor(); astProp.Getter.Body = CreateMethodBody(propDef.GetMethod); @@ -792,7 +794,8 @@ namespace ICSharpCode.Decompiler.Ast } if (propDef.SetMethod != null) { // Create mapping - used in debugger - MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings); + CreateCodeMappings(propDef.SetMethod.MetadataToken.ToInt32(), propDef); + MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[propDef.SetMethod.MetadataToken.ToInt32()], propDef); astProp.Setter = new Accessor(); astProp.Setter.Body = CreateMethodBody(propDef.SetMethod); @@ -853,9 +856,11 @@ namespace ICSharpCode.Decompiler.Ast astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); else astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType); + if (eventDef.AddMethod != null) { // Create mapping - used in debugger - MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings); + CreateCodeMappings(eventDef.AddMethod.MetadataToken.ToInt32(), eventDef); + MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[eventDef.AddMethod.MetadataToken.ToInt32()], eventDef); astEvent.AddAccessor = new Accessor { Body = CreateMethodBody(eventDef.AddMethod) @@ -866,7 +871,8 @@ namespace ICSharpCode.Decompiler.Ast } if (eventDef.RemoveMethod != null) { // Create mapping - used in debugger - MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings); + CreateCodeMappings(eventDef.RemoveMethod.MetadataToken.ToInt32(), eventDef); + MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings[eventDef.RemoveMethod.MetadataToken.ToInt32()], eventDef); astEvent.RemoveAccessor = new Accessor { Body = CreateMethodBody(eventDef.RemoveMethod) @@ -895,6 +901,8 @@ namespace ICSharpCode.Decompiler.Ast FieldDeclaration CreateField(FieldDefinition fieldDef) { + this.DecompiledMemberReferences.Add(fieldDef.MetadataToken.ToInt32(), fieldDef); + FieldDeclaration astField = new FieldDeclaration(); astField.AddAnnotation(fieldDef); VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name)); @@ -1451,11 +1459,6 @@ namespace ICSharpCode.Decompiler.Ast && TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType)); } - /// - /// - /// - public Tuple> CodeMappings { get; private set; } - /// /// Gets the local variables for the current decompiled type, method, etc. /// The key is the metadata token. diff --git a/ICSharpCode.Decompiler/CodeMappings.cs b/ICSharpCode.Decompiler/CodeMappings.cs index 57c9c6979..485792f4a 100644 --- a/ICSharpCode.Decompiler/CodeMappings.cs +++ b/ICSharpCode.Decompiler/CodeMappings.cs @@ -35,14 +35,36 @@ namespace ICSharpCode.Decompiler } /// - /// Interface for decompliler classes : AstBuilder & ReflectionDisassembler. + /// Base class for decompliler classes : AstBuilder & ReflectionDisassembler. /// - public interface ICodeMappings + public abstract class BaseCodeMappings { /// /// Gets the code mappings. + /// Key is the metadata token. /// - Tuple> CodeMappings { get; } + public Dictionary> CodeMappings { get; protected set; } + + /// + /// Gets the MembeReference that is decompiled (a MethodDefinition, PropertyDefinition etc.) + /// Key is the metadata token. + /// + public Dictionary DecompiledMemberReferences { get; protected set; } + + /// + /// Create data in the CodeMappings and DecompiledMemberReferences. + /// + /// Token of the current method. + /// Current member (MethodDefinition, PropertyDefinition, EventDefinition). + /// The token is used in CodeMappings; member (and its token) is used in DecompiledMemberReferences. + protected virtual void CreateCodeMappings(int token, MemberReference member) + { + this.CodeMappings.Add(token, new List()); + + int t = member.MetadataToken.ToInt32(); + if (!this.DecompiledMemberReferences.ContainsKey(t)) + this.DecompiledMemberReferences.Add(t, member); + } } /// @@ -112,9 +134,9 @@ namespace ICSharpCode.Decompiler public MemberReference MemberReference { get; internal set; } /// - /// Metadata token of the method. + /// Metadata token of the member. /// - public uint MetadataToken { get; internal set; } + public int MetadataToken { get; internal set; } /// /// Gets or sets the code size for the member mapping. @@ -148,15 +170,17 @@ namespace ICSharpCode.Decompiler /// Code mappings helper class. /// public static class CodeMappings - { + { /// /// Create code mapping for a method. /// /// Method to create the mapping for. - /// Source code mapping storage. + /// Source code mapping storage. + /// The actual member reference. internal static MemberMapping CreateCodeMapping( this MethodDefinition member, - Tuple> codeMappings) + List codeMappings, + MemberReference actualMemberReference = null) { if (member == null || !member.HasBody) return null; @@ -166,17 +190,16 @@ namespace ICSharpCode.Decompiler // create IL/CSharp code mappings - used in debugger MemberMapping currentMemberMapping = null; - if (codeMappings.Item1 == member.DeclaringType.FullName) { - var mapping = codeMappings.Item2; - if (mapping.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) { - currentMemberMapping = new MemberMapping() { - MetadataToken = (uint)member.MetadataToken.ToInt32(), - MemberReference = member.DeclaringType.Resolve(), - MemberCodeMappings = new List(), - CodeSize = member.Body.CodeSize - }; - mapping.Add(currentMemberMapping); - } + + if (codeMappings.Find(map => map.MetadataToken == member.MetadataToken.ToInt32()) == null) { + currentMemberMapping = new MemberMapping() { + MetadataToken = member.MetadataToken.ToInt32(), + MemberCodeMappings = new List(), + MemberReference = actualMemberReference ?? member, + CodeSize = member.Body.CodeSize + }; + + codeMappings.Add(currentMemberMapping); } return currentMemberMapping; @@ -186,31 +209,19 @@ namespace ICSharpCode.Decompiler /// Gets source code mapping and metadata token based on type name and line number. /// /// Code mappings storage. - /// Type name. + /// Member reference name. /// Line number. /// Metadata token. /// - public static SourceCodeMapping GetInstructionByTypeAndLine( - this Tuple> codeMappings, - string memberReferenceName, + public static SourceCodeMapping GetInstructionByLineNumber( + this List codeMappings, int lineNumber, - out uint metadataToken) + out int metadataToken) { if (codeMappings == null) - throw new ArgumentNullException("CodeMappings storage must be valid!"); + throw new ArgumentException("CodeMappings storage must be valid!"); - if (codeMappings.Item1 != memberReferenceName) { - metadataToken = 0; - return null; - } - - if (lineNumber <= 0) { - metadataToken = 0; - return null; - } - - var methodMappings = codeMappings.Item2; - foreach (var maping in methodMappings) { + foreach (var maping in codeMappings) { var map = maping.MemberCodeMappings.Find(m => m.SourceCodeLine == lineNumber); if (map != null) { metadataToken = maping.MetadataToken; @@ -226,40 +237,32 @@ namespace ICSharpCode.Decompiler /// Gets a mapping given a type, a token and an IL offset. /// /// Code mappings storage. - /// Type name. /// Token. /// IL offset. /// True, if perfect match. /// A code mapping. - public static SourceCodeMapping GetInstructionByTypeTokenAndOffset( - this Tuple> codeMappings, - string memberReferenceName, - uint token, - int ilOffset, out bool isMatch) + public static SourceCodeMapping GetInstructionByTokenAndOffset( + this List codeMappings, + int token, + int ilOffset, + out bool isMatch) { isMatch = false; - memberReferenceName = memberReferenceName.Replace("+", "/"); if (codeMappings == null) throw new ArgumentNullException("CodeMappings storage must be valid!"); - if (codeMappings.Item1 != memberReferenceName) { - return null; - } - - var methodMappings = codeMappings.Item2; - var maping = methodMappings.Find(m => m.MetadataToken == token); + var maping = codeMappings.Find(m => m.MetadataToken == token); - if (maping == null) { + if (maping == null) return null; - } // try find an exact match var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To); if (map == null) { // get the immediate next one - map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From >= ilOffset); + map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From > ilOffset); isMatch = false; if (map == null) map = maping.MemberCodeMappings.LastOrDefault(); // get the last @@ -275,38 +278,32 @@ namespace ICSharpCode.Decompiler /// Gets the source code and type name from metadata token and offset. /// /// Code mappings storage. - /// Current type name. /// Metadata token. /// IL offset. /// Type definition. /// Line number. /// It is possible to exist to different types from different assemblies with the same metadata token. - public static bool GetSourceCodeFromMetadataTokenAndOffset( - this Tuple> codeMappings, - string memberReferenceName, - uint token, + public static bool GetInstructionByTokenAndOffset( + this List codeMappings, + int token, int ilOffset, - out MemberReference type, + out MemberReference member, out int line) { - type = null; + member = null; line = 0; if (codeMappings == null) - throw new ArgumentNullException("CodeMappings storage must be valid!"); - - memberReferenceName = memberReferenceName.Replace("+", "/"); - if (codeMappings.Item1 != memberReferenceName) - return false; + throw new ArgumentException("CodeMappings storage must be valid!"); - var mapping = codeMappings.Item2.Find(m => m.MetadataToken == token); + var mapping = codeMappings.Find(m => m.MetadataToken == token); if (mapping == null) return false; var codeMapping = mapping.MemberCodeMappings.Find( cm => cm.ILInstructionOffset.From <= ilOffset && ilOffset <= cm.ILInstructionOffset.To - 1); if (codeMapping == null) { - codeMapping = mapping.MemberCodeMappings.Find(cm => (cm.ILInstructionOffset.From >= ilOffset)); + codeMapping = mapping.MemberCodeMappings.Find(cm => cm.ILInstructionOffset.From > ilOffset); if (codeMapping == null) { codeMapping = mapping.MemberCodeMappings.LastOrDefault(); if (codeMapping == null) @@ -314,7 +311,7 @@ namespace ICSharpCode.Decompiler } } - type = mapping.MemberReference; + member = mapping.MemberReference; line = codeMapping.SourceCodeLine; return true; } diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 5231b78c1..87a746a1c 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -28,13 +28,14 @@ namespace ICSharpCode.Decompiler.Disassembler /// /// Disassembles type and member definitions. /// - public sealed class ReflectionDisassembler : ICodeMappings + public sealed class ReflectionDisassembler : BaseCodeMappings { ITextOutput output; CancellationToken cancellationToken; bool detectControlStructure; bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings) MethodBodyDisassembler methodBodyDisassembler; + MemberReference currentMember; public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken) { @@ -44,6 +45,9 @@ namespace ICSharpCode.Decompiler.Disassembler this.cancellationToken = cancellationToken; this.detectControlStructure = detectControlStructure; this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); + + this.CodeMappings = new Dictionary>(); + this.DecompiledMemberReferences = new Dictionary(); } #region Disassemble Method @@ -94,6 +98,9 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleMethod(MethodDefinition method) { + // set current member + currentMember = method; + // write method header output.WriteDefinition(".method ", method); DisassembleMethodInternal(method); @@ -118,7 +125,6 @@ namespace ICSharpCode.Decompiler.Disassembler //call convention WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention); - //return type method.ReturnType.WriteTo(output); output.Write(' '); @@ -149,7 +155,9 @@ namespace ICSharpCode.Decompiler.Disassembler if (method.HasBody) { // create IL code mappings - used in debugger - MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings); + CreateCodeMappings(method.MetadataToken.ToInt32(), currentMember); + MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[method.MetadataToken.ToInt32()], currentMember); + methodBodyDisassembler.Disassemble(method.Body, methodMapping); } @@ -194,6 +202,9 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleField(FieldDefinition field) { + // create mappings for decompiled fields only + this.DecompiledMemberReferences.Add(field.MetadataToken.ToInt32(), field); + output.WriteDefinition(".field ", field); WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | FieldAttributes.HasDefault), fieldAttributes); @@ -223,6 +234,9 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleProperty(PropertyDefinition property) { + // set current member + currentMember = property; + output.WriteDefinition(".property ", property); WriteFlags(property.Attributes, propertyAttributes); property.PropertyType.WriteTo(output); @@ -232,6 +246,7 @@ namespace ICSharpCode.Decompiler.Disassembler WriteAttributes(property.CustomAttributes); WriteNestedMethod(".get", property.GetMethod); WriteNestedMethod(".set", property.SetMethod); + foreach (var method in property.OtherMethods) { WriteNestedMethod(".method", method); } @@ -263,6 +278,9 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleEvent(EventDefinition ev) { + // set current member + currentMember = ev; + output.WriteDefinition(".event ", ev); WriteFlags(ev.Attributes, eventAttributes); ev.EventType.WriteTo(output); @@ -316,10 +334,6 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleType(TypeDefinition type) { - // create IL code mappings - used for debugger - if (this.CodeMappings == null) - this.CodeMappings = new Tuple>(type.FullName, new List()); - // start writing IL output.WriteDefinition(".class ", type); @@ -604,11 +618,5 @@ namespace ICSharpCode.Decompiler.Disassembler WriteAttributes(asm.CustomAttributes); CloseBlock(); } - - /// - public Tuple> CodeMappings { - get; - private set; - } } } diff --git a/ICSharpCode.Decompiler/PlainTextOutput.cs b/ICSharpCode.Decompiler/PlainTextOutput.cs index 3e167b01b..7078b6785 100644 --- a/ICSharpCode.Decompiler/PlainTextOutput.cs +++ b/ICSharpCode.Decompiler/PlainTextOutput.cs @@ -26,22 +26,23 @@ namespace ICSharpCode.Decompiler readonly TextWriter writer; int indent; bool needsIndent; + int lineNumber = 1; public PlainTextOutput(TextWriter writer) { if (writer == null) throw new ArgumentNullException("writer"); this.writer = writer; - CurrentLine = 1; } public PlainTextOutput() { this.writer = new StringWriter(); - CurrentLine = 1; } - public int CurrentLine { get; set; } + public int CurrentLine { + get { return lineNumber; } + } public override string ToString() { @@ -82,9 +83,9 @@ namespace ICSharpCode.Decompiler public void WriteLine() { + lineNumber++; writer.WriteLine(); needsIndent = true; - ++CurrentLine; } public void WriteDefinition(string text, object definition) From 8c3717518901ea9cea1c72f55a826bfb161ab2c7 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Tue, 17 May 2011 18:33:09 +0300 Subject: [PATCH 02/57] add icon margin & bookmarks --- .../Ast/TextOutputFormatter.cs | 20 +- ILSpy.sln | 2 +- ILSpy/AvalonEdit/ITextMarker.cs | 123 ++++++++ ILSpy/AvalonEdit/IconBarManager.cs | 83 +++++ ILSpy/AvalonEdit/IconBarMargin.cs | 239 ++++++++++++++ .../AvalonEdit/TextEditorWeakEventManager.cs | 67 ++++ ILSpy/AvalonEdit/TextMarkerService.cs | 292 ++++++++++++++++++ ILSpy/Bookmarks/BookmarkBase.cs | 97 ++++++ ILSpy/Bookmarks/BookmarkEventHandler.cs | 28 ++ ILSpy/Bookmarks/BookmarkManager.cs | 116 +++++++ ILSpy/Bookmarks/IBookmark.cs | 69 +++++ ILSpy/Bookmarks/MarkerBookmark.cs | 21 ++ ILSpy/Bookmarks/MemberBookmark.cs | 162 ++++++++++ ILSpy/CSharpLanguage.cs | 8 +- ILSpy/ILLanguage.cs | 24 +- ILSpy/ILSpy.csproj | 16 +- ILSpy/Language.cs | 74 ++++- ILSpy/TextView/DecompilerTextView.cs | 37 ++- .../CSharp/Ast/CompilationUnit.cs | 18 ++ 19 files changed, 1479 insertions(+), 17 deletions(-) create mode 100644 ILSpy/AvalonEdit/ITextMarker.cs create mode 100644 ILSpy/AvalonEdit/IconBarManager.cs create mode 100644 ILSpy/AvalonEdit/IconBarMargin.cs create mode 100644 ILSpy/AvalonEdit/TextEditorWeakEventManager.cs create mode 100644 ILSpy/AvalonEdit/TextMarkerService.cs create mode 100644 ILSpy/Bookmarks/BookmarkBase.cs create mode 100644 ILSpy/Bookmarks/BookmarkEventHandler.cs create mode 100644 ILSpy/Bookmarks/BookmarkManager.cs create mode 100644 ILSpy/Bookmarks/IBookmark.cs create mode 100644 ILSpy/Bookmarks/MarkerBookmark.cs create mode 100644 ILSpy/Bookmarks/MemberBookmark.cs diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index 1e6915872..f31455d73 100644 --- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -123,12 +123,11 @@ namespace ICSharpCode.Decompiler.Ast public void StartNode(AstNode node) { + // code mappings var ranges = node.Annotation>(); - if (ranges != null && ranges.Count > 0) - { + if (ranges != null && ranges.Count > 0) { // find the ancestor that has method mapping as annotation - if (node.Ancestors != null && node.Ancestors.Count() > 0) - { + if (node.Ancestors != null && node.Ancestors.Count() > 0) { var n = node.Ancestors.FirstOrDefault(a => a.Annotation() != null); if (n != null) { MemberMapping mapping = n.Annotation(); @@ -145,6 +144,19 @@ namespace ICSharpCode.Decompiler.Ast } } + // definitions of types and their members + Predicate predicate = n => n is TypeDeclaration || n is DelegateDeclaration || + n is FieldDeclaration || n is PropertyDeclaration || n is EventDeclaration ||n is MethodDeclaration || n is ConstructorDeclaration || + n is IndexerDeclaration || n is OperatorDeclaration; + + if (predicate(node)) { + var n = node as AttributedNode; + int c = 0; + if (n != null) + c = n.Attributes.Count; + node.AddAnnotation(Tuple.Create(output.CurrentLine + c, 0)); + } + nodeStack.Push(node); } diff --git a/ILSpy.sln b/ILSpy.sln index 7af0dee1b..78bafdde2 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.0.1.7146 +# SharpDevelop 4.1.0.7384-alpha Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" ProjectSection(SolutionItems) = postProject doc\Command Line.txt = doc\Command Line.txt diff --git a/ILSpy/AvalonEdit/ITextMarker.cs b/ILSpy/AvalonEdit/ITextMarker.cs new file mode 100644 index 000000000..8046bb6a9 --- /dev/null +++ b/ILSpy/AvalonEdit/ITextMarker.cs @@ -0,0 +1,123 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Windows.Media; + +using ICSharpCode.ILSpy.Bookmarks; + +namespace ICSharpCode.ILSpy.AvalonEdit +{ + /// + /// Represents a text marker. + /// + public interface ITextMarker + { + /// + /// Gets the start offset of the marked text region. + /// + int StartOffset { get; } + + /// + /// Gets the end offset of the marked text region. + /// + int EndOffset { get; } + + /// + /// Gets the length of the marked region. + /// + int Length { get; } + + /// + /// Deletes the text marker. + /// + void Delete(); + + /// + /// Gets whether the text marker was deleted. + /// + bool IsDeleted { get; } + + /// + /// Event that occurs when the text marker is deleted. + /// + event EventHandler Deleted; + + /// + /// Gets/Sets the background color. + /// + Color? BackgroundColor { get; set; } + + /// + /// Gets/Sets the foreground color. + /// + Color? ForegroundColor { get; set; } + + /// + /// Gets/Sets the type of the marker. Use TextMarkerType.None for normal markers. + /// + TextMarkerType MarkerType { get; set; } + + /// + /// Gets/Sets the color of the marker. + /// + Color MarkerColor { get; set; } + + /// + /// Gets/Sets an object with additional data for this text marker. + /// + object Tag { get; set; } + + /// + /// Gets/Sets an object that will be displayed as tooltip in the text editor. + /// + object ToolTip { get; set; } + + /// + /// Gets or sets if the marker is visible or not. + /// + Predicate IsVisible { get; set; } + + /// + /// Gets or sets the bookmark. + /// + IBookmark Bookmark { get; set; } + } + + public enum TextMarkerType + { + /// + /// Use no marker + /// + None, + /// + /// Use squiggly underline marker + /// + SquigglyUnderline + } + + public interface ITextMarkerService + { + /// + /// Creates a new text marker. The text marker will be invisible at first, + /// you need to set one of the Color properties to make it visible. + /// + ITextMarker Create(int startOffset, int length); + + /// + /// Gets the list of text markers. + /// + IEnumerable TextMarkers { get; } + + /// + /// Removes the specified text marker. + /// + void Remove(ITextMarker marker); + + /// + /// Removes all text markers that match the condition. + /// + void RemoveAll(Predicate predicate); + } +} diff --git a/ILSpy/AvalonEdit/IconBarManager.cs b/ILSpy/AvalonEdit/IconBarManager.cs new file mode 100644 index 000000000..3677df10b --- /dev/null +++ b/ILSpy/AvalonEdit/IconBarManager.cs @@ -0,0 +1,83 @@ +// 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.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; + +using ICSharpCode.ILSpy.Bookmarks; +using ICSharpCode.NRefactory.CSharp; + +namespace ICSharpCode.ILSpy.AvalonEdit +{ + /// + /// Stores the entries in the icon bar margin. Multiple icon bar margins + /// can use the same manager if split view is used. + /// + public class IconBarManager : IBookmarkMargin + { + ObservableCollection bookmarks = new ObservableCollection(); + + public IconBarManager() + { + bookmarks.CollectionChanged += bookmarks_CollectionChanged; + } + + public IList Bookmarks { + get { return bookmarks; } + } + + void bookmarks_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + Redraw(); + } + + public void Redraw() + { + if (RedrawRequested != null) + RedrawRequested(this, EventArgs.Empty); + } + + public event EventHandler RedrawRequested; + + internal void UpdateClassMemberBookmarks(IEnumerable nodes) + { + this.bookmarks.Clear(); + + if (nodes == null || nodes.Count() == 0) + return; + + foreach (var n in nodes) { + switch (n.NodeType) { + case NodeType.TypeDeclaration: + case NodeType.TypeReference: + this.bookmarks.Add(new TypeBookmark(n)); + break; + case NodeType.Member: + this.bookmarks.Add(new MemberBookmark(n)); + break; + default: + // do nothing + break; + } + } + } + } +} diff --git a/ILSpy/AvalonEdit/IconBarMargin.cs b/ILSpy/AvalonEdit/IconBarMargin.cs new file mode 100644 index 000000000..f0f83848d --- /dev/null +++ b/ILSpy/AvalonEdit/IconBarMargin.cs @@ -0,0 +1,239 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; + +using ICSharpCode.AvalonEdit.Editing; +using ICSharpCode.AvalonEdit.Rendering; +using ICSharpCode.AvalonEdit.Utils; +using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.Bookmarks; +using ICSharpCode.NRefactory.CSharp; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.AvalonEdit +{ + public class IconBarMargin : AbstractMargin, IDisposable + { + readonly IconBarManager manager; + + public IconBarMargin(IconBarManager manager) + { + BookmarkManager.Added += delegate { InvalidateVisual(); }; + BookmarkManager.Removed += delegate { InvalidateVisual(); }; + + this.manager = manager; + } + + public IList DecompiledMembers { get; set; } + + public virtual void Dispose() + { + this.TextView = null; // detach from TextView (will also detach from manager) + } + + /// + protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) + { + // accept clicks even when clicking on the background + return new PointHitTestResult(this, hitTestParameters.HitPoint); + } + + /// + protected override Size MeasureOverride(Size availableSize) + { + return new Size(18, 0); + } + + protected override void OnRender(DrawingContext drawingContext) + { + Size renderSize = this.RenderSize; + drawingContext.DrawRectangle(SystemColors.ControlBrush, null, + new Rect(0, 0, renderSize.Width, renderSize.Height)); + drawingContext.DrawLine(new Pen(SystemColors.ControlDarkBrush, 1), + new Point(renderSize.Width - 0.5, 0), + new Point(renderSize.Width - 0.5, renderSize.Height)); + + ICSharpCode.AvalonEdit.Rendering.TextView textView = this.TextView; + if (textView != null && textView.VisualLinesValid) { + // create a dictionary line number => first bookmark + Dictionary bookmarkDict = new Dictionary(); + foreach (var bm in BookmarkManager.Bookmarks) { + if (!DecompiledMembers.Contains(bm.MemberReference)) + continue; + int line = bm.LineNumber; + IBookmark existingBookmark; + if (!bookmarkDict.TryGetValue(line, out existingBookmark) || bm.ZOrder > existingBookmark.ZOrder) + bookmarkDict[line] = bm; + } + + foreach (var bm in manager.Bookmarks) { + int line = bm.LineNumber; + IBookmark existingBookmark; + if (!bookmarkDict.TryGetValue(line, out existingBookmark) || bm.ZOrder > existingBookmark.ZOrder) + bookmarkDict[line] = bm; + } + + Size pixelSize = PixelSnapHelpers.GetPixelSize(this); + foreach (VisualLine line in textView.VisualLines) { + int lineNumber = line.FirstDocumentLine.LineNumber; + IBookmark bm; + if (bookmarkDict.TryGetValue(lineNumber, out bm)) { + Rect rect = new Rect(0, PixelSnapHelpers.Round(line.VisualTop - textView.VerticalOffset, pixelSize.Height), 16, 16); + if (dragDropBookmark == bm && dragStarted) + drawingContext.PushOpacity(0.5); + drawingContext.DrawImage(bm.Image, rect); + if (dragDropBookmark == bm && dragStarted) + drawingContext.Pop(); + } + } + if (dragDropBookmark != null && dragStarted) { + Rect rect = new Rect(0, PixelSnapHelpers.Round(dragDropCurrentPoint - 8, pixelSize.Height), 16, 16); + drawingContext.DrawImage(dragDropBookmark.Image, rect); + } + } + } + + IBookmark dragDropBookmark; // bookmark being dragged (!=null if drag'n'drop is active) + double dragDropStartPoint; + double dragDropCurrentPoint; + bool dragStarted; // whether drag'n'drop operation has started (mouse was moved minimum distance) + + protected override void OnMouseDown(MouseButtonEventArgs e) + { + base.OnMouseDown(e); + int line = GetLineFromMousePosition(e); + if (!e.Handled && line > 0) { + IBookmark bm = GetBookmarkFromLine(line); + if (bm != null) { + bm.MouseDown(e); + if (!e.Handled) { + if (e.ChangedButton == MouseButton.Left && bm.CanDragDrop && CaptureMouse()) { + StartDragDrop(bm, e); + e.Handled = true; + } + } + } + } + // don't allow selecting text through the IconBarMargin + if (e.ChangedButton == MouseButton.Left) + e.Handled = true; + } + + IBookmark GetBookmarkFromLine(int line) + { + BookmarkBase result = null; + foreach (BookmarkBase bm in BookmarkManager.Bookmarks) { + if (bm.LineNumber == line && + this.DecompiledMembers != null && this.DecompiledMembers.Contains(bm.MemberReference)) { + if (result == null || bm.ZOrder > result.ZOrder) + return result; + } + } + + return manager.Bookmarks.FirstOrDefault(b => b.LineNumber == line); + } + + protected override void OnLostMouseCapture(MouseEventArgs e) + { + CancelDragDrop(); + base.OnLostMouseCapture(e); + } + + void StartDragDrop(IBookmark bm, MouseEventArgs e) + { + dragDropBookmark = bm; + dragDropStartPoint = dragDropCurrentPoint = e.GetPosition(this).Y; + if (TextView != null) { + TextArea area = TextView.Services.GetService(typeof(TextArea)) as TextArea; + if (area != null) + area.PreviewKeyDown += TextArea_PreviewKeyDown; + } + } + + void CancelDragDrop() + { + if (dragDropBookmark != null) { + dragDropBookmark = null; + dragStarted = false; + if (TextView != null) { + TextArea area = TextView.Services.GetService(typeof(TextArea)) as TextArea; + if (area != null) + area.PreviewKeyDown -= TextArea_PreviewKeyDown; + } + ReleaseMouseCapture(); + InvalidateVisual(); + } + } + + void TextArea_PreviewKeyDown(object sender, KeyEventArgs e) + { + // any key press cancels drag'n'drop + CancelDragDrop(); + if (e.Key == Key.Escape) + e.Handled = true; + } + + int GetLineFromMousePosition(MouseEventArgs e) + { + ICSharpCode.AvalonEdit.Rendering.TextView textView = this.TextView; + if (textView == null) + return 0; + VisualLine vl = textView.GetVisualLineFromVisualTop(e.GetPosition(textView).Y + textView.ScrollOffset.Y); + if (vl == null) + return 0; + return vl.FirstDocumentLine.LineNumber; + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + if (dragDropBookmark != null) { + dragDropCurrentPoint = e.GetPosition(this).Y; + if (Math.Abs(dragDropCurrentPoint - dragDropStartPoint) > SystemParameters.MinimumVerticalDragDistance) + dragStarted = true; + InvalidateVisual(); + } + } + + protected override void OnMouseUp(MouseButtonEventArgs e) + { + base.OnMouseUp(e); + int line = GetLineFromMousePosition(e); + if (!e.Handled && dragDropBookmark != null) { + if (dragStarted) { + if (line != 0) + dragDropBookmark.Drop(line); + e.Handled = true; + } + CancelDragDrop(); + } + if (!e.Handled && line != 0) { + var bm = GetBookmarkFromLine(line); + if (bm != null) { + bm.MouseUp(e); + + if (bm is BookmarkBase) { + if ((bm as BookmarkBase).CanToggle) { + BookmarkManager.RemoveMark(bm as BookmarkBase); + InvalidateVisual(); + } + } + if (e.Handled) + return; + } + if (e.ChangedButton == MouseButton.Left) { + // TODO: notify subscribers + } + InvalidateVisual(); + } + } + } +} diff --git a/ILSpy/AvalonEdit/TextEditorWeakEventManager.cs b/ILSpy/AvalonEdit/TextEditorWeakEventManager.cs new file mode 100644 index 000000000..2074763d8 --- /dev/null +++ b/ILSpy/AvalonEdit/TextEditorWeakEventManager.cs @@ -0,0 +1,67 @@ +// 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.Windows; +using ICSharpCode.AvalonEdit; +using ICSharpCode.AvalonEdit.Utils; + +namespace ICSharpCode.ILSpy.AvalonEdit +{ + public static class TextEditorWeakEventManager + { + public sealed class MouseHover : WeakEventManagerBase + { + protected override void StopListening(TextEditor source) + { + source.MouseHover -= DeliverEvent; + } + + protected override void StartListening(TextEditor source) + { + source.MouseHover += DeliverEvent; + } + } + + public sealed class MouseHoverStopped : WeakEventManagerBase + { + protected override void StopListening(TextEditor source) + { + source.MouseHoverStopped -= DeliverEvent; + } + + protected override void StartListening(TextEditor source) + { + source.MouseHoverStopped += DeliverEvent; + } + } + + public sealed class MouseDown : WeakEventManagerBase + { + protected override void StopListening(TextEditor source) + { + source.MouseDown -= DeliverEvent; + } + + protected override void StartListening(TextEditor source) + { + source.MouseDown += DeliverEvent; + } + } + } +} diff --git a/ILSpy/AvalonEdit/TextMarkerService.cs b/ILSpy/AvalonEdit/TextMarkerService.cs new file mode 100644 index 000000000..6b97b5650 --- /dev/null +++ b/ILSpy/AvalonEdit/TextMarkerService.cs @@ -0,0 +1,292 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using System.Windows.Threading; + +using ICSharpCode.AvalonEdit; +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Rendering; +using ICSharpCode.ILSpy.Bookmarks; + +namespace ICSharpCode.ILSpy.AvalonEdit +{ + /// + /// Handles the text markers for a code editor. + /// + public sealed class TextMarkerService : DocumentColorizingTransformer, IBackgroundRenderer, ITextMarkerService + { + TextEditor codeEditor; + + TextSegmentCollection markers = new TextSegmentCollection(); + + public TextMarkerService() + { + } + + public TextEditor CodeEditor { + get { return codeEditor; } + set { codeEditor = value; } + } + + #region ITextMarkerService + public ITextMarker Create(int startOffset, int length) + { + int textLength = codeEditor.TextArea.TextView.Document.TextLength; + if (startOffset < 0 || startOffset > textLength) + throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between 0 and " + textLength); + if (length < 0 || startOffset + length > textLength) + throw new ArgumentOutOfRangeException("length", length, "length must not be negative and startOffset+length must not be after the end of the document"); + + TextMarker m = new TextMarker(this, startOffset, length); + markers.Add(m); + // no need to mark segment for redraw: the text marker is invisible until a property is set + return m; + } + + public IEnumerable GetMarkersAtOffset(int offset) + { + return markers.FindSegmentsContaining(offset); + } + + public IEnumerable TextMarkers { + get { return markers; } + } + + public void RemoveAll(Predicate predicate) + { + if (predicate == null) + throw new ArgumentNullException("predicate"); + foreach (TextMarker m in markers.ToArray()) { + if (predicate(m)) + Remove(m); + } + } + + public void Remove(ITextMarker marker) + { + if (marker == null) + return; + + TextMarker m = marker as TextMarker; + if (markers.Remove(m)) { + Redraw(m); + m.OnDeleted(); + } + } + + /// + /// Redraws the specified text segment. + /// + public void Redraw(ISegment segment) + { + codeEditor.TextArea.TextView.Redraw(segment, DispatcherPriority.Normal); + } + #endregion + + #region DocumentColorizingTransformer + protected override void ColorizeLine(DocumentLine line) + { + if (markers == null) + return; + int lineStart = line.Offset; + int lineEnd = lineStart + line.Length; + foreach (TextMarker marker in markers.FindOverlappingSegments(lineStart, line.Length).Reverse()) { + if (!marker.IsVisible(marker.Bookmark)) + continue; + + Brush foregroundBrush = null; + if (marker.ForegroundColor != null) { + foregroundBrush = new SolidColorBrush(marker.ForegroundColor.Value); + foregroundBrush.Freeze(); + } + ChangeLinePart( + Math.Max(marker.StartOffset, lineStart), + Math.Min(marker.EndOffset, lineEnd), + element => { + if (foregroundBrush != null) { + element.TextRunProperties.SetForegroundBrush(foregroundBrush); + } + } + ); + } + } + #endregion + + #region IBackgroundRenderer + public KnownLayer Layer { + get { + // draw behind selection + return KnownLayer.Selection; + } + } + + public void Draw(ICSharpCode.AvalonEdit.Rendering.TextView textView, DrawingContext drawingContext) + { + if (textView == null) + throw new ArgumentNullException("textView"); + if (drawingContext == null) + throw new ArgumentNullException("drawingContext"); + if (markers == null || !textView.VisualLinesValid) + return; + var visualLines = textView.VisualLines; + if (visualLines.Count == 0) + return; + int viewStart = visualLines.First().FirstDocumentLine.Offset; + int viewEnd = visualLines.Last().LastDocumentLine.Offset + visualLines.Last().LastDocumentLine.Length; + foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart).Reverse()) { + if (!marker.IsVisible(marker.Bookmark)) + continue; + + if (marker.BackgroundColor != null) { + BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder(); + geoBuilder.AlignToWholePixels = true; + geoBuilder.CornerRadius = 3; + geoBuilder.AddSegment(textView, marker); + Geometry geometry = geoBuilder.CreateGeometry(); + if (geometry != null) { + Color color = marker.BackgroundColor.Value; + SolidColorBrush brush = new SolidColorBrush(color); + brush.Freeze(); + drawingContext.DrawGeometry(brush, null, geometry); + } + } + if (marker.MarkerType != TextMarkerType.None) { + foreach (Rect r in BackgroundGeometryBuilder.GetRectsForSegment(textView, marker)) { + Point startPoint = r.BottomLeft; + Point endPoint = r.BottomRight; + + Pen usedPen = new Pen(new SolidColorBrush(marker.MarkerColor), 1); + usedPen.Freeze(); + switch (marker.MarkerType) { + case TextMarkerType.SquigglyUnderline: + double offset = 2.5; + + int count = Math.Max((int)((endPoint.X - startPoint.X) / offset) + 1, 4); + + StreamGeometry geometry = new StreamGeometry(); + + using (StreamGeometryContext ctx = geometry.Open()) { + ctx.BeginFigure(startPoint, false, false); + ctx.PolyLineTo(CreatePoints(startPoint, endPoint, offset, count).ToArray(), true, false); + } + + geometry.Freeze(); + + drawingContext.DrawGeometry(Brushes.Transparent, usedPen, geometry); + break; + } + } + } + } + } + + IEnumerable CreatePoints(Point start, Point end, double offset, int count) + { + for (int i = 0; i < count; i++) + yield return new Point(start.X + i * offset, start.Y - ((i + 1) % 2 == 0 ? offset : 0)); + } + #endregion + } + + sealed class TextMarker : TextSegment, ITextMarker + { + readonly TextMarkerService service; + + public TextMarker(TextMarkerService service, int startOffset, int length) + { + if (service == null) + throw new ArgumentNullException("service"); + this.service = service; + this.StartOffset = startOffset; + this.Length = length; + this.markerType = TextMarkerType.None; + } + + public event EventHandler Deleted; + + public bool IsDeleted { + get { return !this.IsConnectedToCollection; } + } + + public void Delete() + { + service.Remove(this); + } + + internal void OnDeleted() + { + if (Deleted != null) + Deleted(this, EventArgs.Empty); + } + + void Redraw() + { + service.Redraw(this); + } + + Color? backgroundColor; + + public Color? BackgroundColor { + get { return backgroundColor; } + set { + if (backgroundColor != value) { + backgroundColor = value; + Redraw(); + } + } + } + + Color? foregroundColor; + + public Color? ForegroundColor { + get { return foregroundColor; } + set { + if (foregroundColor != value) { + foregroundColor = value; + Redraw(); + } + } + } + + public object Tag { get; set; } + + TextMarkerType markerType; + + public TextMarkerType MarkerType { + get { return markerType; } + set { + if (markerType != value) { + markerType = value; + Redraw(); + } + } + } + + Color markerColor; + + public Color MarkerColor { + get { return markerColor; } + set { + if (markerColor != value) { + markerColor = value; + Redraw(); + } + } + + } + /// + public object ToolTip { get; set; } + + /// + public Predicate IsVisible { get; set; } + + /// + public IBookmark Bookmark { get; set; } + } +} diff --git a/ILSpy/Bookmarks/BookmarkBase.cs b/ILSpy/Bookmarks/BookmarkBase.cs new file mode 100644 index 000000000..f6b5ece5d --- /dev/null +++ b/ILSpy/Bookmarks/BookmarkBase.cs @@ -0,0 +1,97 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Windows.Input; +using System.Windows.Media; + +using ICSharpCode.NRefactory.CSharp; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + /// + /// A bookmark that can be attached to an AvalonEdit TextDocument. + /// + public class BookmarkBase : IBookmark + { + AstLocation location; + + protected virtual void RemoveMark() + { + + } + + public AstLocation Location { + get { return location; } + set { location = value; } + } + + public event EventHandler DocumentChanged; + + protected virtual void OnDocumentChanged(EventArgs e) + { + if (DocumentChanged != null) { + DocumentChanged(this, e); + } + } + + protected virtual void Redraw() + { + + } + + public MemberReference MemberReference { get; set; } + + public int LineNumber { + get { return location.Line; } + } + + public int ColumnNumber { + get { return location.Column; } + } + + public virtual int ZOrder { + get { return 0; } + } + + /// + /// Gets if the bookmark can be toggled off using the 'set/unset bookmark' command. + /// + public virtual bool CanToggle { + get { + return true; + } + } + + public BookmarkBase(MemberReference member, AstLocation location) + { + this.MemberReference = member; + this.Location = location; + } + + public virtual ImageSource Image { + get { return null; } + } + + public virtual void MouseDown(MouseButtonEventArgs e) + { + } + + public virtual void MouseUp(MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left && CanToggle) { + RemoveMark(); + e.Handled = true; + } + } + + public virtual bool CanDragDrop { + get { return false; } + } + + public virtual void Drop(int lineNumber) + { + } + } +} diff --git a/ILSpy/Bookmarks/BookmarkEventHandler.cs b/ILSpy/Bookmarks/BookmarkEventHandler.cs new file mode 100644 index 000000000..5dae1beac --- /dev/null +++ b/ILSpy/Bookmarks/BookmarkEventHandler.cs @@ -0,0 +1,28 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + public delegate void BookmarkEventHandler(object sender, BookmarkEventArgs e); + + /// + /// Description of BookmarkEventHandler. + /// + public class BookmarkEventArgs : EventArgs + { + BookmarkBase bookmark; + + public BookmarkBase Bookmark { + get { + return bookmark; + } + } + + public BookmarkEventArgs(BookmarkBase bookmark) + { + this.bookmark = bookmark; + } + } +} diff --git a/ILSpy/Bookmarks/BookmarkManager.cs b/ILSpy/Bookmarks/BookmarkManager.cs new file mode 100644 index 000000000..65a769617 --- /dev/null +++ b/ILSpy/Bookmarks/BookmarkManager.cs @@ -0,0 +1,116 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using ICSharpCode.Decompiler; +using ICSharpCode.NRefactory.CSharp; +using Mono.Cecil; +using Mono.CSharp; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + /// + /// Static class that maintains the list of bookmarks and breakpoints. + /// + public static partial class BookmarkManager + { + static List bookmarks = new List(); + + public static List Bookmarks { + get { + return bookmarks; + } + } + + public static List GetBookmarks(string typeName) + { + if (typeName == null) + throw new ArgumentNullException("typeName"); + + List marks = new List(); + + foreach (BookmarkBase mark in bookmarks) { + if (typeName == mark.MemberReference.FullName) { + marks.Add(mark); + } + } + + return marks; + } + + public static void AddMark(BookmarkBase bookmark) + { + if (bookmark == null) return; + if (bookmarks.Contains(bookmark)) return; + if (bookmarks.Exists(b => IsEqualBookmark(b, bookmark))) return; + bookmarks.Add(bookmark); + OnAdded(new BookmarkEventArgs(bookmark)); + } + + static bool IsEqualBookmark(BookmarkBase a, BookmarkBase b) + { + if (a == b) + return true; + if (a == null || b == null) + return false; + if (a.GetType() != b.GetType()) + return false; + if (a.MemberReference.FullName != b.MemberReference.FullName) + return false; + return a.LineNumber == b.LineNumber; + } + + public static void RemoveMark(BookmarkBase bookmark) + { + bookmarks.Remove(bookmark); + OnRemoved(new BookmarkEventArgs(bookmark)); + } + + public static void Clear() + { + while (bookmarks.Count > 0) { + var b = bookmarks[bookmarks.Count - 1]; + bookmarks.RemoveAt(bookmarks.Count - 1); + OnRemoved(new BookmarkEventArgs(b)); + } + } + + internal static void Initialize() + { + + } + + static void OnRemoved(BookmarkEventArgs e) + { + if (Removed != null) { + Removed(null, e); + } + } + + static void OnAdded(BookmarkEventArgs e) + { + if (Added != null) { + Added(null, e); + } + } + + public static void ToggleBookmark(string typeName, int line, + Predicate canToggle, + Func bookmarkFactory) + { + foreach (BookmarkBase bookmark in GetBookmarks(typeName)) { + if (canToggle(bookmark) && bookmark.LineNumber == line) { + BookmarkManager.RemoveMark(bookmark); + return; + } + } + + // no bookmark at that line: create a new bookmark + BookmarkManager.AddMark(bookmarkFactory(new AstLocation(line, 0))); + } + + public static event BookmarkEventHandler Removed; + public static event BookmarkEventHandler Added; + } +} diff --git a/ILSpy/Bookmarks/IBookmark.cs b/ILSpy/Bookmarks/IBookmark.cs new file mode 100644 index 000000000..37733789a --- /dev/null +++ b/ILSpy/Bookmarks/IBookmark.cs @@ -0,0 +1,69 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Windows.Input; +using System.Windows.Media; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + /// + /// The bookmark margin. + /// + public interface IBookmarkMargin + { + /// + /// Gets the list of bookmarks. + /// + IList Bookmarks { get; } + + /// + /// Redraws the bookmark margin. Bookmarks need to call this method when the Image changes. + /// + void Redraw(); + } + + /// + /// Represents a bookmark in the bookmark margin. + /// + public interface IBookmark + { + /// + /// Gets the line number of the bookmark. + /// + int LineNumber { get; } + + /// + /// Gets the image. + /// + ImageSource Image { get; } + + /// + /// Gets the Z-Order of the bookmark icon. + /// + int ZOrder { get; } + + /// + /// Handles the mouse down event. + /// + void MouseDown(MouseButtonEventArgs e); + + /// + /// Handles the mouse up event. + /// + void MouseUp(MouseButtonEventArgs e); + + /// + /// Gets whether this bookmark can be dragged around. + /// + bool CanDragDrop { get; } + + /// + /// Notifies the bookmark that it was dropped on the specified line. + /// + void Drop(int lineNumber); + } +} diff --git a/ILSpy/Bookmarks/MarkerBookmark.cs b/ILSpy/Bookmarks/MarkerBookmark.cs new file mode 100644 index 000000000..4a587b855 --- /dev/null +++ b/ILSpy/Bookmarks/MarkerBookmark.cs @@ -0,0 +1,21 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.ILSpy.AvalonEdit; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + public abstract class MarkerBookmark : BookmarkBase + { + public MarkerBookmark(MemberReference member, AstLocation location) : base(member, location) + { + } + + public ITextMarker Marker { get; set; } + + public abstract ITextMarker CreateMarker(ITextMarkerService markerService, int offset, int length); + } +} diff --git a/ILSpy/Bookmarks/MemberBookmark.cs b/ILSpy/Bookmarks/MemberBookmark.cs new file mode 100644 index 000000000..27ff141cb --- /dev/null +++ b/ILSpy/Bookmarks/MemberBookmark.cs @@ -0,0 +1,162 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; + +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.TypeSystem; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + /// + /// Bookmark used to give additional operations for class members. + /// Does not derive from SDBookmark because it is not stored in the central BookmarkManager, + /// but only in the document's BookmarkManager. + /// + public class MemberBookmark : IBookmark + { + AstNode node; + + public AstNode Node { + get { + return node; + } + } + + public MemberBookmark(AstNode node) + { + this.node = node; + } + + public virtual ImageSource Image { + get { + var attrNode = (AttributedNode)node; + if (node is FieldDeclaration) + return GetMemberOverlayedImage(attrNode, MemberIcon.Field); + + if (node is PropertyDeclaration) + return GetMemberOverlayedImage(attrNode, MemberIcon.Property); + + if (node is EventDeclaration) + return GetMemberOverlayedImage(attrNode, MemberIcon.Event); + + if (node is IndexerDeclaration) + return GetMemberOverlayedImage(attrNode, MemberIcon.Indexer); + + if (node is OperatorDeclaration) + return GetMemberOverlayedImage(attrNode, MemberIcon.Operator); + + return GetMemberOverlayedImage(attrNode, MemberIcon.Method); + } + } + + ImageSource GetMemberOverlayedImage(AttributedNode attrNode, MemberIcon icon) + { + switch (attrNode.Modifiers & Modifiers.VisibilityMask) { + case Modifiers.Protected: + return Images.GetIcon(icon, AccessOverlayIcon.Protected, (attrNode.Modifiers & Modifiers.Static) == Modifiers.Static); + case Modifiers.Private: + return Images.GetIcon(icon, AccessOverlayIcon.Private, (attrNode.Modifiers & Modifiers.Static) == Modifiers.Static); + case Modifiers.Internal: + return Images.GetIcon(icon, AccessOverlayIcon.Internal, (attrNode.Modifiers & Modifiers.Static) == Modifiers.Static); + } + + return Images.GetIcon(icon, AccessOverlayIcon.Public, (attrNode.Modifiers & Modifiers.Static) == Modifiers.Static); + } + + public int LineNumber { + get { + var t = node.Annotation>(); + if (t != null) + return t.Item1; + return 0; + } + } + + public virtual void MouseDown(MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left) { + // TODO: menu items + } + } + + public virtual void MouseUp(MouseButtonEventArgs e) + { + } + + int IBookmark.ZOrder { + get { return -10; } + } + + bool IBookmark.CanDragDrop { + get { return false; } + } + + void IBookmark.Drop(int lineNumber) + { + throw new NotSupportedException(); + } + } + + public class TypeBookmark : MemberBookmark + { + public TypeBookmark(AstNode node) : base (node) + { + } + + public override ImageSource Image { + get { + var attrNode = (AttributedNode)Node; + + if (Node is DelegateDeclaration) + return GetTypeOverlayedImage(attrNode, TypeIcon.Delegate); + + if (Node is TypeDeclaration) { + var n = Node as TypeDeclaration; + switch (n.ClassType) + { + case ClassType.Delegate: + return GetTypeOverlayedImage(attrNode, TypeIcon.Delegate); + case ClassType.Enum: + return GetTypeOverlayedImage(attrNode, TypeIcon.Enum); + case ClassType.Struct: + return GetTypeOverlayedImage(attrNode, TypeIcon.Struct); + case ClassType.Interface: + return GetTypeOverlayedImage(attrNode, TypeIcon.Interface); + } + } + + return GetTypeOverlayedImage(attrNode, TypeIcon.Class); + } + } + + public override void MouseDown(MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left) { + // TODO: menu items + } + } + + public override void MouseUp(MouseButtonEventArgs e) + { + } + + ImageSource GetTypeOverlayedImage(AttributedNode attrNode, TypeIcon icon) + { + switch (attrNode.Modifiers & Modifiers.VisibilityMask) { + case Modifiers.Protected: + return Images.GetIcon(icon, AccessOverlayIcon.Protected); + case Modifiers.Private: + return Images.GetIcon(icon, AccessOverlayIcon.Private); + case Modifiers.Internal: + return Images.GetIcon(icon, AccessOverlayIcon.Internal); + } + + return Images.GetIcon(icon, AccessOverlayIcon.Public); + } + } +} diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index 50afed4ea..c0fee6954 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -23,11 +23,11 @@ using System.ComponentModel.Composition; using System.IO; using System.Linq; using System.Resources; -using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xaml; using System.Xml; + using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast.Transforms; @@ -91,6 +91,7 @@ namespace ICSharpCode.ILSpy AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true); codeDomBuilder.AddMethod(method); RunTransformsAndGenerateCode(codeDomBuilder, output, options); + NotifyDecompilationFinished(codeDomBuilder); } public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) @@ -99,6 +100,7 @@ namespace ICSharpCode.ILSpy AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true); codeDomBuilder.AddProperty(property); RunTransformsAndGenerateCode(codeDomBuilder, output, options); + NotifyDecompilationFinished(codeDomBuilder); } public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) @@ -107,6 +109,7 @@ namespace ICSharpCode.ILSpy AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true); codeDomBuilder.AddField(field); RunTransformsAndGenerateCode(codeDomBuilder, output, options); + NotifyDecompilationFinished(codeDomBuilder); } public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) @@ -115,6 +118,7 @@ namespace ICSharpCode.ILSpy AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true); codeDomBuilder.AddEvent(ev); RunTransformsAndGenerateCode(codeDomBuilder, output, options); + NotifyDecompilationFinished(codeDomBuilder); } public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) @@ -122,6 +126,7 @@ namespace ICSharpCode.ILSpy AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type); codeDomBuilder.AddType(type); RunTransformsAndGenerateCode(codeDomBuilder, output, options); + NotifyDecompilationFinished(codeDomBuilder); } void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options) @@ -149,6 +154,7 @@ namespace ICSharpCode.ILSpy codeDomBuilder.GenerateCode(output); } } + OnDecompilationFinished(null); } #region WriteProjectFile diff --git a/ILSpy/ILLanguage.cs b/ILSpy/ILLanguage.cs index e77497fa5..5033635ff 100644 --- a/ILSpy/ILLanguage.cs +++ b/ILSpy/ILLanguage.cs @@ -18,8 +18,6 @@ using System; using System.Collections.Generic; -using System.IO; - using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Disassembler; using Mono.Cecil; @@ -52,32 +50,43 @@ namespace ICSharpCode.ILSpy public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { - new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleMethod(method); + var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); + dis.DisassembleMethod(method); + NotifyDecompilationFinished(dis); } public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) { - new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleField(field); + var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); + dis.DisassembleField(field); + NotifyDecompilationFinished(dis); } public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) { - new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleProperty(property); + var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); + dis.DisassembleProperty(property); + NotifyDecompilationFinished(dis); } public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) { - new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleEvent(ev); + var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); + dis.DisassembleEvent(ev); + NotifyDecompilationFinished(dis); } public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) { - new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleType(type); + var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); + dis.DisassembleType(type); + NotifyDecompilationFinished(dis); } public override void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) { new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleNamespace(nameSpace, types); + OnDecompilationFinished(null); } public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) @@ -86,6 +95,7 @@ namespace ICSharpCode.ILSpy output.WriteLine(); new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).WriteAssemblyHeader(assembly.AssemblyDefinition); + OnDecompilationFinished(null); } public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index e14465833..8452df456 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -93,7 +93,18 @@ + + + + + + + + + + + @@ -304,6 +315,9 @@ ICSharpCode.TreeView - + + + + \ No newline at end of file diff --git a/ILSpy/Language.cs b/ILSpy/Language.cs index 539de51c8..0a2523d17 100644 --- a/ILSpy/Language.cs +++ b/ILSpy/Language.cs @@ -17,20 +17,57 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel.Composition.Hosting; using System.Linq; + using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Ast; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.ILAst; +using ICSharpCode.NRefactory.CSharp; using Mono.Cecil; namespace ICSharpCode.ILSpy { + /// + /// Decompilation event arguments. + /// + public sealed class DecompileEventArgs : EventArgs + { + /// + /// Gets ot sets the code mappings + /// + public Dictionary> CodeMappings { get; set; } + + /// + /// Gets or sets the local variables. + /// + public ConcurrentDictionary> LocalVariables { get; set; } + + /// + /// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc) + /// + public Dictionary DecompiledMemberReferences { get; set; } + + /// + /// Gets (or internal sets) the AST nodes. + /// + public IEnumerable AstNodes { get; internal set; } + } + /// /// Base class for language-specific decompiler implementations. /// public abstract class Language { + /// + /// Decompile finished event. + /// + public event EventHandler DecompileFinished; + /// /// Gets the name of the language (as shown in the UI) /// @@ -82,6 +119,7 @@ namespace ICSharpCode.ILSpy public virtual void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, nameSpace); + OnDecompilationFinished(null); } public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) @@ -137,6 +175,40 @@ namespace ICSharpCode.ILSpy { return true; } + + protected virtual void OnDecompilationFinished(DecompileEventArgs e) + { + if (DecompileFinished != null) { + DecompileFinished(this, e); + } + } + + protected void NotifyDecompilationFinished(BaseCodeMappings b) + { + if (b is AstBuilder) { + var builder = b as AstBuilder; + OnDecompilationFinished(new DecompileEventArgs { + CodeMappings = builder.CodeMappings, + LocalVariables = builder.LocalVariables, + DecompiledMemberReferences = builder.DecompiledMemberReferences, + AstNodes = builder.CompilationUnit.GetNodesWithLineNumbers(n => + n is TypeDeclaration || n is DelegateDeclaration || + n is FieldDeclaration || n is PropertyDeclaration || + n is EventDeclaration || n is MethodDeclaration || + n is ConstructorDeclaration || + n is IndexerDeclaration || n is OperatorDeclaration) + }); + } + + if (b is ReflectionDisassembler) { + var dis = b as ReflectionDisassembler; + OnDecompilationFinished(new DecompileEventArgs { + CodeMappings = dis.CodeMappings, + DecompiledMemberReferences = dis.DecompiledMemberReferences, + AstNodes = null // TODO: how can I find the AST nodes? + }); + } + } } public static class Languages @@ -174,4 +246,4 @@ namespace ICSharpCode.ILSpy return AllLanguages.FirstOrDefault(l => l.Name == name) ?? AllLanguages.First(); } } -} +} \ No newline at end of file diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 1241037b1..2d355e006 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -34,12 +34,14 @@ using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Threading; using System.Xml; + using ICSharpCode.AvalonEdit; using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting.Xshd; using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AvalonEdit; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.XmlDoc; using ICSharpCode.NRefactory.Documentation; @@ -64,6 +66,10 @@ namespace ICSharpCode.ILSpy.TextView DefinitionLookup definitionLookup; CancellationTokenSource currentCancellationTokenSource; + readonly IconBarManager manager; + readonly IconBarMargin iconMargin; + readonly TextMarkerService textMarkerService; + #region Constructor public DecompilerTextView() { @@ -85,6 +91,16 @@ namespace ICSharpCode.ILSpy.TextView textEditor.Options.RequireControlModifierForHyperlinkClick = false; textEditor.TextArea.TextView.MouseHover += TextViewMouseHover; textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped; + + // add marker service & margin + iconMargin = new IconBarMargin((manager = new IconBarManager())); + textMarkerService = new TextMarkerService(); + textMarkerService.CodeEditor = textEditor; + textEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService); + textEditor.TextArea.TextView.LineTransformers.Add(textMarkerService); + + textEditor.TextArea.LeftMargins.Add(iconMargin); + textEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); }; } #endregion @@ -339,11 +355,13 @@ namespace ICSharpCode.ILSpy.TextView output.WriteLine(ex.ToString()); } ShowOutput(output); + } finally { + iconMargin.InvalidateVisual(); } }); } - static Task DecompileAsync(DecompilationContext context, int outputLengthLimit) + Task DecompileAsync(DecompilationContext context, int outputLengthLimit) { Debug.WriteLine("Start decompilation of {0} tree nodes", context.TreeNodes.Length); @@ -388,9 +406,10 @@ namespace ICSharpCode.ILSpy.TextView return tcs.Task; } - static void DecompileNodes(DecompilationContext context, ITextOutput textOutput) + void DecompileNodes(DecompilationContext context, ITextOutput textOutput) { var nodes = context.TreeNodes; + context.Language.DecompileFinished += Language_DecompileFinished; for (int i = 0; i < nodes.Length; i++) { if (i > 0) textOutput.WriteLine(); @@ -398,6 +417,20 @@ namespace ICSharpCode.ILSpy.TextView context.Options.CancellationToken.ThrowIfCancellationRequested(); nodes[i].Decompile(context.Language, textOutput, context.Options); } + context.Language.DecompileFinished -= Language_DecompileFinished; + } + + void Language_DecompileFinished(object sender, DecompileEventArgs e) + { + if (e != null) { + manager.UpdateClassMemberBookmarks(e.AstNodes); + if (iconMargin.DecompiledMembers == null) { + iconMargin.DecompiledMembers = new List(); + } + iconMargin.DecompiledMembers.AddRange(e.DecompiledMemberReferences.Values.AsEnumerable()); + } else { + manager.UpdateClassMemberBookmarks(null); + } } #endregion diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs index 9a5047719..94e168140 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs @@ -25,6 +25,9 @@ // THE SOFTWARE. using System; using System.Collections.Generic; +using System.Linq; + +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp { @@ -101,6 +104,21 @@ namespace ICSharpCode.NRefactory.CSharp } } + /// + /// Gets all nodes in that are satisfing a predicate. + /// + /// Predicate to filter the nodes. + /// + public IEnumerable GetNodesWithLineNumbers(Predicate predicate) + { + if (predicate == null) + throw new ArgumentNullException("predicate"); + + return TreeTraversal + .PreOrder((AstNode)this, n => n.Children) + .Where(n => predicate(n) && n.Annotation>() != null); + } + public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitCompilationUnit (this, data); From 6cbd5519ff60080be366d3e50d6d43e19e6dc0d1 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Tue, 17 May 2011 18:44:05 +0300 Subject: [PATCH 03/57] Use AttributedNode; Fix enums --- ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs | 4 +--- ILSpy/Bookmarks/MemberBookmark.cs | 3 +++ ILSpy/Language.cs | 9 ++------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index f31455d73..bba6c1c4a 100644 --- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -145,9 +145,7 @@ namespace ICSharpCode.Decompiler.Ast } // definitions of types and their members - Predicate predicate = n => n is TypeDeclaration || n is DelegateDeclaration || - n is FieldDeclaration || n is PropertyDeclaration || n is EventDeclaration ||n is MethodDeclaration || n is ConstructorDeclaration || - n is IndexerDeclaration || n is OperatorDeclaration; + Predicate predicate = n => n is AttributedNode; if (predicate(node)) { var n = node as AttributedNode; diff --git a/ILSpy/Bookmarks/MemberBookmark.cs b/ILSpy/Bookmarks/MemberBookmark.cs index 27ff141cb..fb8b2ec3b 100644 --- a/ILSpy/Bookmarks/MemberBookmark.cs +++ b/ILSpy/Bookmarks/MemberBookmark.cs @@ -35,6 +35,9 @@ namespace ICSharpCode.ILSpy.Bookmarks public virtual ImageSource Image { get { var attrNode = (AttributedNode)node; + if (node is EnumMemberDeclaration) + return GetMemberOverlayedImage(attrNode, MemberIcon.EnumValue); + if (node is FieldDeclaration) return GetMemberOverlayedImage(attrNode, MemberIcon.Field); diff --git a/ILSpy/Language.cs b/ILSpy/Language.cs index 0a2523d17..9bdb4fc62 100644 --- a/ILSpy/Language.cs +++ b/ILSpy/Language.cs @@ -191,12 +191,7 @@ namespace ICSharpCode.ILSpy CodeMappings = builder.CodeMappings, LocalVariables = builder.LocalVariables, DecompiledMemberReferences = builder.DecompiledMemberReferences, - AstNodes = builder.CompilationUnit.GetNodesWithLineNumbers(n => - n is TypeDeclaration || n is DelegateDeclaration || - n is FieldDeclaration || n is PropertyDeclaration || - n is EventDeclaration || n is MethodDeclaration || - n is ConstructorDeclaration || - n is IndexerDeclaration || n is OperatorDeclaration) + AstNodes = builder.CompilationUnit.GetNodesWithLineNumbers(n => n is AttributedNode) }); } @@ -205,7 +200,7 @@ namespace ICSharpCode.ILSpy OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings, DecompiledMemberReferences = dis.DecompiledMemberReferences, - AstNodes = null // TODO: how can I find the AST nodes? + AstNodes = null // TODO: how can I find the nodes with line numbers from dis? }); } } From 5cf243125cfba2c6c2d0276ffaf69eb6bfda768d Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Tue, 17 May 2011 20:35:47 +0300 Subject: [PATCH 04/57] get AST nodes locally --- ILSpy/Language.cs | 14 ++++++++++---- .../CSharp/Ast/CompilationUnit.cs | 15 --------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/ILSpy/Language.cs b/ILSpy/Language.cs index 9bdb4fc62..4cb85722f 100644 --- a/ILSpy/Language.cs +++ b/ILSpy/Language.cs @@ -28,6 +28,7 @@ using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.ILAst; using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.Utils; using Mono.Cecil; namespace ICSharpCode.ILSpy @@ -40,17 +41,17 @@ namespace ICSharpCode.ILSpy /// /// Gets ot sets the code mappings /// - public Dictionary> CodeMappings { get; set; } + public Dictionary> CodeMappings { get; internal set; } /// /// Gets or sets the local variables. /// - public ConcurrentDictionary> LocalVariables { get; set; } + public ConcurrentDictionary> LocalVariables { get; internal set; } /// /// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc) /// - public Dictionary DecompiledMemberReferences { get; set; } + public Dictionary DecompiledMemberReferences { get; internal set; } /// /// Gets (or internal sets) the AST nodes. @@ -187,11 +188,16 @@ namespace ICSharpCode.ILSpy { if (b is AstBuilder) { var builder = b as AstBuilder; + + var nodes = TreeTraversal + .PreOrder((AstNode)builder.CompilationUnit, n => n.Children) + .Where(n => n is AttributedNode && n.Annotation>() != null); + OnDecompilationFinished(new DecompileEventArgs { CodeMappings = builder.CodeMappings, LocalVariables = builder.LocalVariables, DecompiledMemberReferences = builder.DecompiledMemberReferences, - AstNodes = builder.CompilationUnit.GetNodesWithLineNumbers(n => n is AttributedNode) + AstNodes = nodes }); } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs index 94e168140..6053d6848 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs @@ -104,21 +104,6 @@ namespace ICSharpCode.NRefactory.CSharp } } - /// - /// Gets all nodes in that are satisfing a predicate. - /// - /// Predicate to filter the nodes. - /// - public IEnumerable GetNodesWithLineNumbers(Predicate predicate) - { - if (predicate == null) - throw new ArgumentNullException("predicate"); - - return TreeTraversal - .PreOrder((AstNode)this, n => n.Children) - .Where(n => predicate(n) && n.Annotation>() != null); - } - public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitCompilationUnit (this, data); From 012c024011986ab4021d1e89a7b734a51351ec24 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Wed, 18 May 2011 11:25:01 +0300 Subject: [PATCH 05/57] Add context menu and actions extensibility; add analyze as default --- ILSpy/AvalonEdit/IconBarMargin.cs | 6 +- ILSpy/Bookmarks/BookmarkContextMenuEntry.cs | 189 ++++++++++++++++++++ ILSpy/Bookmarks/Commands.cs | 63 +++++++ ILSpy/Bookmarks/MemberBookmark.cs | 14 -- ILSpy/ILSpy.csproj | 2 + ILSpy/TextView/DecompilerTextView.cs | 4 + 6 files changed, 263 insertions(+), 15 deletions(-) create mode 100644 ILSpy/Bookmarks/BookmarkContextMenuEntry.cs create mode 100644 ILSpy/Bookmarks/Commands.cs diff --git a/ILSpy/AvalonEdit/IconBarMargin.cs b/ILSpy/AvalonEdit/IconBarMargin.cs index f0f83848d..36ac3817a 100644 --- a/ILSpy/AvalonEdit/IconBarMargin.cs +++ b/ILSpy/AvalonEdit/IconBarMargin.cs @@ -32,6 +32,10 @@ namespace ICSharpCode.ILSpy.AvalonEdit this.manager = manager; } + public IconBarManager Manager { + get { return manager; } + } + public IList DecompiledMembers { get; set; } public virtual void Dispose() @@ -181,7 +185,7 @@ namespace ICSharpCode.ILSpy.AvalonEdit e.Handled = true; } - int GetLineFromMousePosition(MouseEventArgs e) + internal int GetLineFromMousePosition(MouseEventArgs e) { ICSharpCode.AvalonEdit.Rendering.TextView textView = this.TextView; if (textView == null) diff --git a/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs b/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs new file mode 100644 index 000000000..e47c4f68e --- /dev/null +++ b/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs @@ -0,0 +1,189 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.ComponentModel.Composition; +using System.Linq; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; + +using ICSharpCode.ILSpy.AvalonEdit; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + #region Context menu extensibility + public interface IBookmarkContextMenuEntry + { + bool IsVisible(IBookmark[] bookmarks); + bool IsEnabled(IBookmark[] bookmarks); + void Execute(IBookmark[] bookmarks); + } + + public interface IBookmarkContextMenuEntryMetadata + { + string Icon { get; } + string Header { get; } + string Category { get; } + + double Order { get; } + } + + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] + public class ExportBookmarkContextMenuEntryAttribute : ExportAttribute, IBookmarkContextMenuEntryMetadata + { + public ExportBookmarkContextMenuEntryAttribute() + : base(typeof(IBookmarkContextMenuEntry)) + { + } + + public string Icon { get; set; } + public string Header { get; set; } + public string Category { get; set; } + public double Order { get; set; } + } + #endregion + + #region Actions (simple clicks) - this will be used for creating bookmarks (e.g. Breakpoint bookmarks) + + public interface IBookmarkActionEntry + { + bool IsEnabled(); + void Execute(); + } + + public interface IBookmarkActionMetadata + { + string Category { get; } + + double Order { get; } + } + + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] + public class ExportBookmarkActionEntryAttribute : ExportAttribute, IBookmarkActionMetadata + { + public ExportBookmarkActionEntryAttribute() + : base(typeof(IBookmarkActionEntry)) + { + } + + public string Icon { get; set; } + public string Header { get; set; } + public string Category { get; set; } + public double Order { get; set; } + } + + #endregion + + internal class BookmarkContextMenuProvider + { + /// + /// Enables extensible context menu support for the specified tree view. + /// + public static void Add(IconBarMargin margin) + { + var provider = new BookmarkContextMenuProvider(margin); + margin.MouseDown += provider.MouseDown; + margin.ContextMenu = new ContextMenu(); + } + + readonly IconBarMargin margin; + + [ImportMany(typeof(IBookmarkContextMenuEntry))] + Lazy[] contextEntries = null; + + [ImportMany(typeof(IBookmarkActionEntry))] + Lazy[] actionEntries = null; + + private BookmarkContextMenuProvider(IconBarMargin margin) + { + this.margin = margin; + App.CompositionContainer.ComposeParts(this); + } + + void MouseDown(object sender, MouseButtonEventArgs e) + { + int line = margin.GetLineFromMousePosition(e); + + var bookmarks = margin.Manager.Bookmarks.ToArray(); + if (bookmarks.Length == 0) { + // don't show the menu + e.Handled = true; + this.margin.ContextMenu = null; + return; + } + + if (e.LeftButton == MouseButtonState.Pressed) { + foreach (var category in actionEntries.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Category)) { + foreach (var entryPair in category) { + IBookmarkActionEntry entry = entryPair.Value; + + if (entryPair.Value.IsEnabled()) { + entry.Execute(); + } + } + } + } + + if (e.RightButton == MouseButtonState.Pressed) { + // check if we are on a Member + var bookmark = bookmarks.FirstOrDefault(b => b.LineNumber == line); + if (bookmark == null) { + // don't show the menu + e.Handled = true; + this.margin.ContextMenu = null; + return; + } + + var marks = new[] { bookmark }; + ContextMenu menu = new ContextMenu(); + foreach (var category in contextEntries.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Category)) { + if (menu.Items.Count > 0) { + menu.Items.Add(new Separator()); + } + foreach (var entryPair in category) { + IBookmarkContextMenuEntry entry = entryPair.Value; + if (entry.IsVisible(marks)) { + MenuItem menuItem = new MenuItem(); + menuItem.Header = entryPair.Metadata.Header; + if (!string.IsNullOrEmpty(entryPair.Metadata.Icon)) { + menuItem.Icon = new Image { + Width = 16, + Height = 16, + Source = Images.LoadImage(entry, entryPair.Metadata.Icon) + }; + } + if (entryPair.Value.IsEnabled(marks)) { + menuItem.Click += delegate { entry.Execute(marks); }; + } else + menuItem.IsEnabled = false; + menu.Items.Add(menuItem); + } + } + } + if (menu.Items.Count > 0) + margin.ContextMenu = menu; + else + // hide the context menu. + e.Handled = true; + } + } + } +} diff --git a/ILSpy/Bookmarks/Commands.cs b/ILSpy/Bookmarks/Commands.cs new file mode 100644 index 000000000..40d71eef0 --- /dev/null +++ b/ILSpy/Bookmarks/Commands.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.ILSpy.TreeNodes.Analyzer; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + [ExportBookmarkContextMenuEntry(Header = "Analyze", Icon = "images/Search.png", Category="Default")] + internal sealed class AnalyzeBookmarkEntry : IBookmarkContextMenuEntry + { + public bool IsVisible(IBookmark[] marks) + { + return true; + } + + public bool IsEnabled(IBookmark[] marks) + { + return true; + } + + public void Execute(IBookmark[] marks) + { + foreach (var node in marks) { + if (!(node is MemberBookmark)) + continue; + + var member = (node as MemberBookmark).Node.Annotation(); + TypeDefinition type = member as TypeDefinition; + if (type != null) + AnalyzerTreeView.Instance.Show(new AnalyzedTypeTreeNode(type)); + FieldDefinition field = member as FieldDefinition; + if (field != null) + AnalyzerTreeView.Instance.Show(new AnalyzedFieldTreeNode(field)); + MethodDefinition method = member as MethodDefinition; + if (method != null) + AnalyzerTreeView.Instance.Show(new AnalyzedMethodTreeNode(method)); + var propertyAnalyzer = AnalyzedPropertyTreeNode.TryCreateAnalyzer(member); + if (propertyAnalyzer != null) + AnalyzerTreeView.Instance.Show(propertyAnalyzer); + var eventAnalyzer = AnalyzedEventTreeNode.TryCreateAnalyzer(member); + if (eventAnalyzer != null) + AnalyzerTreeView.Instance.Show(eventAnalyzer); + } + } + } +} diff --git a/ILSpy/Bookmarks/MemberBookmark.cs b/ILSpy/Bookmarks/MemberBookmark.cs index fb8b2ec3b..9a0996095 100644 --- a/ILSpy/Bookmarks/MemberBookmark.cs +++ b/ILSpy/Bookmarks/MemberBookmark.cs @@ -82,9 +82,6 @@ namespace ICSharpCode.ILSpy.Bookmarks public virtual void MouseDown(MouseButtonEventArgs e) { - if (e.ChangedButton == MouseButton.Left) { - // TODO: menu items - } } public virtual void MouseUp(MouseButtonEventArgs e) @@ -137,17 +134,6 @@ namespace ICSharpCode.ILSpy.Bookmarks } } - public override void MouseDown(MouseButtonEventArgs e) - { - if (e.ChangedButton == MouseButton.Left) { - // TODO: menu items - } - } - - public override void MouseUp(MouseButtonEventArgs e) - { - } - ImageSource GetTypeOverlayedImage(AttributedNode attrNode, TypeIcon icon) { switch (attrNode.Modifiers & Modifiers.VisibilityMask) { diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 8452df456..7579f9c05 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -100,8 +100,10 @@ + + diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 2d355e006..66028707d 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -42,6 +42,7 @@ using ICSharpCode.AvalonEdit.Highlighting.Xshd; using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; using ICSharpCode.ILSpy.AvalonEdit; +using ICSharpCode.ILSpy.Bookmarks; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.XmlDoc; using ICSharpCode.NRefactory.Documentation; @@ -101,6 +102,9 @@ namespace ICSharpCode.ILSpy.TextView textEditor.TextArea.LeftMargins.Add(iconMargin); textEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); }; + + // Bookmarks context menu + BookmarkContextMenuProvider.Add(iconMargin); } #endregion From 6846da89f7a117b6fff38c3abcbab5256eae5586 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Wed, 18 May 2011 11:30:25 +0300 Subject: [PATCH 06/57] Rename and move. --- .../IconMarginActionsProvider.cs} | 10 +++++----- ILSpy/Bookmarks/Commands.cs | 1 + ILSpy/ILSpy.csproj | 2 +- ILSpy/TextView/DecompilerTextView.cs | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) rename ILSpy/{Bookmarks/BookmarkContextMenuEntry.cs => AvalonEdit/IconMarginActionsProvider.cs} (95%) diff --git a/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs b/ILSpy/AvalonEdit/IconMarginActionsProvider.cs similarity index 95% rename from ILSpy/Bookmarks/BookmarkContextMenuEntry.cs rename to ILSpy/AvalonEdit/IconMarginActionsProvider.cs index e47c4f68e..3a7cb9796 100644 --- a/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs +++ b/ILSpy/AvalonEdit/IconMarginActionsProvider.cs @@ -23,9 +23,9 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; -using ICSharpCode.ILSpy.AvalonEdit; +using ICSharpCode.ILSpy.Bookmarks; -namespace ICSharpCode.ILSpy.Bookmarks +namespace ICSharpCode.ILSpy.AvalonEdit { #region Context menu extensibility public interface IBookmarkContextMenuEntry @@ -92,14 +92,14 @@ namespace ICSharpCode.ILSpy.Bookmarks #endregion - internal class BookmarkContextMenuProvider + internal class IconMarginActionsProvider { /// /// Enables extensible context menu support for the specified tree view. /// public static void Add(IconBarMargin margin) { - var provider = new BookmarkContextMenuProvider(margin); + var provider = new IconMarginActionsProvider(margin); margin.MouseDown += provider.MouseDown; margin.ContextMenu = new ContextMenu(); } @@ -112,7 +112,7 @@ namespace ICSharpCode.ILSpy.Bookmarks [ImportMany(typeof(IBookmarkActionEntry))] Lazy[] actionEntries = null; - private BookmarkContextMenuProvider(IconBarMargin margin) + private IconMarginActionsProvider(IconBarMargin margin) { this.margin = margin; App.CompositionContainer.ComposeParts(this); diff --git a/ILSpy/Bookmarks/Commands.cs b/ILSpy/Bookmarks/Commands.cs index 40d71eef0..2e5dbd8b3 100644 --- a/ILSpy/Bookmarks/Commands.cs +++ b/ILSpy/Bookmarks/Commands.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using ICSharpCode.ILSpy.AvalonEdit; using ICSharpCode.ILSpy.TreeNodes.Analyzer; using Mono.Cecil; diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 7579f9c05..460ca4c90 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -95,12 +95,12 @@ + - diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 66028707d..85122e786 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -104,7 +104,7 @@ namespace ICSharpCode.ILSpy.TextView textEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); }; // Bookmarks context menu - BookmarkContextMenuProvider.Add(iconMargin); + IconMarginActionsProvider.Add(iconMargin); } #endregion From c81abc97abf78af14944417263b0b325cbf0da38 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Thu, 19 May 2011 22:09:23 +0300 Subject: [PATCH 07/57] add current column in the node annotation tuple --- ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs | 2 +- ICSharpCode.Decompiler/ITextOutput.cs | 1 + ICSharpCode.Decompiler/PlainTextOutput.cs | 10 +++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index bba6c1c4a..e4ab53351 100644 --- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -152,7 +152,7 @@ namespace ICSharpCode.Decompiler.Ast int c = 0; if (n != null) c = n.Attributes.Count; - node.AddAnnotation(Tuple.Create(output.CurrentLine + c, 0)); + node.AddAnnotation(Tuple.Create(output.CurrentLine + c, output.CurrentColumn)); } nodeStack.Push(node); diff --git a/ICSharpCode.Decompiler/ITextOutput.cs b/ICSharpCode.Decompiler/ITextOutput.cs index 1cced95f2..608a45c64 100644 --- a/ICSharpCode.Decompiler/ITextOutput.cs +++ b/ICSharpCode.Decompiler/ITextOutput.cs @@ -24,6 +24,7 @@ namespace ICSharpCode.Decompiler public interface ITextOutput { int CurrentLine { get; } + int CurrentColumn { get; } void Indent(); void Unindent(); diff --git a/ICSharpCode.Decompiler/PlainTextOutput.cs b/ICSharpCode.Decompiler/PlainTextOutput.cs index 7078b6785..9f7da9113 100644 --- a/ICSharpCode.Decompiler/PlainTextOutput.cs +++ b/ICSharpCode.Decompiler/PlainTextOutput.cs @@ -27,6 +27,7 @@ namespace ICSharpCode.Decompiler int indent; bool needsIndent; int lineNumber = 1; + int columnNumber = 1; public PlainTextOutput(TextWriter writer) { @@ -40,10 +41,14 @@ namespace ICSharpCode.Decompiler this.writer = new StringWriter(); } - public int CurrentLine { + public int CurrentLine { get { return lineNumber; } } + public int CurrentColumn { + get { return columnNumber; } + } + public override string ToString() { return writer.ToString(); @@ -65,6 +70,7 @@ namespace ICSharpCode.Decompiler needsIndent = false; for (int i = 0; i < indent; i++) { writer.Write('\t'); + columnNumber += 4; } } } @@ -73,12 +79,14 @@ namespace ICSharpCode.Decompiler { WriteIndent(); writer.Write(ch); + columnNumber++; } public void Write(string text) { WriteIndent(); writer.Write(text); + columnNumber += text.Length; } public void WriteLine() From 8824e9e8f147041d5d89778ba81a058657e837d0 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Thu, 19 May 2011 22:15:28 +0300 Subject: [PATCH 08/57] reset column number after new line --- ICSharpCode.Decompiler/PlainTextOutput.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/PlainTextOutput.cs b/ICSharpCode.Decompiler/PlainTextOutput.cs index 9f7da9113..86a28a5c8 100644 --- a/ICSharpCode.Decompiler/PlainTextOutput.cs +++ b/ICSharpCode.Decompiler/PlainTextOutput.cs @@ -23,6 +23,8 @@ namespace ICSharpCode.Decompiler { public sealed class PlainTextOutput : ITextOutput { + const int TAB_SIZE = 4; + readonly TextWriter writer; int indent; bool needsIndent; @@ -70,7 +72,7 @@ namespace ICSharpCode.Decompiler needsIndent = false; for (int i = 0; i < indent; i++) { writer.Write('\t'); - columnNumber += 4; + columnNumber += TAB_SIZE - 1; } } } @@ -94,6 +96,7 @@ namespace ICSharpCode.Decompiler lineNumber++; writer.WriteLine(); needsIndent = true; + columnNumber = TAB_SIZE * indent; } public void WriteDefinition(string text, object definition) From 6519982dedc6611c4246af07ead7bbfbafd91512 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Wed, 18 May 2011 12:59:00 +0300 Subject: [PATCH 09/57] small fix in summary --- ILSpy/AvalonEdit/IconMarginActionsProvider.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ILSpy/AvalonEdit/IconMarginActionsProvider.cs b/ILSpy/AvalonEdit/IconMarginActionsProvider.cs index 3a7cb9796..0854806af 100644 --- a/ILSpy/AvalonEdit/IconMarginActionsProvider.cs +++ b/ILSpy/AvalonEdit/IconMarginActionsProvider.cs @@ -95,7 +95,7 @@ namespace ICSharpCode.ILSpy.AvalonEdit internal class IconMarginActionsProvider { /// - /// Enables extensible context menu support for the specified tree view. + /// Enables extensible context menu support for the specified icon margin. /// public static void Add(IconBarMargin margin) { @@ -186,4 +186,6 @@ namespace ICSharpCode.ILSpy.AvalonEdit } } } + + } From 77786a3fdca917ca341e17f33c30edd399b793b6 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Fri, 20 May 2011 16:43:35 +0300 Subject: [PATCH 10/57] Insert icon bar at index 0. --- ILSpy/TextView/DecompilerTextView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 85122e786..3e00b99be 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -100,7 +100,7 @@ namespace ICSharpCode.ILSpy.TextView textEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService); textEditor.TextArea.TextView.LineTransformers.Add(textMarkerService); - textEditor.TextArea.LeftMargins.Add(iconMargin); + textEditor.TextArea.LeftMargins.Insert(0, iconMargin); textEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); }; // Bookmarks context menu From 6b449d5bf3914f8e91038b9affbadb367a39c6a2 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:12:49 +1000 Subject: [PATCH 11/57] Move resource tree nodes to separate folder. --- ILSpy/ILSpy.csproj | 7 ++++--- ILSpy/TreeNodes/{ => ResourceNodes}/ResourceEntryNode.cs | 0 ILSpy/TreeNodes/{ => ResourceNodes}/ResourceTreeNode.cs | 0 ILSpy/TreeNodes/{ => ResourceNodes}/XamlResourceNode.cs | 0 4 files changed, 4 insertions(+), 3 deletions(-) rename ILSpy/TreeNodes/{ => ResourceNodes}/ResourceEntryNode.cs (100%) rename ILSpy/TreeNodes/{ => ResourceNodes}/ResourceTreeNode.cs (100%) rename ILSpy/TreeNodes/{ => ResourceNodes}/XamlResourceNode.cs (100%) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 0bda1e382..1c7bcaadf 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -159,7 +159,7 @@ - + @@ -218,9 +218,9 @@ - + - + @@ -312,5 +312,6 @@ ICSharpCode.TreeView + \ No newline at end of file diff --git a/ILSpy/TreeNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs similarity index 100% rename from ILSpy/TreeNodes/ResourceEntryNode.cs rename to ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs diff --git a/ILSpy/TreeNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs similarity index 100% rename from ILSpy/TreeNodes/ResourceTreeNode.cs rename to ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs diff --git a/ILSpy/TreeNodes/XamlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs similarity index 100% rename from ILSpy/TreeNodes/XamlResourceNode.cs rename to ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs From 68fe9617ba5ca15f3ba78df864aedeb7af58887d Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:26:38 +1000 Subject: [PATCH 12/57] Split classes into separate files. --- .../ResourceNodes/IResourceNodeFactory.cs | 33 ++++++++ .../ResourceNodes/ResourceTreeNode.cs | 65 ++------------- .../ResourceNodes/ResourcesFileTreeNode.cs | 79 +++++++++++++++++++ 3 files changed, 117 insertions(+), 60 deletions(-) create mode 100644 ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs create mode 100644 ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs diff --git a/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs b/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs new file mode 100644 index 000000000..49d5f4893 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs @@ -0,0 +1,33 @@ +// 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.IO; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + /// + /// This interface allows plugins to create custom nodes for resources. + /// + public interface IResourceNodeFactory + { + ILSpyTreeNode CreateNode(Resource resource); + ILSpyTreeNode CreateNode(string key, Stream data); + } +} diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs index 5e79845ba..aecfcc6a3 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs @@ -34,6 +34,10 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { + /// + /// This is the default resource entry tree node, which is used if no specific + /// exists for the given resource type. + /// public class ResourceTreeNode : ILSpyTreeNode { Resource r; @@ -132,63 +136,4 @@ namespace ICSharpCode.ILSpy.TreeNodes return result ?? new ResourceTreeNode(resource); } } - - /// - /// This interface allows plugins to create custom nodes for resources. - /// - public interface IResourceNodeFactory - { - ILSpyTreeNode CreateNode(Resource resource); - ILSpyTreeNode CreateNode(string key, Stream data); - } - - [Export(typeof(IResourceNodeFactory))] - sealed class ResourcesFileTreeNodeFactory : IResourceNodeFactory - { - public ILSpyTreeNode CreateNode(Resource resource) - { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null && er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { - return new ResourcesFileTreeNode(er); - } - return null; - } - - public ILSpyTreeNode CreateNode(string key, Stream data) - { - return null; - } - } - - sealed class ResourcesFileTreeNode : ResourceTreeNode - { - public ResourcesFileTreeNode(EmbeddedResource er) : base(er) - { - this.LazyLoading = true; - } - - public override object Icon - { - get { return Images.ResourceResourcesFile; } - } - - protected override void LoadChildren() - { - EmbeddedResource er = this.Resource as EmbeddedResource; - if (er != null) { - Stream s = er.GetResourceStream(); - s.Position = 0; - ResourceReader reader; - try { - reader = new ResourceReader(s); - } catch (ArgumentException) { - return; - } - foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { - if (entry.Value is Stream) - Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value)); - } - } - } - } -} +} \ No newline at end of file diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs new file mode 100644 index 000000000..0397841a0 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs @@ -0,0 +1,79 @@ +// 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; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Resources; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + [Export(typeof(IResourceNodeFactory))] + sealed class ResourcesFileTreeNodeFactory : IResourceNodeFactory + { + public ILSpyTreeNode CreateNode(Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null && er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { + return new ResourcesFileTreeNode(er); + } + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + return null; + } + } + + sealed class ResourcesFileTreeNode : ResourceTreeNode + { + public ResourcesFileTreeNode(EmbeddedResource er) + : base(er) + { + this.LazyLoading = true; + } + + public override object Icon + { + get { return Images.ResourceResourcesFile; } + } + + protected override void LoadChildren() + { + EmbeddedResource er = this.Resource as EmbeddedResource; + if (er != null) { + Stream s = er.GetResourceStream(); + s.Position = 0; + ResourceReader reader; + try { + reader = new ResourceReader(s); + } + catch (ArgumentException) { + return; + } + foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) + if (entry.Value is Stream) + Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value)); + } + } + } +} From 311a5bb2647408d75279053489534cdd6963a8c8 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:29:21 +1000 Subject: [PATCH 13/57] Tidied 'using' statements. --- ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs index 43638064d..e4b165680 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs @@ -17,14 +17,10 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; using System.ComponentModel.Composition; +using System.IO; using System.Windows.Controls; using System.Windows.Media.Imaging; -using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Decompiler; using ICSharpCode.ILSpy.TextView; using Microsoft.Win32; From 43e97197e1115fdf75e8161f9482090f05f61b1c Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:31:30 +1000 Subject: [PATCH 14/57] Moved BamlResourceEntryNode class to own file in ResourceNodes folder. --- ILSpy/BamlDecompiler.cs | 81 -------------- ILSpy/ILSpy.csproj | 3 + .../ResourceNodes/BamlResourceEntryNode.cs | 104 ++++++++++++++++++ 3 files changed, 107 insertions(+), 81 deletions(-) create mode 100644 ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs diff --git a/ILSpy/BamlDecompiler.cs b/ILSpy/BamlDecompiler.cs index 07c60b13e..19341812f 100644 --- a/ILSpy/BamlDecompiler.cs +++ b/ILSpy/BamlDecompiler.cs @@ -361,85 +361,4 @@ namespace ICSharpCode.ILSpy.Baml } } } - - [Export(typeof(IResourceNodeFactory))] - sealed class BamlResourceNodeFactory : IResourceNodeFactory - { - public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) - { - return null; - } - - public ILSpyTreeNode CreateNode(string key, Stream data) - { - if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) - return new BamlResourceEntryNode(key, data); - else - return null; - } - } - - sealed class BamlResourceEntryNode : ResourceEntryNode - { - public BamlResourceEntryNode(string key, Stream data) : base(key, data) - { - } - - internal override bool View(DecompilerTextView textView) - { - AvalonEditTextOutput output = new AvalonEditTextOutput(); - IHighlightingDefinition highlighting = null; - - textView.RunWithCancellation( - token => Task.Factory.StartNew( - () => { - try { - if (LoadBaml(output)) - highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); - } catch (Exception ex) { - output.Write(ex.ToString()); - } - return output; - }), - t => textView.ShowNode(t.Result, this, highlighting) - ); - return true; - } - - bool LoadBaml(AvalonEditTextOutput output) - { - var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; - - AppDomain bamlDecompilerAppDomain = null; - try { - BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName); - - MemoryStream bamlStream = new MemoryStream(); - Data.Position = 0; - Data.CopyTo(bamlStream); - - output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm))); - return true; - } finally { - if (bamlDecompilerAppDomain != null) - AppDomain.Unload(bamlDecompilerAppDomain); - } - } - - public static BamlDecompiler CreateBamlDecompilerInAppDomain(ref AppDomain appDomain, string assemblyFileName) - { - if (appDomain == null) { - // Construct and initialize settings for a second AppDomain. - AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup(); -// bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName); - bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false; - bamlDecompilerAppDomainSetup.DisallowCodeDownload = true; - bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; - - // Create the second AppDomain. - appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup); - } - return (BamlDecompiler)appDomain.CreateInstanceAndUnwrap(typeof(BamlDecompiler).Assembly.FullName, typeof(BamlDecompiler).FullName); - } - } } \ No newline at end of file diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 1c7bcaadf..0fd9f90e8 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -94,6 +94,7 @@ + @@ -159,6 +160,8 @@ + + diff --git a/ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs new file mode 100644 index 000000000..9bb46ba0a --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs @@ -0,0 +1,104 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.TreeNodes; + +namespace ICSharpCode.ILSpy.Baml +{ + [Export(typeof(IResourceNodeFactory))] + sealed class BamlResourceNodeFactory : IResourceNodeFactory + { + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) + return new BamlResourceEntryNode(key, data); + else + return null; + } + } + + sealed class BamlResourceEntryNode : ResourceEntryNode + { + public BamlResourceEntryNode(string key, Stream data) + : base(key, data) + { + } + + internal override bool View(DecompilerTextView textView) + { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + IHighlightingDefinition highlighting = null; + textView.RunWithCancellation(token => Task.Factory.StartNew(() => { + try { + if (LoadBaml(output)) + highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); + } + catch (Exception ex) { + output.Write(ex.ToString()); + } + return output; + }), t => textView.ShowNode(t.Result, this, highlighting)); + return true; + } + + bool LoadBaml(AvalonEditTextOutput output) + { + var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; + AppDomain bamlDecompilerAppDomain = null; + try { + BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName); + MemoryStream bamlStream = new MemoryStream(); + Data.Position = 0; + Data.CopyTo(bamlStream); + output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm))); + return true; + } + finally { + if (bamlDecompilerAppDomain != null) + AppDomain.Unload(bamlDecompilerAppDomain); + } + } + + public static BamlDecompiler CreateBamlDecompilerInAppDomain(ref AppDomain appDomain, string assemblyFileName) + { + if (appDomain == null) { + // Construct and initialize settings for a second AppDomain. + AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup(); + // bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName); + bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false; + bamlDecompilerAppDomainSetup.DisallowCodeDownload = true; + bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; + // Create the second AppDomain. + appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup); + } + return (BamlDecompiler)appDomain.CreateInstanceAndUnwrap(typeof(BamlDecompiler).Assembly.FullName, typeof(BamlDecompiler).FullName); + } + } +} From 4ede9627212de6386c76c02db09cfc0835c6ca8e Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:41:59 +1000 Subject: [PATCH 15/57] Added resource node for general xml-based resources (xml, xsd, xslt) --- .../ResourceNodes/XmlResourceNode.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs diff --git a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs new file mode 100644 index 000000000..db577d8d9 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs @@ -0,0 +1,88 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Threading.Tasks; + +using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.TreeNodes; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.Xaml +{ + [Export(typeof(IResourceNodeFactory))] + sealed class XmlResourceNodeFactory : IResourceNodeFactory + { + private readonly static string[] xmlFileExtensions = { ".xml", ".xsd", ".xslt" }; + + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null) + return CreateNode(er.Name, er.GetResourceStream()); + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + foreach (string fileExt in xmlFileExtensions) + if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) + return new XmlResourceEntryNode(key, data); + return null; + } + } + + sealed class XmlResourceEntryNode : ResourceEntryNode + { + string xaml; + + public XmlResourceEntryNode(string key, Stream data) : base(key, data) + { + } + + internal override bool View(DecompilerTextView textView) + { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + IHighlightingDefinition highlighting = null; + + textView.RunWithCancellation( + token => Task.Factory.StartNew( + () => { + try { + // cache read XAML because stream will be closed after first read + if (xaml == null) { + using (var reader = new StreamReader(Data)) { + xaml = reader.ReadToEnd(); + } + } + output.Write(xaml); + highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); + } catch (Exception ex) { + output.Write(ex.ToString()); + } + return output; + }), + t => textView.ShowNode(t.Result, this, highlighting) + ); + return true; + } + } +} From fb3523b8302249bfca553c947d2dfc50f385dc7f Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 18:06:12 +1000 Subject: [PATCH 16/57] Handle resources stored as byte arrays. --- ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs index 0397841a0..a99e2a989 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs @@ -70,9 +70,12 @@ namespace ICSharpCode.ILSpy.TreeNodes catch (ArgumentException) { return; } - foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) + foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { if (entry.Value is Stream) Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value)); + else if (entry.Value is byte[]) + Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), new MemoryStream((byte[])entry.Value))); + } } } } From 2ca0012251b370e545689beb3d58ee8524d73fde Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 18:28:38 +1000 Subject: [PATCH 17/57] Added specific icons for general xml-based resource nodes --- ILSpy/ILSpy.csproj | 9 ++++- ILSpy/Images/Images.cs | 3 ++ ILSpy/Images/ResourceXml.png | Bin 0 -> 465 bytes ILSpy/Images/ResourceXsd.png | Bin 0 -> 1398 bytes ILSpy/Images/ResourceXslt.png | Bin 0 -> 1357 bytes .../ResourceNodes/XmlResourceNode.cs | 38 +++++++++++++----- 6 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 ILSpy/Images/ResourceXml.png create mode 100644 ILSpy/Images/ResourceXsd.png create mode 100644 ILSpy/Images/ResourceXslt.png diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 0fd9f90e8..34b7a4d40 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -94,7 +94,7 @@ - + @@ -160,6 +160,7 @@ + @@ -315,6 +316,10 @@ ICSharpCode.TreeView - + + + + + \ No newline at end of file diff --git a/ILSpy/Images/Images.cs b/ILSpy/Images/Images.cs index 8755e772e..8e8f2b08d 100644 --- a/ILSpy/Images/Images.cs +++ b/ILSpy/Images/Images.cs @@ -59,6 +59,9 @@ namespace ICSharpCode.ILSpy public static readonly BitmapImage Resource = LoadBitmap("Resource"); public static readonly BitmapImage ResourceImage = LoadBitmap("ResourceImage"); public static readonly BitmapImage ResourceResourcesFile = LoadBitmap("ResourceResourcesFile"); + public static readonly BitmapImage ResourceXml = LoadBitmap("ResourceXml"); + public static readonly BitmapImage ResourceXsd = LoadBitmap("ResourceXsd"); + public static readonly BitmapImage ResourceXslt = LoadBitmap("ResourceXslt"); public static readonly BitmapImage Class = LoadBitmap("Class"); public static readonly BitmapImage Struct = LoadBitmap("Struct"); diff --git a/ILSpy/Images/ResourceXml.png b/ILSpy/Images/ResourceXml.png new file mode 100644 index 0000000000000000000000000000000000000000..157feead5668e880b027eee9a68e28c52f0decb7 GIT binary patch literal 465 zcmV;?0WSWDP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02XvbSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8JLvUk0003*Nkl#TBt)1Y!kZ#EQe*>GW==L)eC!-2Uc#J?Gv| zCZ^=8#F(zu6{=NrPa3aCi~~;A_H9dm5JF@NI02Cx39WSq@c@57+}Aq*I7R?4kb0*O zuX040gjm-cPbmfU*;vRCU~X{GsNZYMZetrIS|mtz6{3yC)$_~(=w0*C*y{kW|Jt*d z02em}rlr7TDKRCeD}w0nb`I=7EQK9T-+@>*I8U!}mPL3>jYH=^nP^m`IRai<0JS;T zIJ}i^JA>g0qxlsu7UBVlvaq>GoM%PYPv)8H&KYUg0RtSwi^H+pkLDtIfP9g+4or`A zKpJ*1Pv;EiK%I;Jxj$giFd%tILck!-a7(0NKztYDKTUui{R;Zgt@B+400000NkvXX Hu0mjfohZ4O literal 0 HcmV?d00001 diff --git a/ILSpy/Images/ResourceXsd.png b/ILSpy/Images/ResourceXsd.png new file mode 100644 index 0000000000000000000000000000000000000000..4422be59eb79e22c51a50a7cdd56f75a3cbb90fb GIT binary patch literal 1398 zcmeHG|1;BZ7=KI7mrSm3azu9(zgXO<$hVs?bK0@VaiP?t{b0zh`X%CrO6$_)&RyTH zQG9X?HN;HY$mSN?nb_Qf!;H{2Y?wWL{2hAkd7jtvyzcqw^}44jl}aYK__!d12$ZCF z8jkLJG4U6OA&8QBE@|t{4@$rcs7zjA z&74`gUKg|>W6U3%b>A3y-IS}3KcnY`O zxi~4S6d^asUfB&6H8OD0i=B|krWf60-_5(7kBak{EH;sq&khJ9hD0uIF!2i|C7zTX zL=PU)XNW`GAI_X?mz~a#2%Ua$JsD(D#glw2%;~Ym1#`I{pJ}nlBSr+$v;hxw4mKA+ zc9@JgZYvvq8d}qp%Ga9jmwZpjDJr=a-iV$D@~)2RgYV3+cn`(}w={%Dv(>I#<}+Rd zBTGa>RLqB&U6Qo?ve`9|b0qG%?~C`?Ws#;ZBhjB6u5iwYVJSN+rijF7@6jy3W1Ou> zqeHZJT6QkC`o!nA99F}{f?i!ivKyz;-s`BMwmv?}i}2`xU7w?l7d{-@T1U!MsjHUu OUV)N8jctYPs0 literal 0 HcmV?d00001 diff --git a/ILSpy/Images/ResourceXslt.png b/ILSpy/Images/ResourceXslt.png new file mode 100644 index 0000000000000000000000000000000000000000..107c9f2a684ff0192696d1921fa9e3929b3b3a5d GIT binary patch literal 1357 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NSs56Z83KGlT!G@Ip2=ojDJ2XHwZfuxBBGr-`hCWxNB7i!xm(jbY3<}i+ovtv zHGSFcSu6MLU$|!9qIGjt9-OoK;JkH*7p^_BX#LT}n~pEraA5JK6DzlzT)E@i%AM!e z?Y_8f-<6HK&u-jvZp+>an-1OBdFb-)!&mkmyLNEv@r!$oUfy@?>%+FMPbYkRG2_6= zn}<)|JaXpNsq@!PoWFbe;{ChFPhGn4G%83fBye}`v3p?k6(U&{r>mskH7!_fB5*Oa{{R2+|NqZFfByXa z`ya>w`f(JDh5*(OxP3kam{_QeYm>a8!j|*x_jwshoNDGf8LQ++Ste@(m?loNfsN_1wT;GFBLkBV&c59&B3 aS;N>FT&|g0@%}j|J$SnMxvX Task.Factory.StartNew( () => { try { // cache read XAML because stream will be closed after first read - if (xaml == null) { + if (xml == null) { using (var reader = new StreamReader(Data)) { - xaml = reader.ReadToEnd(); + xml = reader.ReadToEnd(); } } - output.Write(xaml); + output.Write(xml); highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); - } catch (Exception ex) { + } + catch (Exception ex) { output.Write(ex.ToString()); } return output; From a42bd6b9ac26e3e0156b1781c3c73cab5539687f Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Wed, 25 May 2011 23:35:19 +0300 Subject: [PATCH 18/57] Show constructor icon; reset icons in about page. --- ILSpy/AboutPage.cs | 5 +++++ ILSpy/Bookmarks/MemberBookmark.cs | 3 +++ ILSpy/TextView/DecompilerTextView.cs | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index fd4fb4891..29e5ac262 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -31,8 +31,10 @@ using System.Windows.Data; using System.Windows.Input; using System.Xml; using System.Xml.Linq; + using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.Bookmarks; using ICSharpCode.ILSpy.TextView; namespace ICSharpCode.ILSpy @@ -94,6 +96,9 @@ namespace ICSharpCode.ILSpy output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt")); output.AddVisualLineElementGenerator(new MyLinkElementGenerator("LGPL", "resource:LGPL.txt")); textView.ShowText(output); + + //reset icon bar + textView.manager.Bookmarks.Clear(); } sealed class MyLinkElementGenerator : LinkElementGenerator diff --git a/ILSpy/Bookmarks/MemberBookmark.cs b/ILSpy/Bookmarks/MemberBookmark.cs index 9a0996095..59fa5ff8d 100644 --- a/ILSpy/Bookmarks/MemberBookmark.cs +++ b/ILSpy/Bookmarks/MemberBookmark.cs @@ -53,6 +53,9 @@ namespace ICSharpCode.ILSpy.Bookmarks if (node is OperatorDeclaration) return GetMemberOverlayedImage(attrNode, MemberIcon.Operator); + if (node is ConstructorDeclaration || node is DestructorDeclaration) + return GetMemberOverlayedImage(attrNode, MemberIcon.Constructor); + return GetMemberOverlayedImage(attrNode, MemberIcon.Method); } } diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 3ade72e99..0fe92d81d 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -69,7 +69,7 @@ namespace ICSharpCode.ILSpy.TextView DefinitionLookup definitionLookup; CancellationTokenSource currentCancellationTokenSource; - readonly IconBarManager manager; + internal readonly IconBarManager manager; readonly IconBarMargin iconMargin; readonly TextMarkerService textMarkerService; From 6fcc05af6833d84e8d5de3bb6d293c015726ff82 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Thu, 26 May 2011 08:37:34 +1000 Subject: [PATCH 19/57] Split out ImageResourceEntryNode, and add support for cursor resources. --- .../ResourceNodes/CursorResourceEntryNode.cs | 95 +++++++++++++++++++ .../ResourceNodes/ImageResourceEntryNode.cs | 87 +++++++++++++++++ .../ResourceNodes/ResourceEntryNode.cs | 59 +----------- 3 files changed, 183 insertions(+), 58 deletions(-) create mode 100644 ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs create mode 100644 ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs diff --git a/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs new file mode 100644 index 000000000..3a5b41b75 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs @@ -0,0 +1,95 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Controls; +using System.Windows.Media.Imaging; +using ICSharpCode.ILSpy.TextView; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + [Export(typeof(IResourceNodeFactory))] + sealed class CursorResourceNodeFactory : IResourceNodeFactory + { + static readonly string[] imageFileExtensions = { ".cur" }; + + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null) { + return CreateNode(er.Name, er.GetResourceStream()); + } + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + foreach (string fileExt in imageFileExtensions) { + if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) + return new CursorResourceEntryNode(key, data); + } + return null; + } + } + + sealed class CursorResourceEntryNode : ResourceEntryNode + { + public CursorResourceEntryNode(string key, Stream data) + : base(key, data) + { + } + + public override object Icon + { + get { return Images.ResourceImage; } + } + + internal override bool View(DecompilerTextView textView) + { + try { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + Data.Position = 0; + BitmapImage image = new BitmapImage(); + + //HACK: windows imaging does not understand that .cur files have the same layout as .ico + // so load to data, and modify the ResourceType in the header to make look like an icon... + byte[] curData = ((MemoryStream)Data).ToArray(); + curData[2] = 1; + using (Stream stream = new MemoryStream(curData)) { + image.BeginInit(); + image.StreamSource = stream; + image.EndInit(); + } + + output.AddUIElement(() => new Image { Source = image }); + output.WriteLine(); + output.AddButton(Images.Save, "Save", delegate { + Save(null); + }); + textView.ShowNode(output, this, null); + return true; + } + catch (Exception) { + return false; + } + } + } +} diff --git a/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs new file mode 100644 index 000000000..b333378ab --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs @@ -0,0 +1,87 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Controls; +using System.Windows.Media.Imaging; +using ICSharpCode.ILSpy.TextView; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + [Export(typeof(IResourceNodeFactory))] + sealed class ImageResourceNodeFactory : IResourceNodeFactory + { + static readonly string[] imageFileExtensions = { ".png", ".gif", ".bmp", ".jpg", ".ico" }; + + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null) { + return CreateNode(er.Name, er.GetResourceStream()); + } + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + foreach (string fileExt in imageFileExtensions) { + if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) + return new ImageResourceEntryNode(key, data); + } + return null; + } + } + + sealed class ImageResourceEntryNode : ResourceEntryNode + { + public ImageResourceEntryNode(string key, Stream data) + : base(key, data) + { + } + + public override object Icon + { + get { return Images.ResourceImage; } + } + + internal override bool View(DecompilerTextView textView) + { + try { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + Data.Position = 0; + BitmapImage image = new BitmapImage(); + image.BeginInit(); + image.StreamSource = Data; + image.EndInit(); + output.AddUIElement(() => new Image { Source = image }); + output.WriteLine(); + output.AddButton(Images.Save, "Save", delegate { + Save(null); + }); + textView.ShowNode(output, this, null); + return true; + } + catch (Exception) { + return false; + } + } + } +} diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs index e4b165680..7a077da2d 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs @@ -91,61 +91,4 @@ namespace ICSharpCode.ILSpy.TreeNodes return true; } } - - [Export(typeof(IResourceNodeFactory))] - sealed class ImageResourceNodeFactory : IResourceNodeFactory - { - static readonly string[] imageFileExtensions = { ".png", ".gif", ".bmp", ".jpg", ".ico" }; - - public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) - { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null) { - return CreateNode(er.Name, er.GetResourceStream()); - } - return null; - } - - public ILSpyTreeNode CreateNode(string key, Stream data) - { - foreach (string fileExt in imageFileExtensions) { - if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) - return new ImageResourceEntryNode(key, data); - } - return null; - } - } - - sealed class ImageResourceEntryNode : ResourceEntryNode - { - public ImageResourceEntryNode(string key, Stream data) - : base(key, data) - { - } - - public override object Icon - { - get { return Images.ResourceImage; } - } - - internal override bool View(DecompilerTextView textView) - { - try { - AvalonEditTextOutput output = new AvalonEditTextOutput(); - Data.Position = 0; - BitmapImage image = new BitmapImage(); - image.BeginInit(); - image.StreamSource = Data; - image.EndInit(); - output.AddUIElement(() => new Image { Source = image }); - output.WriteLine(); - output.AddButton(Images.Save, "Save", delegate { Save(null); }); - textView.ShowNode(output, this, null); - return true; - } - catch (Exception) { - return false; - } - } - } -} +} \ No newline at end of file From 5edd65e73c7928c2cfd9403a0a043fb85ff9cd57 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Thu, 26 May 2011 11:38:38 +0300 Subject: [PATCH 20/57] static class icons in Icon bar --- ILSpy/AvalonEdit/IconMarginActionsProvider.cs | 2 -- ILSpy/Bookmarks/MemberBookmark.cs | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ILSpy/AvalonEdit/IconMarginActionsProvider.cs b/ILSpy/AvalonEdit/IconMarginActionsProvider.cs index 0854806af..3df691d33 100644 --- a/ILSpy/AvalonEdit/IconMarginActionsProvider.cs +++ b/ILSpy/AvalonEdit/IconMarginActionsProvider.cs @@ -186,6 +186,4 @@ namespace ICSharpCode.ILSpy.AvalonEdit } } } - - } diff --git a/ILSpy/Bookmarks/MemberBookmark.cs b/ILSpy/Bookmarks/MemberBookmark.cs index 59fa5ff8d..c5532bf30 100644 --- a/ILSpy/Bookmarks/MemberBookmark.cs +++ b/ILSpy/Bookmarks/MemberBookmark.cs @@ -133,6 +133,9 @@ namespace ICSharpCode.ILSpy.Bookmarks } } + if ((attrNode.Modifiers & Modifiers.Static) == Modifiers.Static) + return GetTypeOverlayedImage(attrNode, TypeIcon.StaticClass); + return GetTypeOverlayedImage(attrNode, TypeIcon.Class); } } From c2eb91797c1cae50bc65fc020e08d6401362447e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 27 May 2011 13:42:36 +0200 Subject: [PATCH 21/57] Make file extension comparison case-insensitive. --- ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs index 004e26272..ce2f1e1d4 100644 --- a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs @@ -64,11 +64,11 @@ namespace ICSharpCode.ILSpy.Xaml get { string text = (string)Text; - if (text.EndsWith(".xml")) + if (text.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) return Images.ResourceXml; - else if (text.EndsWith(".xsd")) + else if (text.EndsWith(".xsd", StringComparison.OrdinalIgnoreCase)) return Images.ResourceXsd; - else if (text.EndsWith(".xslt")) + else if (text.EndsWith(".xslt", StringComparison.OrdinalIgnoreCase)) return Images.ResourceXslt; else return Images.Resource; From e8b6e3d8083c331a6db4c78f982311143b6484e6 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 27 May 2011 13:44:45 +0200 Subject: [PATCH 22/57] Annotate anonymous methods/lambdas with the MethodDefinition representing the lambda body. --- ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index 85ac9da1e..0e431e3f8 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -136,6 +136,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms // Create AnonymousMethodExpression and prepare parameters AnonymousMethodExpression ame = new AnonymousMethodExpression(); + ame.CopyAnnotationsFrom(objectCreateExpression); // copy ILRanges etc. + ame.RemoveAnnotations(); // remove reference to delegate ctor + ame.AddAnnotation(method); // add reference to anonymous method ame.Parameters.AddRange(AstBuilder.MakeParameters(method, isLambda: true)); ame.HasParameterList = true; @@ -180,6 +183,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } if (isLambda) { LambdaExpression lambda = new LambdaExpression(); + lambda.CopyAnnotationsFrom(ame); ame.Parameters.MoveTo(lambda.Parameters); Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression; returnExpr.Remove(); From fe9b4a841a75ed1f7d32fedb6c141dab292d88f6 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Fri, 27 May 2011 16:50:20 +0300 Subject: [PATCH 23/57] Reuse analyze code. Show event icon on the bar. --- ILSpy/Bookmarks/Commands.cs | 22 ++-------- ILSpy/Bookmarks/MemberBookmark.cs | 2 +- .../Analyzer/AnalyzeContextMenuEntry.cs | 43 +++++++++++-------- 3 files changed, 29 insertions(+), 38 deletions(-) diff --git a/ILSpy/Bookmarks/Commands.cs b/ILSpy/Bookmarks/Commands.cs index 2e5dbd8b3..021daee1b 100644 --- a/ILSpy/Bookmarks/Commands.cs +++ b/ILSpy/Bookmarks/Commands.cs @@ -38,26 +38,12 @@ namespace ICSharpCode.ILSpy.Bookmarks public void Execute(IBookmark[] marks) { - foreach (var node in marks) { - if (!(node is MemberBookmark)) + foreach (var mark in marks) { + if (!(mark is MemberBookmark)) continue; - var member = (node as MemberBookmark).Node.Annotation(); - TypeDefinition type = member as TypeDefinition; - if (type != null) - AnalyzerTreeView.Instance.Show(new AnalyzedTypeTreeNode(type)); - FieldDefinition field = member as FieldDefinition; - if (field != null) - AnalyzerTreeView.Instance.Show(new AnalyzedFieldTreeNode(field)); - MethodDefinition method = member as MethodDefinition; - if (method != null) - AnalyzerTreeView.Instance.Show(new AnalyzedMethodTreeNode(method)); - var propertyAnalyzer = AnalyzedPropertyTreeNode.TryCreateAnalyzer(member); - if (propertyAnalyzer != null) - AnalyzerTreeView.Instance.Show(propertyAnalyzer); - var eventAnalyzer = AnalyzedEventTreeNode.TryCreateAnalyzer(member); - if (eventAnalyzer != null) - AnalyzerTreeView.Instance.Show(eventAnalyzer); + var member = (mark as MemberBookmark).Node.Annotation(); + AnalyzeContextMenuEntry.Analyze(member); } } } diff --git a/ILSpy/Bookmarks/MemberBookmark.cs b/ILSpy/Bookmarks/MemberBookmark.cs index c5532bf30..646587ae6 100644 --- a/ILSpy/Bookmarks/MemberBookmark.cs +++ b/ILSpy/Bookmarks/MemberBookmark.cs @@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy.Bookmarks if (node is PropertyDeclaration) return GetMemberOverlayedImage(attrNode, MemberIcon.Property); - if (node is EventDeclaration) + if (node is EventDeclaration || node is CustomEventDeclaration) return GetMemberOverlayedImage(attrNode, MemberIcon.Event); if (node is IndexerDeclaration) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs index 6221bcc37..1c790ebb2 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs @@ -35,10 +35,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { foreach (IMemberTreeNode node in selectedNodes) { if (!(node.Member is TypeDefinition - || node.Member is FieldDefinition - || node.Member is MethodDefinition - || Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member) - || Analyzer.AnalyzedEventTreeNode.CanShow(node.Member))) + || node.Member is FieldDefinition + || node.Member is MethodDefinition + || Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member) + || Analyzer.AnalyzedEventTreeNode.CanShow(node.Member))) return false; } @@ -50,22 +50,27 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer // TODO: figure out when equivalent nodes are already present // and focus those instead. foreach (IMemberTreeNode node in selectedNodes) { - TypeDefinition type = node.Member as TypeDefinition; - if (type != null) - AnalyzerTreeView.Instance.Show(new AnalyzedTypeTreeNode(type)); - FieldDefinition field = node.Member as FieldDefinition; - if (field != null) - AnalyzerTreeView.Instance.Show(new AnalyzedFieldTreeNode(field)); - MethodDefinition method = node.Member as MethodDefinition; - if (method != null) - AnalyzerTreeView.Instance.Show(new AnalyzedMethodTreeNode(method)); - var propertyAnalyzer = Analyzer.AnalyzedPropertyTreeNode.TryCreateAnalyzer(node.Member); - if (propertyAnalyzer != null) - AnalyzerTreeView.Instance.Show(propertyAnalyzer); - var eventAnalyzer = Analyzer.AnalyzedEventTreeNode.TryCreateAnalyzer(node.Member); - if (eventAnalyzer != null) - AnalyzerTreeView.Instance.Show(eventAnalyzer); + Analyze(node.Member); } } + + public static void Analyze(MemberReference member) + { + TypeDefinition type = member as TypeDefinition; + if (type != null) + AnalyzerTreeView.Instance.Show(new AnalyzedTypeTreeNode(type)); + FieldDefinition field = member as FieldDefinition; + if (field != null) + AnalyzerTreeView.Instance.Show(new AnalyzedFieldTreeNode(field)); + MethodDefinition method = member as MethodDefinition; + if (method != null) + AnalyzerTreeView.Instance.Show(new AnalyzedMethodTreeNode(method)); + var propertyAnalyzer = Analyzer.AnalyzedPropertyTreeNode.TryCreateAnalyzer(member); + if (propertyAnalyzer != null) + AnalyzerTreeView.Instance.Show(propertyAnalyzer); + var eventAnalyzer = Analyzer.AnalyzedEventTreeNode.TryCreateAnalyzer(member); + if (eventAnalyzer != null) + AnalyzerTreeView.Instance.Show(eventAnalyzer); + } } } From 56d513da9ab43b2ac50c54a0386b611880cacd41 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Fri, 27 May 2011 20:13:07 +0300 Subject: [PATCH 24/57] Show line margin last using Visibility. --- ILSpy/TextView/DecompilerTextView.cs | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 0fe92d81d..d539cbf1c 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.ComponentModel.Composition; using System.Diagnostics; using System.Globalization; @@ -37,6 +38,7 @@ using System.Windows.Threading; using System.Xml; using ICSharpCode.AvalonEdit; +using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting.Xshd; @@ -70,7 +72,7 @@ namespace ICSharpCode.ILSpy.TextView CancellationTokenSource currentCancellationTokenSource; internal readonly IconBarManager manager; - readonly IconBarMargin iconMargin; + readonly IconBarMargin iconMargin; readonly TextMarkerService textMarkerService; #region Constructor @@ -86,6 +88,7 @@ namespace ICSharpCode.ILSpy.TextView } }); + this.Loaded+= new RoutedEventHandler(DecompilerTextView_Loaded); InitializeComponent(); this.referenceElementGenerator = new ReferenceElementGenerator(this.JumpToReference, this.IsLink); textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator); @@ -96,7 +99,6 @@ namespace ICSharpCode.ILSpy.TextView textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped; textEditor.SetBinding(TextEditor.FontFamilyProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFont") }); textEditor.SetBinding(TextEditor.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFontSize") }); - textEditor.SetBinding(TextEditor.ShowLineNumbersProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("ShowLineNumbers") }); // add marker service & margin iconMargin = new IconBarMargin((manager = new IconBarManager())); @@ -104,13 +106,42 @@ namespace ICSharpCode.ILSpy.TextView textMarkerService.CodeEditor = textEditor; textEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService); textEditor.TextArea.TextView.LineTransformers.Add(textMarkerService); + textEditor.ShowLineNumbers = true; + DisplaySettingsPanel.CurrentDisplaySettings.PropertyChanged += CurrentDisplaySettings_PropertyChanged; textEditor.TextArea.LeftMargins.Insert(0, iconMargin); textEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); }; + ShowLineMargin(); // Bookmarks context menu IconMarginActionsProvider.Add(iconMargin); } + + void DecompilerTextView_Loaded(object sender, RoutedEventArgs e) + { + ShowLineMargin(); + } + + #endregion + + #region Line margin + + void CurrentDisplaySettings_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "ShowLineNumbers") { + ShowLineMargin(); + } + } + + void ShowLineMargin() + { + foreach (var margin in this.textEditor.TextArea.LeftMargins) { + if (margin is LineNumberMargin || margin is System.Windows.Shapes.Line) { + margin.Visibility = DisplaySettingsPanel.CurrentDisplaySettings.ShowLineNumbers ? Visibility.Visible : Visibility.Collapsed; + } + } + } + #endregion #region Tooltip support From 397df1679342e348f689c82cfef4a7b977c1337c Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 11:29:38 +1000 Subject: [PATCH 25/57] Use standard icon --- ILSpy/Images/Delete.png | Bin 575 -> 584 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ILSpy/Images/Delete.png b/ILSpy/Images/Delete.png index 824d938dd67435984f22217cceab55e0c4438e15..560865f301f384826d3960c4ec607c3ae855ae52 100644 GIT binary patch delta 502 zcmV?~JY~rU z2Nl>`zeO-t(+*i8OpEN-EdYlJEL26}Ud~nm9CjKEP$EWwg{*1BsCWlxnjRB@ez3_R z;}QwMJ_K%%l0{Rne|3NM2njvF39{8A#oV8ui1{(?q~iu7ImqHZiN&U9CyzkiO|b<9 zH-MErL%itGlE_0_0VMSTGsyFRvGU^5(%bM-b6;Imk##y^OCbb}+;7O1LKdEPh=q(v z6{MSx*}Jj{QqC@TTit+~`$vvI>C!5^UzpYL??edD8_+&GY&C^DyLgr!R*p3^6pm%(^|2LJ#707*qoM6N<$f>}}D&j0`b delta 491 zcmVp|{G~2o{wE;)*%qi7NB95)5LUl_u1%Q#TA$%R4FARxxBvmfgdQuuZ(cC?cKU$B zFJSV3;V(-k=HrS*fB-@AKdHj*OmJEOy67>`W!Hd~ zJV Date: Sun, 29 May 2011 11:33:03 +1000 Subject: [PATCH 26/57] Slight change to hue of access overlay icons. --- ILSpy/Images/OverlayInternal.png | Bin 1292 -> 1292 bytes ILSpy/Images/OverlayProtected.png | Bin 352 -> 351 bytes ILSpy/Images/OverlayProtectedInternal.png | Bin 440 -> 440 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/ILSpy/Images/OverlayInternal.png b/ILSpy/Images/OverlayInternal.png index fcc53bddecc15a060e83493ac08fdd7967ff9453..3c1cbc6069440ef99f10792e82723c79fbadb13e 100644 GIT binary patch delta 181 zcmV;m080Oi3XBSnX;2>=HYFH3C>upD9ZxqQPc|Z0J0e{{DQ-|QgIF~H~bX&xyl9w}D1fUvYE508ix3tT`5qJ;@A jAi%}V$-&0V2onGR{FKsX0#zd800000NkvXXu0mjfNJUCf delta 181 zcmV;m080Oi3XBSnX;2~@HY^xAFdIcV9Zx|bPeLJBNFrTMDQ;gfgKRN?Zau7*X|kMY zwV-jgqI0>Wb-AZ>ys3D-s(8ShC(f@t(zQgutb4++eZ;bV@7r?!@Qks+qymx92n2yJ zV6L-i16Kh|xR3xJFAvOt3=$$z($Z2Q>~H~bX%Q(Y5h*sffUvZfh=`~Z3tT`DqJ;@A jz|Y0a$-&CZ2onGR2}9DOgu=$(00000NkvXXu0mjfD0)pV diff --git a/ILSpy/Images/OverlayProtected.png b/ILSpy/Images/OverlayProtected.png index 0d125f7d25e4ab710d03227b66922e7c13a467d0..8f789baff05035448e3b3bff7ae01cde7044dcc1 100644 GIT binary patch delta 208 zcmV;>05AXG0^b6Vmw&TKL_t(IPh(&h1;Z%>uB~p$y}Z2s|LJ+9|4&Sb|9@*k#}=af z2h;rJ_R6O}c4zzt;bjFD|8K5uUr3Z8Ae+D3T>A9i(>4El!sP$oT^RNM|1zWhi!=28 z6K%koqdhM{HiI;S@VlA%#2avGR-OmQ-ymB-hQKr*=uZqJ%1H$vMRU^)+(0&i3;;PD z=oM9>HNzCb3?Rw*$hLqCc(Eq-e}AOX|5uI*{cy}YCT|LOIm|4*!p|9|U1#}=af z2h;rJ)yk(oZe;ui;bpBB|8MSZUr3Z8Ae+CuT>A9i*ERopvgQBZ-4pfy|9PYTiyQR* z6K%ko8$B;UHiI;S@Vf*0#2avGZJr0n-ymB-hQKr*Sd1qG}B(QZ)krsaS&QYij7V00000 LNkvXXu0mjfAA)Jb diff --git a/ILSpy/Images/OverlayProtectedInternal.png b/ILSpy/Images/OverlayProtectedInternal.png index dacce33c49fa7d2f9e4cbe20bd5d4829be45dce9..82676812f8f5f3f91df1782689d0af3e40605e65 100644 GIT binary patch delta 283 zcmV+$0p$L;1Goc_rhoE+R$pFK|Nr#D(*GxB#Q$H>mHCorzrr-%JvsBwj{_P1L3mlQ z#s7JYNq2}bBot)x-Q!dL{CmFUe@~?R|GUeg{{LTV^nY=V-hZqH99drf|IpIf{|6RU z|4$2Z{0}nV#`b!!%^=Mn{BD6hZUYX3G&iaLe}Am#|Npx^|9^|)?7{v9*$OfQrnxB0 zvIDCN4lJq$YlImBGAP$e3T!jT0FcwY^#xpU`hV~I3a|l}=DL6l0pZRR4Y&b#oewf~ z=bRE0FMted%CQ3*@M2@^|Na=I|G{P=Za7`AeR}c#<~YOu4av6u^FodO$GU3%_qS5| hudgITSToR602Gl!&leF>xjg^?002ovPDHLkV1jX@la2rY delta 283 zcmV+$0p$L;1Goc_rhm$VR$tyx|Nr#*(*Gw`#{XY2CG#cGeuZhidu8UIA2%}ogYdFe zi~sYwlkN~>NGQnWyO*c_`S*3r|DJ65|9AI9{r`X7=>Osdz5iGZII^k!|Dg@F{|~IG z{+|}(_#b4zjidEon?agE_}u}0+y)#5X`ZA0|NZTv|NlSq{C_V_w+H(hWGl!JnC7Ac z%MPqAIIy-FtPy4i$e`Q^DX`5T13*sqwiIy1>Hoc}D!>L@+Uf!}1cW5>H|NHZl{s%jVxZ!lc_C>}2n{y2RH{{v=&x<$uAM2<2-``Q` hzrLCfVa-5O0Th9X)Q{H?vyA`%002ovPDHLkV1gYAod^H` From 529e9aaf5a8e2d1c3a3d23f5e79c1da3a78f40f9 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 16:34:18 +1000 Subject: [PATCH 27/57] Sort Analyzer results. --- .../Analyzer/AnalyzedEventFiredByTreeNode.cs | 6 ++-- .../AnalyzedEventOverridesTreeNode.cs | 8 +++-- .../Analyzer/AnalyzedFieldAccessTreeNode.cs | 11 ++++--- ...yzedInterfaceEventImplementedByTreeNode.cs | 15 ++++++--- ...zedInterfaceMethodImplementedByTreeNode.cs | 15 ++++++--- ...dInterfacePropertyImplementedByTreeNode.cs | 15 ++++++--- .../AnalyzedMethodOverridesTreeNode.cs | 10 ++++-- .../Analyzer/AnalyzedMethodUsedByTreeNode.cs | 7 ++-- .../Analyzer/AnalyzedMethodUsesTreeNode.cs | 17 ++++++++-- .../AnalyzedPropertyOverridesTreeNode.cs | 8 +++-- .../Analyzer/AnalyzedTypeExposedByTreeNode.cs | 33 ++++++++++++++----- .../AnalyzedTypeExtensionMethodsTreeNode.cs | 8 +++-- .../AnalyzedTypeInstantiationsTreeNode.cs | 11 +++++-- .../AnalyzedVirtualMethodUsedByTreeNode.cs | 13 ++++---- 14 files changed, 127 insertions(+), 50 deletions(-) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs index 02320cc09..f0247dc55 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs @@ -77,7 +77,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { foundMethods = new ConcurrentDictionary(); - foreach (var child in FindReferencesInType(analyzedEvent.DeclaringType)) { + foreach (var child in FindReferencesInType(analyzedEvent.DeclaringType).OrderBy(n => n.Text)) { yield return child; } @@ -117,7 +117,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (found) { MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { - yield return new AnalyzedMethodTreeNode(codeLocation); + var node = new AnalyzedMethodTreeNode(codeLocation); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs index 549152bb7..99aa27af6 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs @@ -71,7 +71,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedEvent, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -86,7 +88,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (TypesHierarchyHelpers.IsBaseEvent(analyzedEvent, eventDef)) { MethodDefinition anyAccessor = eventDef.AddMethod ?? eventDef.RemoveMethod; bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; - yield return new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : ""); + var node = new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : ""); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs index 850ab3141..edc14fd04 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using ICSharpCode.TreeView; using Mono.Cecil; @@ -74,7 +75,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foundMethods = new Lazy(LazyThreadSafetyMode.ExecutionAndPublication); var analyzer = new ScopedWhereUsedAnalyzer(analyzedField, FindReferencesInType); - foreach (var child in analyzer.PerformAnalysis(ct)) { + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { yield return child; } @@ -93,8 +94,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foreach (Instruction instr in method.Body.Instructions) { if (CanBeReference(instr.OpCode.Code)) { FieldReference fr = instr.Operand as FieldReference; - if (fr != null && fr.Name == name && - Helpers.IsReferencedBy(analyzedField.DeclaringType, fr.DeclaringType) && + if (fr != null && fr.Name == name && + Helpers.IsReferencedBy(analyzedField.DeclaringType, fr.DeclaringType) && fr.Resolve() == analyzedField) { found = true; break; @@ -107,7 +108,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (found) { MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { - yield return new AnalyzedMethodTreeNode(codeLocation); + var node = new AnalyzedMethodTreeNode(codeLocation); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs index 09cab0bf3..f6773be82 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs @@ -71,7 +71,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -84,15 +86,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foreach (EventDefinition ev in type.Events.Where(e => e.Name == analyzedEvent.Name)) { MethodDefinition accessor = ev.AddMethod ?? ev.RemoveMethod; - if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef)) - yield return new AnalyzedEventTreeNode(ev); + if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef)) { + var node = new AnalyzedEventTreeNode(ev); + node.Language = this.Language; + yield return node; + } yield break; } foreach (EventDefinition ev in type.Events.Where(e => e.Name.EndsWith(analyzedEvent.Name))) { MethodDefinition accessor = ev.AddMethod ?? ev.RemoveMethod; if (accessor.HasOverrides && accessor.Overrides.Any(m => m.Resolve() == analyzedMethod)) { - yield return new AnalyzedEventTreeNode(ev); + var node = new AnalyzedEventTreeNode(ev); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs index 960f48f89..3f139e040 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs @@ -69,7 +69,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -81,14 +83,19 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer yield break; foreach (MethodDefinition method in type.Methods.Where(m => m.Name == analyzedMethod.Name)) { - if (TypesHierarchyHelpers.MatchInterfaceMethod(method, analyzedMethod, implementedInterfaceRef)) - yield return new AnalyzedMethodTreeNode(method); + if (TypesHierarchyHelpers.MatchInterfaceMethod(method, analyzedMethod, implementedInterfaceRef)) { + var node = new AnalyzedMethodTreeNode(method); + node.Language = this.Language; + yield return node; + } yield break; } foreach (MethodDefinition method in type.Methods) { if (method.HasOverrides && method.Overrides.Any(m => m.Resolve() == analyzedMethod)) { - yield return new AnalyzedMethodTreeNode(method); + var node = new AnalyzedMethodTreeNode(method); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs index 35d9bc3d0..56f89ad13 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs @@ -71,7 +71,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -84,15 +86,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foreach (PropertyDefinition property in type.Properties.Where(e => e.Name == analyzedProperty.Name)) { MethodDefinition accessor = property.GetMethod ?? property.SetMethod; - if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef)) - yield return new AnalyzedPropertyTreeNode(property); + if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef)) { + var node = new AnalyzedPropertyTreeNode(property); + node.Language = this.Language; + yield return node; + } yield break; } foreach (PropertyDefinition property in type.Properties.Where(e => e.Name.EndsWith(analyzedProperty.Name))) { MethodDefinition accessor = property.GetMethod ?? property.SetMethod; if (accessor.HasOverrides && accessor.Overrides.Any(m => m.Resolve() == analyzedMethod)) { - yield return new AnalyzedPropertyTreeNode(property); + var node = new AnalyzedPropertyTreeNode(property); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs index 05a3f5d6a..4e8af7663 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs @@ -76,12 +76,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) { - SharpTreeNode newNode = null; + AnalyzerTreeNode newNode = null; try { if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false)) yield break; @@ -97,8 +99,10 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer // ignore this type definition. maybe add a notification about such cases. } - if (newNode != null) + if (newNode != null) { + newNode.Language = this.Language; yield return newNode; + } } public static bool CanShow(MethodDefinition method) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs index f3f9504e6..175ce4efc 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Threading; using ICSharpCode.TreeView; using Mono.Cecil; @@ -71,7 +72,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foundMethods = new ConcurrentDictionary(); var analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType); - foreach (var child in analyzer.PerformAnalysis(ct)) { + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { yield return child; } @@ -100,7 +101,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (found) { MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { - yield return new AnalyzedMethodTreeNode(codeLocation); + var node= new AnalyzedMethodTreeNode(codeLocation); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs index 5553f5a98..1b18a9ae1 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs @@ -51,14 +51,25 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } protected override void LoadChildren() + { + analyzedMethod.Body = null; + foreach (var child in GetChildren().OrderBy(n => n.Text)) { + this.Children.Add(child); + } + } + + private IEnumerable GetChildren() { foreach (var f in GetUsedFields().Distinct()) { - this.Children.Add(new AnalyzedFieldTreeNode(f)); + var node = new AnalyzedFieldTreeNode(f); + node.Language = this.Language; + yield return node; } foreach (var m in GetUsedMethods().Distinct()) { - this.Children.Add(new AnalyzedMethodTreeNode(m)); + var node = new AnalyzedMethodTreeNode(m); + node.Language = this.Language; + yield return node; } - analyzedMethod.Body = null; } private IEnumerable GetUsedMethods() diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs index 6a6ea0f32..8f264d7ff 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs @@ -72,7 +72,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedProperty, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -88,7 +90,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) { MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod; bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; - yield return new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : ""); + var node = new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : ""); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs index cd14c0575..26c2bca71 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using ICSharpCode.TreeView; using Mono.Cecil; @@ -68,7 +69,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -80,23 +83,35 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer yield break; foreach (FieldDefinition field in type.Fields) { - if (TypeIsExposedBy(field)) - yield return new AnalyzedFieldTreeNode(field); + if (TypeIsExposedBy(field)) { + var node = new AnalyzedFieldTreeNode(field); + node.Language = this.Language; + yield return node; + } } foreach (PropertyDefinition property in type.Properties) { - if (TypeIsExposedBy(property)) - yield return new AnalyzedPropertyTreeNode(property); + if (TypeIsExposedBy(property)) { + var node = new AnalyzedPropertyTreeNode(property); + node.Language = this.Language; + yield return node; + } } foreach (EventDefinition eventDef in type.Events) { - if (TypeIsExposedBy(eventDef)) - yield return new AnalyzedEventTreeNode(eventDef); + if (TypeIsExposedBy(eventDef)) { + var node = new AnalyzedEventTreeNode(eventDef); + node.Language = this.Language; + yield return node; + } } foreach (MethodDefinition method in type.Methods) { - if (TypeIsExposedBy(method)) - yield return new AnalyzedMethodTreeNode(method); + if (TypeIsExposedBy(method)) { + var node = new AnalyzedMethodTreeNode(method); + node.Language = this.Language; + yield return node; + } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs index 3bd42506c..605190b88 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs @@ -69,7 +69,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -79,7 +81,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foreach (MethodDefinition method in type.Methods) { if (method.IsStatic && HasExtensionAttribute(method)) { if (method.HasParameters && method.Parameters[0].ParameterType.Resolve() == analyzedType) { - yield return new AnalyzedMethodTreeNode(method); + var node = new AnalyzedMethodTreeNode(method); + node.Language = this.Language; + yield return node; } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs index 0c2d9465a..10b477bcf 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs @@ -74,7 +74,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer ScopedWhereUsedAnalyzer analyzer; analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindReferencesInType); - return analyzer.PerformAnalysis(ct); + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { + yield return child; + } } private IEnumerable FindReferencesInType(TypeDefinition type) @@ -102,8 +104,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer method.Body = null; - if (found) - yield return new AnalyzedMethodTreeNode(method); + if (found) { + var node = new AnalyzedMethodTreeNode(method); + node.Language = this.Language; + yield return node; + } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs index 26f5e4c65..f31eb5d5e 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs @@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer InitializeAnalyzer(); var analyzer = new ScopedWhereUsedAnalyzer(analyzedMethod, FindReferencesInType); - foreach (var child in analyzer.PerformAnalysis(ct)) { + foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { yield return child; } @@ -95,8 +95,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer possibleTypes = new List(); TypeReference type = analyzedMethod.DeclaringType.BaseType; - while (type !=null) - { + while (type != null) { possibleTypes.Add(type); type = type.Resolve().BaseType; } @@ -120,8 +119,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer MethodReference mr = instr.Operand as MethodReference; if (mr != null && mr.Name == name) { // explicit call to the requested method - if (instr.OpCode.Code == Code.Call - && Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) + if (instr.OpCode.Code == Code.Call + && Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) { found = true; prefix = "(as base) "; @@ -147,7 +146,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (found) { MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { - yield return new AnalyzedMethodTreeNode(codeLocation, prefix); + var node = new AnalyzedMethodTreeNode(codeLocation); + node.Language = this.Language; + yield return node; } } } From 43e867c2ae25f59ee3b95715104e16c94ec99d0c Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 17:02:17 +1000 Subject: [PATCH 28/57] Implement filtering on DerivedTypesTreeNode. --- ILSpy/TreeNodes/DerivedTypesTreeNode.cs | 52 +++++++++++++++++++------ 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs index 2fd497395..9c3f77c70 100644 --- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs @@ -105,13 +105,13 @@ namespace ICSharpCode.ILSpy.TreeNodes class DerivedTypesEntryNode : ILSpyTreeNode, IMemberTreeNode { - TypeDefinition def; + TypeDefinition type; AssemblyDefinition[] assemblies; ThreadingSupport threading; - public DerivedTypesEntryNode(TypeDefinition def, AssemblyDefinition[] assemblies) + public DerivedTypesEntryNode(TypeDefinition type, AssemblyDefinition[] assemblies) { - this.def = def; + this.type = type; this.assemblies = assemblies; this.LazyLoading = true; threading = new ThreadingSupport(); @@ -119,20 +119,50 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool ShowExpander { get { - return !def.IsSealed && base.ShowExpander; + return !type.IsSealed && base.ShowExpander; } } public override object Text { - get { return this.Language.TypeToString(def, true); } + get { return this.Language.TypeToString(type, true); } } public override object Icon { get { - return TypeTreeNode.GetIcon(def); + return TypeTreeNode.GetIcon(type); } } - + + public override FilterResult Filter(FilterSettings settings) + { + if (!settings.ShowInternalApi && !IsPublicAPI) + return FilterResult.Hidden; + if (settings.SearchTermMatches(type.Name)) { + if (type.IsNested && !settings.Language.ShowMember(type)) + return FilterResult.Hidden; + else + return FilterResult.Match; + } else { + return FilterResult.Recurse; + } + } + + public bool IsPublicAPI + { + get + { + switch (type.Attributes & TypeAttributes.VisibilityMask) { + case TypeAttributes.Public: + case TypeAttributes.NestedPublic: + case TypeAttributes.NestedFamily: + case TypeAttributes.NestedFamORAssem: + return true; + default: + return false; + } + } + } + protected override void LoadChildren() { threading.LoadChildren(this, FetchChildren); @@ -141,21 +171,21 @@ namespace ICSharpCode.ILSpy.TreeNodes IEnumerable FetchChildren(CancellationToken ct) { // FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread - return DerivedTypesTreeNode.FindDerivedTypes(def, assemblies, ct); + return DerivedTypesTreeNode.FindDerivedTypes(type, assemblies, ct); } public override void ActivateItem(System.Windows.RoutedEventArgs e) { - e.Handled = BaseTypesEntryNode.ActivateItem(this, def); + e.Handled = BaseTypesEntryNode.ActivateItem(this, type); } public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { - language.WriteCommentLine(output, language.TypeToString(def, true)); + language.WriteCommentLine(output, language.TypeToString(type, true)); } MemberReference IMemberTreeNode.Member { - get { return def; } + get { return type; } } } } From 17f8c8f1efaa4c364babb711165056a85da13500 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 25 May 2011 20:37:54 +0200 Subject: [PATCH 29/57] convert elements with no value to empty elements --- ILSpy.BamlDecompiler/BamlResourceEntryNode.cs | 16 +++++++++++++++- .../XmlBamlReader.cs | 3 --- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs index cce7182f9..79b715105 100644 --- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs +++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs @@ -3,11 +3,12 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; +using System.Xml; using System.Xml.Linq; - using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; @@ -54,8 +55,21 @@ namespace ILSpy.BamlDecompiler using (XmlBamlReader reader = new XmlBamlReader(bamlStream, new CecilTypeResolver(asm))) xamlDocument = XDocument.Load(reader); + ConvertToEmptyElements(xamlDocument.Root); + output.Write(xamlDocument.ToString()); return true; } + + void ConvertToEmptyElements(XElement element) + { + foreach (var el in element.Elements()) { + if (!el.IsEmpty && !el.HasElements && el.Value == "") { + el.RemoveNodes(); + continue; + } + ConvertToEmptyElements(el); + } + } } } \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs index 93ed72c66..7f6fbbfc5 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs @@ -1057,9 +1057,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection private void ReadPropertyComplexEnd() { - if (!(elements.Peek() is XmlBamlPropertyElement)) - throw new InvalidCastException(); - XmlBamlPropertyElement propertyElement = (XmlBamlPropertyElement) elements.Peek(); CloseElement(); From 7c4b9448635e040b191a063521100ed53678c9b2 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 28 May 2011 21:06:08 +0200 Subject: [PATCH 30/57] implement MoveNamespacesToRoot and add Unit Tests --- ILSpy.BamlDecompiler/BamlResourceEntryNode.cs | 49 ++++++-- ILSpy.BamlDecompiler/CecilTypeResolver.cs | 14 ++- ILSpy.BamlDecompiler/Extensions.cs | 22 ++++ .../ILSpy.BamlDecompiler.csproj | 1 + .../Properties/AssemblyInfo.cs | 3 + .../XmlBamlReader.cs | 8 +- ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml | 3 + .../Tests/Cases/Simple.xaml.cs | 26 ++++ .../Tests/ILSpy.BamlDecompiler.Tests.csproj | 111 ++++++++++++++++++ .../Tests/Properties/AssemblyInfo.cs | 31 +++++ ILSpy.BamlDecompiler/Tests/TestRunner.cs | 67 +++++++++++ ILSpy.sln | 12 +- ILSpy/LoadedAssembly.cs | 5 + 13 files changed, 330 insertions(+), 22 deletions(-) create mode 100644 ILSpy.BamlDecompiler/Extensions.cs create mode 100644 ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml create mode 100644 ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml.cs create mode 100644 ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj create mode 100644 ILSpy.BamlDecompiler/Tests/Properties/AssemblyInfo.cs create mode 100644 ILSpy.BamlDecompiler/Tests/TestRunner.cs diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs index 79b715105..71c5f4131 100644 --- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs +++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs @@ -10,8 +10,10 @@ using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.ILSpy; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; +using Mono.Cecil; using Ricciolo.StylesExplorer.MarkupReflection; namespace ILSpy.BamlDecompiler @@ -43,25 +45,56 @@ namespace ILSpy.BamlDecompiler return true; } + const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; + const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; + bool LoadBaml(AvalonEditTextOutput output) { var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; - MemoryStream bamlStream = new MemoryStream(); Data.Position = 0; - Data.CopyTo(bamlStream); - bamlStream.Position = 0; + + XDocument xamlDocument = LoadIntoDocument(asm.GetAssemblyResolver(), asm.AssemblyDefinition, Data); + + output.Write(xamlDocument.ToString()); + return true; + } + + internal static XDocument LoadIntoDocument(IAssemblyResolver resolver, AssemblyDefinition asm, Stream stream) + { XDocument xamlDocument; - using (XmlBamlReader reader = new XmlBamlReader(bamlStream, new CecilTypeResolver(asm))) + using (XmlBamlReader reader = new XmlBamlReader(stream, new CecilTypeResolver(resolver, asm))) xamlDocument = XDocument.Load(reader); - ConvertToEmptyElements(xamlDocument.Root); + MoveNamespacesToRoot(xamlDocument); + return xamlDocument; + } + + static void MoveNamespacesToRoot(XDocument xamlDocument) + { + var additionalXmlns = new List { + new XAttribute("xmlns", DefaultWPFNamespace), + new XAttribute(XName.Get("x", XNamespace.Xmlns.NamespaceName), XWPFNamespace) + }; - output.Write(xamlDocument.ToString()); - return true; + foreach (var element in xamlDocument.Root.DescendantsAndSelf()) { + if (element.Name.NamespaceName != DefaultWPFNamespace && !additionalXmlns.Any(ka => ka.Value == element.Name.NamespaceName)) { + string newPrefix = new string(element.Name.LocalName.Where(c => char.IsUpper(c)).ToArray()).ToLowerInvariant(); + int current = additionalXmlns.Count(ka => ka.Name.Namespace == XNamespace.Xmlns && ka.Name.LocalName.TrimEnd(ch => char.IsNumber(ch)) == newPrefix); + if (current > 0) + newPrefix += (current + 1).ToString(); + XName defaultXmlns = XName.Get(newPrefix, XNamespace.Xmlns.NamespaceName); + if (element.Name.NamespaceName != DefaultWPFNamespace) + additionalXmlns.Add(new XAttribute(defaultXmlns, element.Name.NamespaceName)); + } + } + + foreach (var xmlns in additionalXmlns.Except(xamlDocument.Root.Attributes())) { + xamlDocument.Root.Add(xmlns); + } } - void ConvertToEmptyElements(XElement element) + static void ConvertToEmptyElements(XElement element) { foreach (var el in element.Elements()) { if (!el.IsEmpty && !el.HasElements && el.Value == "") { diff --git a/ILSpy.BamlDecompiler/CecilTypeResolver.cs b/ILSpy.BamlDecompiler/CecilTypeResolver.cs index 853025b06..90d0d0916 100644 --- a/ILSpy.BamlDecompiler/CecilTypeResolver.cs +++ b/ILSpy.BamlDecompiler/CecilTypeResolver.cs @@ -14,11 +14,13 @@ namespace ILSpy.BamlDecompiler /// public class CecilTypeResolver : ITypeResolver { - LoadedAssembly assembly; + IAssemblyResolver resolver; + AssemblyDefinition thisAssembly; - public CecilTypeResolver(LoadedAssembly assembly) + public CecilTypeResolver(IAssemblyResolver resolver, AssemblyDefinition asm) { - this.assembly = assembly; + this.resolver = resolver; + this.thisAssembly = asm; } public IType GetTypeByAssemblyQualifiedName(string name) @@ -31,12 +33,12 @@ namespace ILSpy.BamlDecompiler string fullName = name.Substring(0, comma); string assemblyName = name.Substring(comma + 1).Trim(); - var type = assembly.AssemblyDefinition.MainModule.GetType(fullName); + var type = thisAssembly.MainModule.GetType(fullName); if (type == null) { - var otherAssembly = assembly.LookupReferencedAssembly(assemblyName); + var otherAssembly = resolver.Resolve(assemblyName); if (otherAssembly == null) throw new Exception("could not resolve '" + assemblyName + "'!"); - type = otherAssembly.AssemblyDefinition.MainModule.GetType(fullName); + type = otherAssembly.MainModule.GetType(fullName); } return new CecilType(type); diff --git a/ILSpy.BamlDecompiler/Extensions.cs b/ILSpy.BamlDecompiler/Extensions.cs new file mode 100644 index 000000000..c76a581ea --- /dev/null +++ b/ILSpy.BamlDecompiler/Extensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) + +using System; +using System.Linq; + +namespace ILSpy.BamlDecompiler +{ + public static class Extensions + { + public static string TrimEnd(this string target, Func predicate) + { + if (target == null) + throw new ArgumentNullException("target"); + + while (predicate(target.LastOrDefault())) + target = target.Remove(target.Length - 1); + + return target; + } + } +} diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj index 6514c632b..c87d30781 100644 --- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj +++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj @@ -77,6 +77,7 @@ + diff --git a/ILSpy.BamlDecompiler/Properties/AssemblyInfo.cs b/ILSpy.BamlDecompiler/Properties/AssemblyInfo.cs index f28440c93..a2c459d27 100644 --- a/ILSpy.BamlDecompiler/Properties/AssemblyInfo.cs +++ b/ILSpy.BamlDecompiler/Properties/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; #endregion @@ -22,6 +23,8 @@ using System.Runtime.InteropServices; // If you need to expose a type to COM, use [ComVisible(true)] on that type. [assembly: ComVisible(false)] +[assembly: InternalsVisibleTo("ILSpy.BamlDecompiler.Tests")] + // The assembly version has following format : // // Major.Minor.Build.Revision diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs index 7f6fbbfc5..28120b490 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs @@ -284,13 +284,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection else currentType = (BamlRecordType)type; - if (currentType.ToString().EndsWith("End")) - Debug.Unindent(); - - Debug.WriteLine(currentType); - - if (currentType.ToString().StartsWith("Start")) - Debug.Indent(); +// Debug.WriteLine(currentType); } private bool SetNextNode() diff --git a/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml b/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml new file mode 100644 index 000000000..e54fa6efa --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml.cs b/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml.cs new file mode 100644 index 000000000..12770ff11 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml.cs @@ -0,0 +1,26 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ILSpy.BamlDecompiler.Tests.Cases +{ + /// + /// Interaction logic for Simple.xaml + /// + public partial class Simple : Window + { + public Simple() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj new file mode 100644 index 000000000..4955c4e1b --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -0,0 +1,111 @@ + + + + {1169E6D1-1899-43D4-A500-07CE4235B388} + Debug + x86 + Library + ILSpy.BamlDecompiler.Tests + ILSpy.BamlDecompiler.Tests + v4.0 + Client + False + False + 4 + false + + + x86 + False + Auto + 4194304 + 4096 + + + ..\bin\Debug\ + true + Full + False + True + DEBUG;TRACE + + + ..\bin\Release\ + false + None + True + False + TRACE + + + + ..\..\packages\DiffLib.1.0.0.55\lib\net35-Client\DiffLib.dll + + + ..\..\ICSharpCode.Decompiler\Tests\nunit.framework.dll + + + + 3.0 + + + + 3.0 + + + + 3.5 + + + 4.0 + + + + 3.5 + + + + 3.0 + + + + + Simple.xaml + Code + + + + + + + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22} + ICSharpCode.Decompiler.Tests + + + {1E85EFF9-E370-4683-83E4-8A3D063FF791} + ILSpy + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1} + ICSharpCode.TreeView + + + {A6BAD2BA-76BA-461C-8B6D-418607591247} + ILSpy.BamlDecompiler + + + + + + + + + Always + + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Properties/AssemblyInfo.cs b/ILSpy.BamlDecompiler/Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..30c5daa49 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,31 @@ +#region Using directives + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +#endregion + +// 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.BamlDecompiler.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ILSpy.BamlDecompiler.Tests")] +[assembly: AssemblyCopyright("Copyright 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all the values or you can use the default the Revision and +// Build Numbers by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.*")] diff --git a/ILSpy.BamlDecompiler/Tests/TestRunner.cs b/ILSpy.BamlDecompiler/Tests/TestRunner.cs new file mode 100644 index 000000000..6579dd0a1 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/TestRunner.cs @@ -0,0 +1,67 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Resources; +using System.Xml.Linq; +using ICSharpCode.Decompiler.Tests.Helpers; +using ICSharpCode.ILSpy; +using Mono.Cecil; +using NUnit.Framework; +using Ricciolo.StylesExplorer.MarkupReflection; + +namespace ILSpy.BamlDecompiler.Tests +{ + [TestFixture] + public class TestRunner + { + [Test] + public void Simple() + { + RunTest("cases/simple"); + } + + void RunTest(string name) + { + string asmPath = typeof(TestRunner).Assembly.Location; + var assembly = AssemblyDefinition.ReadAssembly(asmPath); + Resource res = assembly.MainModule.Resources.First(); + Stream bamlStream = LoadBaml(res, name + ".baml"); + Assert.IsNotNull(bamlStream); + XDocument document = BamlResourceEntryNode.LoadIntoDocument(new DefaultAssemblyResolver(), assembly, bamlStream); + string path = Path.Combine("..\\..\\Tests", name + ".xaml"); + + CodeAssert.AreEqual(document.ToString(), File.ReadAllText(path)); + } + + Stream LoadBaml(Resource res, string name) + { + EmbeddedResource er = res as EmbeddedResource; + if (er != null) { + Stream s = er.GetResourceStream(); + s.Position = 0; + ResourceReader reader; + try { + reader = new ResourceReader(s); + } + catch (ArgumentException) { + return null; + } + foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { + if (entry.Key.ToString() == name) { + if (entry.Value is Stream) + return (Stream)entry.Value; + if (entry.Value is byte[]) + return new MemoryStream((byte[])entry.Value); + } + } + } + + return null; + } + } +} diff --git a/ILSpy.sln b/ILSpy.sln index e3c407eb5..22cda9165 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.0.1.7146 +# SharpDevelop 4.1.0.7466-alpha Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" ProjectSection(SolutionItems) = postProject doc\Command Line.txt = doc\Command Line.txt @@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Pdb", "Mono.Ceci EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.BamlDecompiler", "ILSpy.BamlDecompiler\ILSpy.BamlDecompiler.csproj", "{A6BAD2BA-76BA-461C-8B6D-418607591247}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.BamlDecompiler.Tests", "ILSpy.BamlDecompiler\Tests\ILSpy.BamlDecompiler.Tests.csproj", "{1169E6D1-1899-43D4-A500-07CE4235B388}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -115,6 +117,14 @@ Global {A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|Any CPU.ActiveCfg = Release|Any CPU {A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|x86.Build.0 = Release|x86 {A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|x86.ActiveCfg = Release|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.Build.0 = Debug|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|Any CPU.ActiveCfg = Debug|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|x86.Build.0 = Debug|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Debug|x86.ActiveCfg = Debug|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.Build.0 = Release|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Release|Any CPU.ActiveCfg = Release|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Release|x86.Build.0 = Release|x86 + {1169E6D1-1899-43D4-A500-07CE4235B388}.Release|x86.ActiveCfg = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index 8285be9ae..2bb0ae05d 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -171,6 +171,11 @@ namespace ICSharpCode.ILSpy } } + public IAssemblyResolver GetAssemblyResolver() + { + return new MyAssemblyResolver(this); + } + public LoadedAssembly LookupReferencedAssembly(string fullName) { foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) { From 963f8ff94514973aeb6bcf9743ae9d20022e46d2 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 28 May 2011 22:14:16 +0200 Subject: [PATCH 31/57] implemented using base type as root node in decompiled BAML --- ILSpy.BamlDecompiler/CecilType.cs | 10 ++++++ ILSpy.BamlDecompiler/CecilTypeResolver.cs | 11 ++++++ .../AppDomainTypeResolver.cs | 11 ++++++ .../DotNetType.cs | 6 ++++ .../IType.cs | 3 +- .../ITypeResolver.cs | 2 ++ .../KnownInfo.cs | 36 +++++++++++++++---- .../XmlBamlReader.cs | 18 +++++++++- 8 files changed, 89 insertions(+), 8 deletions(-) diff --git a/ILSpy.BamlDecompiler/CecilType.cs b/ILSpy.BamlDecompiler/CecilType.cs index 41a0fc203..e84f95938 100644 --- a/ILSpy.BamlDecompiler/CecilType.cs +++ b/ILSpy.BamlDecompiler/CecilType.cs @@ -67,5 +67,15 @@ namespace ILSpy.BamlDecompiler { return string.Format("[CecilType Type={0}]", type); } + + public IType BaseType { + get { + TypeDefinition td = type.BaseType.Resolve(); + if (td == null) + throw new Exception("could not resolve '" + type.BaseType.FullName + "'!"); + + return new CecilType(td); + } + } } } diff --git a/ILSpy.BamlDecompiler/CecilTypeResolver.cs b/ILSpy.BamlDecompiler/CecilTypeResolver.cs index 90d0d0916..702c37c38 100644 --- a/ILSpy.BamlDecompiler/CecilTypeResolver.cs +++ b/ILSpy.BamlDecompiler/CecilTypeResolver.cs @@ -23,6 +23,11 @@ namespace ILSpy.BamlDecompiler this.thisAssembly = asm; } + public bool IsLocalAssembly(string name) + { + return name == this.thisAssembly.Name.Name; + } + public IType GetTypeByAssemblyQualifiedName(string name) { int comma = name.IndexOf(','); @@ -51,5 +56,11 @@ namespace ILSpy.BamlDecompiler return new CecilDependencyPropertyDescriptor(name, ((CecilType)ownerType).type); } + + public string RuntimeVersion { + get { + return thisAssembly.MainModule.Runtime.ToString(); + } + } } } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs index 9cc329459..b33379323 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs @@ -131,6 +131,17 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return null; } } + + public bool IsLocalAssembly(string name) + { + return false; + } + + public string RuntimeVersion { + get { + throw new NotImplementedException(); + } + } #endregion diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs index 1dbf1b21a..313863bd0 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs @@ -42,6 +42,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection if (_type == null) return false; return this._type.Equals(((DotNetType)type).Type); } + + public IType BaseType { + get { + return new DotNetType(this._type.BaseType.AssemblyQualifiedName); + } + } #endregion diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs index 7ec8c79e4..b420bf480 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs @@ -8,10 +8,11 @@ using System.Text; namespace Ricciolo.StylesExplorer.MarkupReflection { /// - /// Interface rappresenting a DotNet type + /// Interface representing a DotNet type /// public interface IType { + IType BaseType { get; } string AssemblyQualifiedName { get; } bool IsSubclassOf(IType type); bool Equals(IType type); diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs index 71e802a61..993126b32 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs @@ -9,6 +9,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { public interface ITypeResolver { + string RuntimeVersion { get; } + bool IsLocalAssembly(string name); IType GetTypeByAssemblyQualifiedName(string name); IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IType ownerType, IType targetType); } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs index e58762f41..81d7bea20 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs @@ -34,12 +34,16 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public KnownInfo(ITypeResolver resolver) { - KnownAssemblyTable = new string[5]; - KnownAssemblyTable[0] = "PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; - KnownAssemblyTable[1] = "PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; - KnownAssemblyTable[2] = "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; - KnownAssemblyTable[3] = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; - KnownAssemblyTable[4] = "WindowBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + switch (resolver.RuntimeVersion) { + case "Net_2_0": + LoadKnownAssemblies30(); + break; + case "Net_4_0": + LoadKnownAssemblies40(); + break; + default: + throw new NotSupportedException(); + } KnownTypeTable = new TypeDeclaration[760]; KnownTypeTable[0] = new TypeDeclaration(resolver, string.Empty, string.Empty, 0); @@ -1305,6 +1309,26 @@ namespace Ricciolo.StylesExplorer.MarkupReflection KnownResourceTable.Add(0xa9, new ResourceName("SystemParameters.WorkArea")); } + void LoadKnownAssemblies30() + { + KnownAssemblyTable = new string[5]; + KnownAssemblyTable[0] = "PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + KnownAssemblyTable[1] = "PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + KnownAssemblyTable[2] = "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + KnownAssemblyTable[3] = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + KnownAssemblyTable[4] = "WindowBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + } + + void LoadKnownAssemblies40() + { + KnownAssemblyTable = new string[5]; + KnownAssemblyTable[0] = "PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + KnownAssemblyTable[1] = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + KnownAssemblyTable[2] = "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + KnownAssemblyTable[3] = "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + KnownAssemblyTable[4] = "WindowBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; + } + #endregion public bool IsKnownType(string type) diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs index 28120b490..ccb790df6 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs @@ -8,6 +8,7 @@ using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Reflection; using System.Text; using System.Xml; @@ -445,7 +446,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection break; default: throw new NotImplementedException("UnsupportedNode: " + currentType); - break; } } @@ -1182,6 +1182,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } else element = new XmlBamlElement(); + + // the type is defined in the local assembly, i.e., the main assembly + // and this is the root element + if (_resolver.IsLocalAssembly(declaration.Assembly) && parentElement == null) { + declaration = GetKnownTypeDeclarationByName(declaration.Type.BaseType.AssemblyQualifiedName); + } element.TypeDeclaration = declaration; elements.Push(element); @@ -1563,6 +1569,16 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return declaration; } + + TypeDeclaration GetKnownTypeDeclarationByName(string name) + { + foreach (var type in KnownInfo.KnownTypeTable) { + if (name == string.Format("{0}.{1}, {2}", type.Namespace, type.Name, type.Assembly)) + return type; + } + + throw new NotSupportedException(); + } internal string GetAssembly(short identifier) { From f20cd83e6d0c63baee5a34385e5478e1a1ec0b7f Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 29 May 2011 09:19:15 +0200 Subject: [PATCH 32/57] implement x:Class detection in BamlDecompiler --- ILSpy.BamlDecompiler/BamlResourceEntryNode.cs | 14 +++----- .../ILSpy.BamlDecompiler.csproj | 1 + .../XmlBamlReader.cs | 29 ++++++++++++---- .../XmlBamlSimpleProperty.cs | 34 +++++++++++++++++++ 4 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs index 71c5f4131..b79492d1f 100644 --- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs +++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs @@ -45,17 +45,11 @@ namespace ILSpy.BamlDecompiler return true; } - const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; - const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; - bool LoadBaml(AvalonEditTextOutput output) { var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; Data.Position = 0; - - XDocument xamlDocument = LoadIntoDocument(asm.GetAssemblyResolver(), asm.AssemblyDefinition, Data); - output.Write(xamlDocument.ToString()); return true; } @@ -73,18 +67,18 @@ namespace ILSpy.BamlDecompiler static void MoveNamespacesToRoot(XDocument xamlDocument) { var additionalXmlns = new List { - new XAttribute("xmlns", DefaultWPFNamespace), - new XAttribute(XName.Get("x", XNamespace.Xmlns.NamespaceName), XWPFNamespace) + new XAttribute("xmlns", XmlBamlReader.DefaultWPFNamespace), + new XAttribute(XName.Get("x", XNamespace.Xmlns.NamespaceName), XmlBamlReader.XWPFNamespace) }; foreach (var element in xamlDocument.Root.DescendantsAndSelf()) { - if (element.Name.NamespaceName != DefaultWPFNamespace && !additionalXmlns.Any(ka => ka.Value == element.Name.NamespaceName)) { + if (element.Name.NamespaceName != XmlBamlReader.DefaultWPFNamespace && !additionalXmlns.Any(ka => ka.Value == element.Name.NamespaceName)) { string newPrefix = new string(element.Name.LocalName.Where(c => char.IsUpper(c)).ToArray()).ToLowerInvariant(); int current = additionalXmlns.Count(ka => ka.Name.Namespace == XNamespace.Xmlns && ka.Name.LocalName.TrimEnd(ch => char.IsNumber(ch)) == newPrefix); if (current > 0) newPrefix += (current + 1).ToString(); XName defaultXmlns = XName.Get(newPrefix, XNamespace.Xmlns.NamespaceName); - if (element.Name.NamespaceName != DefaultWPFNamespace) + if (element.Name.NamespaceName != XmlBamlReader.DefaultWPFNamespace) additionalXmlns.Add(new XAttribute(defaultXmlns, element.Name.NamespaceName)); } } diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj index c87d30781..a681f07fd 100644 --- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj +++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj @@ -98,6 +98,7 @@ + diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs index ccb790df6..6417549f7 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs @@ -55,6 +55,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection private readonly TypeDeclaration XamlTypeDeclaration; private readonly XmlNameTable _nameTable = new NameTable(); private IDictionary _rootNamespaces; + + public const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; + public const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; #endregion @@ -160,7 +163,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public override bool MoveToFirstAttribute() { intoAttribute = false; - if (nodes.Count > 0 && nodes.Peek() is XmlBamlProperty) + if (nodes.Count > 0 && (nodes.Peek() is XmlBamlProperty || nodes.Peek() is XmlBamlSimpleProperty)) { _currentNode = nodes.Dequeue(); return true; @@ -179,7 +182,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public override bool MoveToNextAttribute() { intoAttribute = false; - if (nodes.Count > 0 && nodes.Peek() is XmlBamlProperty) + if (nodes.Count > 0 && (nodes.Peek() is XmlBamlProperty || nodes.Peek() is XmlBamlSimpleProperty)) { _currentNode = nodes.Dequeue(); return true; @@ -197,7 +200,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection /// public override bool MoveToElement() { - while (nodes.Peek() is XmlBamlProperty) + while (nodes.Peek() is XmlBamlProperty || nodes.Peek() is XmlBamlSimpleProperty) { nodes.Dequeue(); } @@ -295,6 +298,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection _currentNode = nodes.Dequeue(); if ((_currentNode is XmlBamlProperty)) continue; + if ((_currentNode is XmlBamlSimpleProperty)) continue; if (this.NodeType == XmlNodeType.EndElement) { @@ -580,7 +584,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection String localName = String.Empty; XmlBamlNode node = this.CurrentNode; - if (node is XmlBamlProperty) + if (node is XmlBamlSimpleProperty) { + var simpleNode = (XmlBamlSimpleProperty)node; + localName = simpleNode.LocalName; + } else if (node is XmlBamlProperty) { PropertyDeclaration pd = ((XmlBamlProperty)node).PropertyDeclaration; localName = FormatPropertyDeclaration(pd, false, true, true); @@ -1185,13 +1192,19 @@ namespace Ricciolo.StylesExplorer.MarkupReflection // the type is defined in the local assembly, i.e., the main assembly // and this is the root element + TypeDeclaration oldDeclaration = null; if (_resolver.IsLocalAssembly(declaration.Assembly) && parentElement == null) { + oldDeclaration = declaration; declaration = GetKnownTypeDeclarationByName(declaration.Type.BaseType.AssemblyQualifiedName); } element.TypeDeclaration = declaration; elements.Push(element); nodes.Enqueue(element); + + if (oldDeclaration != null) { + nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "Class", string.Format("{0}.{1}", oldDeclaration.Namespace, oldDeclaration.Name))); + } if (parentElement != null && complexPropertyOpened == 0) { @@ -1609,7 +1622,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection TypeDeclaration declaration; XmlBamlNode node = this.CurrentNode; - if (node is XmlBamlProperty) + if (node is XmlBamlSimpleProperty) + return ((XmlBamlSimpleProperty)node).NamespaceName; + else if (node is XmlBamlProperty) { declaration = ((XmlBamlProperty)node).PropertyDeclaration.DeclaringType; TypeDeclaration elementDeclaration = this.readingElements.Peek().TypeDeclaration; @@ -1685,7 +1700,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection get { XmlBamlNode node = this.CurrentNode; - if (node is XmlBamlProperty) + if (node is XmlBamlSimpleProperty) + return ((XmlBamlSimpleProperty)node).Value; + else if (node is XmlBamlProperty) return ((XmlBamlProperty)node).Value.ToString(); else if (node is XmlBamlText) return ((XmlBamlText)node).Text; diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs new file mode 100644 index 000000000..be00e41e1 --- /dev/null +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlSimpleProperty.cs @@ -0,0 +1,34 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace Ricciolo.StylesExplorer.MarkupReflection +{ + class XmlBamlSimpleProperty : XmlBamlNode + { + public string NamespaceName { get; private set; } + public string LocalName { get; private set; } + public string Value { get; private set; } + + public XmlBamlSimpleProperty(string namespaceName, string localName, string value) + { + if (string.IsNullOrWhiteSpace(namespaceName)) + throw new ArgumentException("namespaceName"); + if (string.IsNullOrWhiteSpace(localName)) + throw new ArgumentException("localName"); + if (value == null) + throw new ArgumentNullException("value"); + this.NamespaceName = namespaceName; + this.LocalName = localName; + this.Value = value; + } + + public override XmlNodeType NodeType { + get { return XmlNodeType.Attribute; } + } + } +} From 9af1c54fe295080cdfb6ec37d4b1413b9e238582 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 29 May 2011 09:29:41 +0200 Subject: [PATCH 33/57] add simple unit test for ResourceDictionary --- ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml | 2 +- ILSpy.BamlDecompiler/Tests/Cases/SimpleDictionary.xaml | 1 + .../Tests/ILSpy.BamlDecompiler.Tests.csproj | 1 + ILSpy.BamlDecompiler/Tests/TestRunner.cs | 6 ++++++ 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 ILSpy.BamlDecompiler/Tests/Cases/SimpleDictionary.xaml diff --git a/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml b/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml index e54fa6efa..ab5d5afc6 100644 --- a/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml +++ b/ILSpy.BamlDecompiler/Tests/Cases/Simple.xaml @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/SimpleDictionary.xaml b/ILSpy.BamlDecompiler/Tests/Cases/SimpleDictionary.xaml new file mode 100644 index 000000000..4eb8fb3c7 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/SimpleDictionary.xaml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj index 4955c4e1b..975dfc6ee 100644 --- a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj +++ b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -106,6 +106,7 @@ Always + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/TestRunner.cs b/ILSpy.BamlDecompiler/Tests/TestRunner.cs index 6579dd0a1..441116873 100644 --- a/ILSpy.BamlDecompiler/Tests/TestRunner.cs +++ b/ILSpy.BamlDecompiler/Tests/TestRunner.cs @@ -25,6 +25,12 @@ namespace ILSpy.BamlDecompiler.Tests RunTest("cases/simple"); } + [Test] + public void SimpleDictionary() + { + RunTest("cases/simpledictionary"); + } + void RunTest(string name) { string asmPath = typeof(TestRunner).Assembly.Location; From e32c170ec48d4f6333615fd156bd320251a8a902 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 17:53:33 +1000 Subject: [PATCH 34/57] Move classes to separate files. --- ILSpy/ILSpy.csproj | 3 + ILSpy/TreeNodes/BaseTypesEntryNode.cs | 104 +++++++++++++++++++++ ILSpy/TreeNodes/BaseTypesTreeNode.cs | 96 +++----------------- ILSpy/TreeNodes/DerivedTypesEntryNode.cs | 111 +++++++++++++++++++++++ ILSpy/TreeNodes/DerivedTypesTreeNode.cs | 111 +++-------------------- ILSpy/TreeNodes/FilterResult.cs | 40 ++++++++ ILSpy/TreeNodes/ILSpyTreeNode.cs | 58 ++++-------- 7 files changed, 302 insertions(+), 221 deletions(-) create mode 100644 ILSpy/TreeNodes/BaseTypesEntryNode.cs create mode 100644 ILSpy/TreeNodes/DerivedTypesEntryNode.cs create mode 100644 ILSpy/TreeNodes/FilterResult.cs diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 1589927c7..8956512a1 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -158,6 +158,9 @@ + + + diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs new file mode 100644 index 000000000..821784ccb --- /dev/null +++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs @@ -0,0 +1,104 @@ +// 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.Linq; +using ICSharpCode.Decompiler; +using ICSharpCode.TreeView; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + sealed class BaseTypesEntryNode : ILSpyTreeNode, IMemberTreeNode + { + private TypeReference tr; + private TypeDefinition def; + private bool isInterface; + + public BaseTypesEntryNode(TypeReference tr, bool isInterface) + { + if (tr == null) + throw new ArgumentNullException("tr"); + this.tr = tr; + this.def = tr.Resolve(); + this.isInterface = isInterface; + this.LazyLoading = true; + } + + public override bool ShowExpander + { + get { return def != null && (def.BaseType != null || def.HasInterfaces); } + } + + public override object Text + { + get { return this.Language.TypeToString(tr, true); } + } + + public override object Icon + { + get + { + if (def != null) + return TypeTreeNode.GetIcon(def); + else + return isInterface ? Images.Interface : Images.Class; + } + } + + protected override void LoadChildren() + { + if (def != null) + BaseTypesTreeNode.AddBaseTypes(this.Children, def); + } + + public override void ActivateItem(System.Windows.RoutedEventArgs e) + { + // on item activation, try to resolve once again (maybe the user loaded the assembly in the meantime) + if (def == null) { + def = tr.Resolve(); + if (def != null) + this.LazyLoading = true; + // re-load children + } + e.Handled = ActivateItem(this, def); + } + + internal static bool ActivateItem(SharpTreeNode node, TypeDefinition def) + { + if (def != null) { + var assemblyListNode = node.Ancestors().OfType().FirstOrDefault(); + if (assemblyListNode != null) { + assemblyListNode.Select(assemblyListNode.FindTypeNode(def)); + return true; + } + } + return false; + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, language.TypeToString(tr, true)); + } + + MemberReference IMemberTreeNode.Member + { + get { return tr; } + } + } +} diff --git a/ILSpy/TreeNodes/BaseTypesTreeNode.cs b/ILSpy/TreeNodes/BaseTypesTreeNode.cs index 0209f7410..610458cdf 100644 --- a/ILSpy/TreeNodes/BaseTypesTreeNode.cs +++ b/ILSpy/TreeNodes/BaseTypesTreeNode.cs @@ -17,9 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using System.Windows.Threading; - using ICSharpCode.Decompiler; using ICSharpCode.TreeView; using Mono.Cecil; @@ -32,26 +30,28 @@ namespace ICSharpCode.ILSpy.TreeNodes sealed class BaseTypesTreeNode : ILSpyTreeNode { readonly TypeDefinition type; - + public BaseTypesTreeNode(TypeDefinition type) { this.type = type; this.LazyLoading = true; } - - public override object Text { + + public override object Text + { get { return "Base Types"; } } - - public override object Icon { + + public override object Icon + { get { return Images.SuperTypes; } } - + protected override void LoadChildren() { AddBaseTypes(this.Children, type); } - + internal static void AddBaseTypes(SharpTreeNodeCollection children, TypeDefinition type) { if (type.BaseType != null) @@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy.TreeNodes children.Add(new BaseTypesEntryNode(i, true)); } } - + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren)); @@ -69,78 +69,4 @@ namespace ICSharpCode.ILSpy.TreeNodes } } } - - sealed class BaseTypesEntryNode : ILSpyTreeNode, IMemberTreeNode - { - TypeReference tr; - TypeDefinition def; - bool isInterface; - - public BaseTypesEntryNode(TypeReference tr, bool isInterface) - { - if (tr == null) - throw new ArgumentNullException("tr"); - this.tr = tr; - this.def = tr.Resolve(); - this.isInterface = isInterface; - this.LazyLoading = true; - } - - public override bool ShowExpander { - get { - return def != null && (def.BaseType != null || def.HasInterfaces); - } - } - - public override object Text { - get { return this.Language.TypeToString(tr, true); } - } - - public override object Icon { - get { - if (def != null) - return TypeTreeNode.GetIcon(def); - else - return isInterface ? Images.Interface : Images.Class; - } - } - - protected override void LoadChildren() - { - if (def != null) - BaseTypesTreeNode.AddBaseTypes(this.Children, def); - } - - public override void ActivateItem(System.Windows.RoutedEventArgs e) - { - // on item activation, try to resolve once again (maybe the user loaded the assembly in the meantime) - if (def == null) { - def = tr.Resolve(); - if (def != null) - this.LazyLoading = true; // re-load children - } - e.Handled = ActivateItem(this, def); - } - - internal static bool ActivateItem(SharpTreeNode node, TypeDefinition def) - { - if (def != null) { - var assemblyListNode = node.Ancestors().OfType().FirstOrDefault(); - if (assemblyListNode != null) { - assemblyListNode.Select(assemblyListNode.FindTypeNode(def)); - return true; - } - } - return false; - } - - public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) - { - language.WriteCommentLine(output, language.TypeToString(tr, true)); - } - - MemberReference IMemberTreeNode.Member { - get { return tr; } - } - } -} +} \ No newline at end of file diff --git a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs new file mode 100644 index 000000000..326418633 --- /dev/null +++ b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs @@ -0,0 +1,111 @@ +// 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.Threading; +using ICSharpCode.Decompiler; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + class DerivedTypesEntryNode : ILSpyTreeNode, IMemberTreeNode + { + private TypeDefinition type; + private AssemblyDefinition[] assemblies; + private ThreadingSupport threading; + + public DerivedTypesEntryNode(TypeDefinition type, AssemblyDefinition[] assemblies) + { + this.type = type; + this.assemblies = assemblies; + this.LazyLoading = true; + threading = new ThreadingSupport(); + } + + public override bool ShowExpander + { + get { return !type.IsSealed && base.ShowExpander; } + } + + public override object Text + { + get { return this.Language.TypeToString(type, true); } + } + + public override object Icon + { + get { return TypeTreeNode.GetIcon(type); } + } + + public override FilterResult Filter(FilterSettings settings) + { + if (!settings.ShowInternalApi && !IsPublicAPI) + return FilterResult.Hidden; + if (settings.SearchTermMatches(type.Name)) { + if (type.IsNested && !settings.Language.ShowMember(type)) + return FilterResult.Hidden; + else + return FilterResult.Match; + } else + return FilterResult.Recurse; + } + + public bool IsPublicAPI + { + get + { + switch (type.Attributes & TypeAttributes.VisibilityMask) { + case TypeAttributes.Public: + case TypeAttributes.NestedPublic: + case TypeAttributes.NestedFamily: + case TypeAttributes.NestedFamORAssem: + return true; + default: + return false; + } + } + } + + protected override void LoadChildren() + { + threading.LoadChildren(this, FetchChildren); + } + + IEnumerable FetchChildren(CancellationToken ct) + { + // FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread + return DerivedTypesTreeNode.FindDerivedTypes(type, assemblies, ct); + } + + public override void ActivateItem(System.Windows.RoutedEventArgs e) + { + e.Handled = BaseTypesEntryNode.ActivateItem(this, type); + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, language.TypeToString(type, true)); + } + + MemberReference IMemberTreeNode.Member + { + get { return type; } + } + } +} diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs index 9c3f77c70..0775f58e9 100644 --- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs @@ -20,7 +20,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; - using ICSharpCode.Decompiler; using ICSharpCode.NRefactory.Utils; using Mono.Cecil; @@ -35,7 +34,7 @@ namespace ICSharpCode.ILSpy.TreeNodes readonly AssemblyList list; readonly TypeDefinition type; ThreadingSupport threading; - + public DerivedTypesTreeNode(AssemblyList list, TypeDefinition type) { this.list = list; @@ -43,27 +42,29 @@ namespace ICSharpCode.ILSpy.TreeNodes this.LazyLoading = true; this.threading = new ThreadingSupport(); } - - public override object Text { + + public override object Text + { get { return "Derived Types"; } } - - public override object Icon { + + public override object Icon + { get { return Images.SubTypes; } } - + protected override void LoadChildren() { threading.LoadChildren(this, FetchChildren); } - + IEnumerable FetchChildren(CancellationToken cancellationToken) { // FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread var assemblies = list.GetAssemblies().Select(node => node.AssemblyDefinition).Where(asm => asm != null).ToArray(); return FindDerivedTypes(type, assemblies, cancellationToken); } - + internal static IEnumerable FindDerivedTypes(TypeDefinition type, AssemblyDefinition[] assemblies, CancellationToken cancellationToken) { foreach (AssemblyDefinition asm in assemblies) { @@ -80,7 +81,7 @@ namespace ICSharpCode.ILSpy.TreeNodes } } } - + static bool IsSameType(TypeReference typeRef, TypeDefinition type) { if (typeRef.FullName == type.FullName) @@ -96,96 +97,10 @@ namespace ICSharpCode.ILSpy.TreeNodes return false; return true; } - - public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) - { - threading.Decompile(language, output, options, EnsureLazyChildren); - } - } - - class DerivedTypesEntryNode : ILSpyTreeNode, IMemberTreeNode - { - TypeDefinition type; - AssemblyDefinition[] assemblies; - ThreadingSupport threading; - - public DerivedTypesEntryNode(TypeDefinition type, AssemblyDefinition[] assemblies) - { - this.type = type; - this.assemblies = assemblies; - this.LazyLoading = true; - threading = new ThreadingSupport(); - } - - public override bool ShowExpander { - get { - return !type.IsSealed && base.ShowExpander; - } - } - - public override object Text { - get { return this.Language.TypeToString(type, true); } - } - - public override object Icon { - get { - return TypeTreeNode.GetIcon(type); - } - } - - public override FilterResult Filter(FilterSettings settings) - { - if (!settings.ShowInternalApi && !IsPublicAPI) - return FilterResult.Hidden; - if (settings.SearchTermMatches(type.Name)) { - if (type.IsNested && !settings.Language.ShowMember(type)) - return FilterResult.Hidden; - else - return FilterResult.Match; - } else { - return FilterResult.Recurse; - } - } - - public bool IsPublicAPI - { - get - { - switch (type.Attributes & TypeAttributes.VisibilityMask) { - case TypeAttributes.Public: - case TypeAttributes.NestedPublic: - case TypeAttributes.NestedFamily: - case TypeAttributes.NestedFamORAssem: - return true; - default: - return false; - } - } - } - protected override void LoadChildren() - { - threading.LoadChildren(this, FetchChildren); - } - - IEnumerable FetchChildren(CancellationToken ct) - { - // FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread - return DerivedTypesTreeNode.FindDerivedTypes(type, assemblies, ct); - } - - public override void ActivateItem(System.Windows.RoutedEventArgs e) - { - e.Handled = BaseTypesEntryNode.ActivateItem(this, type); - } - public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { - language.WriteCommentLine(output, language.TypeToString(type, true)); - } - - MemberReference IMemberTreeNode.Member { - get { return type; } + threading.Decompile(language, output, options, EnsureLazyChildren); } } -} +} \ No newline at end of file diff --git a/ILSpy/TreeNodes/FilterResult.cs b/ILSpy/TreeNodes/FilterResult.cs new file mode 100644 index 000000000..106bed1e3 --- /dev/null +++ b/ILSpy/TreeNodes/FilterResult.cs @@ -0,0 +1,40 @@ +// 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. + +namespace ICSharpCode.ILSpy.TreeNodes +{ + public enum FilterResult + { + /// + /// Hides the node. + /// + Hidden, + /// + /// Shows the node (and resets the search term for child nodes). + /// + Match, + /// + /// Hides the node only if all children are hidden (and resets the search term for child nodes). + /// + MatchAndRecurse, + /// + /// Hides the node only if all children are hidden (doesn't reset the search term for child nodes). + /// + Recurse + } +} diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs index ea92d8f22..8b4835fe5 100644 --- a/ILSpy/TreeNodes/ILSpyTreeNode.cs +++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs @@ -17,7 +17,6 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; @@ -33,21 +32,24 @@ namespace ICSharpCode.ILSpy.TreeNodes { FilterSettings filterSettings; bool childrenNeedFiltering; - - public FilterSettings FilterSettings { + + public FilterSettings FilterSettings + { get { return filterSettings; } - set { + set + { if (filterSettings != value) { filterSettings = value; OnFilterSettingsChanged(); } } } - - public Language Language { + + public Language Language + { get { return filterSettings != null ? filterSettings.Language : Languages.AllLanguages[0]; } } - + public virtual FilterResult Filter(FilterSettings settings) { if (string.IsNullOrEmpty(settings.SearchTerm)) @@ -55,15 +57,15 @@ namespace ICSharpCode.ILSpy.TreeNodes else return FilterResult.Hidden; } - + protected static object HighlightSearchMatch(string text, string suffix = null) { // TODO: implement highlighting the search match return text + suffix; } - + public abstract void Decompile(Language language, ITextOutput output, DecompilationOptions options); - + /// /// Used to implement special view logic for some items. /// This method is called on the main thread when only a single item is selected. @@ -73,7 +75,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { return false; } - + /// /// Used to implement special save logic for some items. /// This method is called on the main thread when only a single item is selected. @@ -83,7 +85,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { return false; } - + protected override void OnChildrenChanged(NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { @@ -96,7 +98,7 @@ namespace ICSharpCode.ILSpy.TreeNodes } base.OnChildrenChanged(e); } - + void ApplyFilterToChild(ILSpyTreeNode child) { FilterResult r; @@ -126,7 +128,7 @@ namespace ICSharpCode.ILSpy.TreeNodes throw new InvalidEnumArgumentException(); } } - + FilterSettings StripSearchTerm(FilterSettings filterSettings) { if (filterSettings == null) @@ -137,7 +139,7 @@ namespace ICSharpCode.ILSpy.TreeNodes } return filterSettings; } - + protected virtual void OnFilterSettingsChanged() { RaisePropertyChanged("Text"); @@ -148,13 +150,13 @@ namespace ICSharpCode.ILSpy.TreeNodes childrenNeedFiltering = true; } } - + protected override void OnIsVisibleChanged() { base.OnIsVisibleChanged(); EnsureChildrenFiltered(); } - + void EnsureChildrenFiltered() { EnsureLazyChildren(); @@ -165,24 +167,4 @@ namespace ICSharpCode.ILSpy.TreeNodes } } } - - public enum FilterResult - { - /// - /// Hides the node. - /// - Hidden, - /// - /// Shows the node (and resets the search term for child nodes). - /// - Match, - /// - /// Hides the node only if all children are hidden (and resets the search term for child nodes). - /// - MatchAndRecurse, - /// - /// Hides the node only if all children are hidden (doesn't reset the search term for child nodes). - /// - Recurse - } -} +} \ No newline at end of file From 7ddf11ef7505323c5cddbe2785a15d88fcb6587d Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 18:36:47 +1000 Subject: [PATCH 35/57] Move classes to separate files & organize command functionality under one folder. --- ILSpy/Commands.cs | 178 ------------------ ILSpy/Commands/BrowseBackCommand.cs | 32 ++++ ILSpy/Commands/BrowseForwardCommand.cs | 32 ++++ ILSpy/Commands/CommandWrapper.cs | 58 ++++++ ILSpy/Commands/DecompileAllCommand.cs | 69 +++++++ ILSpy/Commands/ExitCommand.cs | 31 +++ .../{ => Commands}/ExportCommandAttribute.cs | 0 ILSpy/Commands/OpenCommand.cs | 33 ++++ ILSpy/Commands/OpenFromGacCommand.cs | 34 ++++ ILSpy/Commands/RefreshCommand.cs | 33 ++++ ILSpy/Commands/SaveCommand.cs | 32 ++++ ILSpy/Commands/SimpleCommand.cs | 39 ++++ ILSpy/ILSpy.csproj | 14 +- 13 files changed, 405 insertions(+), 180 deletions(-) delete mode 100644 ILSpy/Commands.cs create mode 100644 ILSpy/Commands/BrowseBackCommand.cs create mode 100644 ILSpy/Commands/BrowseForwardCommand.cs create mode 100644 ILSpy/Commands/CommandWrapper.cs create mode 100644 ILSpy/Commands/DecompileAllCommand.cs create mode 100644 ILSpy/Commands/ExitCommand.cs rename ILSpy/{ => Commands}/ExportCommandAttribute.cs (100%) create mode 100644 ILSpy/Commands/OpenCommand.cs create mode 100644 ILSpy/Commands/OpenFromGacCommand.cs create mode 100644 ILSpy/Commands/RefreshCommand.cs create mode 100644 ILSpy/Commands/SaveCommand.cs create mode 100644 ILSpy/Commands/SimpleCommand.cs diff --git a/ILSpy/Commands.cs b/ILSpy/Commands.cs deleted file mode 100644 index 8d89e9afc..000000000 --- a/ILSpy/Commands.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.ComponentModel.Composition; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using System.Windows.Input; -using ICSharpCode.ILSpy.TextView; -using ICSharpCode.ILSpy.TreeNodes; - -namespace ICSharpCode.ILSpy -{ - [ExportMainMenuCommand(Menu = "_File", Header = "E_xit", MenuOrder = 99999, MenuCategory = "Exit")] - sealed class ExitCommand : SimpleCommand - { - public override void Execute(object parameter) - { - MainWindow.Instance.Close(); - } - } - - [ExportToolbarCommand(ToolTip = "Back", ToolbarIcon = "Images/Back.png", ToolbarCategory = "Navigation", ToolbarOrder = 0)] - sealed class BrowseBackCommand : CommandWrapper { - public BrowseBackCommand() : base(NavigationCommands.BrowseBack) {} - } - - [ExportToolbarCommand(ToolTip = "Forward", ToolbarIcon = "Images/Forward.png", ToolbarCategory = "Navigation", ToolbarOrder = 1)] - sealed class BrowseForwardCommand : CommandWrapper { - public BrowseForwardCommand() : base(NavigationCommands.BrowseForward) {} - } - - [ExportToolbarCommand(ToolTip = "Open", ToolbarIcon = "Images/Open.png", ToolbarCategory = "Open", ToolbarOrder = 0)] - [ExportMainMenuCommand(Menu = "_File", MenuIcon = "Images/Open.png", MenuCategory = "Open", MenuOrder = 0)] - sealed class OpenCommand : CommandWrapper { - public OpenCommand() : base(ApplicationCommands.Open) {} - } - - [ExportMainMenuCommand(Menu = "_File", Header = "Open from _GAC", MenuCategory = "Open", MenuOrder = 1)] - sealed class OpenFromGacCommand : SimpleCommand - { - public override void Execute(object parameter) - { - OpenFromGacDialog dlg = new OpenFromGacDialog(); - dlg.Owner = MainWindow.Instance; - if (dlg.ShowDialog() == true) { - MainWindow.Instance.OpenFiles(dlg.SelectedFileNames); - } - } - } - - [ExportToolbarCommand(ToolTip = "Reload all assemblies", ToolbarIcon = "Images/Refresh.png", ToolbarCategory = "Open", ToolbarOrder = 2)] - [ExportMainMenuCommand(Menu = "_File", Header = "Reload", MenuIcon = "Images/Refresh.png", MenuCategory = "Open", MenuOrder = 2)] - sealed class RefreshCommand : CommandWrapper { - public RefreshCommand() : base(NavigationCommands.Refresh) {} - } - - [ExportMainMenuCommand(Menu = "_File", Header = "_Save Code...", MenuIcon = "Images/SaveFile.png", MenuCategory = "Save", MenuOrder = 0)] - sealed class SaveCommand : CommandWrapper - { - public SaveCommand() : base(ApplicationCommands.Save) {} - } - - #if DEBUG - [ExportMainMenuCommand(Menu = "_File", Header = "DEBUG -- Decompile All", MenuCategory = "Open", MenuOrder = 2.5)] - sealed class DecompileAllCommand : SimpleCommand - { - public override bool CanExecute(object parameter) - { - return System.IO.Directory.Exists("c:\\temp\\decompiled"); - } - - public override void Execute(object parameter) - { - MainWindow.Instance.TextView.RunWithCancellation( - ct => Task.Factory.StartNew( - () => { - AvalonEditTextOutput output = new AvalonEditTextOutput(); - Parallel.ForEach( - MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), - new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, - delegate (LoadedAssembly asm) { - if (!asm.HasLoadError) { - Stopwatch w = Stopwatch.StartNew(); - Exception exception = null; - using (var writer = new System.IO.StreamWriter("c:\\temp\\decompiled\\" + asm.ShortName + ".cs")) { - try { - new CSharpLanguage().DecompileAssembly( - asm, new Decompiler.PlainTextOutput(writer), - new DecompilationOptions { FullDecompilation = true, CancellationToken = ct }); - } catch (Exception ex) { - writer.WriteLine(ex.ToString()); - exception = ex; - } - } - lock (output) { - output.Write(asm.ShortName + " - " + w.Elapsed); - if (exception != null) { - output.Write(" - "); - output.Write(exception.GetType().Name); - } - output.WriteLine(); - } - } - }); - return output; - } - ), - task => MainWindow.Instance.TextView.ShowText(task.Result)); - } - } - #endif - - class CommandWrapper : ICommand - { - ICommand wrappedCommand; - - public CommandWrapper(ICommand wrappedCommand) - { - this.wrappedCommand = wrappedCommand; - } - - public static ICommand Unwrap(ICommand command) - { - CommandWrapper w = command as CommandWrapper; - if (w != null) - return w.wrappedCommand; - else - return command; - } - - public event EventHandler CanExecuteChanged { - add { wrappedCommand.CanExecuteChanged += value; } - remove { wrappedCommand.CanExecuteChanged -= value; } - } - - public void Execute(object parameter) - { - wrappedCommand.Execute(parameter); - } - - public bool CanExecute(object parameter) - { - return wrappedCommand.CanExecute(parameter); - } - } - - public abstract class SimpleCommand : ICommand - { - public event EventHandler CanExecuteChanged { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - public abstract void Execute(object parameter); - - public virtual bool CanExecute(object parameter) - { - return true; - } - } -} diff --git a/ILSpy/Commands/BrowseBackCommand.cs b/ILSpy/Commands/BrowseBackCommand.cs new file mode 100644 index 000000000..e5af95db8 --- /dev/null +++ b/ILSpy/Commands/BrowseBackCommand.cs @@ -0,0 +1,32 @@ +// 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.Windows.Input; + +namespace ICSharpCode.ILSpy +{ + [ExportToolbarCommand(ToolTip = "Back", ToolbarIcon = "Images/Back.png", ToolbarCategory = "Navigation", ToolbarOrder = 0)] + sealed class BrowseBackCommand : CommandWrapper + { + public BrowseBackCommand() + : base(NavigationCommands.BrowseBack) + { + } + } +} diff --git a/ILSpy/Commands/BrowseForwardCommand.cs b/ILSpy/Commands/BrowseForwardCommand.cs new file mode 100644 index 000000000..1e0db84a7 --- /dev/null +++ b/ILSpy/Commands/BrowseForwardCommand.cs @@ -0,0 +1,32 @@ +// 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.Windows.Input; + +namespace ICSharpCode.ILSpy +{ + [ExportToolbarCommand(ToolTip = "Forward", ToolbarIcon = "Images/Forward.png", ToolbarCategory = "Navigation", ToolbarOrder = 1)] + sealed class BrowseForwardCommand : CommandWrapper + { + public BrowseForwardCommand() + : base(NavigationCommands.BrowseForward) + { + } + } +} diff --git a/ILSpy/Commands/CommandWrapper.cs b/ILSpy/Commands/CommandWrapper.cs new file mode 100644 index 000000000..f3d89138c --- /dev/null +++ b/ILSpy/Commands/CommandWrapper.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Windows.Input; + +namespace ICSharpCode.ILSpy +{ + class CommandWrapper : ICommand + { + private ICommand wrappedCommand; + + public CommandWrapper(ICommand wrappedCommand) + { + this.wrappedCommand = wrappedCommand; + } + + public static ICommand Unwrap(ICommand command) + { + CommandWrapper w = command as CommandWrapper; + if (w != null) + return w.wrappedCommand; + else + return command; + } + + public event EventHandler CanExecuteChanged + { + add { wrappedCommand.CanExecuteChanged += value; } + remove { wrappedCommand.CanExecuteChanged -= value; } + } + + public void Execute(object parameter) + { + wrappedCommand.Execute(parameter); + } + + public bool CanExecute(object parameter) + { + return wrappedCommand.CanExecute(parameter); + } + } +} diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs new file mode 100644 index 000000000..542c155e4 --- /dev/null +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -0,0 +1,69 @@ +// 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. + +#if DEBUG + +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using ICSharpCode.ILSpy.TextView; + +namespace ICSharpCode.ILSpy +{ + [ExportMainMenuCommand(Menu = "_File", Header = "DEBUG -- Decompile All", MenuCategory = "Open", MenuOrder = 2.5)] + sealed class DecompileAllCommand : SimpleCommand + { + public override bool CanExecute(object parameter) + { + return System.IO.Directory.Exists("c:\\temp\\decompiled"); + } + + public override void Execute(object parameter) + { + MainWindow.Instance.TextView.RunWithCancellation(ct => Task.Factory.StartNew(() => { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + Parallel.ForEach(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate(LoadedAssembly asm) { + if (!asm.HasLoadError) { + Stopwatch w = Stopwatch.StartNew(); + Exception exception = null; + using (var writer = new System.IO.StreamWriter("c:\\temp\\decompiled\\" + asm.ShortName + ".cs")) { + try { + new CSharpLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), new DecompilationOptions { FullDecompilation = true, CancellationToken = ct }); + } + catch (Exception ex) { + writer.WriteLine(ex.ToString()); + exception = ex; + } + } + lock (output) { + output.Write(asm.ShortName + " - " + w.Elapsed); + if (exception != null) { + output.Write(" - "); + output.Write(exception.GetType().Name); + } + output.WriteLine(); + } + } + }); + return output; + }), task => MainWindow.Instance.TextView.ShowText(task.Result)); + } + } +} + +#endif \ No newline at end of file diff --git a/ILSpy/Commands/ExitCommand.cs b/ILSpy/Commands/ExitCommand.cs new file mode 100644 index 000000000..d064aa557 --- /dev/null +++ b/ILSpy/Commands/ExitCommand.cs @@ -0,0 +1,31 @@ +// 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; + +namespace ICSharpCode.ILSpy +{ + [ExportMainMenuCommand(Menu = "_File", Header = "E_xit", MenuOrder = 99999, MenuCategory = "Exit")] + sealed class ExitCommand : SimpleCommand + { + public override void Execute(object parameter) + { + MainWindow.Instance.Close(); + } + } +} \ No newline at end of file diff --git a/ILSpy/ExportCommandAttribute.cs b/ILSpy/Commands/ExportCommandAttribute.cs similarity index 100% rename from ILSpy/ExportCommandAttribute.cs rename to ILSpy/Commands/ExportCommandAttribute.cs diff --git a/ILSpy/Commands/OpenCommand.cs b/ILSpy/Commands/OpenCommand.cs new file mode 100644 index 000000000..74030365f --- /dev/null +++ b/ILSpy/Commands/OpenCommand.cs @@ -0,0 +1,33 @@ +// 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.Windows.Input; + +namespace ICSharpCode.ILSpy +{ + [ExportToolbarCommand(ToolTip = "Open", ToolbarIcon = "Images/Open.png", ToolbarCategory = "Open", ToolbarOrder = 0)] + [ExportMainMenuCommand(Menu = "_File", MenuIcon = "Images/Open.png", MenuCategory = "Open", MenuOrder = 0)] + sealed class OpenCommand : CommandWrapper + { + public OpenCommand() + : base(ApplicationCommands.Open) + { + } + } +} diff --git a/ILSpy/Commands/OpenFromGacCommand.cs b/ILSpy/Commands/OpenFromGacCommand.cs new file mode 100644 index 000000000..ceeff5bdc --- /dev/null +++ b/ILSpy/Commands/OpenFromGacCommand.cs @@ -0,0 +1,34 @@ +// 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; + +namespace ICSharpCode.ILSpy +{ + [ExportMainMenuCommand(Menu = "_File", Header = "Open from _GAC", MenuCategory = "Open", MenuOrder = 1)] + sealed class OpenFromGacCommand : SimpleCommand + { + public override void Execute(object parameter) + { + OpenFromGacDialog dlg = new OpenFromGacDialog(); + dlg.Owner = MainWindow.Instance; + if (dlg.ShowDialog() == true) + MainWindow.Instance.OpenFiles(dlg.SelectedFileNames); + } + } +} diff --git a/ILSpy/Commands/RefreshCommand.cs b/ILSpy/Commands/RefreshCommand.cs new file mode 100644 index 000000000..21edd69c5 --- /dev/null +++ b/ILSpy/Commands/RefreshCommand.cs @@ -0,0 +1,33 @@ +// 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.Windows.Input; + +namespace ICSharpCode.ILSpy +{ + [ExportToolbarCommand(ToolTip = "Reload all assemblies", ToolbarIcon = "Images/Refresh.png", ToolbarCategory = "Open", ToolbarOrder = 2)] + [ExportMainMenuCommand(Menu = "_File", Header = "Reload", MenuIcon = "Images/Refresh.png", MenuCategory = "Open", MenuOrder = 2)] + sealed class RefreshCommand : CommandWrapper + { + public RefreshCommand() + : base(NavigationCommands.Refresh) + { + } + } +} diff --git a/ILSpy/Commands/SaveCommand.cs b/ILSpy/Commands/SaveCommand.cs new file mode 100644 index 000000000..63989d863 --- /dev/null +++ b/ILSpy/Commands/SaveCommand.cs @@ -0,0 +1,32 @@ +// 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.Windows.Input; + +namespace ICSharpCode.ILSpy +{ + [ExportMainMenuCommand(Menu = "_File", Header = "_Save Code...", MenuIcon = "Images/SaveFile.png", MenuCategory = "Save", MenuOrder = 0)] + sealed class SaveCommand : CommandWrapper + { + public SaveCommand() + : base(ApplicationCommands.Save) + { + } + } +} diff --git a/ILSpy/Commands/SimpleCommand.cs b/ILSpy/Commands/SimpleCommand.cs new file mode 100644 index 000000000..d8490a1a6 --- /dev/null +++ b/ILSpy/Commands/SimpleCommand.cs @@ -0,0 +1,39 @@ +// 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.Windows.Input; + +namespace ICSharpCode.ILSpy +{ + public abstract class SimpleCommand : ICommand + { + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public abstract void Execute(object parameter); + + public virtual bool CanExecute(object parameter) + { + return true; + } + } +} diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 8956512a1..f97c43f28 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -93,16 +93,20 @@ + + - + + + DecompilerSettingsPanel.xaml Code - + @@ -126,6 +130,8 @@ + + OpenFromGacDialog.xaml Code @@ -135,6 +141,8 @@ Code + + Code @@ -142,6 +150,7 @@ DisplaySettingsPanel.xaml Code + @@ -325,5 +334,6 @@ + \ No newline at end of file From bf5ddabfc6060f7df1a4564b2ed3c744e20cc862 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 18:41:21 +1000 Subject: [PATCH 36/57] Move IPane to separate file. --- ILSpy/ILSpy.csproj | 1 + ILSpy/IPane.cs | 27 +++++++++++++++++++++++++++ ILSpy/SearchPane.cs | 8 -------- 3 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 ILSpy/IPane.cs diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index f97c43f28..5488709c4 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -123,6 +123,7 @@ + diff --git a/ILSpy/IPane.cs b/ILSpy/IPane.cs new file mode 100644 index 000000000..2447f8bdd --- /dev/null +++ b/ILSpy/IPane.cs @@ -0,0 +1,27 @@ +// 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; + +namespace ICSharpCode.ILSpy +{ + public interface IPane + { + void Closed(); + } +} diff --git a/ILSpy/SearchPane.cs b/ILSpy/SearchPane.cs index d935b424c..1b829ea71 100644 --- a/ILSpy/SearchPane.cs +++ b/ILSpy/SearchPane.cs @@ -35,14 +35,6 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy { - /// - /// Notifies panes when they are closed. - /// - public interface IPane - { - void Closed(); - } - /// /// Search pane /// From 1ca1caef54cefd6912cf551b07e29b31e4496b0a Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 18:46:37 +1000 Subject: [PATCH 37/57] Split ShowAnalyzerCommand into separate file. --- ILSpy/AnalyzerTreeView.cs | 36 ++++++++------------------- ILSpy/Commands/ShowAnalyzerCommand.cs | 31 +++++++++++++++++++++++ ILSpy/ILSpy.csproj | 1 + 3 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 ILSpy/Commands/ShowAnalyzerCommand.cs diff --git a/ILSpy/AnalyzerTreeView.cs b/ILSpy/AnalyzerTreeView.cs index d89174d18..94f4ed66c 100644 --- a/ILSpy/AnalyzerTreeView.cs +++ b/ILSpy/AnalyzerTreeView.cs @@ -17,15 +17,6 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; - using ICSharpCode.ILSpy.TreeNodes.Analyzer; using ICSharpCode.TreeView; @@ -37,9 +28,11 @@ namespace ICSharpCode.ILSpy public partial class AnalyzerTreeView : SharpTreeView, IPane { static AnalyzerTreeView instance; - - public static AnalyzerTreeView Instance { - get { + + public static AnalyzerTreeView Instance + { + get + { if (instance == null) { App.Current.VerifyAccess(); instance = new AnalyzerTreeView(); @@ -47,42 +40,33 @@ namespace ICSharpCode.ILSpy return instance; } } - + private AnalyzerTreeView() { this.ShowRoot = false; this.Root = new AnalyzerTreeNode { Language = MainWindow.Instance.CurrentLanguage }; ContextMenuProvider.Add(this); } - + public void Show() { if (!IsVisible) MainWindow.Instance.ShowInBottomPane("Analyzer", this); } - + public void Show(AnalyzerTreeNode node) { Show(); - + node.IsExpanded = true; this.Root.Children.Add(node); this.SelectedItem = node; this.FocusNode(node); } - + void IPane.Closed() { this.Root.Children.Clear(); } } - - [ExportMainMenuCommand(Menu = "_View", Header = "_Analyzer", MenuCategory = "ShowPane", MenuOrder = 100)] - sealed class ShowAnalyzerCommand : SimpleCommand - { - public override void Execute(object parameter) - { - AnalyzerTreeView.Instance.Show(); - } - } } \ No newline at end of file diff --git a/ILSpy/Commands/ShowAnalyzerCommand.cs b/ILSpy/Commands/ShowAnalyzerCommand.cs new file mode 100644 index 000000000..1dcc74c6d --- /dev/null +++ b/ILSpy/Commands/ShowAnalyzerCommand.cs @@ -0,0 +1,31 @@ +// 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; + +namespace ICSharpCode.ILSpy +{ + [ExportMainMenuCommand(Menu = "_View", Header = "_Analyzer", MenuCategory = "ShowPane", MenuOrder = 100)] + sealed class ShowAnalyzerCommand : SimpleCommand + { + public override void Execute(object parameter) + { + AnalyzerTreeView.Instance.Show(); + } + } +} diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 5488709c4..bdfc4f123 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -152,6 +152,7 @@ Code + From 27461a9717ea57811804822f0ba68c1c6a29715b Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 18:52:55 +1000 Subject: [PATCH 38/57] Move all *Language classes to subfolder. --- ILSpy/ILSpy.csproj | 8 ++++---- ILSpy/{ => Languages}/CSharpLanguage.cs | 0 ILSpy/{ => Languages}/ILAstLanguage.cs | 0 ILSpy/{ => Languages}/ILLanguage.cs | 0 ILSpy/{ => Languages}/Language.cs | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename ILSpy/{ => Languages}/CSharpLanguage.cs (100%) rename ILSpy/{ => Languages}/ILAstLanguage.cs (100%) rename ILSpy/{ => Languages}/ILLanguage.cs (100%) rename ILSpy/{ => Languages}/Language.cs (100%) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index bdfc4f123..9b03b70f8 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -109,7 +109,7 @@ - + @@ -117,15 +117,15 @@ - - + + - + diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs similarity index 100% rename from ILSpy/CSharpLanguage.cs rename to ILSpy/Languages/CSharpLanguage.cs diff --git a/ILSpy/ILAstLanguage.cs b/ILSpy/Languages/ILAstLanguage.cs similarity index 100% rename from ILSpy/ILAstLanguage.cs rename to ILSpy/Languages/ILAstLanguage.cs diff --git a/ILSpy/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs similarity index 100% rename from ILSpy/ILLanguage.cs rename to ILSpy/Languages/ILLanguage.cs diff --git a/ILSpy/Language.cs b/ILSpy/Languages/Language.cs similarity index 100% rename from ILSpy/Language.cs rename to ILSpy/Languages/Language.cs From 60cf22a48cb3f482126b265547553ba65fb889b4 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sun, 29 May 2011 18:56:20 +1000 Subject: [PATCH 39/57] Move Languages collection to separate file. --- ILSpy/ILSpy.csproj | 1 + ILSpy/Languages/Language.cs | 43 +------------------------- ILSpy/Languages/Languages.cs | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 42 deletions(-) create mode 100644 ILSpy/Languages/Languages.cs diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 9b03b70f8..9090a9a0a 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -127,6 +127,7 @@ + diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index d9f566013..2f5f54972 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -18,9 +18,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel.Composition.Hosting; -using System.Linq; using ICSharpCode.Decompiler; using Mono.Cecil; @@ -156,42 +153,4 @@ namespace ICSharpCode.ILSpy return member; } } - - public static class Languages - { - static ReadOnlyCollection allLanguages; - - /// - /// A list of all languages. - /// - public static ReadOnlyCollection AllLanguages - { - get - { - return allLanguages; - } - } - - - internal static void Initialize(CompositionContainer composition) - { - List languages = new List(); - languages.AddRange(composition.GetExportedValues()); - languages.Add(new ILLanguage(true)); -#if DEBUG - languages.AddRange(ILAstLanguage.GetDebugLanguages()); - languages.AddRange(CSharpLanguage.GetDebugLanguages()); -#endif - allLanguages = languages.AsReadOnly(); - } - - /// - /// Gets a language using its name. - /// If the language is not found, C# is returned instead. - /// - public static Language GetLanguage(string name) - { - return AllLanguages.FirstOrDefault(l => l.Name == name) ?? AllLanguages.First(); - } - } -} +} \ No newline at end of file diff --git a/ILSpy/Languages/Languages.cs b/ILSpy/Languages/Languages.cs new file mode 100644 index 000000000..2cdac7a7e --- /dev/null +++ b/ILSpy/Languages/Languages.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Hosting; +using System.Linq; + +namespace ICSharpCode.ILSpy +{ + public static class Languages + { + private static ReadOnlyCollection allLanguages; + + /// + /// A list of all languages. + /// + public static ReadOnlyCollection AllLanguages + { + get { return allLanguages; } + } + + internal static void Initialize(CompositionContainer composition) + { + List languages = new List(); + languages.AddRange(composition.GetExportedValues()); + languages.Add(new ILLanguage(true)); + languages.AddRange(ILAstLanguage.GetDebugLanguages()); + languages.AddRange(CSharpLanguage.GetDebugLanguages()); + allLanguages = languages.AsReadOnly(); + } + + /// + /// Gets a language using its name. + /// If the language is not found, C# is returned instead. + /// + public static Language GetLanguage(string name) + { + return AllLanguages.FirstOrDefault(l => l.Name == name) ?? AllLanguages.First(); + } + } +} From 54cf43a1e14176fcba9cccbefe61a740da01e0cc Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 29 May 2011 13:14:41 +0200 Subject: [PATCH 40/57] Fix build. --- ILSpy/Languages/Languages.cs | 2 ++ Mono.Cecil/symbols/pdb/Mono.Cecil.Pdb.csproj | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ILSpy/Languages/Languages.cs b/ILSpy/Languages/Languages.cs index 2cdac7a7e..5b9e18092 100644 --- a/ILSpy/Languages/Languages.cs +++ b/ILSpy/Languages/Languages.cs @@ -41,8 +41,10 @@ namespace ICSharpCode.ILSpy List languages = new List(); languages.AddRange(composition.GetExportedValues()); languages.Add(new ILLanguage(true)); + #if DEBUG languages.AddRange(ILAstLanguage.GetDebugLanguages()); languages.AddRange(CSharpLanguage.GetDebugLanguages()); + #endif allLanguages = languages.AsReadOnly(); } diff --git a/Mono.Cecil/symbols/pdb/Mono.Cecil.Pdb.csproj b/Mono.Cecil/symbols/pdb/Mono.Cecil.Pdb.csproj index d0f6fe4ef..2d2dfd273 100644 --- a/Mono.Cecil/symbols/pdb/Mono.Cecil.Pdb.csproj +++ b/Mono.Cecil/symbols/pdb/Mono.Cecil.Pdb.csproj @@ -1,4 +1,4 @@ - + net_4_0_Debug @@ -13,6 +13,7 @@ 512 true ..\..\mono.snk + 0649 true From ba4717d5168c2ce94b524424b62bf7463c85966d Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Sun, 29 May 2011 14:19:59 +0300 Subject: [PATCH 41/57] Implement IDisposable for textview. --- ILSpy/TextView/DecompilerTextView.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index d539cbf1c..a072f7311 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy.TextView /// Contains all the threading logic that makes the decompiler work in the background. /// [Export, PartCreationPolicy(CreationPolicy.Shared)] - public sealed partial class DecompilerTextView : UserControl + public sealed partial class DecompilerTextView : UserControl, IDisposable { readonly ReferenceElementGenerator referenceElementGenerator; readonly UIElementGenerator uiElementGenerator; @@ -672,6 +672,11 @@ namespace ICSharpCode.ILSpy.TextView state.DecompiledNodes = decompiledNodes; return state; } + + public void Dispose() + { + DisplaySettingsPanel.CurrentDisplaySettings.PropertyChanged -= CurrentDisplaySettings_PropertyChanged; + } } public class DecompilerTextViewState From 8b611e50a48934f038f6532a2f3162d58a1b6a53 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 29 May 2011 20:01:35 +0200 Subject: [PATCH 42/57] Show architecture of assembly being decompiled. --- ILSpy/Languages/CSharpLanguage.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index ad3ee5ae1..8e7680a32 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -230,6 +230,29 @@ namespace ICSharpCode.ILSpy WriteProjectFile(new TextOutputWriter(output), files, assembly.AssemblyDefinition.MainModule); } else { base.DecompileAssembly(assembly, output, options); + output.WriteLine(); + ModuleDefinition mainModule = assembly.AssemblyDefinition.MainModule; + if (mainModule.EntryPoint != null) { + output.Write("// Entry point: "); + output.WriteReference(mainModule.EntryPoint.DeclaringType.FullName + "." + mainModule.EntryPoint.Name, mainModule.EntryPoint); + output.WriteLine(); + } + switch (mainModule.Architecture) { + case TargetArchitecture.I386: + if ((mainModule.Attributes & ModuleAttributes.Required32Bit) == ModuleAttributes.Required32Bit) + output.WriteLine("// Architecture: x86"); + else + output.WriteLine("// Architecture: AnyCPU"); + break; + case TargetArchitecture.AMD64: + output.WriteLine("// Architecture: x64"); + break; + case TargetArchitecture.IA64: + output.WriteLine("// Architecture: Itanium-64"); + break; + } + output.WriteLine(); + // don't automatically load additional assemblies when an assembly node is selected in the tree view using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) { AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.AssemblyDefinition.MainModule); From f2c001ab55c1740fc66a00c2b64e8023e2603010 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 29 May 2011 20:03:04 +0200 Subject: [PATCH 43/57] Show .NET runtime version. --- ILSpy/Languages/CSharpLanguage.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 8e7680a32..699fee3ad 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -251,6 +251,20 @@ namespace ICSharpCode.ILSpy output.WriteLine("// Architecture: Itanium-64"); break; } + 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; + } output.WriteLine(); // don't automatically load additional assemblies when an assembly node is selected in the tree view From c339b9270a7b620c6b97b38e27bd7fbf9dbbd0fd Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 29 May 2011 20:21:18 +0200 Subject: [PATCH 44/57] Fix crash in disassembler and decompiler when HasPInvokeInfo=true but PInvokeInfo=null (occurs with unmanaged methods in C++/CLI assemblies) --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 2 +- ICSharpCode.Decompiler/Ast/NameVariables.cs | 2 ++ ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs | 2 +- ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs | 2 +- ILSpy/Languages/CSharpLanguage.cs | 3 +++ 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 0c50975b4..f39a4cbf0 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -1151,7 +1151,7 @@ namespace ICSharpCode.Decompiler.Ast MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask; #region DllImportAttribute - if (methodDefinition.HasPInvokeInfo) { + if (methodDefinition.HasPInvokeInfo && methodDefinition.PInvokeInfo != null) { PInvokeInfo info = methodDefinition.PInvokeInfo; Ast.Attribute dllImport = CreateNonCustomAttribute(typeof(DllImportAttribute)); dllImport.Arguments.Add(new PrimitiveExpression(info.Module.Name)); diff --git a/ICSharpCode.Decompiler/Ast/NameVariables.cs b/ICSharpCode.Decompiler/Ast/NameVariables.cs index defc30202..9b3632119 100644 --- a/ICSharpCode.Decompiler/Ast/NameVariables.cs +++ b/ICSharpCode.Decompiler/Ast/NameVariables.cs @@ -284,6 +284,8 @@ namespace ICSharpCode.Decompiler.Ast string GetNameByType(TypeReference type) { + type = TypeAnalysis.UnpackModifiers(type); + GenericInstanceType git = type as GenericInstanceType; if (git != null && git.ElementType.FullName == "System.Nullable`1" && git.GenericArguments.Count == 1) { type = ((GenericInstanceType)type).GenericArguments[0]; diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 4e144924e..f623597da 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -117,7 +117,7 @@ namespace ICSharpCode.Decompiler.Disassembler if ((method.Attributes & MethodAttributes.PInvokeImpl) == MethodAttributes.PInvokeImpl) { output.Write("pinvokeimpl"); - if (method.HasPInvokeInfo) { + if (method.HasPInvokeInfo && method.PInvokeInfo != null) { PInvokeInfo info = method.PInvokeInfo; output.Write("(\"" + NRefactory.CSharp.OutputVisitor.ConvertString(info.Module.Name) + "\""); diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 3667bc895..9eacc13d7 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -849,7 +849,7 @@ namespace ICSharpCode.Decompiler.ILAst return null; } - static TypeReference UnpackModifiers(TypeReference type) + internal static TypeReference UnpackModifiers(TypeReference type) { while (type is OptionalModifierType || type is RequiredModifierType) type = ((TypeSpecification)type).ElementType; diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 699fee3ad..2bca8b859 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -251,6 +251,9 @@ namespace ICSharpCode.ILSpy output.WriteLine("// Architecture: Itanium-64"); break; } + 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"); From df94edc2d4a5fc7d74ca8c4225d5c0983c06d170 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 03:11:12 +0200 Subject: [PATCH 45/57] Fix InvalidCastException when hovering over a type reference. --- ILSpy/XmlDoc/XmlDocKeyProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ILSpy/XmlDoc/XmlDocKeyProvider.cs b/ILSpy/XmlDoc/XmlDocKeyProvider.cs index fc503c115..d4f1e646c 100644 --- a/ILSpy/XmlDoc/XmlDocKeyProvider.cs +++ b/ILSpy/XmlDoc/XmlDocKeyProvider.cs @@ -36,7 +36,7 @@ namespace ICSharpCode.ILSpy.XmlDoc StringBuilder b = new StringBuilder(); if (member is TypeReference) { b.Append("T:"); - AppendTypeName(b, (TypeDefinition)member); + AppendTypeName(b, (TypeReference)member); } else { if (member is FieldReference) b.Append("F:"); From 64f409ad28495bef3f36802b1a064fd284ace6dd Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 18:06:51 +0200 Subject: [PATCH 46/57] Remove duplicate references in BamlDecompiler.Tests. --- ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj index 975dfc6ee..61cfa995c 100644 --- a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj +++ b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -44,11 +44,9 @@ ..\..\ICSharpCode.Decompiler\Tests\nunit.framework.dll - 3.0 - 3.0 @@ -63,7 +61,6 @@ 3.5 - 3.0 From c31f9232c5efb0d8c90cfea244ed0976e7bee65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 2 Jun 2011 17:01:07 +0100 Subject: [PATCH 47/57] Do not fall though the end of try-block. It should never happen in valid IL, but some obfuscators generate such code. Closes #164 --- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index f6edfad85..e569c83e8 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -281,6 +281,8 @@ namespace ICSharpCode.Decompiler.ILAst int varCount = methodDef.Body.Variables.Count; + var exceptionHandlerStarts = new HashSet(methodDef.Body.ExceptionHandlers.Select(eh => instrToByteCode[eh.HandlerStart])); + // Add known states if(methodDef.Body.HasExceptionHandlers) { foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { @@ -347,7 +349,12 @@ namespace ICSharpCode.Decompiler.ILAst // Find all successors List branchTargets = new List(); if (!byteCode.Code.IsUnconditionalControlFlow()) { - branchTargets.Add(byteCode.Next); + if (exceptionHandlerStarts.Contains(byteCode.Next)) { + // Do not fall though down to exception handler + // It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it + } else { + branchTargets.Add(byteCode.Next); + } } if (byteCode.Operand is Instruction[]) { foreach(Instruction inst in (Instruction[])byteCode.Operand) { From 6fd28e8b6eb9f0c594024ef19a03fe4edacc0457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 2 Jun 2011 17:50:48 +0100 Subject: [PATCH 48/57] Remove unreachable return statements. Closes #174. Closes #192 --- ICSharpCode.Decompiler/ILAst/GotoRemoval.cs | 19 ++++++++++++++++++- .../ILAst/ILAstOptimizer.cs | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs index 351c28428..fafe13e1a 100644 --- a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs +++ b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs @@ -98,10 +98,27 @@ namespace ICSharpCode.Decompiler.ILAst } } - // Remove redundant return + // Remove redundant return at the end of method if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { method.Body.RemoveAt(method.Body.Count - 1); } + + // Remove unreachable return statements + bool modified = false; + foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { + for (int i = 0; i < block.Body.Count - 1;) { + if (block.Body[i].IsUnconditionalControlFlow() && block.Body[i+1].Match(ILCode.Ret)) { + modified = true; + block.Body.RemoveAt(i+1); + } else { + i++; + } + } + } + if (modified) { + // More removals might be possible + new GotoRemoval().RemoveGotos(method); + } } IEnumerable GetParents(ILNode node) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index c4447f4d4..31bfc741f 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -56,6 +56,7 @@ namespace ICSharpCode.Decompiler.ILAst RemoveRedundantCode2, GotoRemoval, DuplicateReturns, + GotoRemoval2, ReduceIfNesting, InlineVariables3, CachedDelegateInitialization, @@ -182,6 +183,9 @@ namespace ICSharpCode.Decompiler.ILAst if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) return; DuplicateReturnStatements(method); + if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval2) return; + new GotoRemoval().RemoveGotos(method); + if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) return; ReduceIfNesting(method); From 6daf7cb6bc102435d64acbae74b8534403ea1161 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 19:30:17 +0200 Subject: [PATCH 49/57] Fix some compiler warnings. --- .../Tests/ICSharpCode.Decompiler.Tests.csproj | 2 +- .../TypeDeclaration.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 33227a313..13af1018c 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -13,8 +13,8 @@ False 4 false - 67,169 False + 67,169,1058,728 x86 diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs index 2efaab843..2acc523f4 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs @@ -132,6 +132,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection else return false; } + + public override int GetHashCode() + { + return this.AssemblyId ^ this.Name.GetHashCode() ^ this.Namespace.GetHashCode(); + } } } From 9376ece056af882b0d081086d344b4a4518f8dee Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 19:43:52 +0200 Subject: [PATCH 50/57] Fixed references to enum values nested within generic types. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 12 ++++++------ ICSharpCode.Decompiler/Tests/Generics.cs | 8 ++++++++ ICSharpCode.Decompiler/Tests/TestRunner.cs | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index f39a4cbf0..05e82499f 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -1501,13 +1501,13 @@ namespace ICSharpCode.Decompiler.Ast { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) TypeDefinition enumDefinition = type.Resolve(); if (enumDefinition != null && enumDefinition.IsEnum) { + TypeCode enumBaseTypeCode = TypeCode.Int32; foreach (FieldDefinition field in enumDefinition.Fields) { if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) - return ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + return ConvertType(type).Member(field.Name).WithAnnotation(field); else if (!field.IsStatic && field.IsRuntimeSpecialName) - type = field.FieldType; // use primitive type of the enum + enumBaseTypeCode = TypeAnalysis.GetTypeCode(field.FieldType); // use primitive type of the enum } - TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type); if (IsFlagsEnum(enumDefinition)) { long enumValue = val; Expression expr = null; @@ -1534,7 +1534,7 @@ namespace ICSharpCode.Decompiler.Ast continue; // skip None enum value if ((fieldValue & enumValue) == fieldValue) { - var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); if (expr == null) expr = fieldExpression; else @@ -1543,7 +1543,7 @@ namespace ICSharpCode.Decompiler.Ast enumValue &= ~fieldValue; } if ((fieldValue & negatedEnumValue) == fieldValue) { - var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); if (negatedExpr == null) negatedExpr = fieldExpression; else @@ -1561,7 +1561,7 @@ namespace ICSharpCode.Decompiler.Ast return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr); } } - return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(enumDefinition)); + return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type)); } } TypeCode code = TypeAnalysis.GetTypeCode(type); diff --git a/ICSharpCode.Decompiler/Tests/Generics.cs b/ICSharpCode.Decompiler/Tests/Generics.cs index 9924583d6..9b7bd3fea 100644 --- a/ICSharpCode.Decompiler/Tests/Generics.cs +++ b/ICSharpCode.Decompiler/Tests/Generics.cs @@ -29,6 +29,12 @@ public static class Generics public Y Item2; } + public enum NestedEnum + { + A, + B + } + private T[] arr; public MyArray(int capacity) @@ -75,11 +81,13 @@ public static class Generics } } + private const Generics.MyArray.NestedEnum enumVal = Generics.MyArray.NestedEnum.A; private static Type type1 = typeof(List<>); private static Type type2 = typeof(Generics.MyArray<>); private static Type type3 = typeof(List<>.Enumerator); private static Type type4 = typeof(Generics.MyArray<>.NestedClass<>); private static Type type5 = typeof(List[]); + private static Type type6 = typeof(Generics.MyArray<>.NestedEnum); public static void MethodWithConstraint() where T : class, S where S : ICloneable, new() { diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index a05779ecc..52bef700c 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -158,7 +158,7 @@ namespace ICSharpCode.Decompiler.Tests { CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); - options.CompilerOptions = "/unsafe"; + options.CompilerOptions = "/unsafe /o-"; options.ReferencedAssemblies.Add("System.Core.dll"); CompilerResults results = provider.CompileAssemblyFromSource(options, code); try { From 9cb4de3aa38d2d226daf123a86f93ccc590555f8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 03:11:12 +0200 Subject: [PATCH 51/57] Fix InvalidCastException when hovering over a type reference. --- ILSpy/XmlDoc/XmlDocKeyProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ILSpy/XmlDoc/XmlDocKeyProvider.cs b/ILSpy/XmlDoc/XmlDocKeyProvider.cs index fc503c115..d4f1e646c 100644 --- a/ILSpy/XmlDoc/XmlDocKeyProvider.cs +++ b/ILSpy/XmlDoc/XmlDocKeyProvider.cs @@ -36,7 +36,7 @@ namespace ICSharpCode.ILSpy.XmlDoc StringBuilder b = new StringBuilder(); if (member is TypeReference) { b.Append("T:"); - AppendTypeName(b, (TypeDefinition)member); + AppendTypeName(b, (TypeReference)member); } else { if (member is FieldReference) b.Append("F:"); From 19f5176186f7c7a33ffe529292afb880b93e2795 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 18:06:51 +0200 Subject: [PATCH 52/57] Remove duplicate references in BamlDecompiler.Tests. --- ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj index 975dfc6ee..61cfa995c 100644 --- a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj +++ b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -44,11 +44,9 @@ ..\..\ICSharpCode.Decompiler\Tests\nunit.framework.dll - 3.0 - 3.0 @@ -63,7 +61,6 @@ 3.5 - 3.0 From de4389cb391e2751d5eeea867318df2211eeb6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 2 Jun 2011 17:01:07 +0100 Subject: [PATCH 53/57] Do not fall though the end of try-block. It should never happen in valid IL, but some obfuscators generate such code. Closes #164 --- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index f6edfad85..e569c83e8 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -281,6 +281,8 @@ namespace ICSharpCode.Decompiler.ILAst int varCount = methodDef.Body.Variables.Count; + var exceptionHandlerStarts = new HashSet(methodDef.Body.ExceptionHandlers.Select(eh => instrToByteCode[eh.HandlerStart])); + // Add known states if(methodDef.Body.HasExceptionHandlers) { foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { @@ -347,7 +349,12 @@ namespace ICSharpCode.Decompiler.ILAst // Find all successors List branchTargets = new List(); if (!byteCode.Code.IsUnconditionalControlFlow()) { - branchTargets.Add(byteCode.Next); + if (exceptionHandlerStarts.Contains(byteCode.Next)) { + // Do not fall though down to exception handler + // It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it + } else { + branchTargets.Add(byteCode.Next); + } } if (byteCode.Operand is Instruction[]) { foreach(Instruction inst in (Instruction[])byteCode.Operand) { From f9d877b25a3e251c2358db30f3c903c10b854da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 2 Jun 2011 17:50:48 +0100 Subject: [PATCH 54/57] Remove unreachable return statements. Closes #174. Closes #192 --- ICSharpCode.Decompiler/ILAst/GotoRemoval.cs | 19 ++++++++++++++++++- .../ILAst/ILAstOptimizer.cs | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs index 351c28428..fafe13e1a 100644 --- a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs +++ b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs @@ -98,10 +98,27 @@ namespace ICSharpCode.Decompiler.ILAst } } - // Remove redundant return + // Remove redundant return at the end of method if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { method.Body.RemoveAt(method.Body.Count - 1); } + + // Remove unreachable return statements + bool modified = false; + foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { + for (int i = 0; i < block.Body.Count - 1;) { + if (block.Body[i].IsUnconditionalControlFlow() && block.Body[i+1].Match(ILCode.Ret)) { + modified = true; + block.Body.RemoveAt(i+1); + } else { + i++; + } + } + } + if (modified) { + // More removals might be possible + new GotoRemoval().RemoveGotos(method); + } } IEnumerable GetParents(ILNode node) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index c4447f4d4..31bfc741f 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -56,6 +56,7 @@ namespace ICSharpCode.Decompiler.ILAst RemoveRedundantCode2, GotoRemoval, DuplicateReturns, + GotoRemoval2, ReduceIfNesting, InlineVariables3, CachedDelegateInitialization, @@ -182,6 +183,9 @@ namespace ICSharpCode.Decompiler.ILAst if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) return; DuplicateReturnStatements(method); + if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval2) return; + new GotoRemoval().RemoveGotos(method); + if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) return; ReduceIfNesting(method); From 320b6d96c2ba567bf213639c0200de9ee2b60b83 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 19:30:17 +0200 Subject: [PATCH 55/57] Fix some compiler warnings. --- .../Tests/ICSharpCode.Decompiler.Tests.csproj | 2 +- .../TypeDeclaration.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 33227a313..13af1018c 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -13,8 +13,8 @@ False 4 false - 67,169 False + 67,169,1058,728 x86 diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs index 2efaab843..2acc523f4 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs @@ -132,6 +132,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection else return false; } + + public override int GetHashCode() + { + return this.AssemblyId ^ this.Name.GetHashCode() ^ this.Namespace.GetHashCode(); + } } } From 4f5fb6c140d6c15044bf78ea8c23de56cf9cf892 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 19:43:52 +0200 Subject: [PATCH 56/57] Fixed references to enum values nested within generic types. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 12 ++++++------ ICSharpCode.Decompiler/Tests/Generics.cs | 8 ++++++++ ICSharpCode.Decompiler/Tests/TestRunner.cs | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index a9f5e3063..2a2af5d2c 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -1509,13 +1509,13 @@ namespace ICSharpCode.Decompiler.Ast { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) TypeDefinition enumDefinition = type.Resolve(); if (enumDefinition != null && enumDefinition.IsEnum) { + TypeCode enumBaseTypeCode = TypeCode.Int32; foreach (FieldDefinition field in enumDefinition.Fields) { if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) - return ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + return ConvertType(type).Member(field.Name).WithAnnotation(field); else if (!field.IsStatic && field.IsRuntimeSpecialName) - type = field.FieldType; // use primitive type of the enum + enumBaseTypeCode = TypeAnalysis.GetTypeCode(field.FieldType); // use primitive type of the enum } - TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type); if (IsFlagsEnum(enumDefinition)) { long enumValue = val; Expression expr = null; @@ -1542,7 +1542,7 @@ namespace ICSharpCode.Decompiler.Ast continue; // skip None enum value if ((fieldValue & enumValue) == fieldValue) { - var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); if (expr == null) expr = fieldExpression; else @@ -1551,7 +1551,7 @@ namespace ICSharpCode.Decompiler.Ast enumValue &= ~fieldValue; } if ((fieldValue & negatedEnumValue) == fieldValue) { - var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); if (negatedExpr == null) negatedExpr = fieldExpression; else @@ -1569,7 +1569,7 @@ namespace ICSharpCode.Decompiler.Ast return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr); } } - return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(enumDefinition)); + return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type)); } } TypeCode code = TypeAnalysis.GetTypeCode(type); diff --git a/ICSharpCode.Decompiler/Tests/Generics.cs b/ICSharpCode.Decompiler/Tests/Generics.cs index 9924583d6..9b7bd3fea 100644 --- a/ICSharpCode.Decompiler/Tests/Generics.cs +++ b/ICSharpCode.Decompiler/Tests/Generics.cs @@ -29,6 +29,12 @@ public static class Generics public Y Item2; } + public enum NestedEnum + { + A, + B + } + private T[] arr; public MyArray(int capacity) @@ -75,11 +81,13 @@ public static class Generics } } + private const Generics.MyArray.NestedEnum enumVal = Generics.MyArray.NestedEnum.A; private static Type type1 = typeof(List<>); private static Type type2 = typeof(Generics.MyArray<>); private static Type type3 = typeof(List<>.Enumerator); private static Type type4 = typeof(Generics.MyArray<>.NestedClass<>); private static Type type5 = typeof(List[]); + private static Type type6 = typeof(Generics.MyArray<>.NestedEnum); public static void MethodWithConstraint() where T : class, S where S : ICloneable, new() { diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index a05779ecc..52bef700c 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -158,7 +158,7 @@ namespace ICSharpCode.Decompiler.Tests { CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); - options.CompilerOptions = "/unsafe"; + options.CompilerOptions = "/unsafe /o-"; options.ReferencedAssemblies.Add("System.Core.dll"); CompilerResults results = provider.CompileAssemblyFromSource(options, code); try { From 6af0d51969a176192dd9f8d28648d64cb30d1ac8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 3 Jun 2011 16:36:17 +0200 Subject: [PATCH 57/57] Change version number to 2.0 --- ILSpy/Properties/AssemblyInfo.template.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ILSpy/Properties/AssemblyInfo.template.cs b/ILSpy/Properties/AssemblyInfo.template.cs index b6c0c3fd9..247f8e857 100644 --- a/ILSpy/Properties/AssemblyInfo.template.cs +++ b/ILSpy/Properties/AssemblyInfo.template.cs @@ -31,7 +31,7 @@ using System.Runtime.InteropServices; internal static class RevisionClass { - public const string Major = "1"; + public const string Major = "2"; public const string Minor = "0"; public const string Build = "0"; public const string Revision = "$INSERTREVISION$";