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 }