001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.lazy;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.base.Predicates;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
024    import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
025    import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
026    import org.jetbrains.kotlin.descriptors.PackageViewDescriptor;
027    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
028    import org.jetbrains.kotlin.name.*;
029    import org.jetbrains.kotlin.psi.KtNamedDeclaration;
030    import org.jetbrains.kotlin.psi.KtNamedDeclarationUtil;
031    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
032    
033    import java.util.ArrayList;
034    import java.util.Collection;
035    import java.util.Collections;
036    
037    public class ResolveSessionUtils {
038    
039        private ResolveSessionUtils() {
040        }
041    
042        @NotNull
043        public static Collection<ClassDescriptor> getClassDescriptorsByFqName(@NotNull ModuleDescriptor module, @NotNull FqName fqName) {
044            return getClassOrObjectDescriptorsByFqName(module, fqName, Predicates.<ClassDescriptor>alwaysTrue());
045        }
046    
047        @NotNull
048        public static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
049                @NotNull ModuleDescriptor module,
050                @NotNull FqName fqName,
051                @NotNull Predicate<ClassDescriptor> filter
052        ) {
053            if (fqName.isRoot()) return Collections.emptyList();
054    
055            Collection<ClassDescriptor> result = new ArrayList<ClassDescriptor>(1);
056    
057            FqName packageFqName = fqName.parent();
058            while (true) {
059                PackageViewDescriptor packageDescriptor = module.getPackage(packageFqName);
060                if (!packageDescriptor.isEmpty()) {
061                    FqName relativeClassFqName = FqNamesUtilKt.tail(fqName, packageFqName);
062                    ClassDescriptor classDescriptor = findClassByRelativePath(packageDescriptor.getMemberScope(), relativeClassFqName);
063                    if (classDescriptor != null && filter.apply(classDescriptor)) {
064                        result.add(classDescriptor);
065                    }
066                }
067    
068                if (packageFqName.isRoot()) {
069                    break;
070                }
071    
072                packageFqName = packageFqName.parent();
073            }
074    
075            return result;
076        }
077    
078        @Nullable
079        public static ClassDescriptor findClassByRelativePath(@NotNull MemberScope packageScope, @NotNull FqName path) {
080            if (path.isRoot()) return null;
081    
082            MemberScope scope = packageScope;
083            ClassifierDescriptor classifier = null;
084            for (Name name : path.pathSegments()) {
085                classifier = scope.getContributedClassifier(name, NoLookupLocation.WHEN_FIND_BY_FQNAME);
086                if (!(classifier instanceof ClassDescriptor)) return null;
087                scope = ((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope();
088            }
089    
090            return (ClassDescriptor) classifier;
091        }
092    
093        @NotNull
094        public static Name safeNameForLazyResolve(@NotNull KtNamedDeclaration declaration) {
095            return safeNameForLazyResolve(declaration.getNameAsName());
096        }
097    
098        @NotNull
099        public static Name safeNameForLazyResolve(@Nullable Name name) {
100            return SpecialNames.safeIdentifier(name);
101        }
102    
103        @Nullable
104        public static FqName safeFqNameForLazyResolve(@NotNull KtNamedDeclaration declaration) {
105            //NOTE: should only create special names for package level declarations, so we can safely rely on real fq name for parent
106            FqName parentFqName = KtNamedDeclarationUtil.getParentFqName(declaration);
107            return parentFqName != null ? parentFqName.child(safeNameForLazyResolve(declaration)) : null;
108        }
109    }