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