Skip to content
This repository has been archived by the owner on Mar 9, 2021. It is now read-only.

Inheritable for DefaultMemberReflectabilityAttribute #368

Open
wants to merge 2 commits into
base: develop
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
67 changes: 34 additions & 33 deletions Compiler/Saltarelle.Compiler/AttributeStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,58 +16,63 @@ public class AttributeStore : IAttributeStore {
private readonly IErrorReporter _errorReporter;
private readonly Dictionary<IAssembly, AttributeList> _assemblyStore;
private readonly Dictionary<IEntity, AttributeList> _entityStore;
private readonly List<Tuple<IAssembly, PluginAttributeBase>> _assemblyTransformers;
private readonly List<Tuple<IEntity, PluginAttributeBase>> _entityTransformers;

public AttributeStore(ICompilation compilation, IErrorReporter errorReporter) {
_errorReporter = errorReporter;
_assemblyStore = new Dictionary<IAssembly, AttributeList>();
_entityStore = new Dictionary<IEntity, AttributeList>();
_assemblyTransformers = new List<Tuple<IAssembly, PluginAttributeBase>>();
_entityTransformers = new List<Tuple<IEntity, PluginAttributeBase>>();

foreach (var a in compilation.Assemblies) {
ReadAssemblyAttributes(a, _assemblyTransformers);
ReadAssemblyAttributes(a);
}

foreach (var t in compilation.Assemblies.SelectMany(a => TreeTraversal.PostOrder(a.TopLevelTypeDefinitions, t => t.NestedTypes))) {
foreach (var m in t.Methods) {
ReadEntityAttributes(m, _entityTransformers);
ReadEntityAttributes(m);
}
foreach (var p in t.Properties) {
if (p.CanGet)
ReadEntityAttributes(p.Getter, _entityTransformers);
ReadEntityAttributes(p.Getter);
if (p.CanSet)
ReadEntityAttributes(p.Setter, _entityTransformers);
ReadEntityAttributes(p, _entityTransformers);
ReadEntityAttributes(p.Setter);
ReadEntityAttributes(p);
}
foreach (var f in t.Fields) {
ReadEntityAttributes(f, _entityTransformers);
ReadEntityAttributes(f);
}
foreach (var e in t.Events) {
if (e.CanAdd)
ReadEntityAttributes(e.AddAccessor, _entityTransformers);
ReadEntityAttributes(e.AddAccessor);
if (e.CanRemove)
ReadEntityAttributes(e.RemoveAccessor, _entityTransformers);
ReadEntityAttributes(e, _entityTransformers);
ReadEntityAttributes(e.RemoveAccessor);
ReadEntityAttributes(e);
}
ReadEntityAttributes(t, _entityTransformers);
ReadEntityAttributes(t);
}
}

public void RunAttributeCode() {
foreach (var t in _entityTransformers) {
_errorReporter.Region = t.Item1.Region;
t.Item2.ApplyTo(t.Item1, this, _errorReporter);
foreach (var p in _entityStore)
{
_errorReporter.Region = p.Key.Region;
foreach (var a in p.Value)
{
var pab = a as PluginAttributeBase;
if (pab != null)
pab.ApplyTo(p.Key, this, _errorReporter);
}
}

_errorReporter.Region = default(DomRegion);
foreach (var t in _assemblyTransformers) {
t.Item2.ApplyTo(t.Item1, this, _errorReporter);
}

_entityTransformers.Clear();
_assemblyTransformers.Clear();
foreach (var p in _assemblyStore)
{
foreach (var a in p.Value)
{
var pab = a as PluginAttributeBase;
if (pab != null)
pab.ApplyTo(p.Key, this, _errorReporter);
}
}
}

public AttributeList AttributesFor(IAssembly assembly) {
Expand All @@ -82,25 +87,21 @@ public AttributeList AttributesFor(IEntity entity) {
return result;
}

private void ReadAssemblyAttributes(IAssembly assembly, List<Tuple<IAssembly, PluginAttributeBase>> transformers) {
_assemblyStore[assembly] = ReadAttributes(assembly, assembly.AssemblyAttributes, transformers);
private void ReadAssemblyAttributes(IAssembly assembly) {
_assemblyStore[assembly] = ReadAttributes(assembly, assembly.AssemblyAttributes);
}

private void ReadEntityAttributes(IEntity entity, List<Tuple<IEntity, PluginAttributeBase>> transformers) {
_entityStore[entity] = ReadAttributes(entity, entity.Attributes, transformers);
private void ReadEntityAttributes(IEntity entity) {
_entityStore[entity] = ReadAttributes(entity, entity.Attributes);
}

private AttributeList ReadAttributes<T>(T t, IEnumerable<IAttribute> attributes, List<Tuple<T, PluginAttributeBase>> transformers) {
private AttributeList ReadAttributes<T>(T t, IEnumerable<IAttribute> attributes) {
var l = new AttributeList();
foreach (var a in attributes) {
var type = FindType(a.AttributeType);
if (type != null) {
var attr = ReadAttribute(a, type);
var pab = attr as PluginAttributeBase;
l.Add(attr);
if (pab != null) {
transformers.Add(Tuple.Create(t, pab));
}
l.Add(attr);
}
}
return l;
Expand Down
16 changes: 15 additions & 1 deletion Compiler/Saltarelle.Compiler/Driver/CompilerDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,23 @@ private static IEnumerable<IAssemblyResource> LoadResources(IEnumerable<Embedded
return resources.Select(r => new Resource(r.ResourceName, r.Filename, r.IsPublic));
}

private static IEnumerable<ICSharpCode.NRefactory.TypeSystem.ITypeDefinition> GetBaseAndOuterTypeDefinitions(ICSharpCode.NRefactory.TypeSystem.ITypeDefinition t)
{
foreach (var b in t.DirectBaseTypes)
yield return b.GetDefinition();
if (t.DeclaringTypeDefinition != null)
yield return t.DeclaringTypeDefinition;
}

public static IEnumerable<ICSharpCode.NRefactory.TypeSystem.ITypeDefinition> SortTypes(IEnumerable<ICSharpCode.NRefactory.TypeSystem.ITypeDefinition> types)
{
var l = types.ToList();
return TopologicalSorter.TopologicalSort(l, l.SelectMany(GetBaseAndOuterTypeDefinitions, Edge.Create));
}

private void InitializeAttributeStore(AttributeStore attributeStore, WindsorContainer container, ICompilation compilation) {
var assemblies = compilation.Assemblies;
var types = compilation.GetAllTypeDefinitions().ToList();
var types = SortTypes(compilation.GetAllTypeDefinitions()).ToList();
foreach (var applier in container.ResolveAll<IAutomaticMetadataAttributeApplier>()) {
foreach (var a in assemblies)
applier.Process(a);
Expand Down
11 changes: 2 additions & 9 deletions Compiler/Saltarelle.Compiler/IMetadataImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Saltarelle.Compiler.JSModel.TypeSystem;
using Saltarelle.Compiler.ScriptSemantics;
using TopologicalSort;
using Saltarelle.Compiler.Driver;

namespace Saltarelle.Compiler {
public interface IMetadataImporter {
Expand Down Expand Up @@ -116,16 +117,8 @@ public interface IMetadataImporter {
}

public static class MetadataImporterExtensions {
private static IEnumerable<ITypeDefinition> GetBaseAndOuterTypeDefinitions(ITypeDefinition t) {
foreach (var b in t.DirectBaseTypes)
yield return b.GetDefinition();
if (t.DeclaringTypeDefinition != null)
yield return t.DeclaringTypeDefinition;
}

public static void Prepare(this IMetadataImporter md, IEnumerable<ITypeDefinition> types) {
var l = types.ToList();
foreach (var t in TopologicalSorter.TopologicalSort(l, l.SelectMany(GetBaseAndOuterTypeDefinitions, Edge.Create)))
foreach (var t in CompilerDriver.SortTypes(types))
md.Prepare(t);
}
}
Expand Down
1 change: 1 addition & 0 deletions Runtime/CoreLib.Plugin/CoreLib.Plugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<Link>ScriptMetadata.cs</Link>
</Compile>
<Compile Include="DefaultMemberReflectabilityAttribute.cs" />
<Compile Include="InheritDefaultMemberReflectability.cs" />
<Compile Include="Linker.cs" />
<Compile Include="MakeMembersWithScriptableAttributesReflectable.cs" />
<Compile Include="MemberOrderer.cs" />
Expand Down
49 changes: 49 additions & 0 deletions Runtime/CoreLib.Plugin/InheritDefaultMemberReflectability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using ICSharpCode.NRefactory.TypeSystem;
using Saltarelle.Compiler;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;

namespace CoreLib.Plugin
{
public class InheritDefaultMemberReflectability : IAutomaticMetadataAttributeApplier
{
private readonly IAttributeStore _attributeStore;

public InheritDefaultMemberReflectability(IAttributeStore attributeStore)
{
_attributeStore = attributeStore;
}

public void Process(ITypeDefinition type)
{
var attributes = _attributeStore.AttributesFor(type);
if (attributes.HasAttribute<DefaultMemberReflectabilityAttribute>())
return;
var intReflectability = (int)MemberReflectability.None;
foreach (var bt in type.DirectBaseTypes)
{
var btd = bt.GetDefinition();
var attribute = _attributeStore.AttributesFor(btd).GetAttribute<DefaultMemberReflectabilityAttribute>();
if (attribute == null || !attribute.Inheritable)
continue;
intReflectability = Math.Max(intReflectability, (int)attribute.DefaultReflectability);
}
var reflectability = (MemberReflectability)intReflectability;
if (reflectability == MemberReflectability.None)
return;
var a = new DefaultMemberReflectabilityAttribute(reflectability)
{
Inheritable = true
};
attributes.Add(a);
}

public void Process(IAssembly assembly)
{

}
}
}
52 changes: 52 additions & 0 deletions Runtime/CoreLib.TestScript/Reflection/ReflectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,32 @@ public class C28 {
[Reflectable(false)] private int D5;
}

[DefaultMemberReflectability(MemberReflectability.All, Inheritable = true)]
public class C29
{
public int A1;
}

public class C30 : C29
{
public int A2;
}

public class C31 : C30
{
public int A3;
}

public class C32<T> : C29
{
public int A4;
}

public class C33 : C32<int>
{
public int A5;
}

[Test]
public void GetMembersReturnsMethodsWithAnyScriptableAttributeOrReflectableAttribute() {
var methods = typeof(C1).GetMembers();
Expand Down Expand Up @@ -1632,5 +1658,31 @@ public void MembersReflectableAttributeWorks() {
Assert.IsNotNull(c28.GetField("C5"), "C28.C5");
Assert.IsNull (c28.GetField("D5"), "C28.D5");
}

[Test]
public void MembersReflectableAttributeInheritableWorks()
{
var c29 = typeof(C29);
var c30 = typeof(C30);
var c31 = typeof(C31);
var c32 = typeof(C32<int>);
var c33 = typeof(C33);

Assert.IsNotNull(c29.GetField("A1"), "C29.A1");

Assert.IsNotNull(c30.GetField("A1", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy), "C30.A1");
Assert.IsNotNull(c30.GetField("A2"), "C30.A2");

Assert.IsNotNull(c31.GetField("A1", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy), "C31.A1");
Assert.IsNotNull(c31.GetField("A2", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy), "C31.A2");
Assert.IsNotNull(c31.GetField("A3"), "C31.A3");

Assert.IsNotNull(c32.GetField("A1", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy), "C32.A1");
Assert.IsNotNull(c32.GetField("A4"), "C32.A4");

Assert.IsNotNull(c33.GetField("A1", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy), "C33.A1");
Assert.IsNotNull(c33.GetField("A4", BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy), "C33.A4");
Assert.IsNotNull(c33.GetField("A5"), "C33.A5");
}
}
}
1 change: 1 addition & 0 deletions Runtime/CoreLib/ScriptMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ public sealed partial class DefaultMemberReflectabilityAttribute :
#endif
{
public MemberReflectability DefaultReflectability { get; private set; }
public bool Inheritable { get; set; }

public DefaultMemberReflectabilityAttribute(MemberReflectability defaultReflectability) {
DefaultReflectability = defaultReflectability;
Expand Down