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.ClassId;
021    import org.jetbrains.jet.lang.resolve.name.FqName;
022    
023    public class JvmClassName {
024        @NotNull
025        public static JvmClassName byInternalName(@NotNull String internalName) {
026            return new JvmClassName(internalName);
027        }
028    
029        @NotNull
030        public static JvmClassName byClassId(@NotNull ClassId classId) {
031            FqName packageFqName = classId.getPackageFqName();
032            String relativeClassName = classId.getRelativeClassName().asString().replace('.', '$');
033            return packageFqName.isRoot()
034                   ? new JvmClassName(relativeClassName)
035                   : new JvmClassName(packageFqName.asString().replace('.', '/') + "/" + relativeClassName);
036        }
037    
038        /**
039         * WARNING: fq name cannot be uniquely mapped to JVM class name.
040         */
041        @NotNull
042        public static JvmClassName byFqNameWithoutInnerClasses(@NotNull FqName fqName) {
043            JvmClassName r = new JvmClassName(fqName.asString().replace('.', '/'));
044            r.fqName = fqName;
045            return r;
046        }
047    
048        @NotNull
049        public static JvmClassName byFqNameWithoutInnerClasses(@NotNull String fqName) {
050            return byFqNameWithoutInnerClasses(new FqName(fqName));
051        }
052    
053        private final static String CLASS_OBJECT_REPLACE_GUARD = "<class_object>";
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.CLASS_OBJECT_CLASS_NAME, CLASS_OBJECT_REPLACE_GUARD)
074                        .replace(JvmAbi.TRAIT_IMPL_CLASS_NAME, TRAIT_IMPL_REPLACE_GUARD)
075                        .replace('$', '.')
076                        .replace('/', '.')
077                        .replace(TRAIT_IMPL_REPLACE_GUARD, JvmAbi.TRAIT_IMPL_CLASS_NAME)
078                        .replace(CLASS_OBJECT_REPLACE_GUARD, JvmAbi.CLASS_OBJECT_CLASS_NAME);
079                this.fqName = new FqName(fqName);
080            }
081            return fqName;
082        }
083    
084        @NotNull
085        public FqName getPackageFqName() {
086            int lastSlash = internalName.lastIndexOf("/");
087            if (lastSlash == -1) return FqName.ROOT;
088            return new FqName(internalName.substring(0, lastSlash).replace('/', '.'));
089        }
090    
091        @NotNull
092        public String getInternalName() {
093            return internalName;
094        }
095    
096        @Override
097        public String toString() {
098            return internalName;
099        }
100    
101        @Override
102        public boolean equals(Object o) {
103            if (this == o) return true;
104            if (o == null || getClass() != o.getClass()) return false;
105            return internalName.equals(((JvmClassName) o).internalName);
106        }
107    
108        @Override
109        public int hashCode() {
110            return internalName.hashCode();
111        }
112    }