001 /*
002 * Copyright 2010-2014 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.lazy;
018
019 import com.google.common.base.Predicate;
020 import com.google.common.base.Predicates;
021 import com.google.common.collect.Lists;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
025 import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
026 import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
027 import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
028 import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
029 import org.jetbrains.jet.lang.psi.JetNamedDeclarationUtil;
030 import org.jetbrains.jet.lang.resolve.name.FqName;
031 import org.jetbrains.jet.lang.resolve.name.Name;
032 import org.jetbrains.jet.lang.resolve.name.NamePackage;
033 import org.jetbrains.jet.lang.resolve.name.SpecialNames;
034 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
035
036 import java.util.Collection;
037 import java.util.Collections;
038
039 public class ResolveSessionUtils {
040
041 public static final Predicate<ClassDescriptor> NON_SINGLETON_FILTER = new Predicate<ClassDescriptor>() {
042 @Override
043 public boolean apply(@Nullable ClassDescriptor descriptor) {
044 assert descriptor != null;
045 return !descriptor.getKind().isSingleton();
046 }
047 };
048
049 public static final Predicate<ClassDescriptor> SINGLETON_FILTER = new Predicate<ClassDescriptor>() {
050 @Override
051 public boolean apply(@Nullable ClassDescriptor descriptor) {
052 assert descriptor != null;
053 return descriptor.getKind().isSingleton();
054 }
055 };
056
057 private ResolveSessionUtils() {
058 }
059
060 @NotNull
061 public static Collection<ClassDescriptor> getClassDescriptorsByFqName(@NotNull ModuleDescriptor moduleDescriptor, @NotNull FqName fqName) {
062 return getClassOrObjectDescriptorsByFqName(moduleDescriptor, fqName, NON_SINGLETON_FILTER);
063 }
064
065 @NotNull
066 public static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
067 @NotNull ModuleDescriptor moduleDescriptor,
068 @NotNull FqName fqName,
069 @NotNull Predicate<ClassDescriptor> filter
070 ) {
071 if (fqName.isRoot()) return Collections.emptyList();
072
073 Collection<ClassDescriptor> classDescriptors = Lists.newArrayList();
074
075 FqName packageFqName = fqName.parent();
076 while (true) {
077 PackageViewDescriptor packageDescriptor = moduleDescriptor.getPackage(packageFqName);
078 if (packageDescriptor != null) {
079 FqName classInPackagePath = NamePackage.tail(fqName, packageFqName);
080 ClassDescriptor classDescriptor = findByQualifiedName(packageDescriptor.getMemberScope(), classInPackagePath, filter);
081 if (classDescriptor != null) {
082 classDescriptors.add(classDescriptor);
083 }
084 }
085
086 if (packageFqName.isRoot()) {
087 break;
088 }
089 else {
090 packageFqName = packageFqName.parent();
091 }
092 }
093
094 return classDescriptors;
095 }
096
097 @Nullable
098 public static ClassDescriptor findByQualifiedName(@NotNull JetScope packageScope, @NotNull FqName path) {
099 return findByQualifiedName(packageScope, path, Predicates.<ClassDescriptor>alwaysTrue());
100 }
101
102 @Nullable
103 private static ClassDescriptor findByQualifiedName(
104 @NotNull JetScope jetScope,
105 @NotNull FqName path,
106 @NotNull Predicate<ClassDescriptor> filter
107 ) {
108 if (path.isRoot()) return null;
109
110 if (NamePackage.isOneSegmentFQN(path)) {
111 Name shortName = path.shortName();
112 ClassifierDescriptor classifier = jetScope.getClassifier(shortName);
113 if (classifier instanceof ClassDescriptor) {
114 ClassDescriptor resultDescriptor = (ClassDescriptor) classifier;
115
116 if (filter.apply(resultDescriptor)) {
117 return resultDescriptor;
118 }
119 }
120
121 return null;
122 }
123
124 Name firstName = NamePackage.getFirstSegment(path);
125
126 // Search in internal class
127 ClassifierDescriptor classifier = jetScope.getClassifier(firstName);
128 if (classifier instanceof ClassDescriptor) {
129 return findByQualifiedName(
130 ((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope(),
131 NamePackage.withoutFirstSegment(path),
132 filter);
133 }
134
135 // TODO: search in class object
136
137 return null;
138 }
139
140 @NotNull
141 public static Name safeNameForLazyResolve(@NotNull JetNamedDeclaration declaration) {
142 return safeNameForLazyResolve(declaration.getNameAsName());
143 }
144
145 @NotNull
146 public static Name safeNameForLazyResolve(@Nullable Name name) {
147 return SpecialNames.safeIdentifier(name);
148 }
149
150 @Nullable
151 public static FqName safeFqNameForLazyResolve(@NotNull JetNamedDeclaration declaration) {
152 //NOTE: should only create special names for package level declarations, so we can safely rely on real fq name for parent
153 FqName parentFqName = JetNamedDeclarationUtil.getParentFqName(declaration);
154 return parentFqName != null ? parentFqName.child(safeNameForLazyResolve(declaration)) : null;
155 }
156 }