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