Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

Using TypeExtensionPoints and CustomExtensionAttributes fail #39

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
*~

# Build stuff
obj
/bin
obj/
bin/
*policy*config
*.pc
*.dll
Expand Down Expand Up @@ -33,3 +33,8 @@ Makefile.in
/configure
/install-sh
/missing
.suo
*.suo
*.user
/Test/
/packages/
20 changes: 17 additions & 3 deletions Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
}
Expand All @@ -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)
Expand All @@ -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));
}
}
}
Expand All @@ -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));
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Mono.Addins/Mono.Addins.Database/AddinDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
26 changes: 24 additions & 2 deletions Mono.Addins/Mono.Addins.Database/AddinScanResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> assemblySearchLocations = new List<string>();
Hashtable filesToIgnore;

bool regenerateRelationData;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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 {
Expand Down
53 changes: 44 additions & 9 deletions Mono.Addins/Mono.Addins.Database/AddinScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);
Expand All @@ -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<string,string> prop in att) {
foreach (KeyValuePair<string,string> prop in att.NodeDictionary) {
if (prop.Key != CustomExtensionAttribute.PathFieldKey)
elem.SetAttribute (prop.Key, prop.Value);
}
Expand Down
13 changes: 7 additions & 6 deletions Mono.Addins/Mono.Addins.Database/DefaultAssemblyReflector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 24 additions & 3 deletions Mono.Addins/Mono.Addins.Database/IAssemblyReflector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,16 +297,37 @@ public interface IAssemblyLocator
/// <summary>
/// A custom attribute
/// </summary>
public class CustomAttribute: Dictionary<string,string>
public class CustomAttribute
{
string typeName;

private string typeName;
private Dictionary<string, string> _nodeDictionary;
private Dictionary<string, object> _propertyDictionary;

/// <summary>
/// Constructor
/// </summary>
public CustomAttribute()
{
_nodeDictionary = new Dictionary<string, string>();
_propertyDictionary = new Dictionary<string, object>();
}

/// <summary>
/// Full name of the type of the custom attribute
/// </summary>
public string TypeName {
get { return typeName; }
set { typeName = value; }
}

/// <summary>
/// Returns a dictionary of nodes
/// </summary>
public IDictionary<string, string> NodeDictionary { get { return _nodeDictionary;} }

/// <summary>
/// Returns a dictionary of properties
/// </summary>
public IDictionary<string, object> PropertyDictionary { get { return _propertyDictionary; } }
}
}
4 changes: 3 additions & 1 deletion Mono.Addins/Mono.Addins/AddinEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, RuntimeAddin>();
loadedAssemblies = new Dictionary<Assembly, RuntimeAddin> ();
registry.Dispose ();
registry.Dispose();
registry = null;
startupDirectory = null;
ClearContext ();
Expand Down
32 changes: 24 additions & 8 deletions Mono.Addins/Mono.Addins/CustomExtensionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";

/// <summary>
/// Identifier of the node
Expand Down Expand Up @@ -82,12 +83,27 @@ public string InsertAfter {
public string Path {
get { return path; }
set { path = value; }
}

/// <summary>
/// The extension node bound to this attribute
/// </summary>
public ExtensionNode ExtensionNode { get; internal set; }
}

/// <summary>
/// Type defining the extension point being extended
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public Type Type
{
get { return type; }
set { type = value; }
}

/// <summary>
/// The extension node bound to this attribute
/// </summary>
public ExtensionNode ExtensionNode { get; internal set; }


/// <summary>
Expand Down