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 }