Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono-addins.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Ungureanu <therzok@gmail.com>2020-02-06 09:17:23 +0300
committerLluis Sanchez <llsan@microsoft.com>2020-10-05 13:52:49 +0300
commit8978e8b8a2a1a0030f1ea993c96c28671d3a4534 (patch)
tree0241deab7e4716415b2274d0fbe435f9af615b78
parent3f41519d63aecbc16922c23108dd40cecb5a8300 (diff)
[Localization] Optimize loading AddinLocalizers for the case where a custom localizer is supplied
This should avoid probing for a built-in localizer when a custom one is supplied.
-rw-r--r--Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs35
-rw-r--r--Mono.Addins/Mono.Addins.Database/AddinScanner.cs3
-rw-r--r--Mono.Addins/Mono.Addins/AddinLocalizerAttribute.cs8
-rw-r--r--Mono.Addins/Mono.Addins/RuntimeAddin.cs89
-rw-r--r--Test/CommandExtension/CommandExtension.csproj1
-rw-r--r--Test/CommandExtension/CustomLocalizerFactory.cs49
-rw-r--r--Test/MultiAssemblyAddin/Extensions.cs3
-rw-r--r--Test/MultiAssemblyAddin/MultiAssemblyAddin.csproj4
-rw-r--r--Test/MultiAssemblyAddin/SecondAssembly/CustomLocalizerFactory.cs47
-rw-r--r--Test/MultiAssemblyAddin/SecondAssembly/SecondAssembly.csproj1
-rw-r--r--Test/UnitTests/TestAddinDescription.cs5
-rw-r--r--Test/UnitTests/TestLocalization.cs10
12 files changed, 213 insertions, 42 deletions
diff --git a/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs b/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs
index 9be24bd..8017bb9 100644
--- a/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs
+++ b/Mono.Addins.CecilReflector/Mono.Addins.CecilReflector/Reflector.cs
@@ -130,13 +130,9 @@ namespace Mono.Addins.CecilReflector
for (int n=0; n<typeParameters.Count; n++) {
int ip = typeParameters [n];
string propName = ciParams[ip].Name;
- propName = char.ToUpper (propName [0]) + propName.Substring (1) + "Name";
- PropertyInfo pi = attype.GetProperty (propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ propName = char.ToUpper (propName [0]) + propName.Substring (1);
- if (pi == null)
- throw new InvalidOperationException ("Property '" + propName + "' not found in type '" + attype + "'.");
-
- pi.SetValue (ob, ((TypeReference) att.ConstructorArguments [ip].Value).FullName, null);
+ SetTypeNameAndAssemblyName (propName, attype, ob, (TypeReference)att.ConstructorArguments[ip].Value);
}
}
} else {
@@ -148,20 +144,31 @@ namespace Mono.Addins.CecilReflector
PropertyInfo prop = attype.GetProperty (pname);
if (prop != null) {
if (prop.PropertyType == typeof(System.Type)) {
- // We can't load the type. We have to use the typeName property instead.
- pname += "Name";
- prop = attype.GetProperty (pname, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
-
- if (prop == null)
- throw new InvalidOperationException ("Property '" + pname + "' not found in type '" + attype + "'.");
-
- prop.SetValue (ob, ((TypeReference) namedArgument.Argument.Value).FullName, null);
+ SetTypeNameAndAssemblyName (pname, attype, ob, (TypeReference)namedArgument.Argument.Value);
} else
prop.SetValue (ob, namedArgument.Argument.Value, null);
}
}
return ob;
}
+
+ static void SetTypeNameAndAssemblyName (string basePropName, Type attype, object ob, TypeReference typeReference)
+ {
+ // We can't load the type. We have to use the typeName and typeAssemblyName properties instead.
+ var typeNameProp = basePropName + "Name";
+ var prop = attype.GetProperty (typeNameProp, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+
+ if (prop == null)
+ throw new InvalidOperationException ("Property '" + typeNameProp + "' not found in type '" + attype + "'.");
+
+ prop.SetValue (ob, typeReference.FullName, null);
+
+ prop = attype.GetProperty (basePropName + "AssemblyName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ if (prop == null)
+ return;
+
+ prop.SetValue (ob, typeReference.Resolve ().Module.Assembly.FullName, null);
+ }
public List<MA.CustomAttribute> GetRawCustomAttributes (object obj, Type type, bool inherit)
{
diff --git a/Mono.Addins/Mono.Addins.Database/AddinScanner.cs b/Mono.Addins/Mono.Addins.Database/AddinScanner.cs
index 97b3e6f..6178fb7 100644
--- a/Mono.Addins/Mono.Addins.Database/AddinScanner.cs
+++ b/Mono.Addins/Mono.Addins.Database/AddinScanner.cs
@@ -687,7 +687,10 @@ namespace Mono.Addins.Database
var customLocat = (AddinLocalizerAttribute) reflector.GetCustomAttribute (asm, typeof(AddinLocalizerAttribute), false);
if (customLocat != null) {
var node = new ExtensionNodeDescription ("Localizer");
+
node.SetAttribute ("type", customLocat.TypeName);
+ node.SetAttribute ("assembly", customLocat.TypeAssemblyName);
+
config.Localizer = node;
}
diff --git a/Mono.Addins/Mono.Addins/AddinLocalizerAttribute.cs b/Mono.Addins/Mono.Addins/AddinLocalizerAttribute.cs
index f2706d4..ba187a5 100644
--- a/Mono.Addins/Mono.Addins/AddinLocalizerAttribute.cs
+++ b/Mono.Addins/Mono.Addins/AddinLocalizerAttribute.cs
@@ -36,6 +36,7 @@ namespace Mono.Addins
{
Type type;
string typeName;
+ string typeAssemblyName;
/// <summary>
/// Initializes a new instance of the <see cref="Mono.Addins.AddinLocalizerAttribute"/> class.
@@ -61,12 +62,17 @@ namespace Mono.Addins
/// </summary>
public Type Type {
get { return type; }
- set { type = value; typeName = type.FullName; }
+ set { type = value; typeName = value.FullName; typeAssemblyName = value.Assembly.FullName; }
}
internal string TypeName {
get { return typeName; }
set { typeName = value; type = null; }
}
+
+ internal string TypeAssemblyName {
+ get { return typeAssemblyName; }
+ set { typeAssemblyName = value; type = null; }
+ }
}
}
diff --git a/Mono.Addins/Mono.Addins/RuntimeAddin.cs b/Mono.Addins/Mono.Addins/RuntimeAddin.cs
index 1374ca7..9b67716 100644
--- a/Mono.Addins/Mono.Addins/RuntimeAddin.cs
+++ b/Mono.Addins/Mono.Addins/RuntimeAddin.cs
@@ -316,32 +316,61 @@ namespace Mono.Addins
/// </remarks>
public Type GetType (string typeName, bool throwIfNotFound)
{
+ return GetType (typeName, string.Empty, throwIfNotFound);
+ }
+
+ internal Type GetType (string typeName, string assemblyName, bool throwIfNotFound)
+ {
EnsureAssembliesLoaded ();
-
- // Look in the addin assemblies
-
- Type at = Type.GetType (typeName, false);
+
+ // Look in the addin assemblies and in dependent add-ins.
+ // PERF: Unrolled from GetAllAssemblies and GetAllDependencies to avoid allocations.
+ Type at = (string.IsNullOrEmpty (assemblyName) ? Type.GetType (typeName, false) : null)
+ ?? GetTypeRecursive (typeName, assemblyName);
if (at != null)
return at;
-
- foreach (Assembly asm in GetAllAssemblies ()) {
- Type t = asm.GetType (typeName, false);
- if (t != null)
- return t;
- }
-
- // Look in the dependent add-ins
- foreach (RuntimeAddin addin in GetAllDependencies ()) {
- Type t = addin.GetType (typeName, false);
- if (t != null)
- return t;
- }
-
+
if (throwIfNotFound)
throw new InvalidOperationException ("Type '" + typeName + "' not found in add-in '" + id + "'");
return null;
}
-
+
+ Type GetTypeRecursive (string typeName, string assemblyName)
+ {
+ return FindTypeInAssemblyList (Assemblies, typeName, assemblyName)
+ ?? FindTypeInAssemblyList (parentAddin?.Assemblies, typeName, assemblyName)
+ ?? FindTypeInAddins (GetDepAddins (), typeName, assemblyName)
+ ?? FindTypeInAddins (parentAddin?.GetDepAddins (), typeName, assemblyName);
+ }
+
+ static Type FindTypeInAssemblyList (Assembly[] assemblies, string typeName, string assemblyName)
+ {
+ if (assemblies != null) {
+ foreach (var assembly in assemblies) {
+ if (string.IsNullOrEmpty (assemblyName) || assembly.FullName == assemblyName) {
+ Type type = assembly.GetType (typeName, false);
+ if (type != null)
+ return type;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ static Type FindTypeInAddins (RuntimeAddin[] addins, string typeName, string assemblyName)
+ {
+ if (addins != null) {
+ foreach (RuntimeAddin addin in addins) {
+ Type t = addin.GetTypeRecursive (typeName, assemblyName);
+ if (t != null)
+ return t;
+ }
+ }
+
+ return null;
+ }
+
IEnumerable<ResourceManager> GetAllResourceManagers ()
{
foreach (ResourceManager rm in GetResourceManagers ())
@@ -424,7 +453,12 @@ namespace Mono.Addins
/// </remarks>
public object CreateInstance (string typeName, bool throwIfNotFound)
{
- Type type = GetType (typeName, throwIfNotFound);
+ return CreateInstance (typeName, string.Empty, throwIfNotFound);
+ }
+
+ internal object CreateInstance (string typeName, string assemblyName, bool throwIfNotFound)
+ {
+ Type type = GetType (typeName, assemblyName, throwIfNotFound);
if (type == null)
return null;
else
@@ -608,15 +642,20 @@ namespace Mono.Addins
if (description.Localizer != null) {
string cls = description.Localizer.GetAttribute ("type");
-
+ string assembly = description.Localizer.GetAttribute ("assembly");
+
+ var thisAssembly = GetType ().Assembly;
+
// First try getting one of the stock localizers. If none of found try getting the type.
object fob = null;
- Type t = Type.GetType ("Mono.Addins.Localization." + cls + "Localizer, " + GetType().Assembly.FullName, false);
- if (t != null)
- fob = Activator.CreateInstance (t);
+ if (string.IsNullOrEmpty (assembly) || assembly == thisAssembly.FullName) {
+ Type t = thisAssembly.GetType ("Mono.Addins.Localization." + cls + "Localizer", false);
+ if (t != null)
+ fob = Activator.CreateInstance (t);
+ }
if (fob == null)
- fob = CreateInstance (cls, true);
+ fob = CreateInstance (cls, assembly, true);
IAddinLocalizerFactory factory = fob as IAddinLocalizerFactory;
if (factory == null)
diff --git a/Test/CommandExtension/CommandExtension.csproj b/Test/CommandExtension/CommandExtension.csproj
index 4396402..c040727 100644
--- a/Test/CommandExtension/CommandExtension.csproj
+++ b/Test/CommandExtension/CommandExtension.csproj
@@ -42,6 +42,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CommandExtensionNode.cs" />
+ <Compile Include="CustomLocalizerFactory.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project> \ No newline at end of file
diff --git a/Test/CommandExtension/CustomLocalizerFactory.cs b/Test/CommandExtension/CustomLocalizerFactory.cs
new file mode 100644
index 0000000..8d9e687
--- /dev/null
+++ b/Test/CommandExtension/CustomLocalizerFactory.cs
@@ -0,0 +1,49 @@
+//
+// CustomLocalizerFactory.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2020 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Addins;
+using Mono.Addins.Localization;
+
+[assembly: AddinLocalizer (typeof (CommandExtension.CustomLocalizerFactory))]
+
+namespace CommandExtension
+{
+ class CustomLocalizerFactory : IAddinLocalizerFactory
+ {
+ sealed class Localizer : IAddinLocalizer
+ {
+ public string GetString (string msgid)
+ {
+ return "loc: " + msgid;
+ }
+ }
+
+ public IAddinLocalizer CreateLocalizer (RuntimeAddin addin, NodeElement element)
+ {
+ return new Localizer ();
+ }
+ }
+}
diff --git a/Test/MultiAssemblyAddin/Extensions.cs b/Test/MultiAssemblyAddin/Extensions.cs
index eb890af..fab1fe4 100644
--- a/Test/MultiAssemblyAddin/Extensions.cs
+++ b/Test/MultiAssemblyAddin/Extensions.cs
@@ -28,7 +28,8 @@ using System;
using UnitTests;
using Mono.Addins;
-[assembly:Addin]
+[assembly:Addin ("MultiAssemblyAddin", Version="0.1.0")]
+[assembly:AddinLocalizer (typeof (SecondAssembly.CustomLocalizerFactory))]
[assembly:AddinDependency ("SimpleApp.Core", "0.1.0")]
[assembly:MultiAssemblyTestExtensionPoint ("main1")]
diff --git a/Test/MultiAssemblyAddin/MultiAssemblyAddin.csproj b/Test/MultiAssemblyAddin/MultiAssemblyAddin.csproj
index b386c0c..a4767c0 100644
--- a/Test/MultiAssemblyAddin/MultiAssemblyAddin.csproj
+++ b/Test/MultiAssemblyAddin/MultiAssemblyAddin.csproj
@@ -47,6 +47,10 @@
<Name>UnitTests</Name>
<Private>False</Private>
</ProjectReference>
+ <ProjectReference Include="SecondAssembly\SecondAssembly.csproj">
+ <Project>{EB38A832-1BA5-4073-910C-7ACC5F1D1AD4}</Project>
+ <Name>SecondAssembly</Name>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project> \ No newline at end of file
diff --git a/Test/MultiAssemblyAddin/SecondAssembly/CustomLocalizerFactory.cs b/Test/MultiAssemblyAddin/SecondAssembly/CustomLocalizerFactory.cs
new file mode 100644
index 0000000..3296d99
--- /dev/null
+++ b/Test/MultiAssemblyAddin/SecondAssembly/CustomLocalizerFactory.cs
@@ -0,0 +1,47 @@
+//
+// CustomLocalizerFactory.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2020 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Addins;
+using Mono.Addins.Localization;
+
+namespace SecondAssembly
+{
+ public class CustomLocalizerFactory : IAddinLocalizerFactory
+ {
+ sealed class Localizer : IAddinLocalizer
+ {
+ public string GetString (string msgid)
+ {
+ return "loc: " + msgid;
+ }
+ }
+
+ public IAddinLocalizer CreateLocalizer (RuntimeAddin addin, NodeElement element)
+ {
+ return new Localizer ();
+ }
+ }
+}
diff --git a/Test/MultiAssemblyAddin/SecondAssembly/SecondAssembly.csproj b/Test/MultiAssemblyAddin/SecondAssembly/SecondAssembly.csproj
index cb0ad11..d99d3cf 100644
--- a/Test/MultiAssemblyAddin/SecondAssembly/SecondAssembly.csproj
+++ b/Test/MultiAssemblyAddin/SecondAssembly/SecondAssembly.csproj
@@ -46,6 +46,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <Compile Include="CustomLocalizerFactory.cs" />
<Compile Include="Extensions.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
diff --git a/Test/UnitTests/TestAddinDescription.cs b/Test/UnitTests/TestAddinDescription.cs
index 02a0bc4..f366d33 100644
--- a/Test/UnitTests/TestAddinDescription.cs
+++ b/Test/UnitTests/TestAddinDescription.cs
@@ -30,6 +30,7 @@ using Mono.Addins.Description;
using System.Globalization;
using Mono.Addins;
using System.Xml;
+using System.Collections.Generic;
namespace UnitTests
{
@@ -125,7 +126,9 @@ namespace UnitTests
System.Threading.Thread.CurrentThread.CurrentCulture = oldc;
}
- [TestCase ("SimpleApp.SystemInfoExtension", "StringResource", "")]
+ [TestCase ("SimpleApp.SystemInfoExtension,0.1.0", "StringResource", "")]
+ [TestCase ("SimpleApp.CommandExtension,0.1.0", "CommandExtension.CustomLocalizerFactory", "CommandExtension, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
+ [TestCase ("MultiAssemblyAddin,0.1.0", "SecondAssembly.CustomLocalizerFactory", "SecondAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
public void LocalizerProperties (string addinId, string expectedType, string expectedAssembly)
{
Addin ad = AddinManager.Registry.GetAddin (addinId);
diff --git a/Test/UnitTests/TestLocalization.cs b/Test/UnitTests/TestLocalization.cs
index a09fa72..ea6e8d6 100644
--- a/Test/UnitTests/TestLocalization.cs
+++ b/Test/UnitTests/TestLocalization.cs
@@ -104,5 +104,15 @@ namespace UnitTests
Assert.AreEqual ("Arxiu d'exemple", node.ToString ());
}
*/
+
+ [TestCase ("SimpleApp.CommandExtension,0.1.0")]
+ [TestCase ("MultiAssemblyAddin,0.1.0")]
+ public void TestLocalizationType (string addinId)
+ {
+ AddinManager.AddinEngine.LoadAddin (null, addinId);
+ var addin = AddinManager.AddinEngine.GetAddin (addinId);
+
+ Assert.AreEqual ("loc: message", addin.Localizer.GetString ("message"));
+ }
}
}