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