diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 3f2c0f2926..fed8fc3592 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -706,6 +706,8 @@ + + diff --git a/src/Main/Base/Project/Src/Dom/IAttribute.cs b/src/Main/Base/Project/Src/Dom/IAttribute.cs index 6f106b984a..a639a1ffce 100644 --- a/src/Main/Base/Project/Src/Dom/IAttribute.cs +++ b/src/Main/Base/Project/Src/Dom/IAttribute.cs @@ -20,6 +20,8 @@ namespace ICSharpCode.SharpDevelop.Dom get; } + /* + * These properties are not stored in DomPersistence and cannot not be used! List PositionalArguments { get; } @@ -27,6 +29,7 @@ namespace ICSharpCode.SharpDevelop.Dom SortedList NamedArguments { get; } + */ } public enum AttributeTarget diff --git a/src/Main/Base/Project/Src/Dom/IProperty.cs b/src/Main/Base/Project/Src/Dom/IProperty.cs index 031bfcfdc1..ab65599c74 100644 --- a/src/Main/Base/Project/Src/Dom/IProperty.cs +++ b/src/Main/Base/Project/Src/Dom/IProperty.cs @@ -32,13 +32,5 @@ namespace ICSharpCode.SharpDevelop.Dom bool IsIndexer { get; } - - IMethod GetterMethod { - get; - } - - IMethod SetterMethod { - get; - } } } diff --git a/src/Main/Base/Project/Src/Dom/Implementations/ConstructedReturnType.cs b/src/Main/Base/Project/Src/Dom/Implementations/ConstructedReturnType.cs index 5a92faf24e..412d8887ea 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/ConstructedReturnType.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/ConstructedReturnType.cs @@ -24,16 +24,16 @@ namespace ICSharpCode.SharpDevelop.Dom // Return types that should be substituted for the generic types // If a substitution is unknown (type could not be resolved), the list // contains a null entry. - List typeParameters; + IList typeParameters; IReturnType baseType; - public List TypeArguments { + public IList TypeArguments { get { return typeParameters; } } - public ConstructedReturnType(IReturnType baseType, List typeParameters) + public ConstructedReturnType(IReturnType baseType, IList typeParameters) { if (baseType == null) throw new ArgumentNullException("baseType"); diff --git a/src/Main/Base/Project/Src/Dom/Implementations/DefaultAttribute.cs b/src/Main/Base/Project/Src/Dom/Implementations/DefaultAttribute.cs index fe5d5424b8..c75555f44b 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/DefaultAttribute.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/DefaultAttribute.cs @@ -67,14 +67,7 @@ namespace ICSharpCode.SharpDevelop.Dom } public virtual int CompareTo(IAttribute value) { - int cmp; - - cmp = Name.CompareTo(value.Name); - if (cmp != 0) { - return cmp; - } - - return DiffUtility.Compare(PositionalArguments, value.PositionalArguments); + return Name.CompareTo(value.Name); } int IComparable.CompareTo(object value) { diff --git a/src/Main/Base/Project/Src/Dom/Implementations/DefaultEvent.cs b/src/Main/Base/Project/Src/Dom/Implementations/DefaultEvent.cs index f3964911ce..8ee33808d6 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/DefaultEvent.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/DefaultEvent.cs @@ -13,11 +13,10 @@ namespace ICSharpCode.SharpDevelop.Dom [Serializable] public class DefaultEvent : AbstractMember, IEvent { - protected DomRegion bodyRegion; - protected EventAttributes eventAttributes; - protected IMethod addMethod; - protected IMethod removeMethod; - protected IMethod raiseMethod; + protected DomRegion bodyRegion; + protected IMethod addMethod; + protected IMethod removeMethod; + protected IMethod raiseMethod; public override string DocumentationTag { get { @@ -30,19 +29,13 @@ namespace ICSharpCode.SharpDevelop.Dom return bodyRegion; } } - - public virtual EventAttributes EventAttributes { - get { - return eventAttributes; - } - } public override IMember Clone() { return new DefaultEvent(Name, ReturnType, Modifiers, Region, BodyRegion, DeclaringType); } - protected DefaultEvent(IClass declaringType, string name) : base(declaringType, name) + public DefaultEvent(IClass declaringType, string name) : base(declaringType, name) { } @@ -93,6 +86,5 @@ namespace ICSharpCode.SharpDevelop.Dom return raiseMethod; } } - } } diff --git a/src/Main/Base/Project/Src/Dom/Implementations/DefaultProperty.cs b/src/Main/Base/Project/Src/Dom/Implementations/DefaultProperty.cs index 55d2612c9e..e1f993b0cc 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/DefaultProperty.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/DefaultProperty.cs @@ -14,23 +14,29 @@ namespace ICSharpCode.SharpDevelop.Dom { [Serializable] public class DefaultProperty : AbstractMember, IProperty { - protected DomRegion bodyRegion = DomRegion.Empty; - + DomRegion bodyRegion = DomRegion.Empty; DomRegion getterRegion = DomRegion.Empty; DomRegion setterRegion = DomRegion.Empty; - - protected IMethod getterMethod; - protected IMethod setterMethod; + List parameters = null; - bool isIndexer; - + internal byte accessFlags; + const byte indexerFlag = 1; + const byte getterFlag = 2; + const byte setterFlag = 4; + public bool IsIndexer { - get { - return isIndexer; - } - set { - isIndexer = value; - } + get { return (accessFlags & indexerFlag) == indexerFlag; } + set { if (value) accessFlags |= indexerFlag; else accessFlags &= 255-indexerFlag; } + } + + public bool CanGet { + get { return (accessFlags & getterFlag) == getterFlag; } + set { if (value) accessFlags |= getterFlag; else accessFlags &= 255-getterFlag; } + } + + public bool CanSet { + get { return (accessFlags & setterFlag) == setterFlag; } + set { if (value) accessFlags |= setterFlag; else accessFlags &= 255-setterFlag; } } public override string DocumentationTag { @@ -49,7 +55,7 @@ namespace ICSharpCode.SharpDevelop.Dom { { DefaultProperty p = new DefaultProperty(Name, ReturnType, Modifiers, Region, BodyRegion, DeclaringType); p.parameters = DefaultParameter.Clone(this.Parameters); - p.isIndexer = this.isIndexer; + p.accessFlags = this.accessFlags; return p; } @@ -82,30 +88,6 @@ namespace ICSharpCode.SharpDevelop.Dom { setterRegion = value; } } - - public IMethod GetterMethod { - get { - return getterMethod; - } - } - - public IMethod SetterMethod { - get { - return setterMethod; - } - } - - public virtual bool CanGet { - get { - return !getterRegion.IsEmpty; - } - } - - public virtual bool CanSet { - get { - return !setterRegion.IsEmpty; - } - } public DefaultProperty(IClass declaringType, string name) : base(declaringType, name) { diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/DomPersistence.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/DomPersistence.cs new file mode 100644 index 0000000000..1e2971479d --- /dev/null +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/DomPersistence.cs @@ -0,0 +1,667 @@ +/* + * Created by SharpDevelop. + * User: Daniel Grunwald + * Date: 28.09.2005 + * Time: 19:52 + */ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.IO; +using ICSharpCode.Core; + +namespace ICSharpCode.SharpDevelop.Dom +{ + /// + /// This class can write Dom entity into a binary file for fast loading. + /// + public static class DomPersistence + { + public const long FileMagic = 0x11635233ED2F428C; + public const long IndexFileMagic = 0x11635233ED2F427D; + public const short FileVersion = 1; + + #region Cache management + #if DEBUG + const string tempPathName = "SharpDevelop/DomCacheDebug"; + #else + const string tempPathName = "SharpDevelop/DomCache"; + #endif + + static string MakeTempPath() + { + string tempPath = Path.Combine(Path.GetTempPath(), tempPathName); + if (!Directory.Exists(tempPath)) + Directory.CreateDirectory(tempPath); + return tempPath; + } + + public static string SaveProjectContent(ReflectionProjectContent pc) + { + string assemblyFullName = pc.AssemblyFullName; + int pos = assemblyFullName.IndexOf(','); + string fileName = Path.Combine(MakeTempPath(), + assemblyFullName.Substring(0, pos) + + "." + assemblyFullName.GetHashCode().ToString("x", CultureInfo.InvariantCulture) + + "." + pc.AssemblyLocation.GetHashCode().ToString("x", CultureInfo.InvariantCulture) + + ".dat"); + AddFileNameToCacheIndex(Path.GetFileName(fileName), pc); + using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) { + using (BinaryWriter writer = new BinaryWriter(fs)) { + new ReadWriteHelper(writer).WriteProjectContent(pc); + } + } + return fileName; + } + + public static ReflectionProjectContent LoadProjectContentByAssemblyName(string assemblyName) + { + string cacheFileName; + if (CacheIndex.TryGetValue(assemblyName, out cacheFileName)) { + return LoadProjectContent(Path.Combine(MakeTempPath(), cacheFileName)); + } else { + return null; + } + } + + public static ReflectionProjectContent LoadProjectContent(string cacheFileName) + { + ReflectionProjectContent pc; + using (FileStream fs = new FileStream(cacheFileName, FileMode.Open, FileAccess.Read)) { + using (BinaryReader reader = new BinaryReader(fs)) { + pc = new ReadWriteHelper(reader).ReadProjectContent(); + } + } + pc.InitializeSpecialClasses(); + return pc; + } + #endregion + + #region Cache index + static string GetIndexFileName() { return Path.Combine(MakeTempPath(), "index.dat"); } + + static Dictionary cacheIndex; + + static Dictionary CacheIndex { + get { + if (cacheIndex == null) { + cacheIndex = LoadCacheIndex(); + } + return cacheIndex; + } + } + + static Dictionary LoadCacheIndex() + { + string indexFile = GetIndexFileName(); + Dictionary list = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + if (File.Exists(indexFile)) { + using (FileStream fs = new FileStream(indexFile, FileMode.Open, FileAccess.Read)) { + using (BinaryReader reader = new BinaryReader(fs)) { + if (reader.ReadInt64() != IndexFileMagic) { + LoggingService.Warn("Index cache has wrong file magic"); + return list; + } + if (reader.ReadInt16() != FileVersion) { + LoggingService.Warn("Index cache has wrong file version"); + return list; + } + int count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + string key = reader.ReadString(); + list[key] = reader.ReadString(); + } + return list; + } + } + } else { + return list; + } + } + + static void SaveCacheIndex(Dictionary cacheIndex) + { + string indexFile = GetIndexFileName(); + using (FileStream fs = new FileStream(indexFile, FileMode.Create, FileAccess.Write)) { + using (BinaryWriter writer = new BinaryWriter(fs)) { + writer.Write(IndexFileMagic); + writer.Write(FileVersion); + writer.Write(cacheIndex.Count); + foreach (KeyValuePair e in cacheIndex) { + writer.Write(e.Key); + writer.Write(e.Value); + } + } + } + } + + static void AddFileNameToCacheIndex(string cacheFile, ReflectionProjectContent pc) + { + Dictionary l = LoadCacheIndex(); + l[pc.AssemblyLocation] = cacheFile; + string txt = pc.AssemblyFullName; + l[txt] = cacheFile; + int pos = txt.LastIndexOf(','); + do { + txt = txt.Substring(0, pos); + if (l.ContainsKey(txt)) + break; + l[txt] = cacheFile; + pos = txt.LastIndexOf(','); + } while (pos >= 0); + SaveCacheIndex(l); + cacheIndex = l; + } + #endregion + + private sealed class ReadWriteHelper + { + ReflectionProjectContent pc; + + readonly BinaryWriter writer; + readonly Dictionary classIndices = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + + readonly BinaryReader reader; + IReturnType[] types; + + #region Write/Read ProjectContent + public ReadWriteHelper(BinaryWriter writer) + { + this.writer = writer; + } + + public void WriteProjectContent(ReflectionProjectContent pc) + { + this.pc = pc; + writer.Write(FileMagic); + writer.Write(FileVersion); + writer.Write(pc.AssemblyFullName); + writer.Write(pc.AssemblyLocation); + writer.Write(pc.ReferencedAssemblies.Length); + foreach (AssemblyName name in pc.ReferencedAssemblies) { + writer.Write(name.FullName); + } + WriteClasses(); + } + + public ReadWriteHelper(BinaryReader reader) + { + this.reader = reader; + } + + public ReflectionProjectContent ReadProjectContent() + { + if (reader.ReadInt64() != FileMagic) { + LoggingService.Warn("Read dom: wrong magic"); + return null; + } + if (reader.ReadInt16() != FileVersion) { + LoggingService.Warn("Read dom: wrong version"); + return null; + } + string assemblyName = reader.ReadString(); + string assemblyLocation = reader.ReadString(); + AssemblyName[] referencedAssemblies = new AssemblyName[reader.ReadInt32()]; + for (int i = 0; i < referencedAssemblies.Length; i++) { + referencedAssemblies[i] = new AssemblyName(reader.ReadString()); + } + this.pc = new ReflectionProjectContent(assemblyName, assemblyLocation, referencedAssemblies); + ReadClasses(); + return pc; + } + + void WriteClasses() + { + ICollection classes = pc.Classes; + + classIndices.Clear(); + int i = 0; + foreach (IClass c in classes) { + classIndices[c.FullyQualifiedName] = i; + i += 1; + } + + List externalTypes = new List(); + CreateExternalTypeList(externalTypes, classes.Count, classes); + + writer.Write(classes.Count); + writer.Write(externalTypes.Count); + foreach (IClass c in classes) { + writer.Write(c.FullyQualifiedName); + } + foreach (string type in externalTypes) { + writer.Write(type); + } + foreach (IClass c in classes) { + WriteClass(c); + } + } + + void ReadClasses() + { + int classCount = reader.ReadInt32(); + int externalTypeCount = reader.ReadInt32(); + types = new IReturnType[classCount + externalTypeCount]; + DefaultClass[] classes = new DefaultClass[classCount]; + for (int i = 0; i < classes.Length; i++) { + DefaultClass c = new DefaultClass(pc.AssemblyCompilationUnit, reader.ReadString()); + classes[i] = c; + types[i] = c.DefaultReturnType; + } + for (int i = classCount; i < types.Length; i++) { + types[i] = new GetClassReturnType(pc, reader.ReadString()); + } + for (int i = 0; i < classes.Length; i++) { + ReadClass(classes[i]); + pc.AddClassToNamespaceList(classes[i]); + } + } + #endregion + + #region Write/Read Class + IClass currentClass; + + void WriteClass(IClass c) + { + this.currentClass = c; + WriteTemplates(c.TypeParameters); + writer.Write(c.BaseTypes.Count); + foreach (IReturnType type in c.BaseTypes) { + WriteType(type); + } + writer.Write((int)c.Modifiers); + WriteAttributes(c.Attributes); + writer.Write(c.InnerClasses.Count); + foreach (IClass innerClass in c.InnerClasses) { + WriteString(innerClass.FullyQualifiedName); + WriteClass(innerClass); + } + this.currentClass = c; + writer.Write(c.Methods.Count); + foreach (IMethod method in c.Methods) { + WriteMethod(method); + } + writer.Write(c.Properties.Count); + foreach (IProperty property in c.Properties) { + WriteProperty(property); + } + writer.Write(c.Events.Count); + foreach (IEvent evt in c.Events) { + WriteEvent(evt); + } + writer.Write(c.Fields.Count); + foreach (IField field in c.Fields) { + WriteField(field); + } + this.currentClass = null; + } + + void WriteTemplates(List list) + { + // read code exists twice: in ReadClass and ReadMethod + writer.Write((byte)list.Count); + foreach (ITypeParameter typeParameter in list) { + WriteString(typeParameter.Name); + } + foreach (ITypeParameter typeParameter in list) { + writer.Write(typeParameter.Constraints.Count); + foreach (IReturnType type in typeParameter.Constraints) { + WriteType(type); + } + } + } + + void ReadClass(DefaultClass c) + { + this.currentClass = c; + int count; + count = reader.ReadByte(); + for (int i = 0; i < count; i++) { + c.TypeParameters.Add(new DefaultTypeParameter(c, ReadString(), i)); + } + foreach (ITypeParameter typeParameter in c.TypeParameters) { + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + typeParameter.Constraints.Add(ReadType()); + } + } + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + c.BaseTypes.Add(ReadType()); + } + c.Modifiers = (ModifierEnum)reader.ReadInt32(); + ReadAttributes(c.Attributes); + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + DefaultClass innerClass = new DefaultClass(c.CompilationUnit, c); + innerClass.FullyQualifiedName = ReadString(); + c.InnerClasses.Add(innerClass); + ReadClass(innerClass); + } + this.currentClass = c; + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + c.Methods.Add(ReadMethod()); + } + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + c.Properties.Add(ReadProperty()); + } + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + c.Events.Add(ReadEvent()); + } + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + c.Fields.Add(ReadField()); + } + this.currentClass = null; + } + #endregion + + #region Write/Read return types + /// + /// Finds all return types used in the class collection and adds the unknown ones + /// to the externalTypeIndices and externalTypes collections. + /// + void CreateExternalTypeList(List externalTypes, + int classCount, ICollection classes) + { + foreach (IClass c in classes) { + CreateExternalTypeList(externalTypes, classCount, c.InnerClasses); + foreach (IReturnType returnType in c.BaseTypes) { + AddExternalType(returnType, externalTypes, classCount); + } + foreach (ITypeParameter tp in c.TypeParameters) { + foreach (IReturnType returnType in tp.Constraints) { + AddExternalType(returnType, externalTypes, classCount); + } + } + foreach (IField f in c.Fields) { + AddExternalType(f.ReturnType, externalTypes, classCount); + } + foreach (IEvent f in c.Events) { + AddExternalType(f.ReturnType, externalTypes, classCount); + } + foreach (IProperty p in c.Properties) { + AddExternalType(p.ReturnType, externalTypes, classCount); + foreach (IParameter parameter in p.Parameters) { + AddExternalType(parameter.ReturnType, externalTypes, classCount); + } + } + foreach (IMethod m in c.Methods) { + AddExternalType(m.ReturnType, externalTypes, classCount); + foreach (IParameter parameter in m.Parameters) { + AddExternalType(parameter.ReturnType, externalTypes, classCount); + } + foreach (ITypeParameter tp in m.TypeParameters) { + foreach (IReturnType returnType in tp.Constraints) { + AddExternalType(returnType, externalTypes, classCount); + } + } + } + } + } + + void AddExternalType(IReturnType rt, List externalTypes, int classCount) + { + if (rt.IsDefaultReturnType) { + string name = rt.FullyQualifiedName; + if (!classIndices.ContainsKey(name)) { + classIndices.Add(name, externalTypes.Count + classCount); + externalTypes.Add(name); + } + } else if (rt is ArrayReturnType) { + AddExternalType(((ArrayReturnType)rt).ElementType, externalTypes, classCount); + } else if (rt is ConstructedReturnType) { + ConstructedReturnType crt = (ConstructedReturnType)rt; + AddExternalType(crt.BaseType, externalTypes, classCount); + foreach (IReturnType typeArgument in crt.TypeArguments) { + AddExternalType(typeArgument, externalTypes, classCount); + } + } else if (rt is GenericReturnType) { + // ignore + } else { + LoggingService.Warn("Unknown return type: " + rt.ToString()); + } + } + + const int ArrayRTCode = -1; + const int ConstructedRTCode = -2; + const int TypeGenericRTCode = -3; + const int MethodGenericRTCode = -4; + const int NullRTReferenceCode = -5; + const int VoidRTCode = -6; + + void WriteType(IReturnType rt) + { + if (rt == null) { + writer.Write(NullRTReferenceCode); + return; + } + if (rt.IsDefaultReturnType) { + string name = rt.FullyQualifiedName; + if (name == "System.Void") { + writer.Write(VoidRTCode); + } else { + writer.Write(classIndices[rt.FullyQualifiedName]); + } + } else if (rt is ArrayReturnType) { + ArrayReturnType art = (ArrayReturnType)rt; + writer.Write(ArrayRTCode); + writer.Write(art.ArrayDimensions); + WriteType(art.ElementType); + } else if (rt is ConstructedReturnType) { + ConstructedReturnType crt = (ConstructedReturnType)rt; + writer.Write(ConstructedRTCode); + WriteType(crt.BaseType); + writer.Write((byte)crt.TypeArguments.Count); + foreach (IReturnType typeArgument in crt.TypeArguments) { + WriteType(typeArgument); + } + } else if (rt is GenericReturnType) { + GenericReturnType grt = (GenericReturnType)rt; + if (grt.TypeParameter.Method != null) { + writer.Write(MethodGenericRTCode); + } else { + writer.Write(TypeGenericRTCode); + } + writer.Write(grt.TypeParameter.Index); + } else { + writer.Write(NullRTReferenceCode); + LoggingService.Warn("Unknown return type: " + rt.ToString()); + } + } + + // outerClass and outerMethod are required for generic return types + IReturnType ReadType() + { + int index = reader.ReadInt32(); + switch (index) { + case ArrayRTCode: + int dimensions = reader.ReadInt32(); + return new ArrayReturnType(ReadType(), dimensions); + case ConstructedRTCode: + IReturnType baseType = ReadType(); + IReturnType[] typeArguments = new IReturnType[reader.ReadByte()]; + for (int i = 0; i < typeArguments.Length; i++) { + typeArguments[i] = ReadType(); + } + return new ConstructedReturnType(baseType, typeArguments); + case TypeGenericRTCode: + return new GenericReturnType(currentClass.TypeParameters[reader.ReadInt32()]); + case MethodGenericRTCode: + return new GenericReturnType(currentMethod.TypeParameters[reader.ReadInt32()]); + case NullRTReferenceCode: + return null; + case VoidRTCode: + return ReflectionReturnType.Void; + default: + return types[index]; + } + } + #endregion + + #region Write/Read class member + void WriteString(string text) + { + writer.Write(text ?? string.Empty); + } + + string ReadString() + { + return reader.ReadString(); + } + + void WriteMember(IMember m) + { + WriteString(m.Name); + writer.Write((int)m.Modifiers); + WriteAttributes(m.Attributes); + if (!(m is IMethod)) { + // method must store ReturnType AFTER Template definitions + WriteType(m.ReturnType); + } + } + + void ReadMember(IMember m) + { + // name is already read by the method that calls the member constructor + m.Modifiers = (ModifierEnum)reader.ReadInt32(); + ReadAttributes(m.Attributes); + if (!(m is IMethod)) { + m.ReturnType = ReadType(); + } + } + #endregion + + #region Write/Read attributes + void WriteAttributes(IList attributes) + { + writer.Write((ushort)attributes.Count); + foreach (IAttribute a in attributes) { + WriteString(a.Name); + writer.Write((byte)a.AttributeTarget); + } + } + + void ReadAttributes(IList attributes) + { + int count = reader.ReadUInt16(); + for (int i = 0; i < count; i++) { + string name = ReadString(); + attributes.Add(new DefaultAttribute(name, (AttributeTarget)reader.ReadByte())); + } + } + #endregion + + #region Write/Read parameters + void WriteParameters(IList parameters) + { + writer.Write((ushort)parameters.Count); + foreach (IParameter p in parameters) { + WriteString(p.Name); + WriteType(p.ReturnType); + writer.Write((byte)p.Modifiers); + WriteAttributes(p.Attributes); + } + } + + void ReadParameters(IList parameters) + { + int count = reader.ReadUInt16(); + for (int i = 0; i < count; i++) { + string name = ReadString(); + DefaultParameter p = new DefaultParameter(name, ReadType(), DomRegion.Empty); + p.Modifiers = (ParameterModifiers)reader.ReadByte(); + ReadAttributes(p.Attributes); + parameters.Add(p); + } + } + #endregion + + #region Write/Read Method + IMethod currentMethod; + + void WriteMethod(IMethod m) + { + currentMethod = m; + WriteMember(m); + WriteTemplates(m.TypeParameters); + WriteType(m.ReturnType); + WriteParameters(m.Parameters); + currentMethod = null; + } + + IMethod ReadMethod() + { + DefaultMethod m = new DefaultMethod(currentClass, ReadString()); + currentMethod = m; + ReadMember(m); + int count = reader.ReadByte(); + for (int i = 0; i < count; i++) { + m.TypeParameters.Add(new DefaultTypeParameter(m, ReadString(), i)); + } + foreach (ITypeParameter typeParameter in m.TypeParameters) { + count = reader.ReadInt32(); + for (int i = 0; i < count; i++) { + typeParameter.Constraints.Add(ReadType()); + } + } + m.ReturnType = ReadType(); + ReadParameters(m.Parameters); + currentMethod = null; + return m; + } + #endregion + + #region Write/Read Property + void WriteProperty(IProperty p) + { + WriteMember(p); + writer.Write(((DefaultProperty)p).accessFlags); + WriteParameters(p.Parameters); + } + + IProperty ReadProperty() + { + DefaultProperty p = new DefaultProperty(currentClass, ReadString()); + ReadMember(p); + p.accessFlags = reader.ReadByte(); + ReadParameters(p.Parameters); + return p; + } + #endregion + + #region Write/Read Event + void WriteEvent(IEvent p) + { + WriteMember(p); + } + + IEvent ReadEvent() + { + DefaultEvent p = new DefaultEvent(currentClass, ReadString()); + ReadMember(p); + return p; + } + #endregion + + #region Write/Read Field + void WriteField(IField p) + { + WriteMember(p); + } + + IField ReadField() + { + DefaultField p = new DefaultField(currentClass, ReadString()); + ReadMember(p); + return p; + } + #endregion + } + } +} diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionClass.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionClass.cs index cce9d7d76d..7e093a6695 100644 --- a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionClass.cs +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionClass.cs @@ -16,146 +16,54 @@ namespace ICSharpCode.SharpDevelop.Dom [Serializable] public class ReflectionClass : DefaultClass { - Type type; - const BindingFlags flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Public; - List innerClasses; - - public override List InnerClasses { - get { - if (innerClasses == null) { - innerClasses = new List(); - foreach (Type nestedType in type.GetNestedTypes(flags)) { - string name = nestedType.FullName.Replace('+', '.'); - innerClasses.Add(new ReflectionClass(CompilationUnit, nestedType, name, this)); - } - } - return innerClasses; - } - } - - static Dictionary> fieldCache = new Dictionary>(); - static Dictionary> propertyCache = new Dictionary>(); - static Dictionary> methodCache = new Dictionary>(); - static Dictionary> eventCache = new Dictionary>(); - - public static void ClearMemberCache() + void InitMembers(Type type) { - fieldCache.Clear(); - propertyCache.Clear(); - methodCache.Clear(); - eventCache.Clear(); - } - - public override List Fields { - get { - List fields; - if (!fieldCache.TryGetValue(this, out fields)) { - fields = new List(); - foreach (FieldInfo field in type.GetFields(flags)) { - if (!field.IsPublic && !field.IsFamily) continue; - if (!field.IsSpecialName) { - fields.Add(new ReflectionField(field, this)); - } - } - fieldCache.Add(this, fields); - } - return fields; + foreach (Type nestedType in type.GetNestedTypes(flags)) { + if (!nestedType.IsVisible) continue; + string name = nestedType.FullName.Replace('+', '.'); + InnerClasses.Add(new ReflectionClass(CompilationUnit, nestedType, name, this)); } - } - - public override List Properties { - get { - List properties; - if (!propertyCache.TryGetValue(this, out properties)) { - properties = new List(); - foreach (PropertyInfo propertyInfo in type.GetProperties(flags)) { - ReflectionProperty prop = new ReflectionProperty(propertyInfo, this); - if (prop.IsPublic || prop.IsProtected) - properties.Add(prop); - } - propertyCache.Add(this, properties); + + foreach (FieldInfo field in type.GetFields(flags)) { + if (!field.IsPublic && !field.IsFamily) continue; + if (!field.IsSpecialName) { + Fields.Add(new ReflectionField(field, this)); } - return properties; } - } - - public override List Methods { - get { - List methods; - if (!methodCache.TryGetValue(this, out methods)) { - methods = new List(); - - foreach (ConstructorInfo constructorInfo in type.GetConstructors(flags)) { - if (!constructorInfo.IsPublic && !constructorInfo.IsFamily) continue; - IMethod newMethod = new ReflectionMethod(constructorInfo, this); - methods.Add(newMethod); - } - - foreach (MethodInfo methodInfo in type.GetMethods(flags)) { - if (!methodInfo.IsPublic && !methodInfo.IsFamily) continue; - if (!methodInfo.IsSpecialName) { - IMethod newMethod = new ReflectionMethod(methodInfo, this); - methods.Add(newMethod); - } - } - methodCache.Add(this, methods); - } - return methods; + + foreach (PropertyInfo propertyInfo in type.GetProperties(flags)) { + ReflectionProperty prop = new ReflectionProperty(propertyInfo, this); + if (prop.IsPublic || prop.IsProtected) + Properties.Add(prop); } - } - - public override List Events { - get { - List events; - if (!eventCache.TryGetValue(this, out events)) { - events = new List(); - foreach (EventInfo eventInfo in type.GetEvents(flags)) { - events.Add(new ReflectionEvent(eventInfo, this)); - } - eventCache.Add(this, events); + + foreach (ConstructorInfo constructorInfo in type.GetConstructors(flags)) { + if (!constructorInfo.IsPublic && !constructorInfo.IsFamily) continue; + Methods.Add(new ReflectionMethod(constructorInfo, this)); + } + + foreach (MethodInfo methodInfo in type.GetMethods(flags)) { + if (!methodInfo.IsPublic && !methodInfo.IsFamily) continue; + if (!methodInfo.IsSpecialName) { + Methods.Add(new ReflectionMethod(methodInfo, this)); } - return events; } - } - - public static bool IsDelegate(Type type) - { - return type.IsSubclassOf(typeof(Delegate)) && type != typeof(MulticastDelegate); - } - - #region VoidClass / VoidReturnType - public class VoidClass : ReflectionClass - { - public VoidClass(ICompilationUnit compilationUnit) : base(compilationUnit, typeof(void), typeof(void).FullName, null) {} - protected override IReturnType CreateDefaultReturnType() { - return new VoidReturnType(this); + foreach (EventInfo eventInfo in type.GetEvents(flags)) { + Events.Add(new ReflectionEvent(eventInfo, this)); } } - private class VoidReturnType : DefaultReturnType + public static bool IsDelegate(Type type) { - public VoidReturnType(IClass c) : base(c) {} - public override List GetMethods() { - return new List(1); - } - public override List GetProperties() { - return new List(1); - } - public override List GetFields() { - return new List(1); - } - public override List GetEvents() { - return new List(1); - } + return type.IsSubclassOf(typeof(Delegate)) && type != typeof(MulticastDelegate); } - #endregion static void AddAttributes(IProjectContent pc, List list, IList attributes) { @@ -175,7 +83,6 @@ namespace ICSharpCode.SharpDevelop.Dom public ReflectionClass(ICompilationUnit compilationUnit, Type type, string fullName, IClass declaringType) : base(compilationUnit, declaringType) { - this.type = type; if (fullName.Length > 2 && fullName[fullName.Length - 2] == '`') { FullyQualifiedName = fullName.Substring(0, fullName.Length - 2); } else { @@ -250,6 +157,8 @@ namespace ICSharpCode.SharpDevelop.Dom foreach (Type iface in type.GetInterfaces()) { BaseTypes.Add(ReflectionReturnType.Create(compilationUnit.ProjectContent, iface, false)); } + + InitMembers(type); } } diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionEvent.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionEvent.cs index dcdfaf665e..6813621ff8 100644 --- a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionEvent.cs +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionEvent.cs @@ -15,19 +15,9 @@ namespace ICSharpCode.SharpDevelop.Dom [Serializable] public class ReflectionEvent : DefaultEvent { - EventInfo eventInfo; - - public override IReturnType ReturnType { - get { - return ReflectionReturnType.Create(this, eventInfo.EventHandlerType, false); - } - set { - } - } - public ReflectionEvent(EventInfo eventInfo, IClass declaringType) : base(declaringType, eventInfo.Name) { - this.eventInfo = eventInfo; + this.ReturnType = ReflectionReturnType.Create(this, eventInfo.EventHandlerType, false); // get modifiers MethodInfo methodBase = null; diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionLoader.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionLoader.cs new file mode 100644 index 0000000000..68f8dd0304 --- /dev/null +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionLoader.cs @@ -0,0 +1,85 @@ +/* + * Created by SharpDevelop. + * User: Daniel Grunwald + * Date: 28.09.2005 + * Time: 18:48 + */ + +using System; +using System.IO; +using System.Reflection; +using ICSharpCode.Core; + +namespace ICSharpCode.SharpDevelop.Dom +{ + public sealed class ReflectionLoader : MarshalByRefObject + { + public override string ToString() + { + return "ReflectionLoader in " + AppDomain.CurrentDomain.FriendlyName; + } + + public string LoadAndCreateDatabase(string fileName, string include) + { + try { + ReflectionProjectContent content = LoadProjectContent(fileName, include); + return DomPersistence.SaveProjectContent(content); + } catch (Exception ex) { + LoggingService.Error(ex); + return null; + } + } + + ReflectionProjectContent LoadProjectContent(string fileName, string include) + { + fileName = Path.GetFullPath(fileName); + LoggingService.Debug("Trying to load " + fileName); + Assembly assembly; + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += AssemblyResolve; + lookupDirectory = Path.GetDirectoryName(fileName); + try { + if (File.Exists(fileName)) { + assembly = Assembly.ReflectionOnlyLoadFrom(fileName); + return new ReflectionProjectContent(assembly, fileName); + } + assembly = ProjectContentRegistry.LoadGACAssembly(include, true); + return new ReflectionProjectContent(assembly); + } catch (BadImageFormatException) { + LoggingService.Warn("BadImageFormat: " + include); + return null; + } finally { + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= AssemblyResolve; + lookupDirectory = null; + } + } + + string lookupDirectory; + + Assembly AssemblyResolve(object sender, ResolveEventArgs e) + { + AssemblyName name = new AssemblyName(e.Name); + LoggingService.Debug("ProjectContentRegistry.AssemblyResolve " + e.Name); + string path = Path.Combine(lookupDirectory, name.Name); + if (File.Exists(path + ".dll")) { + return Assembly.ReflectionOnlyLoadFrom(path + ".dll"); + } + if (File.Exists(path + ".exe")) { + return Assembly.ReflectionOnlyLoadFrom(path + ".exe"); + } + if (File.Exists(path)) { + return Assembly.ReflectionOnlyLoadFrom(path); + } + try { + LoggingService.Debug("AssemblyResolve trying ReflectionOnlyLoad"); + return Assembly.ReflectionOnlyLoad(e.Name); + } catch (FileNotFoundException) { + LoggingService.Warn("AssemblyResolve: ReflectionOnlyLoad failed for " + e.Name); + // We can't get the assembly we want. + // But propably we can get a similar version of it. + AssemblyName fixedName = ProjectContentRegistry.FindBestMatchingAssemblyName(e.Name); + LoggingService.Info("AssemblyResolve: FixedName: " + fixedName); + return Assembly.ReflectionOnlyLoad(fixedName.FullName); + } + } + } +} diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionMethod.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionMethod.cs index 99a9458002..b20714c49b 100644 --- a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionMethod.cs +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionMethod.cs @@ -17,49 +17,18 @@ namespace ICSharpCode.SharpDevelop.Dom [Serializable] public class ReflectionMethod : DefaultMethod { - MethodBase methodBase; - - public override bool IsConstructor { - get { - return methodBase is ConstructorInfo; - } - } - - public override IReturnType ReturnType { - get { - if (methodBase is MethodInfo) { - return ReflectionReturnType.Create(this, ((MethodInfo)methodBase).ReturnType, false); - } else if (methodBase is ConstructorInfo) { - return DeclaringType.DefaultReturnType; - } - return null; - } - set { - throw new NotSupportedException(); - } - } - - List parameters; - - public override List Parameters { - get { - if (parameters == null) { - parameters = new List(); - foreach (ParameterInfo paramInfo in methodBase.GetParameters()) { - parameters.Add(new ReflectionParameter(paramInfo, this)); - } - } - return parameters; - } - set { - throw new NotSupportedException(); - } - } - public ReflectionMethod(MethodBase methodBase, IClass declaringType) : base(declaringType, methodBase is ConstructorInfo ? "#ctor" : methodBase.Name) { - this.methodBase = methodBase; + if (methodBase is MethodInfo) { + this.ReturnType = ReflectionReturnType.Create(this, ((MethodInfo)methodBase).ReturnType, false); + } else if (methodBase is ConstructorInfo) { + this.ReturnType = DeclaringType.DefaultReturnType; + } + + foreach (ParameterInfo paramInfo in methodBase.GetParameters()) { + this.Parameters.Add(new ReflectionParameter(paramInfo, this)); + } if (methodBase.IsGenericMethodDefinition) { foreach (Type g in methodBase.GetGenericArguments()) { diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionProperty.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionProperty.cs index 7738418ac1..57c2560ee6 100644 --- a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionProperty.cs +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionProperty.cs @@ -15,27 +15,12 @@ namespace ICSharpCode.SharpDevelop.Dom [Serializable] public class ReflectionProperty : DefaultProperty { - PropertyInfo propertyInfo; - - public override IReturnType ReturnType { - get { - return ReflectionReturnType.Create(this, propertyInfo.PropertyType, false); - } - set { - } - } public ReflectionProperty(PropertyInfo propertyInfo, IClass declaringType) : base(declaringType, propertyInfo.Name) { - this.propertyInfo = propertyInfo; + this.ReturnType = ReflectionReturnType.Create(this, propertyInfo.PropertyType, false); - // show the abstract layer that we have getter & setters - if (propertyInfo.CanRead) { - GetterRegion = new DomRegion(0, 0, 0, 0); - } - - if (propertyInfo.CanWrite) { - SetterRegion = new DomRegion(0, 0, 0, 0); - } + CanGet = propertyInfo.CanRead; + CanSet = propertyInfo.CanWrite; ParameterInfo[] parameterInfo = propertyInfo.GetIndexParameters(); if (parameterInfo != null && parameterInfo.Length > 0) { diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs index 3b745cfe18..a74273cd25 100644 --- a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs @@ -61,15 +61,6 @@ namespace ICSharpCode.SharpDevelop.Dom return type; } } - /// Gets a ReturnType describing System.Void. - public static IReturnType Void { - get { - if (@void == null) { - @void = CreatePrimitive(typeof(void)); - } - return @void; - } - } /// Gets a ReturnType describing System.Array. public static IReturnType Array { get { @@ -107,6 +98,36 @@ namespace ICSharpCode.SharpDevelop.Dom return @delegate; } } + /// Gets a ReturnType describing System.Void. + public static IReturnType Void { + get { + if (@void == null) { + @void = new VoidReturnType(); + } + return @void; + } + } + private class VoidReturnType : AbstractReturnType + { + public VoidReturnType() { + FullyQualifiedName = typeof(void).FullName; + } + public override IClass GetUnderlyingClass() { + return ProjectContentRegistry.Mscorlib.GetClass(FullyQualifiedName); + } + public override List GetMethods() { + return new List(1); + } + public override List GetProperties() { + return new List(1); + } + public override List GetFields() { + return new List(1); + } + public override List GetEvents() { + return new List(1); + } + } /// /// Create a primitive return type. diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index 25828a6b62..51eba87c8d 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -42,7 +42,7 @@ namespace ICSharpCode.Core if (forcedContent != null) return forcedContent; if (ProjectService.CurrentProject == null || !projectContents.ContainsKey(ProjectService.CurrentProject)) { - return defaultProjectContent; + return DefaultProjectContent; } return projectContents[ProjectService.CurrentProject]; } @@ -185,15 +185,9 @@ namespace ICSharpCode.Core LoggingService.Info("ParserUpdateThread started"); // preload mscorlib, we're going to need it anyway IProjectContent dummyVar = ProjectContentRegistry.Mscorlib; - int counter = 0; while (!abortParserUpdateThread) { try { - if (++counter == 10) { - ReflectionClass.ClearMemberCache(); - counter = 0; - } - ParserUpdateStep(); } catch (Exception e) { ICSharpCode.Core.MessageService.ShowError(e); @@ -308,7 +302,22 @@ namespace ICSharpCode.Core return null; } - static IProjectContent defaultProjectContent = new DefaultProjectContent(); + static IProjectContent defaultProjectContent; + + public static IProjectContent DefaultProjectContent { + get { + if (defaultProjectContent == null) { + lock (projectContents) { + if (defaultProjectContent == null) { + defaultProjectContent = new DefaultProjectContent(); + defaultProjectContent.ReferencedContents.Add(ProjectContentRegistry.Mscorlib); + defaultProjectContent.ReferencedContents.Add(ProjectContentRegistry.WinForms); + } + } + } + return defaultProjectContent; + } + } public static ParseInformation ParseFile(string fileName, string fileContent, bool updateCommentTags, bool fireUpdate) { @@ -340,7 +349,7 @@ namespace ICSharpCode.Core // we accept the project content as optional parameter. fileProjectContent = GetProjectContent(fileName); if (fileProjectContent == null) { - fileProjectContent = defaultProjectContent; + fileProjectContent = DefaultProjectContent; } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs index 7d525c86b6..acb73103b4 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs @@ -26,20 +26,32 @@ namespace ICSharpCode.Core public static class ProjectContentRegistry { static Dictionary contents = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - static IProjectContent mscorlibContent; + static ReflectionProjectContent mscorlibContent; public static IProjectContent Mscorlib { get { if (mscorlibContent != null) return mscorlibContent; lock (contents) { if (contents.ContainsKey("mscorlib")) { - mscorlibContent = contents["mscorlib"]; + mscorlibContent = (ReflectionProjectContent)contents["mscorlib"]; return contents["mscorlib"]; } + int time = LoggingService.IsDebugEnabled ? Environment.TickCount : 0; LoggingService.Debug("Loading PC for mscorlib..."); - mscorlibContent = new ReflectionProjectContent(typeof(object).Assembly); + mscorlibContent = DomPersistence.LoadProjectContentByAssemblyName(typeof(object).Assembly.FullName); + if (mscorlibContent == null) { + mscorlibContent = new ReflectionProjectContent(typeof(object).Assembly); + if (time != 0) { + LoggingService.Debug("Loaded mscorlib with reflection in " + (Environment.TickCount - time) + " ms"); + } + DomPersistence.SaveProjectContent(mscorlibContent); + LoggingService.Debug("Saved mscorlib to cache"); + } else { + if (time != 0) { + LoggingService.Debug("Loaded mscorlib from cache in " + (Environment.TickCount - time) + " ms"); + } + } contents["mscorlib"] = mscorlibContent; - LoggingService.Debug("Finished loading mscorlib"); return mscorlibContent; } } @@ -69,8 +81,6 @@ namespace ICSharpCode.Core } } - static string lookupDirectory; - public static IProjectContent GetProjectContentForReference(ReferenceProjectItem item) { if (item is ProjectReferenceProjectItem) { @@ -101,69 +111,64 @@ namespace ICSharpCode.Core StatusBarService.ProgressMonitor.BeginTask("Loading " + shortName + "...", 100); #if DEBUG int time = Environment.TickCount; - string how = "??"; #endif try { Assembly assembly = GetDefaultAssembly(shortName); + ReflectionProjectContent pc; if (assembly != null) { - contents[item.Include] = new ReflectionProjectContent(assembly); - #if DEBUG - how = "typeof"; - #endif - return contents[itemInclude]; - } - lookupDirectory = Path.GetDirectoryName(itemFileName); - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += AssemblyResolve; - try { - try { - if (File.Exists(itemFileName)) { - assembly = LoadReflectionOnlyAssemblyFrom(itemFileName); - if (assembly != null) { - contents[itemFileName] = new ReflectionProjectContent(assembly, itemFileName); - contents[assembly.FullName] = contents[itemFileName]; - #if DEBUG - how = "ReflectionOnly"; - #endif - return contents[itemFileName]; - } - } - } catch (FileNotFoundException) { - // ignore and try loading with LoadGACAssembly - } - try { - assembly = LoadGACAssembly(itemInclude, true); - if (assembly != null) { - contents[itemInclude] = new ReflectionProjectContent(assembly); - contents[assembly.FullName] = contents[itemInclude]; - #if DEBUG - how = "PartialName"; - #endif - return contents[itemInclude]; - } - } catch (Exception e) { - LoggingService.Warn("Can't load assembly '" + itemInclude + "' : " + e.Message); + pc = DomPersistence.LoadProjectContentByAssemblyName(assembly.FullName); + if (pc == null) { + pc = new ReflectionProjectContent(assembly); + DomPersistence.SaveProjectContent(pc); } - } catch (BadImageFormatException) { - LoggingService.Warn("BadImageFormat: " + itemInclude); - } finally { - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= AssemblyResolve; - lookupDirectory = null; + } else { + pc = LoadProjectContent(itemFileName, itemInclude); + } + if (pc != null) { + contents[item.Include] = pc; + contents[shortName] = pc; + contents[pc.AssemblyFullName] = pc; } + return pc; } finally { #if DEBUG - LoggingService.DebugFormatted("Loaded {0} with {2} in {1}ms", itemInclude, Environment.TickCount - time, how); + LoggingService.DebugFormatted("Loaded {0} in {1}ms", itemInclude, Environment.TickCount - time); #endif StatusBarService.ProgressMonitor.Done(); } - return null; } } + static ReflectionProjectContent LoadProjectContent(string filename, string include) + { + ReflectionProjectContent pc = DomPersistence.LoadProjectContentByAssemblyName(filename); + if (pc != null) { + return pc; + } + pc = DomPersistence.LoadProjectContentByAssemblyName(include); + if (pc != null) { + return pc; + } + AppDomainSetup setup = new AppDomainSetup(); + setup.DisallowCodeDownload = true; + setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; + AppDomain domain = AppDomain.CreateDomain("AssemblyLoadingDomain", AppDomain.CurrentDomain.Evidence, setup); + string database; + try { + object o = domain.CreateInstanceAndUnwrap(typeof(ReflectionLoader).Assembly.FullName, typeof(ReflectionLoader).FullName); + ReflectionLoader loader = (ReflectionLoader)o; + database = loader.LoadAndCreateDatabase(filename, include); + } finally { + AppDomain.Unload(domain); + } + LoggingService.Debug("AppDomain finished, loading cache..."); + return DomPersistence.LoadProjectContent(database); + } + static Assembly GetDefaultAssembly(string shortName) { - // GAC Assemblies take some time because first the non-GAC try - // has to fail. - // Therefore, assemblies already in use by SharpDevelop are used directly. + // These assemblies are already loaded by SharpDevelop, so we don't need to load + // them in a separate AppDomain. switch (shortName) { case "System": // System != mscorlib !!! return typeof(Uri).Assembly; @@ -191,74 +196,19 @@ namespace ICSharpCode.Core } } - static Assembly AssemblyResolve(object sender, ResolveEventArgs e) - { - AssemblyName name = new AssemblyName(e.Name); - LoggingService.Debug("ProjectContentRegistry.AssemblyResolve " + e.Name); - string path = Path.Combine(lookupDirectory, name.Name); - if (File.Exists(path + ".dll")) { - return LoadReflectionOnlyAssemblyFrom(path + ".dll"); - } - if (File.Exists(path + ".exe")) { - return LoadReflectionOnlyAssemblyFrom(path + ".exe"); - } - if (File.Exists(path)) { - return LoadReflectionOnlyAssemblyFrom(path); - } - try { - LoggingService.Debug("AssemblyResolve trying ReflectionOnlyLoad"); - return Assembly.ReflectionOnlyLoad(e.Name); - } catch (FileNotFoundException) { - LoggingService.Warn("AssemblyResolve: ReflectionOnlyLoad failed for " + e.Name); - // We can't get the assembly we want. - // But propably we can get a similar version of it. - AssemblyName fixedName = FindBestMatchingAssemblyName(e.Name); - LoggingService.Info("AssemblyResolve: FixedName: " + fixedName); - return Assembly.ReflectionOnlyLoad(fixedName.FullName); - } - } - - static Dictionary loadFromCache; - - static Assembly LoadReflectionOnlyAssemblyFrom(string fileName) - { - fileName = Path.GetFullPath(fileName); - if (loadFromCache == null) { - loadFromCache = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - } - if (loadFromCache.ContainsKey(fileName)) { - LoggingService.Debug("Use " + fileName + " from cache."); - return loadFromCache[fileName]; - } - LoggingService.Debug("Load " + fileName); - Assembly asm = InternalLoadReflectionOnlyAssemblyFrom(fileName); - if (loadFromCache.ContainsKey(asm.FullName)) { - loadFromCache.Add(fileName, loadFromCache[asm.FullName]); - return loadFromCache[asm.FullName]; - } - loadFromCache.Add(fileName, asm); - loadFromCache.Add(asm.FullName, asm); - return asm; - } - static Assembly InternalLoadReflectionOnlyAssemblyFrom(string fileName) + public static Assembly LoadGACAssembly(string partialName, bool reflectionOnly) { - byte[] data; - using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { - if (fs.Length > 10 * 1024 * 1024) { - // more than 10 MB? Do not hold bytes in memory - return Assembly.ReflectionOnlyLoadFrom(fileName); - } - data = new byte[fs.Length]; - for (int i = 0; i < data.Length;) { - int c = fs.Read(data, i, data.Length - i); - i += c; - if (c <= 0) { - throw new IOException("Read returned " + c); - } - } + if (reflectionOnly) { + AssemblyName name = FindBestMatchingAssemblyName(partialName); + if (name == null) + return null; + return Assembly.ReflectionOnlyLoad(name.FullName); + } else { + #pragma warning disable 618 + return Assembly.LoadWithPartialName(partialName); + #pragma warning restore 618 } - return Assembly.ReflectionOnlyLoad(data); } public static AssemblyName FindBestMatchingAssemblyName(string name) @@ -326,19 +276,5 @@ namespace ICSharpCode.Core } return new AssemblyName(best); } - - public static Assembly LoadGACAssembly(string partialName, bool reflectionOnly) - { - if (reflectionOnly) { - AssemblyName name = FindBestMatchingAssemblyName(partialName); - if (name == null) - return null; - return Assembly.ReflectionOnlyLoad(name.FullName); - } else { - #pragma warning disable 618 - return Assembly.LoadWithPartialName(partialName); - #pragma warning restore 618 - } - } } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs index cc19c89163..e97a38a508 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs @@ -14,13 +14,40 @@ using System.Diagnostics; using System.Reflection; using ICSharpCode.SharpDevelop.Project; -using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.Core; -namespace ICSharpCode.Core +namespace ICSharpCode.SharpDevelop.Dom { public class ReflectionProjectContent : DefaultProjectContent { - Assembly assembly; + string assemblyFullName; + AssemblyName[] referencedAssemblies; + ICompilationUnit assemblyCompilationUnit; + string assemblyLocation; + + public string AssemblyLocation { + get { + return assemblyLocation; + } + } + + public string AssemblyFullName { + get { + return assemblyFullName; + } + } + + public AssemblyName[] ReferencedAssemblies { + get { + return referencedAssemblies; + } + } + + public ICompilationUnit AssemblyCompilationUnit { + get { + return assemblyCompilationUnit; + } + } public ReflectionProjectContent(Assembly assembly) : this(assembly, assembly.Location) @@ -28,33 +55,33 @@ namespace ICSharpCode.Core } public ReflectionProjectContent(Assembly assembly, string assemblyLocation) + : this(assembly.FullName, assemblyLocation, assembly.GetReferencedAssemblies()) { - this.assembly = assembly; - - ICompilationUnit assemblyCompilationUnit = new DefaultCompilationUnit(this); - try { foreach (Type type in assembly.GetExportedTypes()) { string name = type.FullName; - if (name.IndexOf('+') < 0) { // type.IsNested + if (name.IndexOf('+') < 0) { // type.IsNested AddClassToNamespaceListInternal(new ReflectionClass(assemblyCompilationUnit, type, name, null)); } } + InitializeSpecialClasses(); } catch (Exception ex) { MessageService.ShowError(ex); } - - if (assembly == typeof(void).Assembly) { - // Replace void through the special class (ReturnType(void).GetMethods() does not return - // the methods of System.Object and System.ValueType) - AddClassToNamespaceListInternal(new ReflectionClass.VoidClass(assemblyCompilationUnit)); - } + } + + public ReflectionProjectContent(string assemblyFullName, string assemblyLocation, AssemblyName[] referencedAssemblies) + { + this.assemblyFullName = assemblyFullName; + this.referencedAssemblies = referencedAssemblies; + this.assemblyLocation = assemblyLocation; + this.assemblyCompilationUnit = new DefaultCompilationUnit(this); string fileName = LookupLocalizedXmlDoc(assemblyLocation); // Not found -> look in runtime directory. if (fileName == null) { string runtimeDirectory = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); - fileName = LookupLocalizedXmlDoc(Path.Combine(runtimeDirectory, Path.GetFileName(assembly.Location))); + fileName = LookupLocalizedXmlDoc(Path.Combine(runtimeDirectory, Path.GetFileName(assemblyLocation))); } if (fileName != null) { @@ -62,6 +89,24 @@ namespace ICSharpCode.Core } } + public void InitializeSpecialClasses() + { + if (ClassLists[0].ContainsKey(VoidClass.VoidName)) { + AddClassToNamespaceList(new VoidClass(assemblyCompilationUnit)); + } + } + + private class VoidClass : ReflectionClass + { + internal static readonly string VoidName = typeof(void).FullName; + + public VoidClass(ICompilationUnit compilationUnit) : base(compilationUnit, typeof(void), VoidName, null) {} + + protected override IReturnType CreateDefaultReturnType() { + return ReflectionReturnType.Void; + } + } + bool initialized = false; ArrayList missingNames; @@ -76,13 +121,14 @@ namespace ICSharpCode.Core missingNames.RemoveAt(i--); } } - if (missingNames.Count == 0) + if (missingNames.Count == 0) { missingNames = null; + } } return; } initialized = true; - foreach (AssemblyName name in assembly.GetReferencedAssemblies()) { + foreach (AssemblyName name in referencedAssemblies) { IProjectContent content = ProjectContentRegistry.GetExistingProjectContent(name); if (content != null) { ReferencedContents.Add(content); @@ -96,7 +142,7 @@ namespace ICSharpCode.Core public override string ToString() { - return string.Format("[{0}: {1}]", GetType().Name, assembly.FullName); + return string.Format("[{0}: {1}]", GetType().Name, assemblyFullName); } } }