001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.jvm;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.kotlin.load.java.JvmAbi;
021    import org.jetbrains.kotlin.name.ClassId;
022    import org.jetbrains.kotlin.name.FqName;
023    
024    public class JvmClassName {
025        @NotNull
026        public static JvmClassName byInternalName(@NotNull String internalName) {
027            return new JvmClassName(internalName);
028        }
029    
030        @NotNull
031        public static JvmClassName byClassId(@NotNull ClassId classId) {
032            FqName packageFqName = classId.getPackageFqName();
033            String relativeClassName = classId.getRelativeClassName().asString().replace('.', '$');
034            return packageFqName.isRoot()
035                   ? new JvmClassName(relativeClassName)
036                   : new JvmClassName(packageFqName.asString().replace('.', '/') + "/" + relativeClassName);
037        }
038    
039        /**
040         * WARNING: fq name cannot be uniquely mapped to JVM class name.
041         */
042        @NotNull
043        public static JvmClassName byFqNameWithoutInnerClasses(@NotNull FqName fqName) {
044            JvmClassName r = new JvmClassName(fqName.asString().replace('.', '/'));
045            r.fqName = fqName;
046            return r;
047        }
048    
049        @NotNull
050        public static JvmClassName byFqNameWithoutInnerClasses(@NotNull String fqName) {
051            return byFqNameWithoutInnerClasses(new FqName(fqName));
052        }
053    
054        private final static String TRAIT_IMPL_REPLACE_GUARD = "<trait_impl>";
055    
056        // Internal name:  kotlin/Map$Entry
057        // FqName:         kotlin.Map.Entry
058    
059        private final String internalName;
060        private FqName fqName;
061    
062        private JvmClassName(@NotNull String internalName) {
063            this.internalName = internalName;
064        }
065    
066        /**
067         * WARNING: internal name cannot be converted to FQ name for a class which contains dollars in the name
068         */
069        @NotNull
070        public FqName getFqNameForClassNameWithoutDollars() {
071            if (fqName == null) {
072                String fqName = internalName
073                        .replace(JvmAbi.TRAIT_IMPL_CLASS_NAME, TRAIT_IMPL_REPLACE_GUARD)
074                        .replace('$', '.')
075                        .replace('/', '.')
076                        .replace(TRAIT_IMPL_REPLACE_GUARD, JvmAbi.TRAIT_IMPL_CLASS_NAME);
077                this.fqName = new FqName(fqName);
078            }
079            return fqName;
080        }
081    
082        @NotNull
083        public FqName getPackageFqName() {
084            int lastSlash = internalName.lastIndexOf("/");
085            if (lastSlash == -1) return FqName.ROOT;
086            return new FqName(internalName.substring(0, lastSlash).replace('/', '.'));
087        }
088    
089        @NotNull
090        public String getInternalName() {
091            return internalName;
092        }
093    
094        @Override
095        public String toString() {
096            return internalName;
097        }
098    
099        @Override
100        public boolean equals(Object o) {
101            if (this == o) return true;
102            if (o == null || getClass() != o.getClass()) return false;
103            return internalName.equals(((JvmClassName) o).internalName);
104        }
105    
106        @Override
107        public int hashCode() {
108            return internalName.hashCode();
109        }
110    }