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.LinkedHashMultimap;
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 = LinkedHashMultimap.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 }