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.KtScope;
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 = findByQualifiedName(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 findByQualifiedName(@NotNull KtScope outerScope, @NotNull FqName path) {
080            if (path.isRoot()) return null;
081    
082            KtScope scope = outerScope;
083            for (Name name : path.pathSegments()) {
084                ClassifierDescriptor classifier = scope.getClassifier(name, NoLookupLocation.UNSORTED);
085                if (!(classifier instanceof ClassDescriptor)) return null;
086                scope = ((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope();
087            }
088    
089            return (ClassDescriptor) scope.getContainingDeclaration();
090        }
091    
092        @NotNull
093        public static Name safeNameForLazyResolve(@NotNull KtNamedDeclaration declaration) {
094            return safeNameForLazyResolve(declaration.getNameAsName());
095        }
096    
097        @NotNull
098        public static Name safeNameForLazyResolve(@Nullable Name name) {
099            return SpecialNames.safeIdentifier(name);
100        }
101    
102        @Nullable
103        public static FqName safeFqNameForLazyResolve(@NotNull KtNamedDeclaration declaration) {
104            //NOTE: should only create special names for package level declarations, so we can safely rely on real fq name for parent
105            FqName parentFqName = KtNamedDeclarationUtil.getParentFqName(declaration);
106            return parentFqName != null ? parentFqName.child(safeNameForLazyResolve(declaration)) : null;
107        }
108    }