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.lang.descriptors.impl;
018    
019    import kotlin.Function0;
020    import kotlin.Function1;
021    import kotlin.Unit;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
026    import org.jetbrains.jet.lang.resolve.DescriptorFactory;
027    import org.jetbrains.jet.lang.resolve.OverridingUtil;
028    import org.jetbrains.jet.lang.resolve.name.Name;
029    import org.jetbrains.jet.lang.resolve.name.SpecialNames;
030    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
031    import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl;
032    import org.jetbrains.jet.lang.types.JetType;
033    import org.jetbrains.jet.lang.types.TypeConstructor;
034    import org.jetbrains.jet.lang.types.TypeConstructorImpl;
035    import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
036    import org.jetbrains.jet.storage.NotNullLazyValue;
037    import org.jetbrains.jet.storage.StorageManager;
038    import org.jetbrains.jet.utils.Printer;
039    
040    import java.util.Collection;
041    import java.util.Collections;
042    import java.util.HashSet;
043    import java.util.Set;
044    
045    public class EnumEntrySyntheticClassDescriptor extends ClassDescriptorBase {
046        private final ClassKind kind;
047        private final TypeConstructor typeConstructor;
048        private final ConstructorDescriptor primaryConstructor;
049        private final JetScope scope;
050        private final EnumEntrySyntheticClassDescriptor classObjectDescriptor;
051        private final NotNullLazyValue<Collection<Name>> enumMemberNames;
052    
053        /**
054         * Creates and initializes descriptors for enum entry with the given name and its class object
055         * @param enumMemberNames needed for fake overrides resolution
056         */
057        @NotNull
058        public static EnumEntrySyntheticClassDescriptor create(
059                @NotNull StorageManager storageManager,
060                @NotNull ClassDescriptor enumClass,
061                @NotNull Name name,
062                @NotNull NotNullLazyValue<Collection<Name>> enumMemberNames
063        ) {
064            JetType enumType = enumClass.getDefaultType();
065    
066            return new EnumEntrySyntheticClassDescriptor(storageManager, enumClass, enumType, name, ClassKind.ENUM_ENTRY, enumMemberNames);
067        }
068    
069        private EnumEntrySyntheticClassDescriptor(
070                @NotNull StorageManager storageManager,
071                @NotNull ClassDescriptor containingClass,
072                @NotNull JetType supertype,
073                @NotNull Name name,
074                @NotNull ClassKind kind,
075                @NotNull NotNullLazyValue<Collection<Name>> enumMemberNames
076        ) {
077            super(storageManager, containingClass, name);
078            this.kind = kind;
079    
080            this.typeConstructor =
081                    new TypeConstructorImpl(this, getAnnotations(), true, "enum entry", Collections.<TypeParameterDescriptor>emptyList(),
082                                            Collections.singleton(supertype));
083    
084            this.scope = new EnumEntryScope(storageManager);
085            this.enumMemberNames = enumMemberNames;
086    
087            ConstructorDescriptorImpl primaryConstructor = DescriptorFactory.createPrimaryConstructorForObject(this);
088            primaryConstructor.setReturnType(getDefaultType());
089            this.primaryConstructor = primaryConstructor;
090    
091            this.classObjectDescriptor =
092                    kind == ClassKind.CLASS_OBJECT
093                    ? null
094                    : new EnumEntrySyntheticClassDescriptor(storageManager, this, getDefaultType(), SpecialNames.getClassObjectName(name),
095                                                            ClassKind.CLASS_OBJECT, enumMemberNames);
096        }
097    
098        @NotNull
099        @Override
100        protected JetScope getScopeForMemberLookup() {
101            return scope;
102        }
103    
104        @NotNull
105        @Override
106        public Collection<ConstructorDescriptor> getConstructors() {
107            return Collections.singleton(primaryConstructor);
108        }
109    
110        @NotNull
111        @Override
112        public TypeConstructor getTypeConstructor() {
113            return typeConstructor;
114        }
115    
116        @Nullable
117        @Override
118        public ClassDescriptor getClassObjectDescriptor() {
119            return classObjectDescriptor;
120        }
121    
122        @NotNull
123        @Override
124        public ClassKind getKind() {
125            return kind;
126        }
127    
128        @NotNull
129        @Override
130        public Modality getModality() {
131            return Modality.FINAL;
132        }
133    
134        @NotNull
135        @Override
136        public Visibility getVisibility() {
137            return Visibilities.PUBLIC;
138        }
139    
140        @Override
141        public boolean isInner() {
142            return false;
143        }
144    
145        @Nullable
146        @Override
147        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
148            return primaryConstructor;
149        }
150    
151        @NotNull
152        @Override
153        public Annotations getAnnotations() {
154            // TODO
155            return Annotations.EMPTY;
156        }
157    
158        private class EnumEntryScope extends JetScopeImpl {
159            private final MemoizedFunctionToNotNull<Name, Collection<FunctionDescriptor>> functions;
160            private final MemoizedFunctionToNotNull<Name, Collection<PropertyDescriptor>> properties;
161            private final NotNullLazyValue<Collection<DeclarationDescriptor>> allDescriptors;
162    
163            public EnumEntryScope(@NotNull StorageManager storageManager) {
164                this.functions = storageManager.createMemoizedFunction(new Function1<Name, Collection<FunctionDescriptor>>() {
165                    @Override
166                    public Collection<FunctionDescriptor> invoke(Name name) {
167                        return computeFunctions(name);
168                    }
169                });
170                this.properties = storageManager.createMemoizedFunction(new Function1<Name, Collection<PropertyDescriptor>>() {
171                    @Override
172                    public Collection<PropertyDescriptor> invoke(Name name) {
173                        return computeProperties(name);
174                    }
175                });
176                this.allDescriptors = storageManager.createLazyValue(new Function0<Collection<DeclarationDescriptor>>() {
177                    @Override
178                    public Collection<DeclarationDescriptor> invoke() {
179                        return computeAllDeclarations();
180                    }
181                });
182            }
183    
184            @NotNull
185            @Override
186            @SuppressWarnings("unchecked")
187            public Collection<VariableDescriptor> getProperties(@NotNull Name name) {
188                return (Collection) properties.invoke(name);
189            }
190    
191            @NotNull
192            @SuppressWarnings("unchecked")
193            private Collection<PropertyDescriptor> computeProperties(@NotNull Name name) {
194                return resolveFakeOverrides(name, (Collection) getSupertypeScope().getProperties(name));
195            }
196    
197            @NotNull
198            @Override
199            public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
200                return functions.invoke(name);
201            }
202    
203            @NotNull
204            private Collection<FunctionDescriptor> computeFunctions(@NotNull Name name) {
205                return resolveFakeOverrides(name, getSupertypeScope().getFunctions(name));
206            }
207    
208            @NotNull
209            private JetScope getSupertypeScope() {
210                Collection<JetType> supertype = getTypeConstructor().getSupertypes();
211                assert supertype.size() == 1 : "Enum entry and its class object both should have exactly one supertype: " + supertype;
212                return supertype.iterator().next().getMemberScope();
213            }
214    
215            @NotNull
216            private <D extends CallableMemberDescriptor> Collection<D> resolveFakeOverrides(
217                    @NotNull Name name,
218                    @NotNull Collection<D> fromSupertypes
219            ) {
220                final Set<D> result = new HashSet<D>();
221    
222                OverridingUtil.generateOverridesInFunctionGroup(
223                        name, fromSupertypes, Collections.<D>emptySet(), EnumEntrySyntheticClassDescriptor.this,
224                        new OverridingUtil.DescriptorSink() {
225                            @Override
226                            @SuppressWarnings("unchecked")
227                            public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
228                                OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, new Function1<CallableMemberDescriptor, Unit>() {
229                                    @Override
230                                    public Unit invoke(@NotNull CallableMemberDescriptor descriptor) {
231                                        // Do nothing
232                                        return Unit.VALUE;
233                                    }
234                                });
235                                result.add((D) fakeOverride);
236                            }
237    
238                            @Override
239                            public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
240                                // Do nothing
241                            }
242                        }
243                );
244    
245                return result;
246            }
247    
248            @NotNull
249            @Override
250            public DeclarationDescriptor getContainingDeclaration() {
251                return EnumEntrySyntheticClassDescriptor.this;
252            }
253    
254            @NotNull
255            @Override
256            public Collection<DeclarationDescriptor> getAllDescriptors() {
257                return allDescriptors.invoke();
258            }
259    
260            @NotNull
261            private Collection<DeclarationDescriptor> computeAllDeclarations() {
262                Collection<DeclarationDescriptor> result = new HashSet<DeclarationDescriptor>();
263                for (Name name : enumMemberNames.invoke()) {
264                    result.addAll(getFunctions(name));
265                    result.addAll(getProperties(name));
266                }
267                return result;
268            }
269    
270            @Override
271            public void printScopeStructure(@NotNull Printer p) {
272                p.println("enum entry scope for " + EnumEntrySyntheticClassDescriptor.this);
273            }
274        }
275    }