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