diff options
author | jfrijters <jfrijters> | 2013-08-07 10:16:48 +0400 |
---|---|---|
committer | jfrijters <jfrijters> | 2013-08-07 10:16:48 +0400 |
commit | 71193b82e8a3029e2acc8413ac032b17bfdae1d0 (patch) | |
tree | f858686a3c9f8ebaa888353bd45feae2b1abaf44 | |
parent | bf04f25dc09a5811abc7a7670c8c3503ea6982ba (diff) |
Compile anonymous and local classes as nested types.
-rw-r--r-- | runtime/DynamicTypeWrapper.cs | 39 | ||||
-rw-r--r-- | runtime/TypeWrapper.cs | 27 |
2 files changed, 53 insertions, 13 deletions
diff --git a/runtime/DynamicTypeWrapper.cs b/runtime/DynamicTypeWrapper.cs index 57825982..f1692b3b 100644 --- a/runtime/DynamicTypeWrapper.cs +++ b/runtime/DynamicTypeWrapper.cs @@ -610,16 +610,24 @@ namespace IKVM.Internal bool cantNest = false; bool setModifiers = false; TypeBuilder enclosing = null; + string enclosingClassName = null; // we only compile inner classes as nested types in the static compiler, because it has a higher cost // and doesn't buy us anything in dynamic mode (and if fact, due to an FXBUG it would make handling // the TypeResolve event very hard) ClassFile.InnerClass outerClass = getOuterClass(); if (outerClass.outerClass != 0) { - string enclosingClassName = classFile.GetConstantPoolClass(outerClass.outerClass); + enclosingClassName = classFile.GetConstantPoolClass(outerClass.outerClass); + } + else if (f.EnclosingMethod != null) + { + enclosingClassName = f.EnclosingMethod[0]; + } + if (enclosingClassName != null) + { if (!CheckInnerOuterNames(f.Name, enclosingClassName)) { - Tracer.Warning(Tracer.Compiler, "Incorrect InnerClasses attribute on {0}", f.Name); + Tracer.Warning(Tracer.Compiler, "Incorrect {0} attribute on {1}", outerClass.outerClass != 0 ? "InnerClasses" : "EnclosingMethod", f.Name); } else { @@ -636,7 +644,7 @@ namespace IKVM.Internal // make sure the relationship is reciprocal (otherwise we run the risk of // baking the outer type before the inner type) and that the inner and outer // class live in the same class loader (when doing a multi target compilation, - // it is possible to split the two classes acros assemblies) + // it is possible to split the two classes across assemblies) JavaTypeImpl oimpl = enclosingClassWrapper.impl as JavaTypeImpl; if (oimpl != null && enclosingClassWrapper.GetClassLoader() == wrapper.GetClassLoader()) { @@ -651,8 +659,8 @@ namespace IKVM.Internal bool ok = false; for (int i = 0; i < outerInnerClasses.Length; i++) { - if (outerInnerClasses[i].outerClass != 0 - && outerClassFile.GetConstantPoolClass(outerInnerClasses[i].outerClass) == outerClassFile.Name + if (((outerInnerClasses[i].outerClass != 0 && outerClassFile.GetConstantPoolClass(outerInnerClasses[i].outerClass) == outerClassFile.Name) + || (outerInnerClasses[i].outerClass == 0 && outerClass.outerClass == 0)) && outerInnerClasses[i].innerClass != 0 && outerClassFile.GetConstantPoolClass(outerInnerClasses[i].innerClass) == f.Name) { @@ -674,6 +682,11 @@ namespace IKVM.Internal { enclosingClassWrapper.CreateStep2(); enclosing = oimpl.typeBuilder; + if (outerClass.outerClass == 0) + { + // we need to record that we're not an inner classes, but an enclosed class + typeAttribs |= TypeAttributes.SpecialName; + } } else { @@ -772,14 +785,16 @@ namespace IKVM.Internal // When we're statically compiling, we associate the typeBuilder with the wrapper. This enables types in referenced assemblies to refer back to // types that we're currently compiling (i.e. a cyclic dependency between the currently assembly we're compiling and a referenced assembly). wrapper.GetClassLoader().SetWrapperForType(typeBuilder, wrapper); - if (enclosing != null && cantNest) - { - AttributeHelper.SetNonNestedOuterClass(typeBuilder, enclosingClassWrapper.Name); - AttributeHelper.SetNonNestedInnerClass(enclosing, f.Name); - } - if (outerClass.outerClass != 0 && enclosing == null) + if (outerClass.outerClass != 0) { - AttributeHelper.SetNonNestedOuterClass(typeBuilder, classFile.GetConstantPoolClass(outerClass.outerClass)); + if (enclosing != null && cantNest) + { + AttributeHelper.SetNonNestedInnerClass(enclosing, f.Name); + } + if (enclosing == null || cantNest) + { + AttributeHelper.SetNonNestedOuterClass(typeBuilder, enclosingClassName); + } } if (classFile.InnerClasses != null) { diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index e0aa3768..68c4cc74 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -1107,6 +1107,11 @@ namespace IKVM.Internal return type.IsDefined(typeofNoPackagePrefixAttribute, false) || type.Assembly.IsDefined(typeofNoPackagePrefixAttribute, false); } + internal static bool HasEnclosingMethodAttribute(Type type) + { + return type.IsDefined(typeofEnclosingMethodAttribute, false); + } + internal static EnclosingMethodAttribute GetEnclosingMethodAttribute(Type type) { #if !STATIC_COMPILER && !STUB_GENERATOR @@ -3878,6 +3883,18 @@ namespace IKVM.Internal return interfaceWrappers; } + private static bool IsNestedTypeAnonymousOrLocalClass(Type type) + { + switch (type.Attributes & (TypeAttributes.SpecialName | TypeAttributes.VisibilityMask)) + { + case TypeAttributes.SpecialName | TypeAttributes.NestedPublic: + case TypeAttributes.SpecialName | TypeAttributes.NestedAssembly: + return AttributeHelper.HasEnclosingMethodAttribute(type); + default: + return false; + } + } + internal override TypeWrapper[] InnerClasses { get @@ -3894,7 +3911,7 @@ namespace IKVM.Internal // (we can't put a HideFromJavaAttribute on it, because we do want the class to be visible as a $Proxy) continue; } - if(!AttributeHelper.IsHideFromJava(nestedTypes[i])) + if(!IsNestedTypeAnonymousOrLocalClass(nestedTypes[i]) && !AttributeHelper.IsHideFromJava(nestedTypes[i])) { wrappers.Add(ClassLoaderWrapper.GetWrapperFromType(nestedTypes[i])); } @@ -3911,6 +3928,10 @@ namespace IKVM.Internal { get { + if(IsNestedTypeAnonymousOrLocalClass(type)) + { + return null; + } Type declaringType = type.DeclaringType; if(declaringType != null) { @@ -4848,6 +4869,10 @@ namespace IKVM.Internal { return DeclaringTypeWrapper.GetSourceFileName(); } + if(IsNestedTypeAnonymousOrLocalClass(type)) + { + return ClassLoaderWrapper.GetWrapperFromType(type.DeclaringType).GetSourceFileName(); + } if(type.Module.IsDefined(typeof(SourceFileAttribute), false)) { return type.Name + ".java"; |