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.declarations;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.collect.Collections2;
021    import com.google.common.collect.HashMultimap;
022    import com.google.common.collect.Multimap;
023    import com.google.common.collect.Sets;
024    import kotlin.jvm.functions.Function0;
025    import org.jetbrains.annotations.NotNull;
026    import org.jetbrains.annotations.Nullable;
027    import org.jetbrains.kotlin.name.FqName;
028    import org.jetbrains.kotlin.psi.KtFile;
029    import org.jetbrains.kotlin.resolve.lazy.data.JetClassLikeInfo;
030    import org.jetbrains.kotlin.storage.NotNullLazyValue;
031    import org.jetbrains.kotlin.storage.StorageManager;
032    
033    import java.util.Collection;
034    import java.util.Set;
035    
036    public class FileBasedDeclarationProviderFactory extends AbstractDeclarationProviderFactory  {
037    
038        private static class Index {
039            private final Multimap<FqName, KtFile> filesByPackage = HashMultimap.create();
040            private final Set<FqName> declaredPackages = Sets.newHashSet();
041        }
042    
043        private final StorageManager storageManager;
044        private final NotNullLazyValue<Index> index;
045    
046        public FileBasedDeclarationProviderFactory(@NotNull StorageManager storageManager, @NotNull final Collection<KtFile> files) {
047            super(storageManager);
048            this.storageManager = storageManager;
049            this.index = storageManager.createLazyValue(new Function0<Index>() {
050                @Override
051                public Index invoke() {
052                    return computeFilesByPackage(files);
053                }
054            });
055        }
056    
057        @NotNull
058        private static Index computeFilesByPackage(@NotNull Collection<KtFile> files) {
059            Index index = new Index();
060            for (KtFile file : files) {
061                FqName packageFqName = file.getPackageFqName();
062                addMeAndParentPackages(index, packageFqName);
063                index.filesByPackage.put(packageFqName, file);
064            }
065            return index;
066        }
067    
068        private static void addMeAndParentPackages(@NotNull Index index, @NotNull FqName name) {
069            index.declaredPackages.add(name);
070            if (!name.isRoot()) {
071                addMeAndParentPackages(index, name.parent());
072            }
073        }
074    
075        /*package*/ boolean isPackageDeclaredExplicitly(@NotNull FqName packageFqName) {
076            return index.invoke().declaredPackages.contains(packageFqName);
077        }
078    
079        /*package*/ Collection<FqName> getAllDeclaredSubPackagesOf(@NotNull final FqName parent) {
080            return Collections2.filter(index.invoke().declaredPackages, new Predicate<FqName>() {
081                @Override
082                public boolean apply(FqName fqName) {
083                    return !fqName.isRoot() && fqName.parent().equals(parent);
084                }
085            });
086        }
087    
088        @Nullable
089        @Override
090        protected PackageMemberDeclarationProvider createPackageMemberDeclarationProvider(@NotNull FqName packageFqName) {
091            if (isPackageDeclaredExplicitly(packageFqName)) {
092                return new FileBasedPackageMemberDeclarationProvider(
093                        storageManager, packageFqName, this, index.invoke().filesByPackage.get(packageFqName));
094            }
095    
096            return null;
097        }
098    
099        @NotNull
100        @Override
101        public ClassMemberDeclarationProvider getClassMemberDeclarationProvider(@NotNull JetClassLikeInfo classLikeInfo) {
102            if (!index.invoke().filesByPackage.containsKey(classLikeInfo.getContainingPackageFqName())) {
103                throw new IllegalStateException("This factory doesn't know about this class: " + classLikeInfo);
104            }
105    
106            return new PsiBasedClassMemberDeclarationProvider(storageManager, classLikeInfo);
107        }
108    }