diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java index 32e489b5b69..54f4917eac8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java @@ -375,7 +375,7 @@ public class JetTypeMapper extends BindingTraceAware { JvmClassName jvmClassName = JvmClassName.byType(asmType); if (JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmClassName.getFqName()).size() > 1) { - return JvmClassName.byClassDescriptor(descriptor).getInternalName(); + return JvmClassName.byClassDescriptor(descriptor).getSignatureName(); } return null; } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java index 45c9e33d8ba..8dadf73f576 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java @@ -89,13 +89,10 @@ public abstract class JetTypeJetSignatureReader extends JetSignatureExceptionsAd private List typeArguments; @Override - public void visitClassType(String name, boolean nullable, boolean forceReal) { - FqName ourName = new FqName(name - .replace('/', '.') - .replace('$', '.') // TODO: not sure - ); + public void visitClassType(String signatureName, boolean nullable, boolean forceReal) { + FqName fqName = JvmClassName.bySignatureName(signatureName).getFqName(); - enterClass(resolveClassDescriptorByFqName(ourName, forceReal), ourName.getFqName(), nullable); + enterClass(resolveClassDescriptorByFqName(fqName, forceReal), fqName.getFqName(), nullable); } private void enterClass(@Nullable ClassDescriptor classDescriptor, @NotNull String className, boolean nullable) { @@ -136,15 +133,12 @@ public abstract class JetTypeJetSignatureReader extends JetSignatureExceptionsAd @Override public void visitInnerClassType(String signatureName, boolean nullable, boolean forceReal) { - int index = signatureName.lastIndexOf("."); - String outerSignatureName = signatureName.substring(0, index); - String innerName = signatureName.substring(index + 1); - - FqName outerFqName = new FqName(outerSignatureName.replace('/', '.')); - ClassDescriptor descriptor = resolveClassDescriptorByFqName(outerFqName, forceReal); - - ClassDescriptor innerClassDescriptor = descriptor != null ? DescriptorUtils.getInnerClassByName(descriptor, innerName) : null; - enterClass(innerClassDescriptor, signatureName, nullable); + JvmClassName jvmClassName = JvmClassName.bySignatureName(signatureName); + ClassDescriptor descriptor = resolveClassDescriptorByFqName(jvmClassName.getOuterClassFqName(), forceReal); + for (String innerClassName : jvmClassName.getInnerClassNameList()) { + descriptor = descriptor != null ? DescriptorUtils.getInnerClassByName(descriptor, innerClassName) : null; + } + enterClass(descriptor, signatureName, nullable); } private static Variance parseVariance(JetSignatureVariance variance) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmClassName.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmClassName.java index 99b7ed9eec8..4eb4fcc1dff 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmClassName.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmClassName.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.collect.Lists; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Type; @@ -25,6 +26,8 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.name.FqName; +import java.util.List; + /** * @author Stepan Koltsov */ @@ -49,7 +52,7 @@ public class JvmClassName { */ @NotNull public static JvmClassName byFqNameWithoutInnerClasses(@NotNull FqName fqName) { - JvmClassName r = new JvmClassName(fqName.getFqName().replace('.', '/')); + JvmClassName r = new JvmClassName(fqNameToInternalName(fqName)); r.fqName = fqName; return r; } @@ -59,6 +62,13 @@ public class JvmClassName { return byFqNameWithoutInnerClasses(new FqName(fqName)); } + @NotNull + public static JvmClassName bySignatureName(@NotNull String signatureName) { + JvmClassName className = new JvmClassName(signatureNameToInternalName(signatureName)); + className.signatureName = signatureName; + return className; + } + private static String encodeSpecialNames(String str) { String encodedObjectNames = StringUtil.replace(str, JvmAbi.CLASS_OBJECT_CLASS_NAME, CLASS_OBJECT_REPLACE_GUARD); return StringUtil.replace(encodedObjectNames, JvmAbi.TRAIT_IMPL_CLASS_NAME, TRAIT_IMPL_REPLACE_GUARD); @@ -70,25 +80,66 @@ public class JvmClassName { } @NotNull - public static JvmClassName byClassDescriptor(@NotNull ClassifierDescriptor classDescriptor) { - //todo inner inner classes - DeclarationDescriptor containingDeclaration = classDescriptor.getContainingDeclaration(); + private static JvmClassName byFqNameAndInnerClassList(@NotNull FqName fqName, @NotNull List innerClassList) { + String outerClassName = fqNameToInternalName(fqName); + StringBuilder sb = new StringBuilder(outerClassName); + for (String innerClassName : innerClassList) { + sb.append("$").append(innerClassName); + } + return new JvmClassName(sb.toString()); + } - if (!(containingDeclaration instanceof ClassDescriptor)) { - return byFqNameWithoutInnerClasses(DescriptorUtils.getFQName(classDescriptor).toSafe()); + @NotNull + public static JvmClassName byClassDescriptor(@NotNull ClassifierDescriptor classDescriptor) { + DeclarationDescriptor descriptor = classDescriptor; + + List innerClassNames = Lists.newArrayList(); + while (descriptor.getContainingDeclaration() instanceof ClassDescriptor) { + innerClassNames.add(descriptor.getName().getName()); + descriptor = descriptor.getContainingDeclaration(); + assert descriptor != null; } - String fqName = DescriptorUtils.getFQName(containingDeclaration).getFqName(); - return new JvmClassName(fqName.replace('.', '/') + "." + classDescriptor.getName()); + return byFqNameAndInnerClassList(DescriptorUtils.getFQName(descriptor).toSafe(), innerClassNames); } + @NotNull + private static String fqNameToInternalName(@NotNull FqName fqName) { + return fqName.getFqName().replace('.', '/'); + } + + @NotNull + private static String signatureNameToInternalName(@NotNull String signatureName) { + return signatureName.replace('.', '$'); + } + + @NotNull + private static String internalNameToFqName(@NotNull String name) { + return decodeSpecialNames(encodeSpecialNames(name).replace('$', '.').replace('/', '.')); + } + + @NotNull + private static String internalNameToSignatureName(@NotNull String name) { + return decodeSpecialNames(encodeSpecialNames(name).replace('$', '.')); + } + + @NotNull + private static String signatureNameToFqName(@NotNull String name) { + return name.replace('/', '.'); + } + + private final static String CLASS_OBJECT_REPLACE_GUARD = ""; private final static String TRAIT_IMPL_REPLACE_GUARD = ""; - @NotNull + // Internal name: jet/Map$Entry + // FqName: jet.Map.Entry + // Signature name: jet/Map.Entry + private final String internalName; private FqName fqName; private String descriptor; + private String signatureName; private Type asmType; @@ -99,7 +150,7 @@ public class JvmClassName { @NotNull public FqName getFqName() { if (fqName == null) { - this.fqName = new FqName(decodeSpecialNames(encodeSpecialNames(internalName).replace('$', '.').replace('/', '.'))); + this.fqName = new FqName(internalNameToFqName(internalName)); } return fqName; } @@ -129,6 +180,36 @@ public class JvmClassName { return asmType; } + @NotNull + public String getSignatureName() { + if (signatureName == null) { + signatureName = internalNameToSignatureName(internalName); + } + return signatureName; + } + + @NotNull + public FqName getOuterClassFqName() { + String signatureName = getSignatureName(); + int index = signatureName.indexOf('.'); + String outerClassName = index != -1 ? signatureName.substring(0, index) : signatureName; + return new FqName(signatureNameToFqName(outerClassName)); + } + + @NotNull + public List getInnerClassNameList() { + List innerClassList = Lists.newArrayList(); + String signatureName = getSignatureName(); + int index = signatureName.indexOf('.'); + while (index != -1) { + int nextIndex = signatureName.indexOf('.', index + 1); + String innerClassName = nextIndex != -1 ? signatureName.substring(index + 1, nextIndex) : signatureName.substring(index + 1); + innerClassList.add(innerClassName); + index = nextIndex; + } + return innerClassList; + } + @Override public String toString() { return getInternalName(); diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/JvmClassNameTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/JvmClassNameTest.java new file mode 100644 index 00000000000..923be922b1e --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/JvmClassNameTest.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.jvm.compiler; + +import com.google.common.collect.Lists; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author svtk + */ +public class JvmClassNameTest { + @Test + public void signatureName() { + testSignatureName("jet/Map", "jet/Map", "jet.Map", "jet.Map", Collections.emptyList()); + } + + @Test + public void signatureNameOfInnerClass() { + testSignatureName("jet/Map.Entry", "jet/Map$Entry", "jet.Map.Entry", "jet.Map", Lists.newArrayList("Entry")); + } + + @Test + public void signatureNameOfDeepInnerClass() { + testSignatureName("jet/Map.Entry.AAA", "jet/Map$Entry$AAA", "jet.Map.Entry.AAA", "jet.Map", Lists.newArrayList("Entry", "AAA")); + } + + @Test + public void simpleName() { + testSignatureName("jet", "jet", "jet", "jet", Collections.emptyList()); + } + + @Test + public void incorrectSignature() { + testSignatureName("jet/Map.", "jet/Map$", "jet.Map.", "jet.Map", Lists.newArrayList("")); + + } + + private static void testSignatureName( + String className, + String innerClassName, + String fqName, + String outerClassName, + List innerClassNameList + ) { + JvmClassName mapEntryName = JvmClassName.bySignatureName(className); + assertEquals(innerClassName, mapEntryName.getInternalName()); + assertEquals(fqName, mapEntryName.getFqName().getFqName()); + assertEquals(outerClassName, mapEntryName.getOuterClassFqName().getFqName()); + assertEquals(innerClassNameList, mapEntryName.getInnerClassNameList()); + } +}