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