001 /*
002 * Copyright 2010-2013 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.collect.ArrayListMultimap;
020 import com.google.common.collect.HashMultimap;
021 import com.google.common.collect.Lists;
022 import com.google.common.collect.Multimap;
023 import com.intellij.openapi.util.Computable;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.jet.lang.psi.*;
026 import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
027 import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
028 import org.jetbrains.jet.lang.resolve.name.Name;
029
030 import java.util.Collection;
031 import java.util.List;
032
033 import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
034
035 public abstract class AbstractPsiBasedDeclarationProvider implements DeclarationProvider {
036
037 protected static class Index {
038 // This mutable state is only modified under inside the computable
039 private final List<JetDeclaration> allDeclarations = Lists.newArrayList();
040 private final Multimap<Name, JetNamedFunction> functions = HashMultimap.create();
041 private final Multimap<Name, JetProperty> properties = HashMultimap.create();
042 private final Multimap<Name, JetClassOrObject> classesAndObjects = ArrayListMultimap.create(); // order matters here
043
044 public void putToIndex(@NotNull JetDeclaration declaration) {
045 if (declaration instanceof JetClassInitializer) {
046 return;
047 }
048 allDeclarations.add(declaration);
049 if (declaration instanceof JetNamedFunction) {
050 JetNamedFunction namedFunction = (JetNamedFunction) declaration;
051 functions.put(safeNameForLazyResolve(namedFunction), namedFunction);
052 }
053 else if (declaration instanceof JetProperty) {
054 JetProperty property = (JetProperty) declaration;
055 properties.put(safeNameForLazyResolve(property), property);
056 }
057 else if (declaration instanceof JetClassOrObject) {
058 JetClassOrObject classOrObject = (JetClassOrObject) declaration;
059 classesAndObjects.put(safeNameForLazyResolve(classOrObject.getNameAsName()), classOrObject);
060 }
061 else if (declaration instanceof JetParameter || declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
062 // Do nothing, just put it into allDeclarations is enough
063 }
064 else {
065 throw new IllegalArgumentException("Unknown declaration: " + declaration);
066 }
067 }
068 }
069
070 private final NotNullLazyValue<Index> index;
071
072 public AbstractPsiBasedDeclarationProvider(@NotNull StorageManager storageManager) {
073 index = storageManager.createLazyValue(new Computable<Index>() {
074 @Override
075 public Index compute() {
076 Index index = new Index();
077 doCreateIndex(index);
078 return index;
079 }
080 });
081 }
082
083 protected abstract void doCreateIndex(@NotNull Index index);
084
085 @Override
086 public List<JetDeclaration> getAllDeclarations() {
087 return index.compute().allDeclarations;
088 }
089
090 @NotNull
091 @Override
092 public List<JetNamedFunction> getFunctionDeclarations(@NotNull Name name) {
093 return Lists.newArrayList(index.compute().functions.get(name));
094 }
095
096 @NotNull
097 @Override
098 public List<JetProperty> getPropertyDeclarations(@NotNull Name name) {
099 return Lists.newArrayList(index.compute().properties.get(name));
100 }
101
102 @NotNull
103 @Override
104 public Collection<JetClassOrObject> getClassOrObjectDeclarations(@NotNull Name name) {
105 return index.compute().classesAndObjects.get(name);
106 }
107 }