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
017package org.jetbrains.jet.lang.resolve.lazy.declarations;
018
019import com.google.common.collect.ArrayListMultimap;
020import com.google.common.collect.HashMultimap;
021import com.google.common.collect.Lists;
022import com.google.common.collect.Multimap;
023import com.intellij.openapi.util.Computable;
024import org.jetbrains.annotations.NotNull;
025import org.jetbrains.jet.lang.psi.*;
026import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
027import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
028import org.jetbrains.jet.lang.resolve.name.Name;
029
030import java.util.Collection;
031import java.util.List;
032
033import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
034
035public 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
071    private final NotNullLazyValue<Index> index;
072
073    public AbstractPsiBasedDeclarationProvider(@NotNull StorageManager storageManager) {
074        index = storageManager.createLazyValue(new Computable<Index>() {
075            @Override
076            public Index compute() {
077                Index index = new Index();
078                doCreateIndex(index);
079                return index;
080            }
081        });
082    }
083
084    protected abstract void doCreateIndex(@NotNull Index index);
085
086    @Override
087    public List<JetDeclaration> getAllDeclarations() {
088        return index.compute().allDeclarations;
089    }
090
091    @NotNull
092    @Override
093    public List<JetNamedFunction> getFunctionDeclarations(@NotNull Name name) {
094        return Lists.newArrayList(index.compute().functions.get(name));
095    }
096
097    @NotNull
098    @Override
099    public List<JetProperty> getPropertyDeclarations(@NotNull Name name) {
100        return Lists.newArrayList(index.compute().properties.get(name));
101    }
102
103    @NotNull
104    @Override
105    public Collection<JetClassOrObject> getClassOrObjectDeclarations(@NotNull Name name) {
106        return index.compute().classesAndObjects.get(name);
107    }
108}