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    }