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.lazy;
018
019 import com.google.common.collect.Lists;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
023 import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
024 import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
025 import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase;
026 import org.jetbrains.jet.lang.psi.JetNamed;
027 import org.jetbrains.jet.lang.resolve.name.FqName;
028 import org.jetbrains.jet.lang.resolve.name.Name;
029 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
030 import org.jetbrains.jet.util.QualifiedNamesUtil;
031
032 import java.util.Arrays;
033 import java.util.Collection;
034 import java.util.Collections;
035 import java.util.List;
036
037 public class ResolveSessionUtils {
038
039 // This name is used as a key for the case when something has no name _due to a syntactic error_
040 // Example: fun (x: Int) = 5
041 // There's no name for this function in the PSI
042 // The name contains a GUID to avoid clashes, if a clash happens, it's not a big deal: the code does not compile anyway
043 public static final Name NO_NAME_FOR_LAZY_RESOLVE = Name.identifier("no_name_in_PSI_for_lazy_resolve_3d19d79d_1ba9_4cd0_b7f5_b46aa3cd5d40");
044
045 private ResolveSessionUtils() {
046 }
047
048 @NotNull
049 public static Collection<ClassDescriptor> getClassDescriptorsByFqName(
050 @NotNull KotlinCodeAnalyzer analyzer,
051 @NotNull FqName fqName
052 ) {
053 return getClassOrObjectDescriptorsByFqName(analyzer, fqName, false);
054 }
055
056 @NotNull
057 public static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
058 @NotNull KotlinCodeAnalyzer analyzer,
059 @NotNull FqName fqName,
060 boolean includeObjectDeclarations
061 ) {
062 if (fqName.isRoot()) {
063 return Collections.emptyList();
064 }
065
066 Collection<ClassDescriptor> classDescriptors = Lists.newArrayList();
067
068 FqName packageFqName = fqName.parent();
069 while (true) {
070 NamespaceDescriptor packageDescriptor = analyzer.getPackageDescriptorByFqName(packageFqName);
071 if (packageDescriptor != null) {
072 FqName classInPackagePath = new FqName(QualifiedNamesUtil.tail(packageFqName, fqName));
073 Collection<ClassDescriptor> descriptors = getClassOrObjectDescriptorsByFqName(packageDescriptor, classInPackagePath,
074 includeObjectDeclarations);
075 classDescriptors.addAll(descriptors);
076 }
077
078 if (packageFqName.isRoot()) {
079 break;
080 }
081 else {
082 packageFqName = packageFqName.parent();
083 }
084 }
085
086 return classDescriptors;
087 }
088
089 private static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
090 NamespaceDescriptor packageDescriptor,
091 FqName path,
092 boolean includeObjectDeclarations
093 ) {
094 if (path.isRoot()) {
095 return Collections.emptyList();
096 }
097
098 Collection<JetScope> scopes = Arrays.asList(packageDescriptor.getMemberScope());
099
100 List<Name> names = path.pathSegments();
101 if (names.size() > 1) {
102 for (Name subName : path.pathSegments().subList(0, names.size() - 1)) {
103 Collection<JetScope> tempScopes = Lists.newArrayList();
104 for (JetScope scope : scopes) {
105 ClassifierDescriptor classifier = scope.getClassifier(subName);
106 if (classifier instanceof ClassDescriptorBase) {
107 ClassDescriptorBase classDescriptor = (ClassDescriptorBase) classifier;
108 tempScopes.add(classDescriptor.getUnsubstitutedInnerClassesScope());
109 }
110 }
111 scopes = tempScopes;
112 }
113 }
114
115 Name shortName = path.shortName();
116 Collection<ClassDescriptor> resultClassifierDescriptors = Lists.newArrayList();
117 for (JetScope scope : scopes) {
118 ClassifierDescriptor classifier = scope.getClassifier(shortName);
119 if (classifier instanceof ClassDescriptor) {
120 resultClassifierDescriptors.add((ClassDescriptor) classifier);
121 }
122 if (includeObjectDeclarations) {
123 ClassDescriptor objectDescriptor = scope.getObjectDescriptor(shortName);
124 if (objectDescriptor != null) {
125 resultClassifierDescriptors.add(objectDescriptor);
126 }
127 }
128 }
129
130 return resultClassifierDescriptors;
131 }
132
133 @NotNull
134 public static Name safeNameForLazyResolve(@NotNull JetNamed named) {
135 Name name = named.getNameAsName();
136 return safeNameForLazyResolve(name);
137 }
138
139 @NotNull
140 public static Name safeNameForLazyResolve(@Nullable Name name) {
141 return name != null ? name : NO_NAME_FOR_LAZY_RESOLVE;
142 }
143 }