This commit is contained in:
Jeffrey Ye 2019-11-24 23:11:14 -08:00
Родитель 0d4922c2cd
Коммит 6fb23b3080
37 изменённых файлов: 1304 добавлений и 222 удалений

Просмотреть файл

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

90
ILSpy.Core/Properties/Resources.Designer.cs сгенерированный
Просмотреть файл

@ -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 &apos;ref&apos; 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>