sync with ILSpy 5.0.2
This commit is contained in:
Родитель
0d4922c2cd
Коммит
6fb23b3080
|
@ -133,7 +133,11 @@ namespace ICSharpCode.ILSpy.Analyzers
|
|||
{
|
||||
yield return self;
|
||||
|
||||
foreach (var assembly in AssemblyList.GetAssemblies()) {
|
||||
string reflectionTypeScopeName = typeScope.Name;
|
||||
if (typeScope.TypeParameterCount > 0)
|
||||
reflectionTypeScopeName += "`" + typeScope.TypeParameterCount;
|
||||
|
||||
foreach (var assembly in AssemblyList.GetAssemblies()) {
|
||||
ct.ThrowIfCancellationRequested();
|
||||
bool found = false;
|
||||
var module = assembly.GetPEFileOrNull();
|
||||
|
@ -148,7 +152,7 @@ namespace ICSharpCode.ILSpy.Analyzers
|
|||
}
|
||||
}
|
||||
}
|
||||
if (found && ModuleReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace))
|
||||
if (found && ModuleReferencesScopeType(module.Metadata, reflectionTypeScopeName, typeScope.Namespace))
|
||||
yield return module;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,17 +41,18 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
|
|||
}
|
||||
|
||||
IEnumerable<IEntity> AnalyzeType(IEvent analyzedEntity, ITypeDefinition type)
|
||||
{
|
||||
var token = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
if (!type.GetAllBaseTypeDefinitions()
|
||||
.Any(t => t.MetadataToken == token && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
{
|
||||
var token = analyzedEntity.MetadataToken;
|
||||
var declaringTypeToken = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
var allTypes = type.GetAllBaseTypeDefinitions();
|
||||
if (!allTypes.Any(t => t.MetadataToken == declaringTypeToken && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
|
||||
foreach (var @event in type.GetEvents(options: GetMemberOptions.ReturnMemberDefinitions)) {
|
||||
if (InheritanceHelper.GetBaseMembers(@event, true)
|
||||
.Any(m => m.DeclaringTypeDefinition.MetadataToken == token && m.ParentModule.PEFile == module))
|
||||
yield return @event;
|
||||
foreach (var @event in type.Events) {
|
||||
var baseMembers = InheritanceHelper.GetBaseMembers(@event, true);
|
||||
if (baseMembers.Any(m => m.MetadataToken == token && m.ParentModule.PEFile == module))
|
||||
yield return @event;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,16 +42,18 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
|
|||
|
||||
IEnumerable<IEntity> AnalyzeType(IEvent analyzedEntity, ITypeDefinition type)
|
||||
{
|
||||
if (!analyzedEntity.DeclaringType.GetAllBaseTypeDefinitions()
|
||||
.Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken && t.ParentModule.PEFile == type.ParentModule.PEFile))
|
||||
yield break;
|
||||
var token = analyzedEntity.MetadataToken;
|
||||
var declaringTypeToken = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
var allTypes = type.GetAllBaseTypeDefinitions();
|
||||
if (!allTypes.Any(t => t.MetadataToken == declaringTypeToken && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
|
||||
foreach (var @event in type.Events) {
|
||||
if (!@event.IsOverride) continue;
|
||||
if (InheritanceHelper.GetBaseMembers(@event, false)
|
||||
.Any(p => p.MetadataToken == analyzedEntity.MetadataToken &&
|
||||
p.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile)) {
|
||||
yield return @event;
|
||||
var baseMembers = InheritanceHelper.GetBaseMembers(@event, false);
|
||||
if (baseMembers.Any(p => p.MetadataToken == token && p.ParentModule.PEFile == module)) {
|
||||
yield return @event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,16 +45,17 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
|
|||
|
||||
IEnumerable<IEntity> AnalyzeType(IMethod analyzedEntity, ITypeDefinition type)
|
||||
{
|
||||
var token = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
if (!type.GetAllBaseTypeDefinitions()
|
||||
.Any(t => t.MetadataToken == token && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
var token = analyzedEntity.MetadataToken;
|
||||
var declaringTypeToken = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
var allTypes = type.GetAllBaseTypeDefinitions();
|
||||
if (!allTypes.Any(t => t.MetadataToken == declaringTypeToken && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
|
||||
foreach (var method in type.GetMethods(options: GetMemberOptions.ReturnMemberDefinitions)) {
|
||||
if (InheritanceHelper.GetBaseMembers(method, true)
|
||||
.Any(m => m.DeclaringTypeDefinition.MetadataToken == token && m.ParentModule.PEFile == module))
|
||||
yield return method;
|
||||
foreach (var method in type.Methods) {
|
||||
var baseMembers = InheritanceHelper.GetBaseMembers(method, true);
|
||||
if (baseMembers.Any(m => m.MetadataToken == token && m.ParentModule.PEFile == module))
|
||||
yield return method;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,17 +44,18 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
|
|||
|
||||
IEnumerable<IEntity> AnalyzeType(IMethod analyzedEntity, ITypeDefinition type)
|
||||
{
|
||||
if (!type.GetAllBaseTypeDefinitions()
|
||||
.Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken
|
||||
&& t.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile))
|
||||
yield break;
|
||||
var token = analyzedEntity.MetadataToken;
|
||||
var declaringTypeToken = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
var allTypes = type.GetAllBaseTypeDefinitions();
|
||||
if (!allTypes.Any(t => t.MetadataToken == declaringTypeToken && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
|
||||
foreach (var method in type.Methods) {
|
||||
if (!method.IsOverride) continue;
|
||||
if (InheritanceHelper.GetBaseMembers(method, false)
|
||||
.Any(p => p.MetadataToken == analyzedEntity.MetadataToken &&
|
||||
p.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile)) {
|
||||
yield return method;
|
||||
var baseMembers = InheritanceHelper.GetBaseMembers(method, false);
|
||||
if (baseMembers.Any(p => p.MetadataToken == token && p.ParentModule.PEFile == module)) {
|
||||
yield return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,16 +42,17 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
|
|||
|
||||
IEnumerable<IEntity> AnalyzeType(IProperty analyzedEntity, ITypeDefinition type)
|
||||
{
|
||||
var token = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
if (!type.GetAllBaseTypeDefinitions()
|
||||
.Any(t => t.MetadataToken == token && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
var token = analyzedEntity.MetadataToken;
|
||||
var declaringTypeToken = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
var allTypes = type.GetAllBaseTypeDefinitions();
|
||||
if (!allTypes.Any(t => t.MetadataToken == declaringTypeToken && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
|
||||
foreach (var property in type.GetProperties(options: GetMemberOptions.ReturnMemberDefinitions)) {
|
||||
if (InheritanceHelper.GetBaseMembers(property, true)
|
||||
.Any(m => m.DeclaringTypeDefinition.MetadataToken == token && m.ParentModule.PEFile == module))
|
||||
yield return property;
|
||||
foreach (var property in type.Properties) {
|
||||
var baseMembers = InheritanceHelper.GetBaseMembers(property, true);
|
||||
if (baseMembers.Any(m => m.MetadataToken == token && m.ParentModule.PEFile == module))
|
||||
yield return property;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,16 +45,18 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
|
|||
|
||||
IEnumerable<IEntity> AnalyzeType(IProperty analyzedEntity, ITypeDefinition type)
|
||||
{
|
||||
if (!analyzedEntity.DeclaringType.GetAllBaseTypeDefinitions()
|
||||
.Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken && t.ParentModule.PEFile == type.ParentModule.PEFile))
|
||||
yield break;
|
||||
var token = analyzedEntity.MetadataToken;
|
||||
var declaringTypeToken = analyzedEntity.DeclaringTypeDefinition.MetadataToken;
|
||||
var module = analyzedEntity.DeclaringTypeDefinition.ParentModule.PEFile;
|
||||
var allTypes = type.GetAllBaseTypeDefinitions();
|
||||
if (!allTypes.Any(t => t.MetadataToken == declaringTypeToken && t.ParentModule.PEFile == module))
|
||||
yield break;
|
||||
|
||||
foreach (var property in type.Properties) {
|
||||
if (!property.IsOverride) continue;
|
||||
if (InheritanceHelper.GetBaseMembers(property, false)
|
||||
.Any(p => p.MetadataToken == analyzedEntity.MetadataToken &&
|
||||
p.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile)) {
|
||||
yield return property;
|
||||
var baseMembers = InheritanceHelper.GetBaseMembers(property, false);
|
||||
if (baseMembers.Any(p => p.MetadataToken == token && p.ParentModule.PEFile == module)) {
|
||||
yield return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Avalonia.Controls;
|
||||
using ICSharpCode.ILSpy.Properties;
|
||||
using ICSharpCode.ILSpy.TreeNodes;
|
||||
using ICSharpCode.TreeView;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace ICSharpCode.ILSpy.TextView
|
||||
{
|
||||
[ExportContextMenuEntry(Header = nameof(Resources._SaveCode), Category = nameof(Resources.Save), Icon = "Images/SaveFile.png")]
|
||||
sealed class SaveCodeContextMenuEntry : IContextMenuEntry
|
||||
{
|
||||
public void Execute(TextViewContext context)
|
||||
{
|
||||
Execute(context.SelectedTreeNodes);
|
||||
}
|
||||
|
||||
public bool IsEnabled(TextViewContext context) => true;
|
||||
|
||||
public bool IsVisible(TextViewContext context)
|
||||
{
|
||||
return CanExecute(context.SelectedTreeNodes);
|
||||
}
|
||||
|
||||
public static bool CanExecute(IReadOnlyList<SharpTreeNode> selectedNodes)
|
||||
{
|
||||
if (selectedNodes == null || selectedNodes.Any(n => !(n is ILSpyTreeNode)))
|
||||
return false;
|
||||
return selectedNodes.Count == 1
|
||||
|| (selectedNodes.Count > 1 && (selectedNodes.All(n => n is AssemblyTreeNode) || selectedNodes.All(n => n is IMemberTreeNode)));
|
||||
}
|
||||
|
||||
public static async Task Execute(IReadOnlyList<SharpTreeNode> selectedNodes)
|
||||
{
|
||||
var currentLanguage = MainWindow.Instance.CurrentLanguage;
|
||||
var textView = MainWindow.Instance.TextView;
|
||||
if (selectedNodes.Count == 1 && selectedNodes[0] is ILSpyTreeNode singleSelection)
|
||||
{
|
||||
// if there's only one treenode selected
|
||||
// we will invoke the custom Save logic
|
||||
if (await singleSelection.Save(textView))
|
||||
return;
|
||||
}
|
||||
else if (selectedNodes.Count > 1 && selectedNodes.All(n => n is AssemblyTreeNode))
|
||||
{
|
||||
var selectedPath = await SelectSolutionFile();
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedPath))
|
||||
{
|
||||
var assemblies = selectedNodes.OfType<AssemblyTreeNode>()
|
||||
.Select(n => n.LoadedAssembly)
|
||||
.Where(a => !a.HasLoadError).ToArray();
|
||||
SolutionWriter.CreateSolution(textView, selectedPath, currentLanguage, assemblies);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: if nobody was able to handle the request, use default behavior.
|
||||
// try to save all nodes to disk.
|
||||
var options = new DecompilationOptions() { FullDecompilation = true };
|
||||
textView.SaveToDisk(currentLanguage, selectedNodes.OfType<ILSpyTreeNode>(), options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a File Selection dialog where the user can select the target file for the solution.
|
||||
/// </summary>
|
||||
/// <param name="path">The initial path to show in the dialog. If not specified, the 'Documents' directory
|
||||
/// will be used.</param>
|
||||
///
|
||||
/// <returns>The full path of the selected target file, or <c>null</c> if the user canceled.</returns>
|
||||
static async Task<string> SelectSolutionFile()
|
||||
{
|
||||
SaveFileDialog dlg = new SaveFileDialog();
|
||||
dlg.InitialFileName = "Solution.sln";
|
||||
dlg.Filters = new List<FileDialogFilter>()
|
||||
{
|
||||
new FileDialogFilter { Name = "Visual Studio Solution file", Extensions = { "sln" } },
|
||||
new FileDialogFilter { Name = "All files", Extensions = { "*"} },
|
||||
};
|
||||
|
||||
string filename = await dlg.ShowAsync(MainWindow.Instance);
|
||||
if (filename != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string selectedPath = Path.GetDirectoryName(filename);
|
||||
bool directoryNotEmpty;
|
||||
try
|
||||
{
|
||||
directoryNotEmpty = Directory.EnumerateFileSystemEntries(selectedPath).Any();
|
||||
}
|
||||
catch (Exception e) when (e is IOException || e is UnauthorizedAccessException || e is System.Security.SecurityException)
|
||||
{
|
||||
await MessageBox.Show(
|
||||
"The directory cannot be accessed. Please ensure it exists and you have sufficient rights to access it.",
|
||||
"Solution directory not accessible",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (directoryNotEmpty)
|
||||
{
|
||||
var result = await MessageBox.Show(
|
||||
Resources.AssemblySaveCodeDirectoryNotEmpty,
|
||||
Resources.AssemblySaveCodeDirectoryNotEmptyTitle,
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
|
||||
if (result == MessageBoxResult.No)
|
||||
return null; // -> abort
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,12 +27,12 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" />
|
||||
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.4850-preview2-debug" />
|
||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="$(AvaloniaVersion)" />
|
||||
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.2.5153" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader" Version="1.3.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader.Converter.Xml" Version="1.1.0-beta1-63314-01" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Composition" Version="15.8.98" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Composition" Version="16.4.11" />
|
||||
<PackageReference Include="NuGet.Client" Version="4.2.0" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -0,0 +1,437 @@
|
|||
// Copyright (c) 2018 Siegfried Pammer
|
||||
//
|
||||
// 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.Diagnostics;
|
||||
using AvaloniaEdit.Document;
|
||||
using ICSharpCode.ILSpy.TextView;
|
||||
|
||||
namespace ICSharpCode.ILSpy
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches matching brackets for C#.
|
||||
/// </summary>
|
||||
class CSharpBracketSearcher : IBracketSearcher
|
||||
{
|
||||
string openingBrackets = "([{";
|
||||
string closingBrackets = ")]}";
|
||||
|
||||
public BracketSearchResult SearchBracket(IDocument document, int offset)
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
char c = document.GetCharAt(offset - 1);
|
||||
int index = openingBrackets.IndexOf(c);
|
||||
int otherOffset = -1;
|
||||
if (index > -1)
|
||||
otherOffset = SearchBracketForward(document, offset, openingBrackets[index], closingBrackets[index]);
|
||||
|
||||
index = closingBrackets.IndexOf(c);
|
||||
if (index > -1)
|
||||
otherOffset = SearchBracketBackward(document, offset - 2, openingBrackets[index], closingBrackets[index]);
|
||||
|
||||
if (otherOffset > -1)
|
||||
{
|
||||
var result = new BracketSearchResult(Math.Min(offset - 1, otherOffset), 1,
|
||||
Math.Max(offset - 1, otherOffset), 1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#region SearchBracket helper functions
|
||||
static int ScanLineStart(IDocument document, int offset)
|
||||
{
|
||||
for (int i = offset - 1; i > 0; --i)
|
||||
{
|
||||
if (document.GetCharAt(i) == '\n')
|
||||
return i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of code at offset.<br/>
|
||||
/// 0 = Code,<br/>
|
||||
/// 1 = Comment,<br/>
|
||||
/// 2 = String<br/>
|
||||
/// Block comments and multiline strings are not supported.
|
||||
/// </summary>
|
||||
static int GetStartType(IDocument document, int linestart, int offset)
|
||||
{
|
||||
bool inString = false;
|
||||
bool inChar = false;
|
||||
bool verbatim = false;
|
||||
int result = 0;
|
||||
for (int i = linestart; i < offset; i++)
|
||||
{
|
||||
switch (document.GetCharAt(i))
|
||||
{
|
||||
case '/':
|
||||
if (!inString && !inChar && i + 1 < document.TextLength)
|
||||
{
|
||||
if (document.GetCharAt(i + 1) == '/')
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (!inChar)
|
||||
{
|
||||
if (inString && verbatim)
|
||||
{
|
||||
if (i + 1 < document.TextLength && document.GetCharAt(i + 1) == '"')
|
||||
{
|
||||
++i; // skip escaped quote
|
||||
inString = false; // let the string go on
|
||||
}
|
||||
else
|
||||
{
|
||||
verbatim = false;
|
||||
}
|
||||
}
|
||||
else if (!inString && i > 0 && document.GetCharAt(i - 1) == '@')
|
||||
{
|
||||
verbatim = true;
|
||||
}
|
||||
inString = !inString;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
if (!inString) inChar = !inChar;
|
||||
break;
|
||||
case '\\':
|
||||
if ((inString && !verbatim) || inChar)
|
||||
++i; // skip next character
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (inString || inChar) ? 2 : result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SearchBracketBackward
|
||||
int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
|
||||
{
|
||||
if (offset + 1 >= document.TextLength) return -1;
|
||||
// this method parses a c# document backwards to find the matching bracket
|
||||
|
||||
// first try "quick find" - find the matching bracket if there is no string/comment in the way
|
||||
int quickResult = QuickSearchBracketBackward(document, offset, openBracket, closingBracket);
|
||||
if (quickResult >= 0) return quickResult;
|
||||
|
||||
// we need to parse the line from the beginning, so get the line start position
|
||||
int linestart = ScanLineStart(document, offset + 1);
|
||||
|
||||
// we need to know where offset is - in a string/comment or in normal code?
|
||||
// ignore cases where offset is in a block comment
|
||||
int starttype = GetStartType(document, linestart, offset + 1);
|
||||
if (starttype == 1)
|
||||
{
|
||||
return -1; // start position is in a comment
|
||||
}
|
||||
|
||||
// I don't see any possibility to parse a C# document backwards...
|
||||
// We have to do it forwards and push all bracket positions on a stack.
|
||||
Stack<int> bracketStack = new Stack<int>();
|
||||
bool blockComment = false;
|
||||
bool lineComment = false;
|
||||
bool inChar = false;
|
||||
bool inString = false;
|
||||
bool verbatim = false;
|
||||
|
||||
for (int i = 0; i <= offset; ++i)
|
||||
{
|
||||
char ch = document.GetCharAt(i);
|
||||
switch (ch)
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
lineComment = false;
|
||||
inChar = false;
|
||||
if (!verbatim) inString = false;
|
||||
break;
|
||||
case '/':
|
||||
if (blockComment)
|
||||
{
|
||||
Debug.Assert(i > 0);
|
||||
if (document.GetCharAt(i - 1) == '*')
|
||||
{
|
||||
blockComment = false;
|
||||
}
|
||||
}
|
||||
if (!inString && !inChar && i + 1 < document.TextLength)
|
||||
{
|
||||
if (!blockComment && document.GetCharAt(i + 1) == '/')
|
||||
{
|
||||
lineComment = true;
|
||||
}
|
||||
if (!lineComment && document.GetCharAt(i + 1) == '*')
|
||||
{
|
||||
blockComment = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (!(inChar || lineComment || blockComment))
|
||||
{
|
||||
if (inString && verbatim)
|
||||
{
|
||||
if (i + 1 < document.TextLength && document.GetCharAt(i + 1) == '"')
|
||||
{
|
||||
++i; // skip escaped quote
|
||||
inString = false; // let the string go
|
||||
}
|
||||
else
|
||||
{
|
||||
verbatim = false;
|
||||
}
|
||||
}
|
||||
else if (!inString && offset > 0 && document.GetCharAt(i - 1) == '@')
|
||||
{
|
||||
verbatim = true;
|
||||
}
|
||||
inString = !inString;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
if (!(inString || lineComment || blockComment))
|
||||
{
|
||||
inChar = !inChar;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
if ((inString && !verbatim) || inChar)
|
||||
++i; // skip next character
|
||||
break;
|
||||
default:
|
||||
if (ch == openBracket)
|
||||
{
|
||||
if (!(inString || inChar || lineComment || blockComment))
|
||||
{
|
||||
bracketStack.Push(i);
|
||||
}
|
||||
}
|
||||
else if (ch == closingBracket)
|
||||
{
|
||||
if (!(inString || inChar || lineComment || blockComment))
|
||||
{
|
||||
if (bracketStack.Count > 0)
|
||||
bracketStack.Pop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bracketStack.Count > 0) return (int)bracketStack.Pop();
|
||||
return -1;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SearchBracketForward
|
||||
int SearchBracketForward(IDocument document, int offset, char openBracket, char closingBracket)
|
||||
{
|
||||
bool inString = false;
|
||||
bool inChar = false;
|
||||
bool verbatim = false;
|
||||
|
||||
bool lineComment = false;
|
||||
bool blockComment = false;
|
||||
|
||||
if (offset < 0) return -1;
|
||||
|
||||
// first try "quick find" - find the matching bracket if there is no string/comment in the way
|
||||
int quickResult = QuickSearchBracketForward(document, offset, openBracket, closingBracket);
|
||||
if (quickResult >= 0) return quickResult;
|
||||
|
||||
// we need to parse the line from the beginning, so get the line start position
|
||||
int linestart = ScanLineStart(document, offset);
|
||||
|
||||
// we need to know where offset is - in a string/comment or in normal code?
|
||||
// ignore cases where offset is in a block comment
|
||||
int starttype = GetStartType(document, linestart, offset);
|
||||
if (starttype != 0) return -1; // start position is in a comment/string
|
||||
|
||||
int brackets = 1;
|
||||
|
||||
while (offset < document.TextLength)
|
||||
{
|
||||
char ch = document.GetCharAt(offset);
|
||||
switch (ch)
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
lineComment = false;
|
||||
inChar = false;
|
||||
if (!verbatim) inString = false;
|
||||
break;
|
||||
case '/':
|
||||
if (blockComment)
|
||||
{
|
||||
Debug.Assert(offset > 0);
|
||||
if (document.GetCharAt(offset - 1) == '*')
|
||||
{
|
||||
blockComment = false;
|
||||
}
|
||||
}
|
||||
if (!inString && !inChar && offset + 1 < document.TextLength)
|
||||
{
|
||||
if (!blockComment && document.GetCharAt(offset + 1) == '/')
|
||||
{
|
||||
lineComment = true;
|
||||
}
|
||||
if (!lineComment && document.GetCharAt(offset + 1) == '*')
|
||||
{
|
||||
blockComment = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (!(inChar || lineComment || blockComment))
|
||||
{
|
||||
if (inString && verbatim)
|
||||
{
|
||||
if (offset + 1 < document.TextLength && document.GetCharAt(offset + 1) == '"')
|
||||
{
|
||||
++offset; // skip escaped quote
|
||||
inString = false; // let the string go
|
||||
}
|
||||
else
|
||||
{
|
||||
verbatim = false;
|
||||
}
|
||||
}
|
||||
else if (!inString && offset > 0 && document.GetCharAt(offset - 1) == '@')
|
||||
{
|
||||
verbatim = true;
|
||||
}
|
||||
inString = !inString;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
if (!(inString || lineComment || blockComment))
|
||||
{
|
||||
inChar = !inChar;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
if ((inString && !verbatim) || inChar)
|
||||
++offset; // skip next character
|
||||
break;
|
||||
default:
|
||||
if (ch == openBracket)
|
||||
{
|
||||
if (!(inString || inChar || lineComment || blockComment))
|
||||
{
|
||||
++brackets;
|
||||
}
|
||||
}
|
||||
else if (ch == closingBracket)
|
||||
{
|
||||
if (!(inString || inChar || lineComment || blockComment))
|
||||
{
|
||||
--brackets;
|
||||
if (brackets == 0)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endregion
|
||||
|
||||
int QuickSearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
|
||||
{
|
||||
int brackets = -1;
|
||||
// first try "quick find" - find the matching bracket if there is no string/comment in the way
|
||||
for (int i = offset; i >= 0; --i)
|
||||
{
|
||||
char ch = document.GetCharAt(i);
|
||||
if (ch == openBracket)
|
||||
{
|
||||
++brackets;
|
||||
if (brackets == 0) return i;
|
||||
}
|
||||
else if (ch == closingBracket)
|
||||
{
|
||||
--brackets;
|
||||
}
|
||||
else if (ch == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch == '\'')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch == '/' && i > 0)
|
||||
{
|
||||
if (document.GetCharAt(i - 1) == '/') break;
|
||||
if (document.GetCharAt(i - 1) == '*') break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int QuickSearchBracketForward(IDocument document, int offset, char openBracket, char closingBracket)
|
||||
{
|
||||
int brackets = 1;
|
||||
// try "quick find" - find the matching bracket if there is no string/comment in the way
|
||||
for (int i = offset; i < document.TextLength; ++i)
|
||||
{
|
||||
char ch = document.GetCharAt(i);
|
||||
if (ch == openBracket)
|
||||
{
|
||||
++brackets;
|
||||
}
|
||||
else if (ch == closingBracket)
|
||||
{
|
||||
--brackets;
|
||||
if (brackets == 0) return i;
|
||||
}
|
||||
else if (ch == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch == '\'')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch == '/' && i > 0)
|
||||
{
|
||||
if (document.GetCharAt(i - 1) == '/') break;
|
||||
}
|
||||
else if (ch == '*' && i > 0)
|
||||
{
|
||||
if (document.GetCharAt(i - 1) == '/') break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,20 @@
|
|||
using System;
|
||||
// Copyright (c) 2018 Siegfried Pammer
|
||||
//
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AvaloniaEdit.Highlighting;
|
||||
|
@ -254,8 +270,10 @@ namespace ICSharpCode.ILSpy
|
|||
HighlightingColor color = null;
|
||||
switch (type) {
|
||||
case "new":
|
||||
color = typeKeywordsColor;
|
||||
break;
|
||||
case "notnull":
|
||||
// Not sure if reference type or value type
|
||||
color = referenceTypeKeywordsColor;
|
||||
break;
|
||||
case "bool":
|
||||
case "byte":
|
||||
case "char":
|
||||
|
@ -271,7 +289,8 @@ namespace ICSharpCode.ILSpy
|
|||
case "uint":
|
||||
case "ushort":
|
||||
case "ulong":
|
||||
color = valueTypeKeywordsColor;
|
||||
case "unmanaged":
|
||||
color = valueTypeKeywordsColor;
|
||||
break;
|
||||
case "class":
|
||||
case "object":
|
||||
|
|
|
@ -35,8 +35,10 @@ using ICSharpCode.Decompiler.CSharp.Syntax;
|
|||
using ICSharpCode.Decompiler.CSharp.Transforms;
|
||||
using ICSharpCode.Decompiler.Metadata;
|
||||
using ICSharpCode.Decompiler.Output;
|
||||
using ICSharpCode.Decompiler.Solution;
|
||||
using ICSharpCode.Decompiler.TypeSystem;
|
||||
using ICSharpCode.Decompiler.Util;
|
||||
using ICSharpCode.ILSpy.TextView;
|
||||
using ICSharpCode.ILSpy.TreeNodes;
|
||||
|
||||
namespace ICSharpCode.ILSpy
|
||||
|
@ -379,13 +381,13 @@ namespace ICSharpCode.ILSpy
|
|||
}
|
||||
}
|
||||
|
||||
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
|
||||
public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
|
||||
{
|
||||
var module = assembly.GetPEFileOrNull();
|
||||
if (options.FullDecompilation && options.SaveAsProjectDirectory != null)
|
||||
{
|
||||
var decompiler = new ILSpyWholeProjectDecompiler(assembly, options);
|
||||
decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken);
|
||||
return decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -436,7 +438,7 @@ namespace ICSharpCode.ILSpy
|
|||
if (metadata.IsAssembly)
|
||||
{
|
||||
var asm = metadata.GetAssemblyDefinition();
|
||||
if (asm.HashAlgorithm != System.Reflection.AssemblyHashAlgorithm.None)
|
||||
if (asm.HashAlgorithm != AssemblyHashAlgorithm.None)
|
||||
output.WriteLine("// Hash algorithm: " + asm.HashAlgorithm.ToString().ToUpper());
|
||||
if (!asm.PublicKey.IsNil)
|
||||
{
|
||||
|
@ -467,6 +469,7 @@ namespace ICSharpCode.ILSpy
|
|||
}
|
||||
WriteCode(output, options.DecompilerSettings, st, decompiler.TypeSystem);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,6 +484,7 @@ namespace ICSharpCode.ILSpy
|
|||
this.options = options;
|
||||
base.Settings = options.DecompilerSettings;
|
||||
base.AssemblyResolver = assembly.GetAssemblyResolver();
|
||||
base.DebugInfoProvider = assembly.GetDebugInfoOrNull();
|
||||
}
|
||||
|
||||
protected override IEnumerable<Tuple<string, string>> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
|
||||
|
@ -490,7 +494,6 @@ namespace ICSharpCode.ILSpy
|
|||
if (handler.CanHandle(fileName, options))
|
||||
{
|
||||
entryStream.Position = 0;
|
||||
fileName = Path.Combine(targetDirectory, fileName);
|
||||
fileName = handler.WriteResourceToFile(assembly, fileName, entryStream, options);
|
||||
return new[] { Tuple.Create(handler.EntryType, fileName) };
|
||||
}
|
||||
|
@ -576,7 +579,7 @@ namespace ICSharpCode.ILSpy
|
|||
return EntityToString(@event, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName);
|
||||
}
|
||||
|
||||
string ToCSharpString(MetadataReader metadata, TypeDefinitionHandle handle, bool fullName)
|
||||
string ToCSharpString(MetadataReader metadata, TypeDefinitionHandle handle, bool fullName, bool omitGenerics)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
var currentTypeDefHandle = handle;
|
||||
|
@ -589,7 +592,7 @@ namespace ICSharpCode.ILSpy
|
|||
typeDef = metadata.GetTypeDefinition(currentTypeDefHandle);
|
||||
var part = ReflectionHelper.SplitTypeParameterCountFromReflectionName(metadata.GetString(typeDef.Name), out int typeParamCount);
|
||||
var genericParams = typeDef.GetGenericParameters();
|
||||
if (genericParams.Count > 0)
|
||||
if (!omitGenerics && genericParams.Count > 0)
|
||||
{
|
||||
builder.Insert(0, '>');
|
||||
int firstIndex = genericParams.Count - typeParamCount;
|
||||
|
@ -613,18 +616,18 @@ namespace ICSharpCode.ILSpy
|
|||
return builder.ToString();
|
||||
}
|
||||
|
||||
public override string GetEntityName(PEFile module, EntityHandle handle, bool fullName)
|
||||
public override string GetEntityName(PEFile module, EntityHandle handle, bool fullName, bool omitGenerics)
|
||||
{
|
||||
MetadataReader metadata = module.Metadata;
|
||||
switch (handle.Kind)
|
||||
{
|
||||
case HandleKind.TypeDefinition:
|
||||
return ToCSharpString(metadata, (TypeDefinitionHandle)handle, fullName);
|
||||
return ToCSharpString(metadata, (TypeDefinitionHandle)handle, fullName, omitGenerics);
|
||||
case HandleKind.FieldDefinition:
|
||||
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)handle);
|
||||
var declaringType = fd.GetDeclaringType();
|
||||
if (fullName)
|
||||
return ToCSharpString(metadata, declaringType, fullName) + "." + metadata.GetString(fd.Name);
|
||||
return ToCSharpString(metadata, declaringType, fullName, omitGenerics) + "." + metadata.GetString(fd.Name);
|
||||
return metadata.GetString(fd.Name);
|
||||
case HandleKind.MethodDefinition:
|
||||
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)handle);
|
||||
|
@ -649,7 +652,7 @@ namespace ICSharpCode.ILSpy
|
|||
break;
|
||||
default:
|
||||
var genericParams = md.GetGenericParameters();
|
||||
if (genericParams.Count > 0)
|
||||
if (!omitGenerics && genericParams.Count > 0)
|
||||
{
|
||||
methodName += "<";
|
||||
int i = 0;
|
||||
|
@ -665,19 +668,19 @@ namespace ICSharpCode.ILSpy
|
|||
break;
|
||||
}
|
||||
if (fullName)
|
||||
return ToCSharpString(metadata, declaringType, fullName) + "." + methodName;
|
||||
return ToCSharpString(metadata, declaringType, fullName, omitGenerics) + "." + methodName;
|
||||
return methodName;
|
||||
case HandleKind.EventDefinition:
|
||||
var ed = metadata.GetEventDefinition((EventDefinitionHandle)handle);
|
||||
declaringType = metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
|
||||
if (fullName)
|
||||
return ToCSharpString(metadata, declaringType, fullName) + "." + metadata.GetString(ed.Name);
|
||||
return ToCSharpString(metadata, declaringType, fullName, omitGenerics) + "." + metadata.GetString(ed.Name);
|
||||
return metadata.GetString(ed.Name);
|
||||
case HandleKind.PropertyDefinition:
|
||||
var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)handle);
|
||||
declaringType = metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType();
|
||||
if (fullName)
|
||||
return ToCSharpString(metadata, declaringType, fullName) + "." + metadata.GetString(pd.Name);
|
||||
return ToCSharpString(metadata, declaringType, fullName, omitGenerics) + "." + metadata.GetString(pd.Name);
|
||||
return metadata.GetString(pd.Name);
|
||||
default:
|
||||
return null;
|
||||
|
@ -700,5 +703,10 @@ namespace ICSharpCode.ILSpy
|
|||
{
|
||||
return CSharpDecompiler.GetCodeMappingInfo(module, member);
|
||||
}
|
||||
|
||||
CSharpBracketSearcher bracketSearcher = new CSharpBracketSearcher();
|
||||
|
||||
public override IBracketSearcher BracketSearcher => bracketSearcher;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ namespace ICSharpCode.ILSpy
|
|||
var reader = new ILReader(typeSystem.MainModule);
|
||||
reader.UseDebugSymbols = options.DecompilerSettings.UseDebugSymbols;
|
||||
var methodBody = module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
|
||||
ILFunction il = reader.ReadIL((SRM.MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: options.CancellationToken);
|
||||
ILFunction il = reader.ReadIL((SRM.MethodDefinitionHandle)method.MetadataToken, methodBody, kind: ILFunctionKind.TopLevelFunction, cancellationToken: options.CancellationToken);
|
||||
var namespaces = new HashSet<string>();
|
||||
var decompiler = new CSharpDecompiler(typeSystem, options.DecompilerSettings) { CancellationToken = options.CancellationToken };
|
||||
ILTransformContext context = decompiler.CreateILTransformContext(il);
|
||||
|
|
|
@ -27,6 +27,8 @@ using System.Reflection.Metadata.Ecma335;
|
|||
using System.Linq;
|
||||
using ICSharpCode.Decompiler.Metadata;
|
||||
using ICSharpCode.Decompiler.TypeSystem;
|
||||
using ICSharpCode.Decompiler.Util;
|
||||
using ICSharpCode.Decompiler.Solution;
|
||||
|
||||
namespace ICSharpCode.ILSpy
|
||||
{
|
||||
|
@ -150,7 +152,7 @@ namespace ICSharpCode.ILSpy
|
|||
dis.DisassembleNamespace(nameSpace, module, types.Select(t => (TypeDefinitionHandle)t.MetadataToken));
|
||||
}
|
||||
|
||||
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
|
||||
public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
|
||||
{
|
||||
output.WriteLine("// " + assembly.FileName);
|
||||
output.WriteLine();
|
||||
|
@ -174,6 +176,7 @@ namespace ICSharpCode.ILSpy
|
|||
dis.WriteModuleContents(module);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Text;
|
|||
using AvaloniaEdit.Highlighting;
|
||||
using ICSharpCode.Decompiler;
|
||||
using ICSharpCode.Decompiler.Metadata;
|
||||
using ICSharpCode.Decompiler.Solution;
|
||||
using ICSharpCode.Decompiler.TypeSystem;
|
||||
using ICSharpCode.Decompiler.TypeSystem.Implementation;
|
||||
using ICSharpCode.Decompiler.Util;
|
||||
|
@ -107,6 +108,12 @@ namespace ICSharpCode.ILSpy
|
|||
}
|
||||
}
|
||||
|
||||
public virtual TextView.IBracketSearcher BracketSearcher {
|
||||
get {
|
||||
return TextView.DefaultBracketSearcher.DefaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options)
|
||||
{
|
||||
WriteCommentLine(output, TypeToString(method.DeclaringTypeDefinition, includeNamespace: true) + "." + method.Name);
|
||||
|
@ -137,11 +144,11 @@ namespace ICSharpCode.ILSpy
|
|||
WriteCommentLine(output, nameSpace);
|
||||
}
|
||||
|
||||
public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
|
||||
public virtual ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
|
||||
{
|
||||
WriteCommentLine(output, assembly.FileName);
|
||||
var asm = assembly.GetPEFileOrNull();
|
||||
if (asm == null) return;
|
||||
if (asm == null) return null;
|
||||
var metadata = asm.Metadata;
|
||||
if (metadata.IsAssembly) {
|
||||
var name = metadata.GetAssemblyDefinition();
|
||||
|
@ -153,6 +160,7 @@ namespace ICSharpCode.ILSpy
|
|||
} else {
|
||||
WriteCommentLine(output, metadata.GetString(metadata.GetModuleDefinition().Name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void WriteCommentLine(ITextOutput output, string comment)
|
||||
|
@ -446,42 +454,42 @@ namespace ICSharpCode.ILSpy
|
|||
/// <summary>
|
||||
/// This should produce a string representation of the entity for search to match search strings against.
|
||||
/// </summary>
|
||||
public virtual string GetEntityName(PEFile module, EntityHandle handle, bool fullName)
|
||||
public virtual string GetEntityName(PEFile module, EntityHandle handle, bool fullName, bool omitGenerics)
|
||||
{
|
||||
MetadataReader metadata = module.Metadata;
|
||||
switch (handle.Kind) {
|
||||
case HandleKind.TypeDefinition:
|
||||
if (fullName)
|
||||
return EscapeName(((TypeDefinitionHandle)handle).GetFullTypeName(metadata).ToILNameString());
|
||||
return EscapeName(((TypeDefinitionHandle)handle).GetFullTypeName(metadata).ToILNameString(omitGenerics));
|
||||
var td = metadata.GetTypeDefinition((TypeDefinitionHandle)handle);
|
||||
return EscapeName(metadata.GetString(td.Name));
|
||||
case HandleKind.FieldDefinition:
|
||||
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)handle);
|
||||
var declaringType = fd.GetDeclaringType();
|
||||
if (fullName)
|
||||
return EscapeName(fd.GetDeclaringType().GetFullTypeName(metadata).ToILNameString() + "." + metadata.GetString(fd.Name));
|
||||
return EscapeName(fd.GetDeclaringType().GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(fd.Name));
|
||||
return EscapeName(metadata.GetString(fd.Name));
|
||||
case HandleKind.MethodDefinition:
|
||||
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)handle);
|
||||
declaringType = md.GetDeclaringType();
|
||||
string methodName = metadata.GetString(md.Name);
|
||||
int genericParamCount = md.GetGenericParameters().Count;
|
||||
if (genericParamCount > 0)
|
||||
methodName += "``" + genericParamCount;
|
||||
if (fullName)
|
||||
return EscapeName(md.GetDeclaringType().GetFullTypeName(metadata).ToILNameString() + "." + methodName);
|
||||
if (!omitGenerics) {
|
||||
int genericParamCount = md.GetGenericParameters().Count;
|
||||
if (genericParamCount > 0)
|
||||
methodName += "``" + genericParamCount;
|
||||
}
|
||||
if (fullName)
|
||||
return EscapeName(md.GetDeclaringType().GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + methodName);
|
||||
return EscapeName(methodName);
|
||||
case HandleKind.EventDefinition:
|
||||
var ed = metadata.GetEventDefinition((EventDefinitionHandle)handle);
|
||||
declaringType = metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
|
||||
var declaringType = metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
|
||||
if (fullName)
|
||||
return EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString() + "." + metadata.GetString(ed.Name));
|
||||
return EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(ed.Name));
|
||||
return EscapeName(metadata.GetString(ed.Name));
|
||||
case HandleKind.PropertyDefinition:
|
||||
var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)handle);
|
||||
declaringType = metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType();
|
||||
if (fullName)
|
||||
return EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString() + "." + metadata.GetString(pd.Name));
|
||||
return EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(pd.Name));
|
||||
return EscapeName(metadata.GetString(pd.Name));
|
||||
default:
|
||||
return null;
|
||||
|
|
|
@ -149,20 +149,28 @@ namespace ICSharpCode.ILSpy
|
|||
|
||||
PEFile LoadAssembly(object state)
|
||||
{
|
||||
var stream = state as Stream;
|
||||
PEFile module;
|
||||
|
||||
// runs on background thread
|
||||
if (stream != null)
|
||||
{
|
||||
// Read the module from a precrafted stream
|
||||
module = new PEFile(fileName, stream, metadataOptions: DecompilerSettingsPanel.CurrentDecompilerSettings.ApplyWindowsRuntimeProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None);
|
||||
MetadataReaderOptions options;
|
||||
if (DecompilerSettingsPanel.CurrentDecompilerSettings.ApplyWindowsRuntimeProjections)
|
||||
{
|
||||
options = MetadataReaderOptions.ApplyWindowsRuntimeProjections;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
options = MetadataReaderOptions.None;
|
||||
}
|
||||
|
||||
// runs on background thread
|
||||
PEFile module;
|
||||
|
||||
if (state is Stream stream)
|
||||
{
|
||||
// Read the module from a precrafted stream
|
||||
module = new PEFile(fileName, stream, metadataOptions: DecompilerSettingsPanel.CurrentDecompilerSettings.ApplyWindowsRuntimeProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None);
|
||||
} else {
|
||||
// Read the module from disk (by default)
|
||||
module = new PEFile(fileName, new FileStream(fileName, FileMode.Open, FileAccess.Read), PEStreamOptions.PrefetchEntireImage,
|
||||
metadataOptions: DecompilerSettingsPanel.CurrentDecompilerSettings.ApplyWindowsRuntimeProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None);
|
||||
stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
|
||||
module = new PEFile(fileName, stream, PEStreamOptions.PrefetchEntireImage,
|
||||
metadataOptions: options);
|
||||
}
|
||||
|
||||
if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) {
|
||||
|
@ -179,7 +187,7 @@ namespace ICSharpCode.ILSpy
|
|||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
|
||||
void LoadSymbols(PEFile module)
|
||||
{
|
||||
try {
|
||||
|
@ -246,17 +254,17 @@ namespace ICSharpCode.ILSpy
|
|||
|
||||
[ThreadStatic]
|
||||
static int assemblyLoadDisableCount;
|
||||
|
||||
|
||||
public static IDisposable DisableAssemblyLoad()
|
||||
{
|
||||
assemblyLoadDisableCount++;
|
||||
return new DecrementAssemblyLoadDisableCount();
|
||||
}
|
||||
|
||||
|
||||
sealed class DecrementAssemblyLoadDisableCount : IDisposable
|
||||
{
|
||||
bool disposed;
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!disposed) {
|
||||
|
@ -267,16 +275,16 @@ namespace ICSharpCode.ILSpy
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sealed class MyAssemblyResolver : IAssemblyResolver
|
||||
{
|
||||
readonly LoadedAssembly parent;
|
||||
|
||||
|
||||
public MyAssemblyResolver(LoadedAssembly parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
|
||||
public PEFile Resolve(Decompiler.Metadata.IAssemblyReference reference)
|
||||
{
|
||||
return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull();
|
||||
|
@ -287,7 +295,7 @@ namespace ICSharpCode.ILSpy
|
|||
return parent.LookupReferencedModule(mainModule, moduleName)?.GetPEFileOrNull();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public IAssemblyResolver GetAssemblyResolver()
|
||||
{
|
||||
return new MyAssemblyResolver(this);
|
||||
|
@ -302,7 +310,7 @@ namespace ICSharpCode.ILSpy
|
|||
return null;
|
||||
return debugInfoProvider;
|
||||
}
|
||||
|
||||
|
||||
public LoadedAssembly LookupReferencedAssembly(Decompiler.Metadata.IAssemblyReference reference)
|
||||
{
|
||||
if (reference == null)
|
||||
|
@ -441,7 +449,7 @@ namespace ICSharpCode.ILSpy
|
|||
{
|
||||
return this.assemblyTask.ContinueWith(onAssemblyLoaded, default(CancellationToken), TaskContinuationOptions.RunContinuationsAsynchronously, taskScheduler);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Wait until the assembly is loaded.
|
||||
/// Throws an AggregateException when loading the assembly fails.
|
||||
|
|
|
@ -53,12 +53,14 @@
|
|||
<ComboBox Name="languageComboBox" Width="120"
|
||||
BorderThickness="1"
|
||||
Items="{x:Static local:Languages.AllLanguages}"
|
||||
SelectedItem="{Binding FilterSettings.Language}"/>
|
||||
SelectedItem="{Binding FilterSettings.Language}"
|
||||
ToolTip.Tip="{x:Static properties:Resources.SelectLanguageDropdownTooltip}"/>
|
||||
<ComboBox Name="languageVersionComboBox" Width="160"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding SelectedItem.HasLanguageVersions, ElementName=languageComboBox}"
|
||||
Items="{Binding SelectedItem.LanguageVersions, ElementName=languageComboBox}"
|
||||
SelectedItem="{Binding FilterSettings.LanguageVersion}"/>
|
||||
SelectedItem="{Binding FilterSettings.LanguageVersion}"
|
||||
ToolTip.Tip="{x:Static properties:Resources.SelectVersionDropdownTooltip}"/>
|
||||
<ComboBox x:Name="Themes" SelectedIndex="0" Width="100">
|
||||
<ComboBoxItem>Light</ComboBoxItem>
|
||||
<ComboBoxItem>Dark</ComboBoxItem>
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace ICSharpCode.ILSpy
|
|||
public partial class MainWindow : PlatformDependentWindow, IRoutedCommandBindable
|
||||
{
|
||||
bool refreshInProgress;
|
||||
bool handlingNugetPackageSelection;
|
||||
readonly NavigationHistory<NavigationState> history = new NavigationHistory<NavigationState>();
|
||||
ILSpySettings spySettingsForMainWindow_Loaded;
|
||||
internal SessionSettings sessionSettings;
|
||||
|
@ -212,7 +213,7 @@ namespace ICSharpCode.ILSpy
|
|||
|
||||
CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Open, OpenCommandExecuted));
|
||||
CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Refresh, RefreshCommandExecuted));
|
||||
CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Save, SaveCommandExecuted));
|
||||
CommandBindings.Add(new RoutedCommandBinding(ApplicationCommands.Save, SaveCommandExecuted, SaveCommandCanExecute));
|
||||
CommandBindings.Add(new RoutedCommandBinding(NavigationCommands.BrowseBack, BackCommandExecuted, BackCommandCanExecute));
|
||||
CommandBindings.Add(new RoutedCommandBinding(NavigationCommands.BrowseForward, ForwardCommandExecuted, ForwardCommandCanExecute));
|
||||
CommandBindings.Add(new RoutedCommandBinding(NavigationCommands.Search, SearchCommandExecuted));
|
||||
|
@ -459,7 +460,7 @@ namespace ICSharpCode.ILSpy
|
|||
i++;
|
||||
}
|
||||
}
|
||||
LoadAssemblies(args.AssembliesToLoad, commandLineLoadedAssemblies, false);
|
||||
LoadAssemblies(args.AssembliesToLoad, commandLineLoadedAssemblies, focusNode: false);
|
||||
if (args.Language != null)
|
||||
sessionSettings.FilterSettings.Language = Languages.GetLanguage(args.Language);
|
||||
return true;
|
||||
|
@ -472,9 +473,13 @@ namespace ICSharpCode.ILSpy
|
|||
void HandleCommandLineArgumentsAfterShowList(CommandLineArguments args, ILSpySettings spySettings = null)
|
||||
{
|
||||
if (nugetPackagesToLoad.Count > 0) {
|
||||
LoadAssemblies(nugetPackagesToLoad, commandLineLoadedAssemblies, focusNode: false);
|
||||
var relevantPackages = nugetPackagesToLoad.ToArray();
|
||||
nugetPackagesToLoad.Clear();
|
||||
}
|
||||
|
||||
// Show the nuget package open dialog after the command line/window message was processed.
|
||||
Dispatcher.UIThread.InvokeAsync(new Action(() => LoadAssemblies(relevantPackages, commandLineLoadedAssemblies, focusNode: false)), DispatcherPriority.Normal);
|
||||
|
||||
}
|
||||
var relevantAssemblies = commandLineLoadedAssemblies.ToList();
|
||||
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
|
||||
NavigateOnLaunch(args.NavigateTo, sessionSettings.ActiveTreeViewPath, spySettings, relevantAssemblies);
|
||||
|
@ -508,7 +513,14 @@ namespace ICSharpCode.ILSpy
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if (navigateTo == "none")
|
||||
{
|
||||
// Don't navigate anywhere; start empty.
|
||||
// Used by ILSpy VS addin, it'll send us the real location to navigate to via IPC.
|
||||
found = true;
|
||||
|
||||
} else {
|
||||
IEntity mr = await Task.Run(() => FindEntityInRelevantAssemblies(navigateTo, relevantAssemblies));
|
||||
if (mr != null && mr.ParentModule.PEFile != null) {
|
||||
found = true;
|
||||
|
@ -522,24 +534,24 @@ namespace ICSharpCode.ILSpy
|
|||
output.Write(string.Format("Cannot find '{0}' in command line specified assemblies.", navigateTo));
|
||||
decompilerTextView.ShowText(output);
|
||||
}
|
||||
} else if (commandLineLoadedAssemblies.Count == 1) {
|
||||
} else if (relevantAssemblies.Count == 1) {
|
||||
// NavigateTo == null and an assembly was given on the command-line:
|
||||
// Select the newly loaded assembly
|
||||
AssemblyTreeNode asmNode = assemblyListTreeNode.FindAssemblyNode(commandLineLoadedAssemblies[0]);
|
||||
AssemblyTreeNode asmNode = assemblyListTreeNode.FindAssemblyNode(relevantAssemblies[0]);
|
||||
if (asmNode != null && treeView.SelectedItem == initialSelection) {
|
||||
SelectNode(asmNode);
|
||||
}
|
||||
} else if (spySettings != null) {
|
||||
SharpTreeNode node = null;
|
||||
if (sessionSettings.ActiveTreeViewPath?.Length > 0) {
|
||||
if (activeTreeViewPath?.Length > 0) {
|
||||
foreach (var asm in assemblyList.GetAssemblies()) {
|
||||
if (asm.FileName == sessionSettings.ActiveTreeViewPath[0]) {
|
||||
if (asm.FileName == activeTreeViewPath[0]) {
|
||||
// FindNodeByPath() blocks the UI if the assembly is not yet loaded,
|
||||
// so use an async wait instead.
|
||||
await asm.GetPEFileAsync().Catch<Exception>(ex => { });
|
||||
}
|
||||
}
|
||||
node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true);
|
||||
node = FindNodeByPath(activeTreeViewPath, true);
|
||||
}
|
||||
if (treeView.SelectedItem == initialSelection) {
|
||||
if (node != null) {
|
||||
|
@ -781,7 +793,7 @@ namespace ICSharpCode.ILSpy
|
|||
if (CurrentAssemblyListChanged != null)
|
||||
CurrentAssemblyListChanged(this, e);
|
||||
}
|
||||
|
||||
|
||||
void LoadInitialAssemblies()
|
||||
{
|
||||
// Called when loading an empty assembly list; so that
|
||||
|
@ -795,7 +807,7 @@ namespace ICSharpCode.ILSpy
|
|||
foreach (System.Reflection.Assembly asm in initialAssemblies)
|
||||
assemblyList.OpenAssembly(asm.Location);
|
||||
}
|
||||
|
||||
|
||||
void filterSettings_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
RefreshTreeViewFilter();
|
||||
|
@ -803,7 +815,7 @@ namespace ICSharpCode.ILSpy
|
|||
DecompileSelectedNodes(recordHistory: false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RefreshTreeViewFilter()
|
||||
{
|
||||
// filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable.
|
||||
|
@ -812,11 +824,11 @@ namespace ICSharpCode.ILSpy
|
|||
if (assemblyListTreeNode != null)
|
||||
assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone();
|
||||
}
|
||||
|
||||
|
||||
internal AssemblyListTreeNode AssemblyListTreeNode {
|
||||
get { return assemblyListTreeNode; }
|
||||
}
|
||||
|
||||
|
||||
#region Node Selection
|
||||
|
||||
public void SelectNode(SharpTreeNode obj)
|
||||
|
@ -842,7 +854,7 @@ namespace ICSharpCode.ILSpy
|
|||
treeView.SetSelectedNodes(nodes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a node using the .ToString() representations of its ancestors.
|
||||
/// </summary>
|
||||
|
@ -867,7 +879,7 @@ namespace ICSharpCode.ILSpy
|
|||
else
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the .ToString() representation of the node's ancestors.
|
||||
/// </summary>
|
||||
|
@ -883,7 +895,7 @@ namespace ICSharpCode.ILSpy
|
|||
path.Reverse();
|
||||
return path.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public ILSpyTreeNode FindTreeNode(object reference)
|
||||
{
|
||||
switch (reference) {
|
||||
|
@ -905,12 +917,12 @@ namespace ICSharpCode.ILSpy
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void JumpToReference(object reference)
|
||||
{
|
||||
JumpToReferenceAsync(reference).HandleExceptions();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Jumps to the specified reference.
|
||||
/// </summary>
|
||||
|
@ -1049,7 +1061,7 @@ namespace ICSharpCode.ILSpy
|
|||
{
|
||||
if (fileNames == null)
|
||||
throw new ArgumentNullException(nameof(fileNames));
|
||||
|
||||
|
||||
if (focusNode)
|
||||
treeView.UnselectAll();
|
||||
|
||||
|
@ -1063,25 +1075,39 @@ namespace ICSharpCode.ILSpy
|
|||
string file = Uri.UnescapeDataString(name);
|
||||
switch (Path.GetExtension(file)) {
|
||||
case ".nupkg":
|
||||
LoadedNugetPackage package = new LoadedNugetPackage(file);
|
||||
var selectionDialog = new NugetPackageBrowserDialog(package);
|
||||
if (await selectionDialog.ShowDialog<bool>(this) != true)
|
||||
break;
|
||||
foreach (var entry in selectionDialog.SelectedItems) {
|
||||
var nugetAsm = assemblyList.OpenAssembly("nupkg://" + file + ";" + entry.Name, entry.Stream, true);
|
||||
if (nugetAsm != null) {
|
||||
if (loadedAssemblies != null)
|
||||
loadedAssemblies.Add(nugetAsm);
|
||||
else {
|
||||
var node = assemblyListTreeNode.FindAssemblyNode(nugetAsm);
|
||||
if (node != null && focusNode) {
|
||||
treeView.SelectedItems.Add(node);
|
||||
lastNode = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
this.handlingNugetPackageSelection = true;
|
||||
try
|
||||
{
|
||||
LoadedNugetPackage package = new LoadedNugetPackage(file);
|
||||
var selectionDialog = new NugetPackageBrowserDialog(package);
|
||||
selectionDialog.Owner = this;
|
||||
if (await selectionDialog.ShowDialog<bool>(this) != true)
|
||||
break;
|
||||
foreach (var entry in selectionDialog.SelectedItems)
|
||||
{
|
||||
var nugetAsm = assemblyList.OpenAssembly("nupkg://" + file + ";" + entry.Name, entry.Stream, true);
|
||||
if (nugetAsm != null)
|
||||
{
|
||||
if (loadedAssemblies != null)
|
||||
loadedAssemblies.Add(nugetAsm);
|
||||
else
|
||||
{
|
||||
var node = assemblyListTreeNode.FindAssemblyNode(nugetAsm);
|
||||
if (node != null && focusNode)
|
||||
{
|
||||
treeView.SelectedItems.Add(node);
|
||||
lastNode = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.handlingNugetPackageSelection = false;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
var asm = assemblyList.OpenAssembly(file);
|
||||
if (asm != null) {
|
||||
|
@ -1131,10 +1157,10 @@ namespace ICSharpCode.ILSpy
|
|||
if (SelectionChanged != null)
|
||||
SelectionChanged(sender, e);
|
||||
}
|
||||
|
||||
|
||||
Task decompilationTask;
|
||||
bool ignoreDecompilationRequests;
|
||||
|
||||
|
||||
void DecompileSelectedNodes(DecompilerTextViewState state = null, bool recordHistory = true)
|
||||
{
|
||||
if (ignoreDecompilationRequests)
|
||||
|
@ -1161,15 +1187,15 @@ namespace ICSharpCode.ILSpy
|
|||
decompilationTask = decompilerTextView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = state });
|
||||
}
|
||||
|
||||
async void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
void SaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
|
||||
{
|
||||
if (this.SelectedNodes.Count() == 1) {
|
||||
if (await this.SelectedNodes.Single().Save(this.TextView))
|
||||
return;
|
||||
}
|
||||
this.TextView.SaveToDisk(this.CurrentLanguage,
|
||||
this.SelectedNodes,
|
||||
new DecompilationOptions() { FullDecompilation = true });
|
||||
e.Handled = true;
|
||||
e.CanExecute = SaveCodeContextMenuEntry.CanExecute(SelectedNodes.ToList());
|
||||
}
|
||||
|
||||
void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
SaveCodeContextMenuEntry.Execute(SelectedNodes.ToList());
|
||||
}
|
||||
|
||||
public void RefreshDecompiledView()
|
||||
|
@ -1206,7 +1232,7 @@ namespace ICSharpCode.ILSpy
|
|||
e.Handled = true;
|
||||
e.CanExecute = history.CanNavigateBack;
|
||||
}
|
||||
|
||||
|
||||
void BackCommandExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
if (history.CanNavigateBack) {
|
||||
|
@ -1214,13 +1240,13 @@ namespace ICSharpCode.ILSpy
|
|||
NavigateHistory(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ForwardCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
e.CanExecute = history.CanNavigateForward;
|
||||
}
|
||||
|
||||
|
||||
void ForwardCommandExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
if (history.CanNavigateForward) {
|
||||
|
@ -1228,18 +1254,17 @@ namespace ICSharpCode.ILSpy
|
|||
NavigateHistory(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NavigateHistory(bool forward)
|
||||
{
|
||||
var dtState = decompilerTextView.GetState();
|
||||
if(dtState != null)
|
||||
if (dtState != null)
|
||||
history.UpdateCurrent(new NavigationState(dtState));
|
||||
var newState = forward ? history.GoForward() : history.GoBack();
|
||||
|
||||
|
||||
ignoreDecompilationRequests = true;
|
||||
treeView.SelectedItems.Clear();
|
||||
foreach (var node in newState.TreeNodes)
|
||||
{
|
||||
foreach (var node in newState.TreeNodes) {
|
||||
treeView.SelectedItems.Add(node);
|
||||
}
|
||||
if (newState.TreeNodes.Any())
|
||||
|
@ -1289,7 +1314,7 @@ namespace ICSharpCode.ILSpy
|
|||
|
||||
return loadedAssy.FileName;
|
||||
}
|
||||
|
||||
|
||||
#region Top/Bottom Pane management
|
||||
|
||||
/// <summary>
|
||||
|
@ -1303,14 +1328,12 @@ namespace ICSharpCode.ILSpy
|
|||
var pane2Height = pane2Row.Height;
|
||||
|
||||
//only star height values are normalized.
|
||||
if (!pane1Height.IsStar || !pane2Height.IsStar)
|
||||
{
|
||||
if (!pane1Height.IsStar || !pane2Height.IsStar) {
|
||||
return;
|
||||
}
|
||||
|
||||
var totalHeight = pane1Height.Value + pane2Height.Value;
|
||||
if (totalHeight == 0)
|
||||
{
|
||||
if (totalHeight == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,9 @@ namespace ICSharpCode.ILSpy.Options
|
|||
.Where(p => p.GetCustomAttribute<BrowsableAttribute>()?.Browsable != false);
|
||||
foreach (var p in properties)
|
||||
{
|
||||
p.SetValue(newSettings, (bool?)e.Attribute(p.Name) ?? true);
|
||||
var value = (bool?)e.Attribute(p.Name);
|
||||
if (value.HasValue)
|
||||
p.SetValue(newSettings, value.Value);
|
||||
}
|
||||
return newSettings;
|
||||
}
|
||||
|
|
|
@ -255,6 +255,21 @@ namespace ICSharpCode.ILSpy.Options
|
|||
}
|
||||
}
|
||||
|
||||
bool highlightMatchingBraces = true;
|
||||
|
||||
public bool HighlightMatchingBraces
|
||||
{
|
||||
get { return highlightMatchingBraces; }
|
||||
set
|
||||
{
|
||||
if (highlightMatchingBraces != value)
|
||||
{
|
||||
highlightMatchingBraces = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyValues(DisplaySettings s)
|
||||
{
|
||||
this.SelectedFont = s.selectedFont;
|
||||
|
@ -271,6 +286,7 @@ namespace ICSharpCode.ILSpy.Options
|
|||
this.IndentationUseTabs = s.indentationUseTabs;
|
||||
this.IndentationTabSize = s.indentationTabSize;
|
||||
this.IndentationSize = s.indentationSize;
|
||||
this.HighlightMatchingBraces = s.highlightMatchingBraces;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
<CheckBox IsChecked="{Binding ShowDebugInfo}" Content="{x:Static properties:Resources.ShowInfoFromDebugSymbolsAvailable}"></CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableWordWrap}" Content="{x:Static properties:Resources.EnableWordWrap}"></CheckBox>
|
||||
<CheckBox IsChecked="{Binding FoldBraces}" Content="{x:Static properties:Resources.EnableFoldingBlocksBraces}"></CheckBox>
|
||||
<CheckBox IsChecked="{Binding HighlightMatchingBraces}" Content="{x:Static properties:Resources.HighlightMatchingBraces}"></CheckBox>
|
||||
<CheckBox IsChecked="{Binding SortResults}" Content="{x:Static properties:Resources.SortResultsFitness}"></CheckBox>
|
||||
<CheckBox IsChecked="{Binding ExpandMemberDefinitions}" Content="{x:Static properties:Resources.ExpandMemberDefinitionsAfterDecompilation}"></CheckBox>
|
||||
<CheckBox IsChecked="{Binding ExpandUsingDeclarations}" Content="{x:Static properties:Resources.ExpandUsingDeclarationsAfterDecompilation}"></CheckBox>
|
||||
|
|
|
@ -126,6 +126,7 @@ namespace ICSharpCode.ILSpy.Options
|
|||
s.IndentationUseTabs = (bool?)e.Attribute("IndentationUseTabs") ?? true;
|
||||
s.IndentationSize = (int?)e.Attribute("IndentationSize") ?? 4;
|
||||
s.IndentationTabSize = (int?)e.Attribute("IndentationTabSize") ?? 4;
|
||||
s.HighlightMatchingBraces = (bool?)e.Attribute("HighlightMatchingBraces") ?? true;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -145,9 +146,11 @@ namespace ICSharpCode.ILSpy.Options
|
|||
section.SetAttributeValue("SortResults", s.SortResults);
|
||||
section.SetAttributeValue("FoldBraces", s.FoldBraces);
|
||||
section.SetAttributeValue("ExpandMemberDefinitions", s.ExpandMemberDefinitions);
|
||||
section.SetAttributeValue("ExpandUsingDeclarations", s.ExpandUsingDeclarations);
|
||||
section.SetAttributeValue("IndentationUseTabs", s.IndentationUseTabs);
|
||||
section.SetAttributeValue("IndentationSize", s.IndentationSize);
|
||||
section.SetAttributeValue("IndentationTabSize", s.IndentationTabSize);
|
||||
section.SetAttributeValue("HighlightMatchingBraces", s.HighlightMatchingBraces);
|
||||
|
||||
XElement existingElement = root.Element("DisplaySettings");
|
||||
if (existingElement != null)
|
||||
|
|
|
@ -37,9 +37,9 @@ internal static class RevisionClass
|
|||
{
|
||||
public const string Major = "5";
|
||||
public const string Minor = "0";
|
||||
public const string Build = "0";
|
||||
public const string Revision = "1";
|
||||
public const string VersionName = "preview2";
|
||||
public const string Build = "2";
|
||||
public const string Revision = "0";
|
||||
public const string VersionName = "beta";
|
||||
|
||||
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision + "." + VersionName;
|
||||
}
|
||||
|
|
|
@ -303,6 +303,25 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The directory is not empty. File will be overwritten.
|
||||
///Are you sure you want to continue?.
|
||||
/// </summary>
|
||||
public static string AssemblySaveCodeDirectoryNotEmpty {
|
||||
get {
|
||||
return ResourceManager.GetString("AssemblySaveCodeDirectoryNotEmpty", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Project Directory not empty.
|
||||
/// </summary>
|
||||
public static string AssemblySaveCodeDirectoryNotEmptyTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("AssemblySaveCodeDirectoryNotEmptyTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Automatically check for updates every week.
|
||||
/// </summary>
|
||||
|
@ -474,6 +493,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use 'ref' extension methods.
|
||||
/// </summary>
|
||||
public static string DecompilerSettings_AllowExtensionMethodSyntaxOnRef {
|
||||
get {
|
||||
return ResourceManager.GetString("DecompilerSettings.AllowExtensionMethodSyntaxOnRef", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always cast targets of explicit interface implementation calls.
|
||||
/// </summary>
|
||||
|
@ -483,6 +511,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always show enum member values.
|
||||
/// </summary>
|
||||
public static string DecompilerSettings_AlwaysShowEnumMemberValues {
|
||||
get {
|
||||
return ResourceManager.GetString("DecompilerSettings.AlwaysShowEnumMemberValues", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always use braces.
|
||||
/// </summary>
|
||||
|
@ -700,11 +737,11 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Introduce local functions (NOT IMPLEMENTED!).
|
||||
/// Looks up a localized string similar to Introduce local functions.
|
||||
/// </summary>
|
||||
public static string DecompilerSettings_IntroduceLocalFunctionsNOTIMPLEMENTED {
|
||||
public static string DecompilerSettings_IntroduceLocalFunctions {
|
||||
get {
|
||||
return ResourceManager.GetString("DecompilerSettings.IntroduceLocalFunctionsNOTIMPLEMENTED", resourceCulture);
|
||||
return ResourceManager.GetString("DecompilerSettings.IntroduceLocalFunctions", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -773,6 +810,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Remove dead stores (use with caution!).
|
||||
/// </summary>
|
||||
public static string DecompilerSettings_RemoveDeadStores {
|
||||
get {
|
||||
return ResourceManager.GetString("DecompilerSettings.RemoveDeadStores", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Remove optional arguments, if possible.
|
||||
/// </summary>
|
||||
|
@ -908,6 +954,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use throw expressions.
|
||||
/// </summary>
|
||||
public static string DecompilerSettings_UseThrowExpressions {
|
||||
get {
|
||||
return ResourceManager.GetString("DecompilerSettings.UseThrowExpressions", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use tuple type syntax.
|
||||
/// </summary>
|
||||
|
@ -1115,6 +1170,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Highlight matching braces.
|
||||
/// </summary>
|
||||
public static string HighlightMatchingBraces {
|
||||
get {
|
||||
return ResourceManager.GetString("HighlightMatchingBraces", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ILSpy version .
|
||||
/// </summary>
|
||||
|
@ -1386,7 +1450,7 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ReloadAssemblies.
|
||||
/// Looks up a localized string similar to Reload all assemblies.
|
||||
/// </summary>
|
||||
public static string RefreshCommand_ReloadAssemblies {
|
||||
get {
|
||||
|
@ -1520,6 +1584,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Select language to decompile to.
|
||||
/// </summary>
|
||||
public static string SelectLanguageDropdownTooltip {
|
||||
get {
|
||||
return ResourceManager.GetString("SelectLanguageDropdownTooltip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Select a list:.
|
||||
/// </summary>
|
||||
|
@ -1529,6 +1602,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Select version of language to output.
|
||||
/// </summary>
|
||||
public static string SelectVersionDropdownTooltip {
|
||||
get {
|
||||
return ResourceManager.GetString("SelectVersionDropdownTooltip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shell.
|
||||
/// </summary>
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
<value>Generate portable PDB</value>
|
||||
</data>
|
||||
<data name="RefreshCommand_ReloadAssemblies" xml:space="preserve">
|
||||
<value>ReloadAssemblies</value>
|
||||
<value>Reload all assemblies</value>
|
||||
</data>
|
||||
<data name="_Reload" xml:space="preserve">
|
||||
<value>_Reload</value>
|
||||
|
@ -702,8 +702,8 @@
|
|||
<data name="DecompilerSettings.RemoveOptionalArgumentsIfPossible" xml:space="preserve">
|
||||
<value>Remove optional arguments, if possible</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.IntroduceLocalFunctionsNOTIMPLEMENTED" xml:space="preserve">
|
||||
<value>Introduce local functions (NOT IMPLEMENTED!)</value>
|
||||
<data name="DecompilerSettings.IntroduceLocalFunctions" xml:space="preserve">
|
||||
<value>Introduce local functions</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve">
|
||||
<value>Nullable reference types</value>
|
||||
|
@ -729,4 +729,7 @@
|
|||
<data name="CannotAnalyzeMissingRef" xml:space="preserve">
|
||||
<value>Entity could not be resolved. Cannot analyze entities from missing assembly references. Add the missing reference and try again.</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.AllowExtensionMethodSyntaxOnRef" xml:space="preserve">
|
||||
<value>Use 'ref' extension methods</value>
|
||||
</data>
|
||||
</root>
|
|
@ -676,7 +676,7 @@
|
|||
<value>IsByRefLikeAttribute应替换为结构上的 "ref" 修饰符</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.IsReadOnlyAttributeShouldBeReplacedWithReadonlyInModifiersOnStructsParameters" xml:space="preserve">
|
||||
<value>IsReadOnlyAttribute 应替为结构参数上的 "readonly"/"中的修饰符</value>
|
||||
<value>IsReadOnlyAttribute 应替为结构参数上的 "readonly"/"in"中的修饰符</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.IsUnmanagedAttributeOnTypeParametersShouldBeReplacedWithUnmanagedConstraints" xml:space="preserve">
|
||||
<value>类型参数上的IsUnmanagedAttribute 应替换为 "非托管" 约束</value>
|
||||
|
@ -702,8 +702,8 @@
|
|||
<data name="DecompilerSettings.RemoveOptionalArgumentsIfPossible" xml:space="preserve">
|
||||
<value>如果可能, 删除可选参数</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.IntroduceLocalFunctionsNOTIMPLEMENTED" xml:space="preserve">
|
||||
<value>引入本地功能 (未实现!)</value>
|
||||
<data name="DecompilerSettings.IntroduceLocalFunctions" xml:space="preserve">
|
||||
<value>引入本地功能 </value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.C70LocalFunctionsAreNotImplemented" xml:space="preserve">
|
||||
<value>C# 7.0 本地函数未实现!</value>
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
protected readonly string[] searchTerm;
|
||||
protected readonly Regex regex;
|
||||
protected readonly bool fullNameSearch;
|
||||
protected readonly bool omitGenerics;
|
||||
protected readonly Language language;
|
||||
protected readonly ApiVisibility apiVisibility;
|
||||
private readonly IProducerConsumerCollection<SearchResult> resultQueue;
|
||||
|
@ -31,6 +32,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
{
|
||||
var regexString = search.Substring(1, search.Length - 1);
|
||||
fullNameSearch = search.Contains("\\.");
|
||||
omitGenerics = !search.Contains("<");
|
||||
if (regexString.EndsWith("/", StringComparison.Ordinal))
|
||||
regexString = regexString.Substring(0, regexString.Length - 1);
|
||||
regex = SafeNewRegex(regexString);
|
||||
|
@ -38,6 +40,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
else
|
||||
{
|
||||
fullNameSearch = search.Contains(".");
|
||||
omitGenerics = !search.Contains("<");
|
||||
}
|
||||
}
|
||||
searchTerm = terms;
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
foreach (var handle in metadata.TypeDefinitions)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch, omitGenerics);
|
||||
if (languageSpecificName != null && !IsMatch(languageSpecificName))
|
||||
continue;
|
||||
var type = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
|
||||
|
@ -47,7 +47,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
foreach (var handle in metadata.MethodDefinitions)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch, omitGenerics);
|
||||
if (languageSpecificName != null && !IsMatch(languageSpecificName))
|
||||
continue;
|
||||
var method = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
|
||||
|
@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
foreach (var handle in metadata.FieldDefinitions)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch, omitGenerics);
|
||||
if (languageSpecificName != null && !IsMatch(languageSpecificName))
|
||||
continue;
|
||||
var field = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
|
||||
|
@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
foreach (var handle in metadata.PropertyDefinitions)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch, omitGenerics);
|
||||
if (languageSpecificName != null && !IsMatch(languageSpecificName))
|
||||
continue;
|
||||
var property = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
|
||||
|
@ -89,7 +89,7 @@ namespace ICSharpCode.ILSpy.Search
|
|||
foreach (var handle in metadata.EventDefinitions)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch);
|
||||
string languageSpecificName = language.GetEntityName(module, handle, fullNameSearch, omitGenerics);
|
||||
if (!IsMatch(languageSpecificName))
|
||||
continue;
|
||||
var @event = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle);
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ICSharpCode.Decompiler;
|
||||
using ICSharpCode.Decompiler.Solution;
|
||||
using ICSharpCode.Decompiler.Util;
|
||||
using ICSharpCode.ILSpy.TextView;
|
||||
|
||||
namespace ICSharpCode.ILSpy
|
||||
{
|
||||
/// <summary>
|
||||
/// An utility class that creates a Visual Studio solution containing projects for the
|
||||
/// decompiled assemblies.
|
||||
/// </summary>
|
||||
internal class SolutionWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a Visual Studio solution that contains projects with decompiled code
|
||||
/// of the specified <paramref name="assemblies"/>. The solution file will be saved
|
||||
/// to the <paramref name="solutionFilePath"/>. The directory of this file must either
|
||||
/// be empty or not exist.
|
||||
/// </summary>
|
||||
/// <param name="textView">A reference to the <see cref="DecompilerTextView"/> instance.</param>
|
||||
/// <param name="solutionFilePath">The target file path of the solution file.</param>
|
||||
/// <param name="assemblies">The assembly nodes to decompile.</param>
|
||||
///
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="solutionFilePath"/> is null,
|
||||
/// an empty or a whitespace string.</exception>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="textView"/>> or
|
||||
/// <paramref name="assemblies"/> is null.</exception>
|
||||
public static void CreateSolution(DecompilerTextView textView, string solutionFilePath, Language language, IEnumerable<LoadedAssembly> assemblies)
|
||||
{
|
||||
if (textView == null) {
|
||||
throw new ArgumentNullException(nameof(textView));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(solutionFilePath)) {
|
||||
throw new ArgumentException("The solution file path cannot be null or empty.", nameof(solutionFilePath));
|
||||
}
|
||||
|
||||
if (assemblies == null) {
|
||||
throw new ArgumentNullException(nameof(assemblies));
|
||||
}
|
||||
|
||||
var writer = new SolutionWriter(solutionFilePath);
|
||||
|
||||
textView
|
||||
.RunWithCancellation(ct => writer.CreateSolution(assemblies, language, ct))
|
||||
.Then(output => textView.ShowText(output))
|
||||
.HandleExceptions();
|
||||
}
|
||||
|
||||
readonly string solutionFilePath;
|
||||
readonly string solutionDirectory;
|
||||
readonly ConcurrentBag<ProjectItem> projects;
|
||||
readonly ConcurrentBag<string> statusOutput;
|
||||
|
||||
SolutionWriter(string solutionFilePath)
|
||||
{
|
||||
this.solutionFilePath = solutionFilePath;
|
||||
solutionDirectory = Path.GetDirectoryName(solutionFilePath);
|
||||
statusOutput = new ConcurrentBag<string>();
|
||||
projects = new ConcurrentBag<ProjectItem>();
|
||||
}
|
||||
|
||||
async Task<AvaloniaEditTextOutput> CreateSolution(IEnumerable<LoadedAssembly> assemblies, Language language, CancellationToken ct)
|
||||
{
|
||||
var result = new AvaloniaEditTextOutput();
|
||||
|
||||
var duplicates = new HashSet<string>();
|
||||
if (assemblies.Any(asm => !duplicates.Add(asm.ShortName))) {
|
||||
result.WriteLine("Duplicate assembly names selected, cannot generate a solution.");
|
||||
return result;
|
||||
}
|
||||
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
|
||||
try {
|
||||
await Task.Run(() => Parallel.ForEach(assemblies, n => WriteProject(n, language, solutionDirectory, ct)))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await Task.Run(() => SolutionCreator.WriteSolutionFile(solutionFilePath, projects))
|
||||
.ConfigureAwait(false);
|
||||
} catch (AggregateException ae) {
|
||||
if (ae.Flatten().InnerExceptions.All(e => e is OperationCanceledException)) {
|
||||
result.WriteLine();
|
||||
result.WriteLine("Generation was cancelled.");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.WriteLine();
|
||||
result.WriteLine("Failed to generate the Visual Studio Solution. Errors:");
|
||||
ae.Handle(e => {
|
||||
result.WriteLine(e.Message);
|
||||
return true;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var item in statusOutput) {
|
||||
result.WriteLine(item);
|
||||
}
|
||||
|
||||
if (statusOutput.Count == 0) {
|
||||
result.WriteLine("Successfully decompiled the following assemblies into Visual Studio projects:");
|
||||
foreach (var item in assemblies.Select(n => n.Text.ToString())) {
|
||||
result.WriteLine(item);
|
||||
}
|
||||
|
||||
result.WriteLine();
|
||||
|
||||
if (assemblies.Count() == projects.Count) {
|
||||
result.WriteLine("Created the Visual Studio Solution file.");
|
||||
}
|
||||
|
||||
result.WriteLine();
|
||||
result.WriteLine("Elapsed time: " + stopwatch.Elapsed.TotalSeconds.ToString("F1") + " seconds.");
|
||||
result.WriteLine();
|
||||
result.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + solutionFilePath + "\""); });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void WriteProject(LoadedAssembly loadedAssembly, Language language, string targetDirectory, CancellationToken ct)
|
||||
{
|
||||
targetDirectory = Path.Combine(targetDirectory, loadedAssembly.ShortName);
|
||||
string projectFileName = Path.Combine(targetDirectory, loadedAssembly.ShortName + language.ProjectFileExtension);
|
||||
|
||||
if (!Directory.Exists(targetDirectory)) {
|
||||
try {
|
||||
Directory.CreateDirectory(targetDirectory);
|
||||
} catch (Exception e) {
|
||||
statusOutput.Add($"Failed to create a directory '{targetDirectory}':{Environment.NewLine}{e}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
using (var projectFileWriter = new StreamWriter(projectFileName)) {
|
||||
var projectFileOutput = new PlainTextOutput(projectFileWriter);
|
||||
var options = new DecompilationOptions() {
|
||||
FullDecompilation = true,
|
||||
CancellationToken = ct,
|
||||
SaveAsProjectDirectory = targetDirectory
|
||||
};
|
||||
|
||||
var projectInfo = language.DecompileAssembly(loadedAssembly, projectFileOutput, options);
|
||||
if (projectInfo != null) {
|
||||
projects.Add(new ProjectItem(projectFileName, projectInfo.PlatformName, projectInfo.Guid));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) when (!(e is OperationCanceledException)) {
|
||||
statusOutput.Add($"Failed to decompile the assembly '{loadedAssembly.FileName}':{Environment.NewLine}{e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
// 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 Avalonia.Media;
|
||||
using AvaloniaEdit.Document;
|
||||
using AvaloniaEdit.Rendering;
|
||||
|
||||
namespace ICSharpCode.ILSpy.TextView
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows language specific search for matching brackets.
|
||||
/// </summary>
|
||||
public interface IBracketSearcher
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches for a matching bracket from the given offset to the start of the document.
|
||||
/// </summary>
|
||||
/// <returns>A BracketSearchResult that contains the positions and lengths of the brackets. Return null if there is nothing to highlight.</returns>
|
||||
BracketSearchResult SearchBracket(IDocument document, int offset);
|
||||
}
|
||||
|
||||
public class DefaultBracketSearcher : IBracketSearcher
|
||||
{
|
||||
public static readonly DefaultBracketSearcher DefaultInstance = new DefaultBracketSearcher();
|
||||
|
||||
public BracketSearchResult SearchBracket(IDocument document, int offset)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a pair of matching brackets found by <see cref="IBracketSearcher"/>.
|
||||
/// </summary>
|
||||
public class BracketSearchResult
|
||||
{
|
||||
public int OpeningBracketOffset { get; private set; }
|
||||
|
||||
public int OpeningBracketLength { get; private set; }
|
||||
|
||||
public int ClosingBracketOffset { get; private set; }
|
||||
|
||||
public int ClosingBracketLength { get; private set; }
|
||||
|
||||
public BracketSearchResult(int openingBracketOffset, int openingBracketLength,
|
||||
int closingBracketOffset, int closingBracketLength)
|
||||
{
|
||||
this.OpeningBracketOffset = openingBracketOffset;
|
||||
this.OpeningBracketLength = openingBracketLength;
|
||||
this.ClosingBracketOffset = closingBracketOffset;
|
||||
this.ClosingBracketLength = closingBracketLength;
|
||||
}
|
||||
}
|
||||
|
||||
public class BracketHighlightRenderer : IBackgroundRenderer
|
||||
{
|
||||
BracketSearchResult result;
|
||||
IPen borderPen;
|
||||
IBrush backgroundBrush;
|
||||
global::AvaloniaEdit.Rendering.TextView textView;
|
||||
|
||||
public void SetHighlight(BracketSearchResult result)
|
||||
{
|
||||
if (this.result != result) {
|
||||
this.result = result;
|
||||
textView.InvalidateLayer(this.Layer);
|
||||
}
|
||||
}
|
||||
|
||||
public BracketHighlightRenderer(global::AvaloniaEdit.Rendering.TextView textView)
|
||||
{
|
||||
if (textView == null)
|
||||
throw new ArgumentNullException("textView");
|
||||
|
||||
this.borderPen = new Pen(new SolidColorBrush(Color.FromArgb(52, 0, 0, 255)), 1).ToImmutable();
|
||||
|
||||
this.backgroundBrush = new SolidColorBrush(Color.FromArgb(22, 0, 0, 255)).ToImmutable();
|
||||
|
||||
this.textView = textView;
|
||||
|
||||
this.textView.BackgroundRenderers.Add(this);
|
||||
}
|
||||
|
||||
public KnownLayer Layer {
|
||||
get {
|
||||
return KnownLayer.Selection;
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(global::AvaloniaEdit.Rendering.TextView textView, DrawingContext drawingContext)
|
||||
{
|
||||
if (this.result == null)
|
||||
return;
|
||||
|
||||
BackgroundGeometryBuilder builder = new BackgroundGeometryBuilder();
|
||||
|
||||
builder.CornerRadius = 1;
|
||||
|
||||
builder.AddSegment(textView, new TextSegment() { StartOffset = result.OpeningBracketOffset, Length = result.OpeningBracketLength });
|
||||
builder.CloseFigure(); // prevent connecting the two segments
|
||||
builder.AddSegment(textView, new TextSegment() { StartOffset = result.ClosingBracketOffset, Length = result.ClosingBracketLength });
|
||||
|
||||
Geometry geometry = builder.CreateGeometry();
|
||||
if (geometry != null) {
|
||||
drawingContext.DrawGeometry(backgroundBrush, borderPen, geometry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -67,7 +67,8 @@ namespace ICSharpCode.ILSpy.TextView
|
|||
readonly UIElementGenerator uiElementGenerator;
|
||||
List<VisualLineElementGenerator> activeCustomElementGenerators = new List<VisualLineElementGenerator>();
|
||||
RichTextColorizer activeRichTextColorizer;
|
||||
FoldingManager foldingManager;
|
||||
BracketHighlightRenderer bracketHighlightRenderer;
|
||||
FoldingManager foldingManager;
|
||||
ILSpyTreeNode[] decompiledNodes;
|
||||
|
||||
DefinitionLookup definitionLookup;
|
||||
|
@ -90,12 +91,14 @@ namespace ICSharpCode.ILSpy.TextView
|
|||
this.referenceElementGenerator = new ReferenceElementGenerator(this.JumpToReference, this.IsLink);
|
||||
textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator);
|
||||
this.uiElementGenerator = new UIElementGenerator();
|
||||
textEditor.TextArea.TextView.ElementGenerators.Add(uiElementGenerator);
|
||||
this.bracketHighlightRenderer = new BracketHighlightRenderer(textEditor.TextArea.TextView);
|
||||
textEditor.TextArea.TextView.ElementGenerators.Add(uiElementGenerator);
|
||||
textEditor.Options.RequireControlModifierForHyperlinkClick = false;
|
||||
textEditor.TextArea.TextView.PointerHover += TextViewMouseHover;
|
||||
textEditor.TextArea.TextView.PointerHoverStopped += TextViewMouseHoverStopped;
|
||||
textEditor.TextArea.AddHandler(PointerPressedEvent, TextAreaMouseDown, RoutingStrategies.Tunnel);
|
||||
textEditor.TextArea.AddHandler(PointerReleasedEvent, TextAreaMouseUp, RoutingStrategies.Tunnel);
|
||||
textEditor.TextArea.Caret.PositionChanged += HighlightBrackets;
|
||||
textEditor.Bind(TextEditor.FontFamilyProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = "SelectedFont" });
|
||||
textEditor.Bind(TextEditor.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = "SelectedFontSize" });
|
||||
textEditor.Bind(TextEditor.WordWrapProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = "EnableWordWrap" });
|
||||
|
@ -239,18 +242,33 @@ namespace ICSharpCode.ILSpy.TextView
|
|||
}
|
||||
return renderer.CreateTextBlock();
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region RunWithCancellation
|
||||
/// <summary>
|
||||
/// Switches the GUI into "waiting" mode, then calls <paramref name="taskCreation"/> to create
|
||||
/// the task.
|
||||
/// When the task completes without being cancelled, the <paramref name="taskCompleted"/>
|
||||
/// callback is called on the GUI thread.
|
||||
/// When the task is cancelled before completing, the callback is not called; and any result
|
||||
/// of the task (including exceptions) are ignored.
|
||||
/// </summary>
|
||||
[Obsolete("RunWithCancellation(taskCreation).ContinueWith(taskCompleted) instead")]
|
||||
#region Highlight brackets
|
||||
void HighlightBrackets(object sender, EventArgs e)
|
||||
{
|
||||
if (DisplaySettingsPanel.CurrentDisplaySettings.HighlightMatchingBraces)
|
||||
{
|
||||
var result = MainWindow.Instance.CurrentLanguage.BracketSearcher.SearchBracket(textEditor.Document, textEditor.CaretOffset);
|
||||
bracketHighlightRenderer.SetHighlight(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
bracketHighlightRenderer.SetHighlight(null);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region RunWithCancellation
|
||||
/// <summary>
|
||||
/// Switches the GUI into "waiting" mode, then calls <paramref name="taskCreation"/> to create
|
||||
/// the task.
|
||||
/// When the task completes without being cancelled, the <paramref name="taskCompleted"/>
|
||||
/// callback is called on the GUI thread.
|
||||
/// When the task is cancelled before completing, the callback is not called; and any result
|
||||
/// of the task (including exceptions) are ignored.
|
||||
/// </summary>
|
||||
[Obsolete("RunWithCancellation(taskCreation).ContinueWith(taskCompleted) instead")]
|
||||
public void RunWithCancellation<T>(Func<CancellationToken, Task<T>> taskCreation, Action<Task<T>> taskCompleted)
|
||||
{
|
||||
RunWithCancellation(taskCreation).ContinueWith(taskCompleted, CancellationToken.None, TaskContinuationOptions.NotOnCanceled, TaskScheduler.FromCurrentSynchronizationContext());
|
||||
|
@ -631,13 +649,14 @@ namespace ICSharpCode.ILSpy.TextView
|
|||
if (referenceSegment == null) {
|
||||
ClearLocalReferenceMarks();
|
||||
} else if(referenceSegment.IsLocal || !referenceSegment.IsDefinition) {
|
||||
JumpToReference(referenceSegment);
|
||||
textEditor.TextArea.ClearSelection();
|
||||
}
|
||||
// cancel mouse selection to avoid AvalonEdit selecting between the new
|
||||
// cursor position and the mouse position.
|
||||
//textEditor.TextArea.MouseSelectionMode = MouseSelectionMode.None;
|
||||
}
|
||||
// cancel mouse selection to avoid AvalonEdit selecting between the new
|
||||
// cursor position and the mouse position.
|
||||
textEditor.TextArea.Selection = Selection.Create(textEditor.TextArea, 0, 0);
|
||||
|
||||
JumpToReference(referenceSegment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClearLocalReferenceMarks()
|
||||
|
|
|
@ -252,6 +252,10 @@
|
|||
<Word>int16</Word>
|
||||
<Word>int32</Word>
|
||||
<Word>int64</Word>
|
||||
<Word>uint8</Word>
|
||||
<Word>uint16</Word>
|
||||
<Word>uint32</Word>
|
||||
<Word>uint64</Word>
|
||||
<Word>float</Word>
|
||||
<Word>float32</Word>
|
||||
<Word>float64</Word>
|
||||
|
|
|
@ -334,10 +334,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
|
|||
foreach (string entry in Directory.GetFileSystemEntries(options.SaveAsProjectDirectory)) {
|
||||
if (!string.Equals(entry, filename, StringComparison.OrdinalIgnoreCase)) {
|
||||
var result = await MessageBox.Show(
|
||||
"The directory is not empty. File will be overwritten." + Environment.NewLine +
|
||||
"Are you sure you want to continue?",
|
||||
"Project Directory not empty",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
|
||||
Resources.AssemblySaveCodeDirectoryNotEmpty,
|
||||
Resources.AssemblySaveCodeDirectoryNotEmptyTitle,
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
|
||||
if (result == MessageBoxResult.No)
|
||||
return true; // don't save, but mark the Save operation as handled
|
||||
break;
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
|
|||
|
||||
public override object Text
|
||||
{
|
||||
get { return type.FullName + type.MetadataToken.ToSuffixString(); }
|
||||
get { return Language.TypeToString(type, includeNamespace: true) + type.MetadataToken.ToSuffixString(); }
|
||||
}
|
||||
|
||||
public override object Icon => TypeTreeNode.GetIcon(type);
|
||||
|
|
|
@ -89,7 +89,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
|
|||
output.WriteLine();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.Desktop" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -47,6 +47,6 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AvaloniaEdit\src\AvaloniaEdit\AvaloniaEdit.csproj" />
|
||||
<PackageReference Include="Avalonia" />
|
||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Загрузка…
Ссылка в новой задаче