diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
index 78ac881be1..cdb63cb3f9 100644
--- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
+++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
@@ -160,6 +160,7 @@
ToolTipService.cs
+
@@ -878,6 +879,10 @@
ICSharpCode.AvalonEdit
False
+
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}
+ Mono.Cecil
+
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}
ICSharpCode.NRefactory
diff --git a/src/Main/Base/Project/Parser/DefaultAssemblySearcher.cs b/src/Main/Base/Project/Parser/DefaultAssemblySearcher.cs
new file mode 100644
index 0000000000..e0b17ffae8
--- /dev/null
+++ b/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> localAssemblies;
+
+ public DefaultAssemblySearcher(FileName mainAssemblyFileName)
+ {
+ if (mainAssemblyFileName == null)
+ throw new ArgumentNullException("mainAssemblyFileName");
+ this.mainAssemblyFileName = mainAssemblyFileName;
+ this.baseDirectory = mainAssemblyFileName.GetParentDirectory();
+ this.localAssemblies = new Lazy>(
+ delegate {
+ var list = new Dictionary();
+ 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();
+ 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);
+ }
+ }
+}
+
+
diff --git a/src/Main/Base/Project/Parser/IAssemblyParserService.cs b/src/Main/Base/Project/Parser/IAssemblyParserService.cs
index 8982d3ecc5..9562056fed 100644
--- a/src/Main/Base/Project/Parser/IAssemblyParserService.cs
+++ b/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)
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
///
/// Loads the specified assembly file from disk.
///
- IUnresolvedAssembly GetAssembly(FileName fileName, CancellationToken cancellationToken = default(CancellationToken));
-
- ///
- /// Loads the specified assembly file from disk.
- ///
- Task GetAssemblyAsync(FileName fileName, CancellationToken cancellationToken = default(CancellationToken));
+ IUnresolvedAssembly GetAssembly(FileName fileName, bool includeInternalMembers = false, CancellationToken cancellationToken = default(CancellationToken));
///
/// using (AssemblyParserService.AvoidRedundantChecks())
@@ -47,30 +46,21 @@ namespace ICSharpCode.SharpDevelop.Parser
///
/// Creates a compilation for the specified assembly.
///
- ICompilation CreateCompilationForAssembly(IAssemblyModel assembly);
+ ICompilation CreateCompilationForAssembly(IAssemblyModel assembly, bool includeInternalMembers = false);
+
+ ///
+ /// Creates a compilation for the specified assembly.
+ ///
+ ICompilation CreateCompilationForAssembly(FileName assembly, bool includeInternalMembers = false);
+
+ ///
+ /// Creates an IAssemblyModel for the given assembly file.
+ ///
+ 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();
- }
- }
}
diff --git a/src/Main/SharpDevelop/Parser/AssemblyParserService.cs b/src/Main/SharpDevelop/Parser/AssemblyParserService.cs
index 1797c43253..4690909f61 100644
--- a/src/Main/SharpDevelop/Parser/AssemblyParserService.cs
+++ b/src/Main/SharpDevelop/Parser/AssemblyParserService.cs
@@ -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
sealed class AssemblyParserService : IAssemblyParserService
{
#region Get Assembly By File Name
+ [Serializable]
+ [FastSerializerVersion(1)]
sealed class LoadedAssembly
{
- public readonly Task ProjectContent;
+ public readonly IUnresolvedAssembly ProjectContent;
public readonly DateTime AssemblyFileLastWriteTime;
+ public readonly bool HasInternalMembers;
+ public readonly IReadOnlyList References;
- public LoadedAssembly(Task projectContent, DateTime assemblyFileLastWriteTime)
+ public LoadedAssembly(IUnresolvedAssembly projectContent, DateTime assemblyFileLastWriteTime, bool hasInternalMembers, IEnumerable references)
{
this.ProjectContent = projectContent;
this.AssemblyFileLastWriteTime = assemblyFileLastWriteTime;
+ this.HasInternalMembers = hasInternalMembers;
+ this.References = references.ToArray();
}
}
@@ -43,26 +51,11 @@ namespace ICSharpCode.SharpDevelop.Parser
[ThreadStatic] static Dictionary 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 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;
}
///
@@ -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
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(() => 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
#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
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
}
}
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
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
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
}
}
- Task SaveToCacheAsync(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc)
+ Task SaveToCacheAsync(string cacheFileName, DateTime lastWriteTime, LoadedAssembly asm)
{
if (cacheFileName == null)
return Task.FromResult