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. 88
      src/Main/SharpDevelop/Parser/AssemblyParserService.cs

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

@ -160,6 +160,7 @@ @@ -160,6 +160,7 @@
<DependentUpon>ToolTipService.cs</DependentUpon>
</Compile>
<Compile Include="Editor\ToolTipService.cs" />
<Compile Include="Parser\DefaultAssemblySearcher.cs" />
<Compile Include="Parser\DomAssemblyName.cs" />
<Compile Include="Parser\IAssemblyParserService.cs" />
<Compile Include="Parser\IGlobalAssemblyCacheService.cs" />
@ -878,6 +879,10 @@ @@ -878,6 +879,10 @@
<Name>ICSharpCode.AvalonEdit</Name>
<Private>False</Private>
</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">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>

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

@ -0,0 +1,75 @@ @@ -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 @@ @@ -2,11 +2,15 @@
// 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 System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
@ -21,12 +25,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -21,12 +25,7 @@ namespace ICSharpCode.SharpDevelop.Parser
/// <summary>
/// Loads the specified assembly file from disk.
/// </summary>
IUnresolvedAssembly GetAssembly(FileName fileName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Loads the specified assembly file from disk.
/// </summary>
Task<IUnresolvedAssembly> GetAssemblyAsync(FileName fileName, CancellationToken cancellationToken = default(CancellationToken));
IUnresolvedAssembly GetAssembly(FileName fileName, bool includeInternalMembers = false, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// <code>using (AssemblyParserService.AvoidRedundantChecks())</code>
@ -47,30 +46,21 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -47,30 +46,21 @@ namespace ICSharpCode.SharpDevelop.Parser
/// <summary>
/// Creates a compilation for the specified assembly.
/// </summary>
ICompilation CreateCompilationForAssembly(IAssemblyModel assembly);
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>
IAssemblyModel GetAssemblyModel(FileName fileName, bool includeInternalMembers = false);
}
public interface IAssemblySearcher
{
FileName FindAssembly(DomAssemblyName fullName);
}
public class DefaultAssemblySearcher : IAssemblySearcher
{
FileName mainAssemblyFileName;
DirectoryName baseDirectory;
public DefaultAssemblySearcher(FileName mainAssemblyFileName)
{
if (mainAssemblyFileName == null)
throw new ArgumentNullException("mainAssemblyFileName");
this.mainAssemblyFileName = mainAssemblyFileName;
this.baseDirectory = mainAssemblyFileName.GetParentDirectory();
}
public FileName FindAssembly(DomAssemblyName fullName)
{
throw new NotImplementedException();
}
}
}

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

@ -11,11 +11,13 @@ using System.Threading; @@ -11,11 +11,13 @@ using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
using Mono.Cecil;
namespace ICSharpCode.SharpDevelop.Parser
@ -26,15 +28,21 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -26,15 +28,21 @@ namespace ICSharpCode.SharpDevelop.Parser
sealed class AssemblyParserService : IAssemblyParserService
{
#region Get Assembly By File Name
[Serializable]
[FastSerializerVersion(1)]
sealed class LoadedAssembly
{
public readonly Task<IUnresolvedAssembly> ProjectContent;
public readonly IUnresolvedAssembly ProjectContent;
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.AssemblyFileLastWriteTime = assemblyFileLastWriteTime;
this.HasInternalMembers = hasInternalMembers;
this.References = references.ToArray();
}
}
@ -43,26 +51,11 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -43,26 +51,11 @@ namespace ICSharpCode.SharpDevelop.Parser
[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
// with a different cancellation token might request the same assembly.
bool isNewTask;
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;
return GetLoadedAssembly(fileName, includeInternalMembers).ProjectContent;
}
/// <summary>
@ -99,9 +92,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -99,9 +92,8 @@ namespace ICSharpCode.SharpDevelop.Parser
projectContentDictionary.Remove(key);
}
LoadedAssembly GetLoadedAssembly(FileName fileName, out bool isNewTask)
LoadedAssembly GetLoadedAssembly(FileName fileName, bool includeInternalMembers)
{
isNewTask = false;
LoadedAssembly asm;
var up2dateProjectContents = AssemblyParserService.up2dateProjectContents;
if (up2dateProjectContents != null) {
@ -112,15 +104,13 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -112,15 +104,13 @@ namespace ICSharpCode.SharpDevelop.Parser
lock (projectContentDictionary) {
if (projectContentDictionary.TryGetValue(fileName, out asm)) {
if (asm.AssemblyFileLastWriteTime == lastWriteTime) {
return asm;
if (!includeInternalMembers || includeInternalMembers == asm.HasInternalMembers)
return asm;
}
} else {
asm = null;
}
var task = new Task<IUnresolvedAssembly>(() => LoadAssembly(fileName, CancellationToken.None));
isNewTask = true;
asm = new LoadedAssembly(task, lastWriteTime);
asm = LoadAssembly(fileName, CancellationToken.None, includeInternalMembers);
if (up2dateProjectContents == null)
CleanWeakDictionary();
// The assembly might already be in the dictionary if we had loaded it before,
@ -133,11 +123,11 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -133,11 +123,11 @@ namespace ICSharpCode.SharpDevelop.Parser
#endregion
#region Load Assembly
IUnresolvedAssembly LoadAssembly(FileName fileName, CancellationToken cancellationToken)
LoadedAssembly LoadAssembly(FileName fileName, CancellationToken cancellationToken, bool includeInternalMembers)
{
DateTime lastWriteTime = File.GetLastWriteTimeUtc(fileName);
string cacheFileName = GetCacheFileName(fileName);
IUnresolvedAssembly pc = TryReadFromCache(cacheFileName, lastWriteTime);
LoadedAssembly pc = TryReadFromCache(cacheFileName, lastWriteTime);
if (pc != null)
return pc;
@ -148,6 +138,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -148,6 +138,7 @@ namespace ICSharpCode.SharpDevelop.Parser
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(fileName, param);
CecilLoader l = new CecilLoader();
l.IncludeInternalMembers = includeInternalMembers;
string xmlDocFile = FindXmlDocumentation(fileName, asm.MainModule.Runtime);
if (xmlDocFile != null) {
try {
@ -161,7 +152,9 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -161,7 +152,9 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
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();
//SaveToCache(cacheFileName, lastWriteTime, pc);
return pc;
@ -244,7 +237,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -244,7 +237,7 @@ namespace ICSharpCode.SharpDevelop.Parser
return cacheFileName;
}
static IUnresolvedAssembly TryReadFromCache(string cacheFileName, DateTime lastWriteTime)
static LoadedAssembly TryReadFromCache(string cacheFileName, DateTime lastWriteTime)
{
if (cacheFileName == null || !File.Exists(cacheFileName))
return null;
@ -257,7 +250,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -257,7 +250,7 @@ namespace ICSharpCode.SharpDevelop.Parser
return null;
}
FastSerializer s = new FastSerializer();
return (IUnresolvedAssembly)s.Deserialize(reader);
return s.Deserialize(reader) as LoadedAssembly;
}
}
} catch (IOException ex) {
@ -272,19 +265,19 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -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)
return Task.FromResult<object>(null);
// Call SaveToCache on a background task:
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);
return task;
}
void SaveToCache(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc)
void SaveToCache(string cacheFileName, DateTime lastWriteTime, LoadedAssembly asm)
{
if (cacheFileName == null)
return;
@ -295,7 +288,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -295,7 +288,7 @@ namespace ICSharpCode.SharpDevelop.Parser
using (BinaryWriter writer = new BinaryWriterWith7BitEncodedInts(fs)) {
writer.Write(lastWriteTime.Ticks);
FastSerializer s = new FastSerializer();
s.Serialize(writer, pc);
s.Serialize(writer, asm);
}
}
} catch (IOException ex) {
@ -309,18 +302,33 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -309,18 +302,33 @@ namespace ICSharpCode.SharpDevelop.Parser
}
#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
.Select(r => FindAssembly(r, assembly))
.Select(searcher.FindAssembly)
.Where(f => f != null);
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