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.load.kotlin;
018
019 import com.intellij.openapi.util.Condition;
020 import com.intellij.openapi.util.io.FileUtil;
021 import com.intellij.openapi.vfs.VirtualFile;
022 import com.intellij.util.PathUtil;
023 import com.intellij.util.containers.ContainerUtil;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
026 import org.jetbrains.kotlin.name.FqName;
027 import org.jetbrains.kotlin.name.Name;
028 import org.jetbrains.kotlin.psi.JetDeclaration;
029 import org.jetbrains.kotlin.psi.JetFile;
030 import org.jetbrains.kotlin.psi.JetNamedFunction;
031 import org.jetbrains.kotlin.psi.JetProperty;
032 import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
033 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
034 import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf;
035 import org.jetbrains.org.objectweb.asm.Type;
036
037 import java.util.Collection;
038 import java.util.List;
039
040 import static org.jetbrains.kotlin.load.kotlin.PackageClassUtils.getPackageClassFqName;
041
042 public class PackagePartClassUtils {
043 public static int getPathHashCode(@NotNull VirtualFile file) {
044 // Conversion to system-dependent name seems to be unnecessary, but it's hard to check now:
045 // it was introduced when fixing KT-2839, which appeared again (KT-3639).
046 // If you try to remove it, run tests on Windows.
047 return FileUtil.toSystemDependentName(file.getPath()).hashCode();
048 }
049
050 @NotNull
051 private static String replaceSpecialSymbols(@NotNull String str) {
052 return str.replace('.', '_');
053 }
054
055 @NotNull
056 public static FqName getPackagePartFqName(@NotNull FqName facadeFqName, @NotNull VirtualFile file) {
057 String fileName = FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.getName()));
058
059 // path hashCode to prevent same name / different path collision
060 String srcName = String.format(
061 "%s$%s$%08x",
062 facadeFqName.shortName().asString(),
063 replaceSpecialSymbols(fileName),
064 getPathHashCode(file)
065 );
066
067 return facadeFqName.parent().child(Name.identifier(srcName));
068 }
069
070 @NotNull
071 public static Type getPackagePartType(@NotNull JetFile file) {
072 return Type.getObjectType(getPackagePartInternalName(file));
073 }
074
075 @NotNull
076 public static String getPackagePartInternalName(@NotNull JetFile file) {
077 FqName fqName = getPackagePartFqName(file);
078 return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
079 }
080
081 @NotNull
082 public static FqName getPackagePartFqName(@NotNull JetFile file) {
083 return getPackagePartFqName(getPackageClassFqName(file.getPackageFqName()), file.getVirtualFile());
084 }
085
086 @NotNull
087 public static FqName getPackagePartFqName(@NotNull DeserializedCallableMemberDescriptor callable) {
088 FqName packageFqName = ((PackageFragmentDescriptor) callable.getContainingDeclaration()).getFqName();
089 return packageFqName.child(callable.getNameResolver().getName(callable.getProto().getExtension(JvmProtoBuf.implClassName)));
090 }
091
092 @NotNull
093 public static List<JetFile> getPackageFilesWithCallables(@NotNull Collection<JetFile> packageFiles) {
094 return ContainerUtil.filter(packageFiles, new Condition<JetFile>() {
095 @Override
096 public boolean value(JetFile packageFile) {
097 return fileHasCallables(packageFile);
098 }
099 });
100 }
101
102 public static boolean fileHasCallables(@NotNull JetFile file) {
103 for (JetDeclaration declaration : file.getDeclarations()) {
104 if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
105 return true;
106 }
107 }
108 return false;
109 }
110
111 }