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