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 }