Browse Source

add implementation of IAssemblySearcher

newNRILSpyDebugger
Siegfried Pammer 12 years ago
parent
commit
42adad308c
  1. 5
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  2. 75
      src/Main/Base/Project/Parser/DefaultAssemblySearcher.cs
  3. 42
      src/Main/Base/Project/Parser/IAssemblyParserService.cs
  4. 86
      src/Main/SharpDevelop/Parser/AssemblyParserService.cs

5
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -160,6 +160,7 @@
<DependentUpon>ToolTipService.cs</DependentUpon> <DependentUpon>ToolTipService.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Editor\ToolTipService.cs" /> <Compile Include="Editor\ToolTipService.cs" />
<Compile Include="Parser\DefaultAssemblySearcher.cs" />
<Compile Include="Parser\DomAssemblyName.cs" /> <Compile Include="Parser\DomAssemblyName.cs" />
<Compile Include="Parser\IAssemblyParserService.cs" /> <Compile Include="Parser\IAssemblyParserService.cs" />
<Compile Include="Parser\IGlobalAssemblyCacheService.cs" /> <Compile Include="Parser\IGlobalAssemblyCacheService.cs" />
@ -878,6 +879,10 @@
<Name>ICSharpCode.AvalonEdit</Name> <Name>ICSharpCode.AvalonEdit</Name>
<Private>False</Private> <Private>False</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\Libraries\cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> <Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name> <Name>ICSharpCode.NRefactory</Name>

75
src/Main/Base/Project/Parser/DefaultAssemblySearcher.cs

@ -0,0 +1,75 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Core;
using Mono.Cecil;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
namespace ICSharpCode.SharpDevelop.Parser
{
public class DefaultAssemblySearcher : IAssemblySearcher
{
FileName mainAssemblyFileName;
DirectoryName baseDirectory;
Lazy<IDictionary<DomAssemblyName, FileName>> localAssemblies;
public DefaultAssemblySearcher(FileName mainAssemblyFileName)
{
if (mainAssemblyFileName == null)
throw new ArgumentNullException("mainAssemblyFileName");
this.mainAssemblyFileName = mainAssemblyFileName;
this.baseDirectory = mainAssemblyFileName.GetParentDirectory();
this.localAssemblies = new Lazy<IDictionary<DomAssemblyName, FileName>>(
delegate {
var list = new Dictionary<DomAssemblyName, FileName>();
var dirInfo = new DirectoryInfo(baseDirectory);
foreach (var file in dirInfo.GetFiles("*.dll").Concat(dirInfo.GetFiles("*.exe"))) {
try {
var definition = AssemblyDefinition.ReadAssembly(file.FullName);
var name = new DomAssemblyName(definition.FullName);
if (!list.ContainsKey(name))
list.Add(name, new FileName(file.FullName));
} catch (IOException ex) {
LoggingService.Warn("Ignoring error while scanning local assemblies from " + baseDirectory, ex);
} catch (UnauthorizedAccessException ex) {
LoggingService.Warn("Ignoring error while scanning local assemblies from " + baseDirectory, ex);
}
}
return list;
}
);
}
public FileName FindAssembly(DomAssemblyName fullName)
{
// look for the assembly in the current loaded assembly lists
var classBrowser = SD.GetRequiredService<IClassBrowser>();
var relevantClassBrowserAssemblies = classBrowser.AssemblyLists
.Where(l => l.Assemblies.Any(a => a.Location == mainAssemblyFileName))
.SelectMany(l => l.Assemblies);
foreach (var asm in relevantClassBrowserAssemblies) {
// TODO I am pretty sure we need the full name here as well...
if (asm.AssemblyName == fullName.ShortName)
return asm.Location;
}
// scan current directory
var files = localAssemblies.Value;
FileName file;
if (files.TryGetValue(fullName, out file))
return file;
// look in GAC
return SD.GlobalAssemblyCache.FindAssemblyInNetGac(fullName);
}
}
}

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

@ -2,11 +2,15 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser; using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
@ -21,12 +25,7 @@ namespace ICSharpCode.SharpDevelop.Parser
/// <summary> /// <summary>
/// Loads the specified assembly file from disk. /// Loads the specified assembly file from disk.
/// </summary> /// </summary>
IUnresolvedAssembly GetAssembly(FileName fileName, CancellationToken cancellationToken = default(CancellationToken)); IUnresolvedAssembly GetAssembly(FileName fileName, bool includeInternalMembers = false, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Loads the specified assembly file from disk.
/// </summary>
Task<IUnresolvedAssembly> GetAssemblyAsync(FileName fileName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary> /// <summary>
/// <code>using (AssemblyParserService.AvoidRedundantChecks())</code> /// <code>using (AssemblyParserService.AvoidRedundantChecks())</code>
@ -47,30 +46,21 @@ namespace ICSharpCode.SharpDevelop.Parser
/// <summary> /// <summary>
/// Creates a compilation for the specified assembly. /// Creates a compilation for the specified assembly.
/// </summary> /// </summary>
ICompilation CreateCompilationForAssembly(IAssemblyModel assembly); ICompilation CreateCompilationForAssembly(IAssemblyModel assembly, bool includeInternalMembers = false);
}
public interface IAssemblySearcher
{
FileName FindAssembly(DomAssemblyName fullName);
}
public class DefaultAssemblySearcher : IAssemblySearcher /// <summary>
{ /// Creates a compilation for the specified assembly.
FileName mainAssemblyFileName; /// </summary>
DirectoryName baseDirectory; ICompilation CreateCompilationForAssembly(FileName assembly, bool includeInternalMembers = false);
public DefaultAssemblySearcher(FileName mainAssemblyFileName) /// <summary>
{ /// Creates an IAssemblyModel for the given assembly file.
if (mainAssemblyFileName == null) /// </summary>
throw new ArgumentNullException("mainAssemblyFileName"); IAssemblyModel GetAssemblyModel(FileName fileName, bool includeInternalMembers = false);
this.mainAssemblyFileName = mainAssemblyFileName;
this.baseDirectory = mainAssemblyFileName.GetParentDirectory();
} }
public FileName FindAssembly(DomAssemblyName fullName) public interface IAssemblySearcher
{ {
throw new NotImplementedException(); FileName FindAssembly(DomAssemblyName fullName);
}
} }
} }

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

@ -11,11 +11,13 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Documentation; using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.SharpDevelop.Parser namespace ICSharpCode.SharpDevelop.Parser
@ -26,15 +28,21 @@ namespace ICSharpCode.SharpDevelop.Parser
sealed class AssemblyParserService : IAssemblyParserService sealed class AssemblyParserService : IAssemblyParserService
{ {
#region Get Assembly By File Name #region Get Assembly By File Name
[Serializable]
[FastSerializerVersion(1)]
sealed class LoadedAssembly sealed class LoadedAssembly
{ {
public readonly Task<IUnresolvedAssembly> ProjectContent; public readonly IUnresolvedAssembly ProjectContent;
public readonly DateTime AssemblyFileLastWriteTime; public readonly DateTime AssemblyFileLastWriteTime;
public readonly bool HasInternalMembers;
public readonly IReadOnlyList<DomAssemblyName> References;
public LoadedAssembly(Task<IUnresolvedAssembly> projectContent, DateTime assemblyFileLastWriteTime) public LoadedAssembly(IUnresolvedAssembly projectContent, DateTime assemblyFileLastWriteTime, bool hasInternalMembers, IEnumerable<DomAssemblyName> references)
{ {
this.ProjectContent = projectContent; this.ProjectContent = projectContent;
this.AssemblyFileLastWriteTime = assemblyFileLastWriteTime; this.AssemblyFileLastWriteTime = assemblyFileLastWriteTime;
this.HasInternalMembers = hasInternalMembers;
this.References = references.ToArray();
} }
} }
@ -43,26 +51,11 @@ namespace ICSharpCode.SharpDevelop.Parser
[ThreadStatic] static Dictionary<FileName, LoadedAssembly> up2dateProjectContents; [ThreadStatic] static Dictionary<FileName, LoadedAssembly> up2dateProjectContents;
public IUnresolvedAssembly GetAssembly(FileName fileName, CancellationToken cancellationToken = default(CancellationToken)) public IUnresolvedAssembly GetAssembly(FileName fileName, bool includeInternalMembers = false, CancellationToken cancellationToken = default(CancellationToken))
{ {
// We currently do not support cancelling the load operation itself, because another GetAssembly() call // We currently do not support cancelling the load operation itself, because another GetAssembly() call
// with a different cancellation token might request the same assembly. // with a different cancellation token might request the same assembly.
bool isNewTask; return GetLoadedAssembly(fileName, includeInternalMembers).ProjectContent;
LoadedAssembly asm = GetLoadedAssembly(fileName, out isNewTask);
if (isNewTask)
asm.ProjectContent.RunSynchronously();
else
asm.ProjectContent.Wait(cancellationToken);
return asm.ProjectContent.Result;
}
public Task<IUnresolvedAssembly> GetAssemblyAsync(FileName fileName, CancellationToken cancellationToken = default(CancellationToken))
{
bool isNewTask;
LoadedAssembly asm = GetLoadedAssembly(fileName, out isNewTask);
if (isNewTask)
asm.ProjectContent.Start();
return asm.ProjectContent;
} }
/// <summary> /// <summary>
@ -99,9 +92,8 @@ namespace ICSharpCode.SharpDevelop.Parser
projectContentDictionary.Remove(key); projectContentDictionary.Remove(key);
} }
LoadedAssembly GetLoadedAssembly(FileName fileName, out bool isNewTask) LoadedAssembly GetLoadedAssembly(FileName fileName, bool includeInternalMembers)
{ {
isNewTask = false;
LoadedAssembly asm; LoadedAssembly asm;
var up2dateProjectContents = AssemblyParserService.up2dateProjectContents; var up2dateProjectContents = AssemblyParserService.up2dateProjectContents;
if (up2dateProjectContents != null) { if (up2dateProjectContents != null) {
@ -112,15 +104,13 @@ namespace ICSharpCode.SharpDevelop.Parser
lock (projectContentDictionary) { lock (projectContentDictionary) {
if (projectContentDictionary.TryGetValue(fileName, out asm)) { if (projectContentDictionary.TryGetValue(fileName, out asm)) {
if (asm.AssemblyFileLastWriteTime == lastWriteTime) { if (asm.AssemblyFileLastWriteTime == lastWriteTime) {
if (!includeInternalMembers || includeInternalMembers == asm.HasInternalMembers)
return asm; return asm;
} }
} else { } else {
asm = null; asm = null;
} }
var task = new Task<IUnresolvedAssembly>(() => LoadAssembly(fileName, CancellationToken.None)); asm = LoadAssembly(fileName, CancellationToken.None, includeInternalMembers);
isNewTask = true;
asm = new LoadedAssembly(task, lastWriteTime);
if (up2dateProjectContents == null) if (up2dateProjectContents == null)
CleanWeakDictionary(); CleanWeakDictionary();
// The assembly might already be in the dictionary if we had loaded it before, // The assembly might already be in the dictionary if we had loaded it before,
@ -133,11 +123,11 @@ namespace ICSharpCode.SharpDevelop.Parser
#endregion #endregion
#region Load Assembly #region Load Assembly
IUnresolvedAssembly LoadAssembly(FileName fileName, CancellationToken cancellationToken) LoadedAssembly LoadAssembly(FileName fileName, CancellationToken cancellationToken, bool includeInternalMembers)
{ {
DateTime lastWriteTime = File.GetLastWriteTimeUtc(fileName); DateTime lastWriteTime = File.GetLastWriteTimeUtc(fileName);
string cacheFileName = GetCacheFileName(fileName); string cacheFileName = GetCacheFileName(fileName);
IUnresolvedAssembly pc = TryReadFromCache(cacheFileName, lastWriteTime); LoadedAssembly pc = TryReadFromCache(cacheFileName, lastWriteTime);
if (pc != null) if (pc != null)
return pc; return pc;
@ -148,6 +138,7 @@ namespace ICSharpCode.SharpDevelop.Parser
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(fileName, param); AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(fileName, param);
CecilLoader l = new CecilLoader(); CecilLoader l = new CecilLoader();
l.IncludeInternalMembers = includeInternalMembers;
string xmlDocFile = FindXmlDocumentation(fileName, asm.MainModule.Runtime); string xmlDocFile = FindXmlDocumentation(fileName, asm.MainModule.Runtime);
if (xmlDocFile != null) { if (xmlDocFile != null) {
try { try {
@ -161,7 +152,9 @@ namespace ICSharpCode.SharpDevelop.Parser
} }
} }
l.CancellationToken = cancellationToken; l.CancellationToken = cancellationToken;
pc = l.LoadAssembly(asm); var references = asm.MainModule.AssemblyReferences
.Select(anr => new DomAssemblyName(anr.FullName));
pc = new LoadedAssembly(l.LoadAssembly(asm), lastWriteTime, includeInternalMembers, references);
SaveToCacheAsync(cacheFileName, lastWriteTime, pc).FireAndForget(); SaveToCacheAsync(cacheFileName, lastWriteTime, pc).FireAndForget();
//SaveToCache(cacheFileName, lastWriteTime, pc); //SaveToCache(cacheFileName, lastWriteTime, pc);
return pc; return pc;
@ -244,7 +237,7 @@ namespace ICSharpCode.SharpDevelop.Parser
return cacheFileName; return cacheFileName;
} }
static IUnresolvedAssembly TryReadFromCache(string cacheFileName, DateTime lastWriteTime) static LoadedAssembly TryReadFromCache(string cacheFileName, DateTime lastWriteTime)
{ {
if (cacheFileName == null || !File.Exists(cacheFileName)) if (cacheFileName == null || !File.Exists(cacheFileName))
return null; return null;
@ -257,7 +250,7 @@ namespace ICSharpCode.SharpDevelop.Parser
return null; return null;
} }
FastSerializer s = new FastSerializer(); FastSerializer s = new FastSerializer();
return (IUnresolvedAssembly)s.Deserialize(reader); return s.Deserialize(reader) as LoadedAssembly;
} }
} }
} catch (IOException ex) { } catch (IOException ex) {
@ -272,19 +265,19 @@ namespace ICSharpCode.SharpDevelop.Parser
} }
} }
Task SaveToCacheAsync(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc) Task SaveToCacheAsync(string cacheFileName, DateTime lastWriteTime, LoadedAssembly asm)
{ {
if (cacheFileName == null) if (cacheFileName == null)
return Task.FromResult<object>(null); return Task.FromResult<object>(null);
// Call SaveToCache on a background task: // Call SaveToCache on a background task:
var shutdownService = SD.ShutdownService; var shutdownService = SD.ShutdownService;
var task = IOTaskScheduler.Factory.StartNew(delegate { SaveToCache(cacheFileName, lastWriteTime, pc); }, shutdownService.ShutdownToken); var task = IOTaskScheduler.Factory.StartNew(delegate { SaveToCache(cacheFileName, lastWriteTime, asm); }, shutdownService.ShutdownToken);
shutdownService.AddBackgroundTask(task); shutdownService.AddBackgroundTask(task);
return task; return task;
} }
void SaveToCache(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc) void SaveToCache(string cacheFileName, DateTime lastWriteTime, LoadedAssembly asm)
{ {
if (cacheFileName == null) if (cacheFileName == null)
return; return;
@ -295,7 +288,7 @@ namespace ICSharpCode.SharpDevelop.Parser
using (BinaryWriter writer = new BinaryWriterWith7BitEncodedInts(fs)) { using (BinaryWriter writer = new BinaryWriterWith7BitEncodedInts(fs)) {
writer.Write(lastWriteTime.Ticks); writer.Write(lastWriteTime.Ticks);
FastSerializer s = new FastSerializer(); FastSerializer s = new FastSerializer();
s.Serialize(writer, pc); s.Serialize(writer, asm);
} }
} }
} catch (IOException ex) { } catch (IOException ex) {
@ -309,18 +302,33 @@ namespace ICSharpCode.SharpDevelop.Parser
} }
#endregion #endregion
public ICompilation CreateCompilationForAssembly(IAssemblyModel assembly) public ICompilation CreateCompilationForAssembly(IAssemblyModel assembly, bool includeInternalMembers = false)
{ {
var mainAssembly = GetAssembly(new FileName(assembly.Context.Location)); var fileName = new FileName(assembly.Location);
var mainAssembly = GetAssembly(fileName, includeInternalMembers);
var searcher = new DefaultAssemblySearcher(fileName);
var references = assembly.References var references = assembly.References
.Select(r => FindAssembly(r, assembly)) .Select(searcher.FindAssembly)
.Where(f => f != null); .Where(f => f != null);
return new SimpleCompilation(mainAssembly, references.Select(fn => GetAssembly(fn))); return new SimpleCompilation(mainAssembly, references.Select(fn => GetAssembly(fn)));
} }
FileName FindAssembly(DomAssemblyName name, IAssemblyModel mainAssembly) public ICompilation CreateCompilationForAssembly(FileName assembly, bool includeInternalMembers = false)
{ {
throw new NotImplementedException(); return CreateCompilationForAssembly(GetAssemblyModel(assembly, includeInternalMembers), includeInternalMembers);
}
public IAssemblyModel GetAssemblyModel(FileName fileName, bool includeInternalMembers = false)
{
LoadedAssembly assembly = GetLoadedAssembly(fileName, includeInternalMembers);
IEntityModelContext context = new AssemblyEntityModelContext(assembly.ProjectContent);
IUpdateableAssemblyModel model = SD.GetService<IModelFactory>().CreateAssemblyModel(context);
model.Update(EmptyList<IUnresolvedTypeDefinition>.Instance, assembly.ProjectContent.TopLevelTypeDefinitions.ToList());
model.AssemblyName = assembly.ProjectContent.AssemblyName;
model.References = assembly.References.ToList();
return model;
} }
} }
} }

Loading…
Cancel
Save