diff --git a/.gitignore b/.gitignore index d6cdbc8e..abf76716 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,8 @@ *~ # Build stuff -obj -/bin +obj/ +bin/ *policy*config *.pc *.dll @@ -33,3 +33,8 @@ Makefile.in /configure /install-sh /missing +.suo +*.suo +*.user +/Test/ +/packages/ diff --git a/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs b/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs index b22c4a6e..3613da5f 100644 --- a/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs +++ b/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs @@ -206,7 +206,7 @@ MA.CustomAttribute ConvertToRawAttribute (CustomAttribute att, string expectedTy NodeAttributeAttribute bat = (NodeAttributeAttribute) GetCustomAttribute (par, typeof(NodeAttributeAttribute), false); if (bat != null) name = bat.Name; - mat.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture)); + mat.NodeDictionary.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture)); } } } @@ -217,6 +217,20 @@ MA.CustomAttribute ConvertToRawAttribute (CustomAttribute att, string expectedTy if (val == null) continue; + if (val is TypeReference) + { + var typeRef = (TypeReference) val; + var typeDef = typeRef.Resolve(); + if (typeDef == null) + throw new InvalidOperationException(string.Format("Cannot resolve assembly '{0}'", typeDef.Module.Assembly.FullName)); + + val = Type.GetType(typeDef.FullName + ", " + typeDef.Module.Assembly.FullName, false); + if (val == null) + throw new InvalidOperationException(string.Format("Cannot resolve type '{0}' at assembly '{1}'", typeDef.FullName, typeDef.Module.Assembly.FullName)); + } + + mat.PropertyDictionary.Add(pname, val); + foreach (TypeDefinition td in GetInheritanceChain (attType)) { PropertyDefinition prop = GetMember (td.Properties, pname); if (prop == null) @@ -225,7 +239,7 @@ MA.CustomAttribute ConvertToRawAttribute (CustomAttribute att, string expectedTy NodeAttributeAttribute bat = (NodeAttributeAttribute) GetCustomAttribute (prop, typeof(NodeAttributeAttribute), false); if (bat != null) { string name = string.IsNullOrEmpty (bat.Name) ? prop.Name : bat.Name; - mat.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture)); + mat.NodeDictionary.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture)); } } } @@ -242,7 +256,7 @@ MA.CustomAttribute ConvertToRawAttribute (CustomAttribute att, string expectedTy NodeAttributeAttribute bat = (NodeAttributeAttribute) GetCustomAttribute (field, typeof(NodeAttributeAttribute), false); if (bat != null) { string name = string.IsNullOrEmpty (bat.Name) ? field.Name : bat.Name; - mat.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture)); + mat.NodeDictionary.Add (name, Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture)); } } } diff --git a/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs b/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs index bdaa33fc..454e11c8 100644 --- a/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs +++ b/Mono.Addins/Mono.Addins.Database/AddinDatabase.cs @@ -1441,6 +1441,7 @@ public void ParseAddin (IProgressStatus progressStatus, string domain, string fi } AddinScanResult sr = new AddinScanResult (); + sr.AddAssemblySearchLocation(registry.StartupDirectory); sr.Domain = domain; AddinScanner scanner = new AddinScanner (this, sr, progressStatus); diff --git a/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs b/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs index e33becc2..6b47468d 100644 --- a/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs +++ b/Mono.Addins/Mono.Addins.Database/AddinScanResult.cs @@ -48,7 +48,8 @@ internal class AddinScanResult: MarshalByRefObject, IAssemblyLocator Hashtable visitedFolders = new Hashtable (); Hashtable assemblyLocations = new Hashtable (); - Hashtable assemblyLocationsByFullName = new Hashtable (); + Hashtable assemblyLocationsByFullName = new Hashtable(); + List assemblySearchLocations = new List(); Hashtable filesToIgnore; bool regenerateRelationData; @@ -164,6 +165,11 @@ public void AddAssemblyLocation (string file) } list.Add (file); } + + public void AddAssemblySearchLocation(string directory) + { + assemblySearchLocations.Add(directory); + } public string GetAssemblyLocation (string fullName) { @@ -177,8 +183,24 @@ public string GetAssemblyLocation (string fullName) return GetType ().Assembly.Location; ArrayList list = assemblyLocations [name] as ArrayList; if (list == null) + { + var assemblyName = new AssemblyName(fullName); + foreach (var assemblySearchLocation in assemblySearchLocations) + { + string filePath = Path.Combine(assemblySearchLocation, assemblyName.Name + ".dll"); + if (File.Exists(filePath)) + { + var existingAssembly = AssemblyName.GetAssemblyName(filePath); + if (existingAssembly.FullName == assemblyName.FullName) + { + return filePath; + } + } + } + return null; - + } + string lastAsm = null; foreach (string file in list.ToArray ()) { try { diff --git a/Mono.Addins/Mono.Addins.Database/AddinScanner.cs b/Mono.Addins/Mono.Addins.Database/AddinScanner.cs index 5a8e7717..b443d6e7 100644 --- a/Mono.Addins/Mono.Addins.Database/AddinScanner.cs +++ b/Mono.Addins/Mono.Addins.Database/AddinScanner.cs @@ -748,7 +748,7 @@ void ReportReflectionException (IProgressStatus monitor, Exception ex, AddinDesc scanResult.AddFileToWithFailure (config.AddinFile); monitor.ReportWarning ("[" + config.AddinId + "] Could not load some add-in assemblies: " + ex.Message); if (monitor.LogLevel <= 1) - return; + return; ReflectionTypeLoadException rex = ex as ReflectionTypeLoadException; if (rex != null) { @@ -904,21 +904,32 @@ void ScanAssemblyContents (IAssemblyReflector reflector, AddinDescription config // Get extension points object[] extPoints = reflector.GetCustomAttributes (asm, typeof(ExtensionPointAttribute), false); - foreach (ExtensionPointAttribute ext in extPoints) { - ExtensionPoint ep = config.AddExtensionPoint (ext.Path); + foreach (ExtensionPointAttribute ext in extPoints) + { + ExtensionPoint ep; + if (ext.Path.Length > 0) + { + ep = config.AddExtensionPoint(ext.Path); + } + else + { + ep = config.AddExtensionPoint(GetDefaultTypeExtensionPath(config, ext.ObjectTypeName)); + } + ep.Description = ext.Description; ep.Name = ext.Name; ep.DefaultInsertBefore = ext.DefaultInsertBefore; ep.DefaultInsertAfter = ext.DefaultInsertAfter; ExtensionNodeType nt = ep.AddExtensionNode (ext.NodeName, ext.NodeTypeName); nt.ExtensionAttributeTypeName = ext.ExtensionAttributeTypeName; + nt.ObjectTypeName = ext.ObjectTypeName; } } // Look for extension nodes declared using assembly attributes foreach (CustomAttribute att in reflector.GetRawCustomAttributes (asm, typeof(CustomExtensionAttribute), true)) - AddCustomAttributeExtension (module, att, "Type"); + AddCustomAttributeExtension (null, null, module, att, "Type"); // Get extensions or extension points applied to types @@ -1015,7 +1026,7 @@ void ScanAssemblyContents (IAssemblyReflector reflector, AddinDescription config else { // Look for custom extension attribtues foreach (CustomAttribute att in reflector.GetRawCustomAttributes (t, typeof(CustomExtensionAttribute), false)) { - ExtensionNodeDescription elem = AddCustomAttributeExtension (module, att, "Type"); + ExtensionNodeDescription elem = AddCustomAttributeExtension (reflector, t, module, att, "Type"); elem.SetAttribute ("type", typeFullName); if (string.IsNullOrEmpty (elem.GetAttribute ("id"))) elem.SetAttribute ("id", typeFullName); @@ -1025,13 +1036,37 @@ void ScanAssemblyContents (IAssemblyReflector reflector, AddinDescription config } } - ExtensionNodeDescription AddCustomAttributeExtension (ModuleDescription module, CustomAttribute att, string nameName) + ExtensionNodeDescription AddCustomAttributeExtension (IAssemblyReflector reflector, object t, ModuleDescription module, + CustomAttribute att, string nameName) { - string path; - if (!att.TryGetValue (CustomExtensionAttribute.PathFieldKey, out path)) + string path; + if (!att.NodeDictionary.TryGetValue(CustomExtensionAttribute.PathFieldKey, out path) && reflector != null && t != null) + { + object type; + if (att.PropertyDictionary.TryGetValue("Type", out type) && type is Type) + { + var concreteType = (Type) type; + path = "$" + concreteType.FullName; + } + else + { + path = GetBaseTypeNameList(reflector, t); + if (path == "$") + { + // The type does not implement any interface and has no superclass. + // Will be reported later as an error. + string typeFullName = reflector.GetTypeFullName(t); + path = "$" + typeFullName; + } + } + } + else + { path = "%" + att.TypeName; + } + ExtensionNodeDescription elem = module.AddExtensionNode (path, nameName); - foreach (KeyValuePair prop in att) { + foreach (KeyValuePair prop in att.NodeDictionary) { if (prop.Key != CustomExtensionAttribute.PathFieldKey) elem.SetAttribute (prop.Key, prop.Value); } diff --git a/Mono.Addins/Mono.Addins.Database/DefaultAssemblyReflector.cs b/Mono.Addins/Mono.Addins.Database/DefaultAssemblyReflector.cs index b835f8a2..213255c7 100644 --- a/Mono.Addins/Mono.Addins.Database/DefaultAssemblyReflector.cs +++ b/Mono.Addins/Mono.Addins.Database/DefaultAssemblyReflector.cs @@ -95,21 +95,22 @@ CustomAttribute ConvertAttribute (object ob) NodeAttributeAttribute bt = (NodeAttributeAttribute) Attribute.GetCustomAttribute (prop, typeof(NodeAttributeAttribute), true); if (bt != null) { string name = string.IsNullOrEmpty (bt.Name) ? prop.Name : bt.Name; - at [name] = Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture); + at.NodeDictionary[name] = Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture); } } - } - foreach (FieldInfo field in type.GetFields (BindingFlags.Public | BindingFlags.Instance)) { + at.PropertyDictionary[prop.Name] = val; + } + foreach (FieldInfo field in type.GetFields (BindingFlags.Public | BindingFlags.Instance)) { object val = field.GetValue (ob); if (val != null) { NodeAttributeAttribute bt = (NodeAttributeAttribute) Attribute.GetCustomAttribute (field, typeof(NodeAttributeAttribute), true); if (bt != null) { string name = string.IsNullOrEmpty (bt.Name) ? field.Name : bt.Name; - at [name] = Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture); + at.NodeDictionary[name] = Convert.ToString (val, System.Globalization.CultureInfo.InvariantCulture); } } - } - return at; + } + return at; } public string GetTypeName (object type) diff --git a/Mono.Addins/Mono.Addins.Database/IAssemblyReflector.cs b/Mono.Addins/Mono.Addins.Database/IAssemblyReflector.cs index 5c763320..04f3dadb 100644 --- a/Mono.Addins/Mono.Addins.Database/IAssemblyReflector.cs +++ b/Mono.Addins/Mono.Addins.Database/IAssemblyReflector.cs @@ -297,10 +297,21 @@ public interface IAssemblyLocator /// /// A custom attribute /// - public class CustomAttribute: Dictionary + public class CustomAttribute { - string typeName; - + private string typeName; + private Dictionary _nodeDictionary; + private Dictionary _propertyDictionary; + + /// + /// Constructor + /// + public CustomAttribute() + { + _nodeDictionary = new Dictionary(); + _propertyDictionary = new Dictionary(); + } + /// /// Full name of the type of the custom attribute /// @@ -308,5 +319,15 @@ public string TypeName { get { return typeName; } set { typeName = value; } } + + /// + /// Returns a dictionary of nodes + /// + public IDictionary NodeDictionary { get { return _nodeDictionary;} } + + /// + /// Returns a dictionary of properties + /// + public IDictionary PropertyDictionary { get { return _propertyDictionary; } } } } diff --git a/Mono.Addins/Mono.Addins/AddinEngine.cs b/Mono.Addins/Mono.Addins/AddinEngine.cs index e0af4c26..5bba0ec8 100755 --- a/Mono.Addins/Mono.Addins/AddinEngine.cs +++ b/Mono.Addins/Mono.Addins/AddinEngine.cs @@ -224,12 +224,14 @@ Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args) public void Shutdown () { lock (LocalLock) { + ResetCachedData(); + initialized = false; AppDomain.CurrentDomain.AssemblyLoad -= new AssemblyLoadEventHandler (OnAssemblyLoaded); AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomainAssemblyResolve; loadedAddins = new Dictionary(); loadedAssemblies = new Dictionary (); - registry.Dispose (); + registry.Dispose(); registry = null; startupDirectory = null; ClearContext (); diff --git a/Mono.Addins/Mono.Addins/CustomExtensionAttribute.cs b/Mono.Addins/Mono.Addins/CustomExtensionAttribute.cs index d500190a..fef57d92 100644 --- a/Mono.Addins/Mono.Addins/CustomExtensionAttribute.cs +++ b/Mono.Addins/Mono.Addins/CustomExtensionAttribute.cs @@ -41,8 +41,9 @@ public class CustomExtensionAttribute: Attribute string insertBefore; string insertAfter; string path; - - internal const string PathFieldKey = "__path"; + Type type; + + internal const string PathFieldKey = "__path"; /// /// Identifier of the node @@ -82,12 +83,27 @@ public string InsertAfter { public string Path { get { return path; } set { path = value; } - } - - /// - /// The extension node bound to this attribute - /// - public ExtensionNode ExtensionNode { get; internal set; } + } + + /// + /// Type defining the extension point being extended + /// + /// + /// This property can be used to explicitly specify the type that defines the extension point + /// to be extended. By default, Mono.Addins will try to find any extension point defined in any + /// of the base classes or interfaces. This property can be used when there is more than one + /// base type providing an extension point. + /// + public Type Type + { + get { return type; } + set { type = value; } + } + + /// + /// The extension node bound to this attribute + /// + public ExtensionNode ExtensionNode { get; internal set; } ///