Browse Source

Merge remote-tracking branch 'remotes/origin/master' into classbrowser

Conflicts:
	src/Main/SharpDevelop/Parser/AssemblyParserService.cs
pull/80/head
Andreas Weizel 12 years ago
parent
commit
1316bdcebd
  1. 3
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
  2. 5
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
  3. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionWrapper.cs
  4. 4
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs
  5. 4
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs
  6. 6
      src/AddIns/Debugger/Debugger.Core/Process.cs
  7. 70
      src/AddIns/DisplayBindings/ILSpyAddIn/DecompiledViewContent.cs
  8. 7
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin
  9. 3
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj
  10. 112
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDecompilerService.cs
  11. 34
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDisplayBinding.cs
  12. 5
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyFullParseInformation.cs
  13. 24
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyParser.cs
  14. 65
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs
  15. 8
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyUnresolvedFile.cs
  16. 2
      src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs
  17. 9
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Xml/DocumentationElement.cs
  18. 30
      src/Main/Base/Project/Dom/IEntityModelContext.cs
  19. 2
      src/Main/Base/Project/Editor/ContextActions/ContextActionViewModel.cs
  20. 10
      src/Main/Base/Project/Parser/IAssemblyParserService.cs
  21. 6
      src/Main/Base/Project/Parser/IParser.cs
  22. 2
      src/Main/Base/Project/Refactoring/ContextAction.cs
  23. 31
      src/Main/SharpDevelop/Parser/AssemblyParserService.cs
  24. 2
      src/Main/SharpDevelop/Parser/ParserService.cs
  25. 6
      src/Main/SharpDevelop/Parser/ParserServiceEntry.cs
  26. 18
      src/Main/SharpDevelop/Workbench/DisplayBinding/DisplayBindingService.cs

3
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin

@ -16,7 +16,8 @@ @@ -16,7 +16,8 @@
<Doozer name="CSharpCodeActionProvider" class="CSharpBinding.Refactoring.CSharpCodeActionProviderDoozer"/>
</Import>
<Import assembly = ":ICSharpCode.SharpDevelop"/>
<Import assembly = ":ICSharpCode.NRefactory.CSharp.Refactoring"/>
<Import assembly = ":ICSharpCode.NRefactory.CSharp"/> <!-- used for CSharpAmbience -->
<Import assembly = ":ICSharpCode.NRefactory.CSharp.Refactoring"/> <!-- used for issues and refactorings -->
</Runtime>
<Path name = "/SharpDevelop/Workbench/Ambiences">

5
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs

@ -68,6 +68,11 @@ namespace CSharpBinding.Parser @@ -68,6 +68,11 @@ namespace CSharpBinding.Parser
}
*/
public ITextSource GetFileContent(FileName fileName)
{
return SD.FileService.GetFileContent(fileName);
}
public ParseInformation Parse(FileName fileName, ITextSource fileContent, bool fullParseInformationRequested,
IProject parentProject, CancellationToken cancellationToken)
{

1
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionWrapper.cs

@ -54,7 +54,6 @@ namespace CSharpBinding.Refactoring @@ -54,7 +54,6 @@ namespace CSharpBinding.Refactoring
public void Execute(EditorRefactoringContext context)
{
SD.AnalyticsMonitor.TrackFeature(provider.ID);
var resolver = context.GetAstResolverAsync().Result;
var refactoringContext = new SDRefactoringContext(context.Editor, resolver, context.CaretLocation);
var action = getUpdatedCodeAction(refactoringContext);

4
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs

@ -39,9 +39,9 @@ namespace ICSharpCode.XamlBinding @@ -39,9 +39,9 @@ namespace ICSharpCode.XamlBinding
return Path.GetExtension(fileName).Equals(".xaml", StringComparison.OrdinalIgnoreCase);
}
public bool CanParse(IProject project)
public ITextSource GetFileContent(FileName fileName)
{
return false;
return SD.FileService.GetFileContent(fileName);
}
volatile IncrementalParserState parserState;

4
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs

@ -124,7 +124,7 @@ namespace Debugger.AddIn @@ -124,7 +124,7 @@ namespace Debugger.AddIn
}
if (!allowMethodInvoke && (importedMember is IMethod))
throw new InvalidOperationException("Method invocation not allowed in the current context!");
Value val = Value.GetMemberValue(evalThread, target, importedMember);
Value val = Value.GetMemberValue(evalThread, target, importedMember.Specialize(context.MethodInfo.Substitution));
if (val == null)
throw new GetValueException("Member not found!");
return val;
@ -272,7 +272,7 @@ namespace Debugger.AddIn @@ -272,7 +272,7 @@ namespace Debugger.AddIn
return Convert(val);
}
/// <remark
/// <remarks>
/// See $7.10.10 of C# 4 Spec for details.
/// </remarks>
Value Visit(TypeIsResolveResult result)

6
src/AddIns/Debugger/Debugger.Core/Process.cs

@ -613,12 +613,14 @@ namespace Debugger @@ -613,12 +613,14 @@ namespace Debugger
internal void OnAppDomainCreated(AppDomain appDomain)
{
if (AppDomainCreated != null)
AppDomainCreated(this, new AppDomainEventArgs(appDomain));
}
internal void OnAppDomainDestroyed(AppDomain appDomain)
{
if (AppDomainDestroyed != null)
AppDomainDestroyed(this, new AppDomainEventArgs(appDomain));
}
}
}

70
src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs → src/AddIns/DisplayBindings/ILSpyAddIn/DecompiledViewContent.cs

@ -48,11 +48,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -48,11 +48,7 @@ namespace ICSharpCode.ILSpyAddIn
this.jumpToEntityIdStringWhenDecompilationFinished = entityTag;
this.TitleName = "[" + ReflectionHelper.SplitTypeParameterCountFromReflectionName(typeName.Type.Name) + "]";
DecompilationThread();
// Thread thread = new Thread(DecompilationThread);
// thread.Name = "Decompiler (" + shortTypeName + ")";
// thread.Start();
// thread.Join();
InitializeView();
SD.BookmarkManager.BookmarkRemoved += BookmarkManager_Removed;
SD.BookmarkManager.BookmarkAdded += BookmarkManager_Added;
@ -63,56 +59,6 @@ namespace ICSharpCode.ILSpyAddIn @@ -63,56 +59,6 @@ namespace ICSharpCode.ILSpyAddIn
}
#endregion
public static DecompiledViewContent Get(DecompiledTypeReference name)
{
var viewContents = SD.Workbench.ViewContentCollection.OfType<DecompiledViewContent>();
return viewContents.FirstOrDefault(c => c.DecompiledTypeName == name);
}
public static DecompiledViewContent Get(IEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
// Get the underlying entity for generic instance members
if (entity is IMember)
entity = ((IMember)entity).MemberDefinition;
ITypeDefinition declaringType = (entity as ITypeDefinition) ?? entity.DeclaringTypeDefinition;
if (declaringType == null)
return null;
// get the top-level type
while (declaringType.DeclaringTypeDefinition != null)
declaringType = declaringType.DeclaringTypeDefinition;
FileName assemblyLocation = declaringType.ParentAssembly.GetRuntimeAssemblyLocation();
if (assemblyLocation != null && File.Exists(assemblyLocation)) {
return Get(assemblyLocation, declaringType.ReflectionName);
}
return null;
}
public static DecompiledViewContent Get(FileName assemblyFile, string typeName)
{
if (assemblyFile == null)
throw new ArgumentNullException("assemblyFile");
if (string.IsNullOrEmpty(typeName))
throw new ArgumentException("typeName is null or empty");
var type = new FullTypeName(typeName);
foreach (var viewContent in SD.Workbench.ViewContentCollection.OfType<DecompiledViewContent>()) {
var viewContentName = viewContent.DecompiledTypeName;
if (viewContentName.AssemblyFile == assemblyFile && type == viewContentName.Type) {
return viewContent;
}
}
var newViewContent = new DecompiledViewContent(new DecompiledTypeReference(assemblyFile, new FullTypeName(typeName)), null);
SD.Workbench.ShowView(newViewContent);
return newViewContent;
}
#region Properties
public DecompiledTypeReference DecompiledTypeName { get; private set; }
@ -173,13 +119,15 @@ namespace ICSharpCode.ILSpyAddIn @@ -173,13 +119,15 @@ namespace ICSharpCode.ILSpyAddIn
#endregion
#region Decompilation
void DecompilationThread()
async void InitializeView()
{
try {
var file = ILSpyDecompilerService.DecompileType(DecompiledTypeName);
var parseInformation = await SD.ParserService.ParseAsync(DecompiledTypeName.ToFileName(), cancellationToken: cancellation.Token);
if (parseInformation == null || !(parseInformation.UnresolvedFile is ILSpyUnresolvedFile)) return;
var file = (ILSpyUnresolvedFile)parseInformation.UnresolvedFile;
memberLocations = file.MemberLocations;
DebugSymbols = file.DebugSymbols;
OnDecompilationFinished(file.Writer);
OnDecompilationFinished(file.Output);
} catch (OperationCanceledException) {
// ignore cancellation
} catch (Exception ex) {
@ -193,15 +141,15 @@ namespace ICSharpCode.ILSpyAddIn @@ -193,15 +141,15 @@ namespace ICSharpCode.ILSpyAddIn
writer.WriteLine(string.Format("Exception while decompiling {0} ({1})", DecompiledTypeName.Type, DecompiledTypeName.AssemblyFile));
writer.WriteLine();
writer.WriteLine(ex.ToString());
SD.MainThread.InvokeAsyncAndForget(() => OnDecompilationFinished(writer));
OnDecompilationFinished(writer.ToString());
}
}
void OnDecompilationFinished(StringWriter output)
void OnDecompilationFinished(string output)
{
if (cancellation.IsCancellationRequested)
return;
codeEditor.Document.Text = output.ToString();
codeEditor.Document.Text = output;
codeEditor.Document.UndoStack.ClearAll();
this.decompilationFinished = true;

7
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin

@ -32,4 +32,11 @@ @@ -32,4 +32,11 @@
<MenuItem id="ILSpySeparator" type="Separator" />
<MenuItem id="ILSpy" icon="ILSpy" type="Item" label="${res:ILSpyAddIn.OpenILSpyCommand}" class="ICSharpCode.ILSpyAddIn.OpenInILSpyCommand"/>
</Path>
<Path name = "/SharpDevelop/Workbench/DisplayBindings/UrlBased">
<DisplayBinding id = "ILSpyView"
class = "ICSharpCode.ILSpyAddIn.ILSpyDisplayBinding"
fileNamePattern = "^ilspy://"
title = "ILSpy Decompiler View"/>
</Path>
</AddIn>

3
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj

@ -66,7 +66,9 @@ @@ -66,7 +66,9 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="DebuggerTextOutput.cs" />
<Compile Include="DecompiledViewContent.cs" />
<Compile Include="ILSpyDecompilerService.cs" />
<Compile Include="ILSpyDisplayBinding.cs" />
<Compile Include="ILSpyFullParseInformation.cs" />
<Compile Include="ILSpyParser.cs" />
<Compile Include="ILSpySymbolSource.cs" />
@ -81,7 +83,6 @@ @@ -81,7 +83,6 @@
<DependentUpon>SetILSpyPathDialog.cs</DependentUpon>
</Compile>
<Compile Include="LaunchILSpy\OpenInILSpyCommand.cs" />
<Compile Include="ViewContent\DecompiledViewContent.cs" />
<EmbeddedResource Include="LaunchILSpy\SetILSpyPathDialog.resx">
<DependentUpon>SetILSpyPathDialog.cs</DependentUpon>
</EmbeddedResource>

112
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDecompilerService.cs

@ -13,6 +13,7 @@ using ICSharpCode.Core; @@ -13,6 +13,7 @@ using ICSharpCode.Core;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using Mono.Cecil;
@ -23,45 +24,46 @@ namespace ICSharpCode.ILSpyAddIn @@ -23,45 +24,46 @@ namespace ICSharpCode.ILSpyAddIn
/// </summary>
public static class ILSpyDecompilerService
{
class AssemblyCacheInfo
class ModuleCacheInfo
{
public readonly DateTime LastUpdateTime;
public readonly WeakReference<AssemblyDefinition> Assembly;
public readonly WeakReference<ModuleDefinition> Module;
public AssemblyCacheInfo(DateTime lastUpdateTime, AssemblyDefinition assembly)
public ModuleCacheInfo(DateTime lastUpdateTime, ModuleDefinition assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
this.LastUpdateTime = lastUpdateTime;
this.Assembly = new WeakReference<AssemblyDefinition>(assembly);
this.Module = new WeakReference<ModuleDefinition>(assembly);
}
}
static readonly Dictionary<FileName, AssemblyCacheInfo> assemblyCache = new Dictionary<FileName, AssemblyCacheInfo>();
static readonly Dictionary<FileName, ModuleCacheInfo> moduleCache = new Dictionary<FileName, ModuleCacheInfo>();
static AssemblyDefinition GetAssemblyDefinitionFromCache(FileName file, ReaderParameters parameters = null)
static ModuleDefinition GetModuleDefinitionFromCache(FileName file)
{
if (file == null) return null;
if (parameters == null) parameters = new ReaderParameters();
ReaderParameters parameters = new ReaderParameters();
var resolver = new ILSpyAssemblyResolver(file);
var lastUpdateTime = File.GetLastWriteTimeUtc(file);
lock (assemblyCache) {
AssemblyCacheInfo info;
AssemblyDefinition asm;
if (!assemblyCache.TryGetValue(file, out info)) {
asm = AssemblyDefinition.ReadAssembly(file, parameters);
assemblyCache.Add(file, new AssemblyCacheInfo(lastUpdateTime, asm));
return asm;
lock (moduleCache) {
ModuleCacheInfo info;
ModuleDefinition module;
if (!moduleCache.TryGetValue(file, out info)) {
module = ModuleDefinition.ReadModule(file, parameters);
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module));
return module;
} else if (info.LastUpdateTime < lastUpdateTime) {
assemblyCache.Remove(file);
asm = AssemblyDefinition.ReadAssembly(file, parameters);
assemblyCache.Add(file, new AssemblyCacheInfo(lastUpdateTime, asm));
return asm;
moduleCache.Remove(file);
module = ModuleDefinition.ReadModule(file, parameters);
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module));
return module;
} else {
if (info.Assembly.TryGetTarget(out asm))
return asm;
asm = AssemblyDefinition.ReadAssembly(file, parameters);
info.Assembly.SetTarget(asm);
return asm;
if (info.Module.TryGetTarget(out module))
return module;
module = ModuleDefinition.ReadModule(file, parameters);
info.Module.SetTarget(module);
return module;
}
}
}
@ -77,14 +79,19 @@ namespace ICSharpCode.ILSpyAddIn @@ -77,14 +79,19 @@ namespace ICSharpCode.ILSpyAddIn
{
}
/// <summary>
/// Used to remember the referenced assemblies for the WeakReference cache policy.
/// </summary>
readonly ISet<AssemblyDefinition> resolvedAssemblies = new HashSet<AssemblyDefinition>();
AssemblyDefinition Resolve(DomAssemblyName name, ReaderParameters parameters)
{
var assemblyDefinition = GetAssemblyDefinitionFromCache(FindAssembly(name), parameters);
if (assemblyDefinition != null)
resolvedAssemblies.Add(assemblyDefinition);
return assemblyDefinition;
var moduleDefinition = GetModuleDefinitionFromCache(FindAssembly(name));
if (moduleDefinition != null) {
resolvedAssemblies.Add(moduleDefinition.Assembly);
return moduleDefinition.Assembly;
}
return null;
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
@ -108,31 +115,24 @@ namespace ICSharpCode.ILSpyAddIn @@ -108,31 +115,24 @@ namespace ICSharpCode.ILSpyAddIn
}
}
public static ILSpyUnresolvedFile DecompileType(DecompiledTypeReference name)
public static ILSpyFullParseInformation DecompileType(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
if (name == null)
throw new ArgumentNullException("entity");
return DoDecompile(name);
}
public static async Task<ILSpyUnresolvedFile> DecompileTypeAsync(DecompiledTypeReference name, CancellationToken cancellationToken)
{
return await Task.Run(
delegate() { return DoDecompile(name, cancellationToken); },
cancellationToken);
throw new ArgumentNullException("name");
var astBuilder = CreateAstBuilder(name, cancellationToken);
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree);
}
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, out AssemblyDefinition[] neededAssemblies, CancellationToken cancellationToken = default(CancellationToken))
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
ReaderParameters readerParameters = new ReaderParameters();
// Use new assembly resolver instance so that the AssemblyDefinitions
// can be garbage-collected once the code is decompiled.
var resolver = new ILSpyAssemblyResolver(name.AssemblyFile);
readerParameters.AssemblyResolver = resolver;
AssemblyDefinition asm = GetAssemblyDefinitionFromCache(name.AssemblyFile, readerParameters);
if (asm == null)
ModuleDefinition module = GetModuleDefinitionFromCache(name.AssemblyFile);
if (module == null)
throw new InvalidOperationException("Could not find assembly file");
ModuleDefinition module = asm.MainModule;
TypeDefinition typeDefinition = module.GetType(name.Type.ReflectionName);
if (typeDefinition == null)
throw new InvalidOperationException("Could not find type");
@ -140,30 +140,21 @@ namespace ICSharpCode.ILSpyAddIn @@ -140,30 +140,21 @@ namespace ICSharpCode.ILSpyAddIn
context.CancellationToken = cancellationToken;
AstBuilder astBuilder = new AstBuilder(context);
astBuilder.AddType(typeDefinition);
neededAssemblies = resolver.ResolvedAssemblies.ToArray();
return astBuilder;
}
static ILSpyUnresolvedFile DoDecompile(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
AssemblyDefinition[] assemblies;
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, out assemblies, cancellationToken));
}
public static ILSpyFullParseInformation ParseDecompiledType(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
AssemblyDefinition[] assemblies;
var astBuilder = CreateAstBuilder(name, out assemblies, cancellationToken);
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree, assemblies);
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, cancellationToken));
}
}
public class DecompiledTypeReference : IEquatable<DecompiledTypeReference>
{
public FileName AssemblyFile { get; private set; }
public FullTypeName Type { get; private set; }
public TopLevelTypeName Type { get; private set; }
public DecompiledTypeReference(FileName assemblyFile, FullTypeName type)
public DecompiledTypeReference(FileName assemblyFile, TopLevelTypeName type)
{
this.AssemblyFile = assemblyFile;
this.Type = type;
@ -185,7 +176,16 @@ namespace ICSharpCode.ILSpyAddIn @@ -185,7 +176,16 @@ namespace ICSharpCode.ILSpyAddIn
asm = match.Groups[1].Value;
typeName = UnescapeTypeName(match.Groups[2].Value);
return new DecompiledTypeReference(new FileName(asm), new FullTypeName(typeName));
return new DecompiledTypeReference(new FileName(asm), new TopLevelTypeName(typeName));
}
public static DecompiledTypeReference FromTypeDefinition(ITypeDefinition definition)
{
FileName assemblyLocation = definition.ParentAssembly.GetRuntimeAssemblyLocation();
if (assemblyLocation != null && SD.FileSystem.FileExists(assemblyLocation)) {
return new DecompiledTypeReference(assemblyLocation, definition.FullTypeName.TopLevelTypeName);
}
return null;
}
public static string EscapeTypeName(string typeName)
@ -204,9 +204,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -204,9 +204,7 @@ namespace ICSharpCode.ILSpyAddIn
{
if (typeName == null)
throw new ArgumentNullException("typeName");
foreach (var ch in Path.GetInvalidFileNameChars().Concat(new[] { '_' })) {
typeName = unescapeRegex.Replace(typeName, m => ((char)int.Parse(m.Groups[1].Value, System.Globalization.NumberStyles.HexNumber)).ToString());
}
typeName = unescapeRegex.Replace(typeName, m => ((char)int.Parse(m.Groups[1].Value, System.Globalization.NumberStyles.HexNumber)).ToString());
return typeName;
}

34
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDisplayBinding.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Workbench;
namespace ICSharpCode.ILSpyAddIn
{
public class ILSpyDisplayBinding : IDisplayBinding
{
public bool IsPreferredBindingForFile(FileName fileName)
{
return fileName.ToString().StartsWith("ilspy://", StringComparison.OrdinalIgnoreCase);
}
public bool CanCreateContentForFile(FileName fileName)
{
return fileName.ToString().StartsWith("ilspy://", StringComparison.OrdinalIgnoreCase);
}
public double AutoDetectFileContent(FileName fileName, Stream fileContent, string detectedMimeType)
{
return 1;
}
public IViewContent CreateContentForFile(OpenedFile file)
{
return new DecompiledViewContent(DecompiledTypeReference.FromFileName(file.FileName), "");
}
}
}

5
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyFullParseInformation.cs

@ -17,14 +17,11 @@ namespace ICSharpCode.ILSpyAddIn @@ -17,14 +17,11 @@ namespace ICSharpCode.ILSpyAddIn
public class ILSpyFullParseInformation : ParseInformation
{
SyntaxTree syntaxTree;
// Required to make WeakReferences work properly as cache policy.
AssemblyDefinition[] neededAssemblies;
public ILSpyFullParseInformation(ILSpyUnresolvedFile unresolvedFile, ITextSourceVersion parsedVersion, SyntaxTree syntaxTree, IEnumerable<AssemblyDefinition> neededAssemblies)
public ILSpyFullParseInformation(ILSpyUnresolvedFile unresolvedFile, ITextSourceVersion parsedVersion, SyntaxTree syntaxTree)
: base(unresolvedFile, parsedVersion, true)
{
this.syntaxTree = syntaxTree;
this.neededAssemblies = neededAssemblies.ToArray();
}
public SyntaxTree SyntaxTree { get { return syntaxTree; } }

24
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyParser.cs

@ -32,16 +32,23 @@ namespace ICSharpCode.ILSpyAddIn @@ -32,16 +32,23 @@ namespace ICSharpCode.ILSpyAddIn
return fileName != null && fileName.StartsWith("ilspy://", StringComparison.OrdinalIgnoreCase);
}
readonly static ITextSource EmptyFileContent = new StringTextSource("");
public ITextSource GetFileContent(FileName fileName)
{
return EmptyFileContent;
}
public ParseInformation Parse(FileName fileName, ITextSource fileContent, bool fullParseInformationRequested, IProject parentProject, CancellationToken cancellationToken)
{
return ILSpyDecompilerService.ParseDecompiledType(DecompiledTypeReference.FromFileName(fileName), cancellationToken);
return ILSpyDecompilerService.DecompileType(DecompiledTypeReference.FromFileName(fileName), cancellationToken);
}
public ResolveResult Resolve(ParseInformation parseInfo, TextLocation location, ICompilation compilation, CancellationToken cancellationToken)
{
var decompiledParseInfo = parseInfo as ILSpyFullParseInformation;
if (decompiledParseInfo == null)
throw new ArgumentException("Parse info does not have SyntaxTree");
throw new ArgumentException("ParseInfo does not have SyntaxTree");
return ResolveAtLocation.Resolve(compilation, null, decompiledParseInfo.SyntaxTree, location, cancellationToken);
}
@ -55,16 +62,6 @@ namespace ICSharpCode.ILSpyAddIn @@ -55,16 +62,6 @@ namespace ICSharpCode.ILSpyAddIn
throw new NotImplementedException();
}
static readonly Lazy<IAssemblyReference[]> defaultReferences = new Lazy<IAssemblyReference[]>(
delegate {
Assembly[] assemblies = {
typeof(object).Assembly,
typeof(Uri).Assembly,
typeof(Enumerable).Assembly
};
return assemblies.Select(asm => new CecilLoader().LoadAssemblyFile(asm.Location)).ToArray();
});
public ICompilation CreateCompilationForSingleFile(FileName fileName, IUnresolvedFile unresolvedFile)
{
DecompiledTypeReference reference = DecompiledTypeReference.FromFileName(fileName);
@ -73,10 +70,9 @@ namespace ICSharpCode.ILSpyAddIn @@ -73,10 +70,9 @@ namespace ICSharpCode.ILSpyAddIn
if (model == null)
model = SD.AssemblyParserService.GetAssemblyModelSafe(reference.AssemblyFile, true);
if (model != null)
return SD.AssemblyParserService.CreateCompilationForAssembly(model, true);
return model.Context.GetCompilation();
}
return new CSharpProjectContent()
.AddAssemblyReferences(defaultReferences.Value)
.AddOrUpdateFiles(unresolvedFile)
.CreateCompilation();
}

65
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs

@ -8,6 +8,7 @@ using ICSharpCode.Decompiler; @@ -8,6 +8,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.ILSpyAddIn
{
@ -20,28 +21,23 @@ namespace ICSharpCode.ILSpyAddIn @@ -20,28 +21,23 @@ namespace ICSharpCode.ILSpyAddIn
public bool IsCompilerGenerated(IMethod method)
{
var symbols = GetSymbols(method);
return symbols == null || symbols.SequencePoints.Count == 0;
return false;
}
public static MethodDebugSymbols GetSymbols(IMethod method)
public static ILSpyUnresolvedFile GetSymbols(IMethod method)
{
// Use the non-specialised method definition to look up decompiled symbols
var id = IdStringProvider.GetIdString(method.MemberDefinition);
var content = DecompiledViewContent.Get(method);
if (content != null && content.DebugSymbols.ContainsKey(id)) {
return content.DebugSymbols[id];
}
return null;
var typeName = DecompiledTypeReference.FromTypeDefinition(method.DeclaringTypeDefinition);
if (typeName == null) return null;
return SD.ParserService.ParseFile(typeName.ToFileName()) as ILSpyUnresolvedFile;
}
public Debugger.SequencePoint GetSequencePoint(IMethod method, int iloffset)
{
string id = IdStringProvider.GetIdString(method.MemberDefinition);
var content = DecompiledViewContent.Get(method);
if (content == null || !content.DebugSymbols.ContainsKey(id))
var file = GetSymbols(method);
if (file == null || !file.DebugSymbols.ContainsKey(id))
return null;
var symbols = content.DebugSymbols[id];
var symbols = file.DebugSymbols[id];
var seqs = symbols.SequencePoints;
var seq = seqs.FirstOrDefault(p => p.ILRanges.Any(r => r.From <= iloffset && iloffset < r.To));
if (seq == null)
@ -52,7 +48,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -52,7 +48,7 @@ namespace ICSharpCode.ILSpyAddIn
seq = seqs.Where(p => p.ILRanges.Any(r => r.From <= iloffset && iloffset < r.To))
.OrderByDescending(p => p.ILRanges.Last().To - p.ILRanges.First().From)
.FirstOrDefault();
return seq.ToDebugger(symbols, content.PrimaryFileName);
return seq.ToDebugger(symbols, file.FileName);
}
return null;
}
@ -63,28 +59,31 @@ namespace ICSharpCode.ILSpyAddIn @@ -63,28 +59,31 @@ namespace ICSharpCode.ILSpyAddIn
if (name == null || !FileUtility.IsEqualFileName(module.FullPath, name.AssemblyFile))
yield break;
var content = DecompiledViewContent.Get(name);
if (content == null)
var file = SD.ParserService.ParseFile(name.ToFileName()) as ILSpyUnresolvedFile;
if (file == null)
yield break;
TextLocation loc = new TextLocation(line, column);
foreach(var symbols in content.DebugSymbols.Values.Where(s => s.StartLocation <= loc && loc <= s.EndLocation)) {
foreach(var symbols in file.DebugSymbols.Values.Where(s => s.StartLocation <= loc && loc <= s.EndLocation)) {
Decompiler.SequencePoint seq = null;
if (column != 0)
seq = symbols.SequencePoints.FirstOrDefault(p => p.StartLocation <= loc && loc <= p.EndLocation);
if (seq == null)
seq = symbols.SequencePoints.FirstOrDefault(p => line <= p.StartLocation.Line);
if (seq != null)
yield return seq.ToDebugger(symbols, content.PrimaryFileName);
yield return seq.ToDebugger(symbols, filename);
}
}
public IEnumerable<ILRange> GetIgnoredILRanges(IMethod method)
{
var symbols = GetSymbols(method);
if (symbols == null)
string id = IdStringProvider.GetIdString(method.MemberDefinition);
var file = GetSymbols(method);
if (file == null || !file.DebugSymbols.ContainsKey(id))
return new ILRange[] { };
var symbols = file.DebugSymbols[id];
int codesize = symbols.CecilMethod.Body.CodeSize;
var inv = ICSharpCode.Decompiler.ILAst.ILRange.Invert(symbols.SequencePoints.SelectMany(s => s.ILRanges), codesize);
return inv.Select(r => new ILRange(r.From, r.To));
@ -92,17 +91,25 @@ namespace ICSharpCode.ILSpyAddIn @@ -92,17 +91,25 @@ namespace ICSharpCode.ILSpyAddIn
public IEnumerable<ILLocalVariable> GetLocalVariables(IMethod method)
{
var symbols = GetSymbols(method);
if (symbols == null)
string id = IdStringProvider.GetIdString(method.MemberDefinition);
var file = GetSymbols(method);
if (file == null || !file.DebugSymbols.ContainsKey(id))
return null;
return symbols.LocalVariables.Select(v => new Debugger.ILLocalVariable() {
Index = v.OriginalVariable.Index,
Type = method.Compilation.FindType(KnownTypeCode.Object), // TODO
Name = v.Name,
IsCompilerGenerated = false,
ILRanges = new [] { new Debugger.ILRange(0, int.MaxValue) }
});
var symbols = file.DebugSymbols[id];
var context = new SimpleTypeResolveContext(method);
var loader = new CecilLoader();
return symbols.LocalVariables.Select(
v => new Debugger.ILLocalVariable() {
Index = v.OriginalVariable.Index,
Type = loader.ReadTypeReference(v.Type).Resolve(context),
Name = v.Name,
IsCompilerGenerated = false,
ILRanges = new [] { new ILRange(0, int.MaxValue) }
});
}
}

8
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyUnresolvedFile.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -20,7 +20,7 @@ namespace ICSharpCode.ILSpyAddIn
public class ILSpyUnresolvedFile : CSharpUnresolvedFile
{
DecompiledTypeReference name;
StringWriter writer;
string output;
public static ILSpyUnresolvedFile Create(DecompiledTypeReference name, AstBuilder builder)
{
@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpyAddIn
file.MemberLocations = output.MemberLocations;
file.DebugSymbols = output.DebugSymbols;
file.writer = writer;
file.output = writer.ToString();
return file;
}
@ -53,8 +53,8 @@ namespace ICSharpCode.ILSpyAddIn @@ -53,8 +53,8 @@ namespace ICSharpCode.ILSpyAddIn
public Dictionary<string, MethodDebugSymbols> DebugSymbols { get; private set; }
public StringWriter Writer {
get { return writer; }
public string Output {
get { return output; }
}
public FileName AssemblyFile {

2
src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpyAddIn
if (string.IsNullOrEmpty(typeName))
throw new ArgumentException("typeName is null or empty");
var type = new FullTypeName(typeName);
var type = new TopLevelTypeName(typeName);
var target = new DecompiledTypeReference(assemblyFile, type);
foreach (var viewContent in SD.Workbench.ViewContentCollection.OfType<DecompiledViewContent>()) {

9
src/Libraries/NRefactory/ICSharpCode.NRefactory.Xml/DocumentationElement.cs

@ -46,6 +46,12 @@ namespace ICSharpCode.NRefactory.Xml @@ -46,6 +46,12 @@ namespace ICSharpCode.NRefactory.Xml
IMember member = entity as IMember;
if (inheritDocIfMissing && member != null) {
if (member.SymbolKind == SymbolKind.Constructor) {
// For constructors, the documentation of the base class ctor
// isn't really suitable as constructors are not inherited.
// We'll use the type's documentation instead:
return Get(entity.DeclaringTypeDefinition, inheritDocIfMissing);
}
foreach (IMember baseMember in InheritanceHelper.GetBaseMembers(member, includeImplementedInterfaces: true)) {
documentationComment = baseMember.Documentation;
if (documentationComment != null)
@ -104,6 +110,7 @@ namespace ICSharpCode.NRefactory.Xml @@ -104,6 +110,7 @@ namespace ICSharpCode.NRefactory.Xml
{
if (text == null)
throw new ArgumentNullException("text");
this.declaringEntity = declaringEntity;
this.textContent = text;
}
@ -112,7 +119,7 @@ namespace ICSharpCode.NRefactory.Xml @@ -112,7 +119,7 @@ namespace ICSharpCode.NRefactory.Xml
/// May return null.
/// </summary>
public IEntity DeclaringEntity {
get { return null; }
get { return declaringEntity; }
}
IEntity referencedEntity;

30
src/Main/Base/Project/Dom/IEntityModelContext.cs

@ -107,20 +107,40 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -107,20 +107,40 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
public class DomAssemblyNameReference : IAssemblyReference
{
DomAssemblyName name;
IAssemblySearcher searcher;
public DomAssemblyNameReference(DomAssemblyName name, IAssemblySearcher searcher)
{
if (name == null)
throw new ArgumentNullException("name");
if (searcher == null)
throw new ArgumentNullException("searcher");
this.name = name;
this.searcher = searcher;
}
public IAssembly Resolve(ITypeResolveContext context)
{
return SD.AssemblyParserService.GetAssembly(searcher.FindAssembly(name), true).Resolve(context);
}
}
public class AssemblyEntityModelContext : IEntityModelContext
{
ICompilation compilation;
Lazy<ICompilation> compilation;
IUnresolvedAssembly mainAssembly;
IAssemblyReference[] references;
public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, params IAssemblyReference[] references)
public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, IAssemblyReference[] references)
{
if (mainAssembly == null)
throw new ArgumentNullException("mainAssembly");
this.mainAssembly = mainAssembly;
this.references = references;
// implement lazy init + weak caching
this.compilation = new SimpleCompilation(mainAssembly, references);
this.compilation = new Lazy<ICompilation>(() => new SimpleCompilation(mainAssembly, references));
}
public string AssemblyName {
@ -137,7 +157,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -137,7 +157,7 @@ namespace ICSharpCode.SharpDevelop.Dom
public ICompilation GetCompilation()
{
return compilation;
return compilation.Value;
}
public bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2)

2
src/Main/Base/Project/Editor/ContextActions/ContextActionViewModel.cs

@ -86,6 +86,8 @@ namespace ICSharpCode.SharpDevelop.Editor.ContextActions @@ -86,6 +86,8 @@ namespace ICSharpCode.SharpDevelop.Editor.ContextActions
public void Execute(object parameter)
{
if (action.Provider != null)
SD.AnalyticsMonitor.TrackFeature(action.Provider.ID);
this.action.Execute(context);
}

10
src/Main/Base/Project/Parser/IAssemblyParserService.cs

@ -51,16 +51,6 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -51,16 +51,6 @@ namespace ICSharpCode.SharpDevelop.Parser
event EventHandler<RefreshAssemblyEventArgs> AssemblyRefreshed;
/// <summary>
/// Creates a compilation for the specified assembly.
/// </summary>
ICompilation CreateCompilationForAssembly(IAssemblyModel assembly, bool includeInternalMembers = false);
/// <summary>
/// Creates a compilation for the specified assembly.
/// </summary>
ICompilation CreateCompilationForAssembly(FileName assembly, bool includeInternalMembers = false);
/// <summary>
/// Creates an IAssemblyModel for the given assembly file.
/// </summary>

6
src/Main/Base/Project/Parser/IParser.cs

@ -34,10 +34,14 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -34,10 +34,14 @@ namespace ICSharpCode.SharpDevelop.Parser
/// </summary>
bool CanParse(string fileName);
/// <summary>
/// Returns the content for a given filename.
/// </summary>
ITextSource GetFileContent(FileName fileName);
/// <summary>
/// Parses a file.
/// </summary>
/// <param name="projectContent">The parent project of the file.</param>
/// <param name="fileName">The name of the file being parsed.</param>
/// <param name="fileContent">The content of the file.</param>
/// <param name="fullParseInformationRequested">

2
src/Main/Base/Project/Refactoring/ContextAction.cs

@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
{
/// <summary>
/// Base class for implementing one context action.
/// Useful for implementing <see cref="IContextActionsProvider" /> that provides just one action - common scenario.
/// Useful for implementing <see cref="IContextActionProvider" /> that provides just one action - common scenario.
/// </summary>
public abstract class ContextAction : IContextActionProvider, IContextAction
{

31
src/Main/SharpDevelop/Parser/AssemblyParserService.cs

@ -83,15 +83,15 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -83,15 +83,15 @@ namespace ICSharpCode.SharpDevelop.Parser
void CleanWeakDictionary()
{
Debug.Assert(Monitor.IsEntered(projectContentDictionary));
List<FileName> removed = new List<FileName>();
foreach (var pair in projectContentDictionary) {
//if (!pair.Value.IsAlive)
// removed.Add(pair.Key);
// Debug.Assert(Monitor.IsEntered(projectContentDictionary));
// List<FileName> removed = new List<FileName>();
// foreach (var pair in projectContentDictionary) {
// if (!pair.Value.IsAlive)
// removed.Add(pair.Key);
// }
// foreach (var key in removed)
// projectContentDictionary.Remove(key);
}
foreach (var key in removed)
projectContentDictionary.Remove(key);
}
LoadedAssembly GetLoadedAssembly(FileName fileName, bool includeInternalMembers)
{
@ -327,21 +327,6 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -327,21 +327,6 @@ namespace ICSharpCode.SharpDevelop.Parser
}
#endregion
public ICompilation CreateCompilationForAssembly(IAssemblyModel assembly, bool includeInternalMembers = false)
{
var mainAssembly = GetAssembly(assembly.Location, includeInternalMembers);
var searcher = new DefaultAssemblySearcher(assembly.Location);
var references = assembly.References
.Select(searcher.FindAssembly)
.Where(f => f != null);
return new SimpleCompilation(mainAssembly, references.Select(fn => GetAssembly(fn, includeInternalMembers)));
}
public ICompilation CreateCompilationForAssembly(FileName assembly, bool includeInternalMembers = false)
{
return CreateCompilationForAssembly(GetAssemblyModel(assembly, includeInternalMembers), includeInternalMembers);
}
public IAssemblyModel GetAssemblyModel(FileName fileName, bool includeInternalMembers = false)
{
LoadedAssembly assembly = GetLoadedAssembly(fileName, includeInternalMembers);

2
src/Main/SharpDevelop/Parser/ParserService.cs

@ -315,7 +315,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -315,7 +315,7 @@ namespace ICSharpCode.SharpDevelop.Parser
if (entry.parser == null)
return;
if (fileContent == null)
fileContent = SD.FileService.GetFileContent(fileName);
fileContent = entry.parser.GetFileContent(fileName);
if (compilation == null)
compilation = GetCompilationForFile(fileName);
var parseInfo = await entry.ParseAsync(fileContent, compilation.GetProject(), cancellationToken).ConfigureAwait(false);

6
src/Main/SharpDevelop/Parser/ParserServiceEntry.cs

@ -167,7 +167,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -167,7 +167,7 @@ namespace ICSharpCode.SharpDevelop.Parser
public ParseInformation Parse(ITextSource fileContent, IProject parentProject, CancellationToken cancellationToken)
{
if (fileContent == null) {
fileContent = SD.FileService.GetFileContent(fileName);
fileContent = parser.GetFileContent(fileName);
}
return DoParse(fileContent, parentProject, true, cancellationToken).CachedParseInformation;
@ -176,7 +176,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -176,7 +176,7 @@ namespace ICSharpCode.SharpDevelop.Parser
public IUnresolvedFile ParseFile(ITextSource fileContent, IProject parentProject, CancellationToken cancellationToken)
{
if (fileContent == null) {
fileContent = SD.FileService.GetFileContent(fileName);
fileContent = parser.GetFileContent(fileName);
}
return DoParse(fileContent, parentProject, false, cancellationToken).UnresolvedFile;
@ -302,7 +302,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -302,7 +302,7 @@ namespace ICSharpCode.SharpDevelop.Parser
// Let's look up the file in the list of open files right now
// so that we don't need to SafeThreadCall() later on.
lookupOpenFileOnTargetThread = false;
fileContent = SD.FileService.GetFileContentForOpenFile(fileName);
fileContent = parser.GetFileContent(fileName);
}
Task<ProjectEntry> task;
lock (this) {

18
src/Main/SharpDevelop/Workbench/DisplayBinding/DisplayBindingService.cs

@ -15,15 +15,18 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -15,15 +15,18 @@ namespace ICSharpCode.SharpDevelop.Workbench
sealed class DisplayBindingService : IDisplayBindingService
{
const string displayBindingPath = "/SharpDevelop/Workbench/DisplayBindings";
const string urlBasedDisplayBindingPath = "/SharpDevelop/Workbench/DisplayBindings/UrlBased";
Properties displayBindingServiceProperties;
List<DisplayBindingDescriptor> bindings;
List<DisplayBindingDescriptor> urlBasedBindings;
List<ExternalProcessDisplayBinding> externalProcessDisplayBindings = new List<ExternalProcessDisplayBinding>();
public DisplayBindingService()
{
bindings = AddInTree.BuildItems<DisplayBindingDescriptor>(displayBindingPath, null, true);
urlBasedBindings = AddInTree.BuildItems<DisplayBindingDescriptor>(urlBasedDisplayBindingPath, null, false);
displayBindingServiceProperties = SD.PropertyService.NestedProperties("DisplayBindingService");
foreach (var binding in displayBindingServiceProperties.GetList<ExternalProcessDisplayBinding>("ExternalProcesses")) {
if (binding != null) {
@ -84,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -84,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
if (FileUtility.IsUrl(filename)) {
// The normal display binding dispatching code can't handle URLs (e.g. because it uses Path.GetExtension),
// so we'll directly return the browser display binding.
return new BrowserDisplayBinding.BrowserDisplayBinding();
return GetBindingForUrl(filename);
}
DisplayBindingDescriptor codon = GetDefaultCodonPerFileName(filename);
return codon == null ? null : codon.Binding;
@ -112,13 +115,24 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -112,13 +115,24 @@ namespace ICSharpCode.SharpDevelop.Workbench
if (IsPrimaryBindingValidForFileName(binding, filename)) {
if (binding.Binding.IsPreferredBindingForFile(filename))
return binding;
else if (binding.Binding is AutoDetectDisplayBinding)
if (binding.Binding is AutoDetectDisplayBinding)
autoDetectDescriptor = binding;
}
}
return autoDetectDescriptor;
}
IDisplayBinding GetBindingForUrl(FileName url)
{
foreach (DisplayBindingDescriptor binding in urlBasedBindings) {
if (IsPrimaryBindingValidForFileName(binding, url)) {
if (binding.Binding.IsPreferredBindingForFile(url))
return binding.Binding;
}
}
return new BrowserDisplayBinding.BrowserDisplayBinding();
}
public void SetDefaultCodon(string extension, DisplayBindingDescriptor bindingDescriptor)
{
SD.MainThread.VerifyAccess();

Loading…
Cancel
Save