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