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