001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.resolve.java;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.jet.lang.resolve.name.FqName;
021 import org.jetbrains.jet.lang.resolve.name.Name;
022
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.List;
026
027 public class JvmClassName {
028 @NotNull
029 public static JvmClassName byInternalName(@NotNull String internalName) {
030 return new JvmClassName(internalName);
031 }
032
033 /**
034 * WARNING: fq name cannot be uniquely mapped to JVM class name.
035 */
036 @NotNull
037 public static JvmClassName byFqNameWithoutInnerClasses(@NotNull FqName fqName) {
038 JvmClassName r = new JvmClassName(fqName.asString().replace('.', '/'));
039 r.fqName = fqName;
040 return r;
041 }
042
043 @NotNull
044 public static JvmClassName byFqNameWithoutInnerClasses(@NotNull String fqName) {
045 return byFqNameWithoutInnerClasses(new FqName(fqName));
046 }
047
048 private final static String CLASS_OBJECT_REPLACE_GUARD = "<class_object>";
049 private final static String TRAIT_IMPL_REPLACE_GUARD = "<trait_impl>";
050
051 // Internal name: kotlin/Map$Entry
052 // FqName: kotlin.Map.Entry
053
054 private final String internalName;
055 private FqName fqName;
056
057 private JvmClassName(@NotNull String internalName) {
058 this.internalName = internalName;
059 }
060
061 /**
062 * WARNING: internal name cannot be converted to FQ name for a class which contains dollars in the name
063 */
064 @NotNull
065 public FqName getFqNameForClassNameWithoutDollars() {
066 if (fqName == null) {
067 String fqName = internalName
068 .replace(JvmAbi.CLASS_OBJECT_CLASS_NAME, CLASS_OBJECT_REPLACE_GUARD)
069 .replace(JvmAbi.TRAIT_IMPL_CLASS_NAME, TRAIT_IMPL_REPLACE_GUARD)
070 .replace('$', '.')
071 .replace('/', '.')
072 .replace(TRAIT_IMPL_REPLACE_GUARD, JvmAbi.TRAIT_IMPL_CLASS_NAME)
073 .replace(CLASS_OBJECT_REPLACE_GUARD, JvmAbi.CLASS_OBJECT_CLASS_NAME);
074 this.fqName = new FqName(fqName);
075 }
076 return fqName;
077 }
078
079 @NotNull
080 public String getInternalName() {
081 return internalName;
082 }
083
084 @NotNull
085 public FqName getPackageFqName() {
086 int packageNameEnd = internalName.lastIndexOf("/");
087 if (packageNameEnd == -1) {
088 return FqName.ROOT;
089 }
090 return FqName.fromSegments(Arrays.asList(internalName.substring(0, packageNameEnd).split("/")));
091 }
092
093 @NotNull
094 public FqName getHeuristicClassFqName() {
095 String name = internalName.substring(internalName.lastIndexOf("/") + 1);
096 char[] chars = name.toCharArray();
097 //treat all 'stand-alone' dollars as dots, except for last and first char of class name
098 for (int i = 1; i < chars.length - 1; ++i) {
099 if (name.charAt(i) == '$' && name.charAt(i - 1) != '$' && name.charAt(i + 1) != '$') {
100 chars[i] = '.';
101 }
102 }
103 return new FqName(new String(chars));
104 }
105
106 @Override
107 public String toString() {
108 return internalName;
109 }
110
111 @Override
112 public boolean equals(Object o) {
113 if (this == o) return true;
114 if (o == null || getClass() != o.getClass()) return false;
115 return internalName.equals(((JvmClassName) o).internalName);
116 }
117
118 @Override
119 public int hashCode() {
120 return internalName.hashCode();
121 }
122 }