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.lazy;
018
019 import com.google.common.base.Predicate;
020 import com.google.common.base.Predicates;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.descriptors.ClassDescriptor;
024 import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
025 import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
026 import org.jetbrains.kotlin.descriptors.PackageViewDescriptor;
027 import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
028 import org.jetbrains.kotlin.name.*;
029 import org.jetbrains.kotlin.psi.KtNamedDeclaration;
030 import org.jetbrains.kotlin.psi.KtNamedDeclarationUtil;
031 import org.jetbrains.kotlin.resolve.scopes.MemberScope;
032
033 import java.util.ArrayList;
034 import java.util.Collection;
035 import java.util.Collections;
036
037 public class ResolveSessionUtils {
038
039 private ResolveSessionUtils() {
040 }
041
042 @NotNull
043 public static Collection<ClassDescriptor> getClassDescriptorsByFqName(@NotNull ModuleDescriptor module, @NotNull FqName fqName) {
044 return getClassOrObjectDescriptorsByFqName(module, fqName, Predicates.<ClassDescriptor>alwaysTrue());
045 }
046
047 @NotNull
048 public static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
049 @NotNull ModuleDescriptor module,
050 @NotNull FqName fqName,
051 @NotNull Predicate<ClassDescriptor> filter
052 ) {
053 if (fqName.isRoot()) return Collections.emptyList();
054
055 Collection<ClassDescriptor> result = new ArrayList<ClassDescriptor>(1);
056
057 FqName packageFqName = fqName.parent();
058 while (true) {
059 PackageViewDescriptor packageDescriptor = module.getPackage(packageFqName);
060 if (!packageDescriptor.isEmpty()) {
061 FqName relativeClassFqName = FqNamesUtilKt.tail(fqName, packageFqName);
062 ClassDescriptor classDescriptor = findClassByRelativePath(packageDescriptor.getMemberScope(), relativeClassFqName);
063 if (classDescriptor != null && filter.apply(classDescriptor)) {
064 result.add(classDescriptor);
065 }
066 }
067
068 if (packageFqName.isRoot()) {
069 break;
070 }
071
072 packageFqName = packageFqName.parent();
073 }
074
075 return result;
076 }
077
078 @Nullable
079 public static ClassDescriptor findClassByRelativePath(@NotNull MemberScope packageScope, @NotNull FqName path) {
080 if (path.isRoot()) return null;
081
082 MemberScope scope = packageScope;
083 ClassifierDescriptor classifier = null;
084 for (Name name : path.pathSegments()) {
085 classifier = scope.getContributedClassifier(name, NoLookupLocation.WHEN_FIND_BY_FQNAME);
086 if (!(classifier instanceof ClassDescriptor)) return null;
087 scope = ((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope();
088 }
089
090 return (ClassDescriptor) classifier;
091 }
092
093 @NotNull
094 public static Name safeNameForLazyResolve(@NotNull KtNamedDeclaration declaration) {
095 return safeNameForLazyResolve(declaration.getNameAsName());
096 }
097
098 @NotNull
099 public static Name safeNameForLazyResolve(@Nullable Name name) {
100 return SpecialNames.safeIdentifier(name);
101 }
102
103 @Nullable
104 public static FqName safeFqNameForLazyResolve(@NotNull KtNamedDeclaration declaration) {
105 //NOTE: should only create special names for package level declarations, so we can safely rely on real fq name for parent
106 FqName parentFqName = KtNamedDeclarationUtil.getParentFqName(declaration);
107 return parentFqName != null ? parentFqName.child(safeNameForLazyResolve(declaration)) : null;
108 }
109 }