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