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