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 }