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.descriptors.serialization.descriptors;
018    
019    import com.intellij.openapi.util.Computable;
020    import com.intellij.util.Function;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.descriptors.serialization.DescriptorDeserializer;
024    import org.jetbrains.jet.descriptors.serialization.Flags;
025    import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
026    import org.jetbrains.jet.lang.descriptors.*;
027    import org.jetbrains.jet.lang.resolve.lazy.storage.MemoizedFunctionToNotNull;
028    import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
029    import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
030    import org.jetbrains.jet.lang.resolve.name.LabelName;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033    
034    import java.util.*;
035    
036    import static org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager.ReferenceKind.STRONG;
037    
038    public abstract class DeserializedMemberScope implements JetScope {
039    
040        private static final Filter<ProtoBuf.Callable.CallableKind> FUNCTION = new Filter<ProtoBuf.Callable.CallableKind>() {
041            @Override
042            public boolean accept(ProtoBuf.Callable.CallableKind value) {
043                return value == ProtoBuf.Callable.CallableKind.FUN;
044            }
045        };
046        private static final Filter<ProtoBuf.Callable.CallableKind> PROPERTY = new Filter<ProtoBuf.Callable.CallableKind>() {
047            @Override
048            public boolean accept(ProtoBuf.Callable.CallableKind value) {
049                return value == ProtoBuf.Callable.CallableKind.VAL ||
050                       value == ProtoBuf.Callable.CallableKind.VAR ||
051                       value == ProtoBuf.Callable.CallableKind.OBJECT_PROPERTY;
052            }
053        };
054    
055        private final DeclarationDescriptor containingDeclaration;
056        private final DescriptorDeserializer deserializer;
057    
058        // Never modified after creation
059        private final Map<Name, List<ProtoBuf.Callable>> membersProtos;
060    
061        private final MemoizedFunctionToNotNull<Name, Collection<FunctionDescriptor>> functions;
062        private final MemoizedFunctionToNotNull<Name, Collection<VariableDescriptor>> properties;
063        private final NotNullLazyValue<Collection<DeclarationDescriptor>> allDescriptors;
064        private final NotNullLazyValue<Collection<ClassDescriptor>> objectDescriptors;
065    
066        public DeserializedMemberScope(
067                @NotNull StorageManager storageManager,
068                @NotNull DeclarationDescriptor containingDeclaration,
069                @NotNull DescriptorDeserializer deserializer,
070                @NotNull List<ProtoBuf.Callable> membersList
071        ) {
072            this.containingDeclaration = containingDeclaration;
073            this.deserializer = deserializer;
074    
075            this.membersProtos = groupByName(membersList);
076            this.functions = storageManager.createMemoizedFunction(new Function<Name, Collection<FunctionDescriptor>>() {
077                @Override
078                public Collection<FunctionDescriptor> fun(Name name) {
079                    return computeFunctions(name);
080                }
081            }, STRONG);
082            this.properties = storageManager.createMemoizedFunction(new Function<Name, Collection<VariableDescriptor>>() {
083                @Override
084                public Collection<VariableDescriptor> fun(Name name) {
085                    return computeProperties(name);
086                }
087            }, STRONG);
088            this.allDescriptors = storageManager.createLazyValue(new Computable<Collection<DeclarationDescriptor>>() {
089                @Override
090                public Collection<DeclarationDescriptor> compute() {
091                    return computeAllDescriptors();
092                }
093            });
094            this.objectDescriptors = storageManager.createLazyValue(new Computable<Collection<ClassDescriptor>>() {
095                @Override
096                public Collection<ClassDescriptor> compute() {
097                    return computeAllObjectDescriptors();
098                }
099            });
100        }
101    
102        @NotNull
103        private Map<Name, List<ProtoBuf.Callable>> groupByName(@NotNull Collection<ProtoBuf.Callable> membersList) {
104            Map<Name, List<ProtoBuf.Callable>> map = new HashMap<Name, List<ProtoBuf.Callable>>();
105            for (ProtoBuf.Callable memberProto : membersList) {
106                Name name = deserializer.getNameResolver().getName(memberProto.getName());
107                List<ProtoBuf.Callable> protos = map.get(name);
108                if (protos == null) {
109                    protos = new ArrayList<ProtoBuf.Callable>(1);
110                    map.put(name, protos);
111                }
112                protos.add(memberProto);
113            }
114            return map;
115        }
116    
117        @NotNull
118        private <D extends CallableMemberDescriptor> Collection<D> computeMembersByName(Name name, Filter<ProtoBuf.Callable.CallableKind> callableKind) {
119            List<ProtoBuf.Callable> memberProtos = membersProtos.get(name);
120    
121            Collection<D> descriptors = new LinkedHashSet<D>(memberProtos != null ? memberProtos.size() : 0);
122            if (memberProtos != null) {
123                for (ProtoBuf.Callable memberProto : memberProtos) {
124                    if (callableKind.accept(Flags.CALLABLE_KIND.get(memberProto.getFlags()))) {
125                        //noinspection unchecked
126                        descriptors.add((D) deserializer.loadCallable(memberProto));
127                    }
128                }
129            }
130            return descriptors;
131        }
132    
133        @NotNull
134        private Collection<FunctionDescriptor> computeFunctions(@NotNull Name name) {
135            Collection<FunctionDescriptor> descriptors = computeMembersByName(name, FUNCTION);
136            computeNonDeclaredFunctions(name, descriptors);
137            return descriptors;
138        }
139    
140        protected void computeNonDeclaredFunctions(@NotNull Name name, @NotNull Collection<FunctionDescriptor> functions) {
141        }
142    
143        @NotNull
144        @Override
145        public final Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
146            return functions.fun(name);
147        }
148    
149        @NotNull
150        private Collection<VariableDescriptor> computeProperties(@NotNull Name name) {
151            Collection<PropertyDescriptor> descriptors = computeMembersByName(name, PROPERTY);
152            computeNonDeclaredProperties(name, descriptors);
153            //noinspection unchecked
154            return (Collection) descriptors;
155        }
156    
157        protected void computeNonDeclaredProperties(@NotNull Name name, @NotNull Collection<PropertyDescriptor> descriptors) {
158        }
159    
160        @NotNull
161        @Override
162        public Collection<VariableDescriptor> getProperties(@NotNull Name name) {
163            return properties.fun(name);
164        }
165    
166        @Nullable
167        @Override
168        public final ClassifierDescriptor getClassifier(@NotNull Name name) {
169            return getClassDescriptor(name);
170        }
171    
172        @Nullable
173        protected abstract ClassifierDescriptor getClassDescriptor(@NotNull Name name);
174    
175        protected abstract void addAllClassDescriptors(@NotNull Collection<DeclarationDescriptor> result);
176    
177        @Nullable
178        @Override
179        public abstract ClassDescriptor getObjectDescriptor(@NotNull Name name);
180    
181        @NotNull
182        protected abstract Collection<ClassDescriptor> computeAllObjectDescriptors();
183    
184        @NotNull
185        @Override
186        public Collection<ClassDescriptor> getObjectDescriptors() {
187            return objectDescriptors.compute();
188        }
189    
190        @Nullable
191        @Override
192        public NamespaceDescriptor getNamespace(@NotNull Name name) {
193            return null;
194        }
195    
196        @Nullable
197        @Override
198        public VariableDescriptor getLocalVariable(@NotNull Name name) {
199            return null;
200        }
201    
202        @NotNull
203        @Override
204        public DeclarationDescriptor getContainingDeclaration() {
205            return containingDeclaration;
206        }
207    
208        @NotNull
209        @Override
210        public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
211            throw new UnsupportedOperationException("Should not be called");
212        }
213    
214        @Nullable
215        @Override
216        public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) {
217            throw new UnsupportedOperationException("Should not be called");
218        }
219    
220        private Collection<DeclarationDescriptor> computeAllDescriptors() {
221            Collection<DeclarationDescriptor> result = new LinkedHashSet<DeclarationDescriptor>(0);
222    
223            for (Name name : membersProtos.keySet()) {
224                result.addAll(getFunctions(name));
225                result.addAll(getProperties(name));
226            }
227    
228            addNonDeclaredDescriptors(result);
229    
230            addAllClassDescriptors(result);
231    
232            return result;
233        }
234    
235        protected abstract void addNonDeclaredDescriptors(@NotNull Collection<DeclarationDescriptor> result);
236    
237        @NotNull
238        @Override
239        public final Collection<DeclarationDescriptor> getAllDescriptors() {
240            return allDescriptors.compute();
241        }
242    
243        @NotNull
244        @Override
245        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
246            ReceiverParameterDescriptor receiver = getImplicitReceiver();
247            if (receiver != null) {
248                return Collections.singletonList(receiver);
249            }
250            return Collections.emptyList();
251        }
252    
253        @Nullable
254        protected abstract ReceiverParameterDescriptor getImplicitReceiver();
255    
256        @NotNull
257        @Override
258        public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
259            return getAllDescriptors();
260        }
261    
262        private interface Filter<T> {
263            boolean accept(T value);
264        }
265    
266    }