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