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