001 /*
002 * Copyright 2010-2015 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.kotlin.descriptors.impl;
018
019 import kotlin.jvm.functions.Function0;
020 import kotlin.jvm.functions.Function1;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.descriptors.*;
024 import org.jetbrains.kotlin.descriptors.annotations.Annotations;
025 import org.jetbrains.kotlin.name.Name;
026 import org.jetbrains.kotlin.resolve.DescriptorFactory;
027 import org.jetbrains.kotlin.resolve.OverridingUtil;
028 import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
029 import org.jetbrains.kotlin.resolve.scopes.JetScope;
030 import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl;
031 import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinClass;
032 import org.jetbrains.kotlin.storage.MemoizedFunctionToNotNull;
033 import org.jetbrains.kotlin.storage.NotNullLazyValue;
034 import org.jetbrains.kotlin.storage.StorageManager;
035 import org.jetbrains.kotlin.types.JetType;
036 import org.jetbrains.kotlin.types.TypeConstructor;
037 import org.jetbrains.kotlin.types.TypeConstructorImpl;
038 import org.jetbrains.kotlin.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 TypeConstructor typeConstructor;
047 private final ConstructorDescriptor primaryConstructor;
048 private final JetScope scope;
049 private final JetScope staticScope = new StaticScopeForKotlinClass(this);
050 private final NotNullLazyValue<Collection<Name>> enumMemberNames;
051
052 /**
053 * Creates and initializes descriptors for enum entry with the given name and its companion 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 @NotNull SourceElement source
063 ) {
064 JetType enumType = enumClass.getDefaultType();
065
066 return new EnumEntrySyntheticClassDescriptor(storageManager, enumClass, enumType, name, enumMemberNames, source);
067 }
068
069 private EnumEntrySyntheticClassDescriptor(
070 @NotNull StorageManager storageManager,
071 @NotNull ClassDescriptor containingClass,
072 @NotNull JetType supertype,
073 @NotNull Name name,
074 @NotNull NotNullLazyValue<Collection<Name>> enumMemberNames,
075 @NotNull SourceElement source
076 ) {
077 super(storageManager, containingClass, name, source);
078 assert containingClass.getKind() == ClassKind.ENUM_CLASS;
079
080 this.typeConstructor =
081 TypeConstructorImpl.createForClass(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, source);
088 primaryConstructor.setReturnType(getDefaultType());
089 this.primaryConstructor = primaryConstructor;
090 }
091
092 @NotNull
093 @Override
094 protected JetScope getScopeForMemberLookup() {
095 return scope;
096 }
097
098 @NotNull
099 @Override
100 public JetScope getStaticScope() {
101 return staticScope;
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 getCompanionObjectDescriptor() {
119 return null;
120 }
121
122 @NotNull
123 @Override
124 public ClassKind getKind() {
125 return ClassKind.ENUM_ENTRY;
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 @Override
146 public boolean isCompanionObject() {
147 return false;
148 }
149
150 @Nullable
151 @Override
152 public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
153 return primaryConstructor;
154 }
155
156 @NotNull
157 @Override
158 public Annotations getAnnotations() {
159 // TODO
160 return Annotations.EMPTY;
161 }
162
163 @Override
164 public String toString() {
165 return "enum entry " + getName();
166 }
167
168 private class EnumEntryScope extends JetScopeImpl {
169 private final MemoizedFunctionToNotNull<Name, Collection<FunctionDescriptor>> functions;
170 private final MemoizedFunctionToNotNull<Name, Collection<PropertyDescriptor>> properties;
171 private final NotNullLazyValue<Collection<DeclarationDescriptor>> allDescriptors;
172
173 public EnumEntryScope(@NotNull StorageManager storageManager) {
174 this.functions = storageManager.createMemoizedFunction(new Function1<Name, Collection<FunctionDescriptor>>() {
175 @Override
176 public Collection<FunctionDescriptor> invoke(Name name) {
177 return computeFunctions(name);
178 }
179 });
180
181 this.properties = storageManager.createMemoizedFunction(new Function1<Name, Collection<PropertyDescriptor>>() {
182 @Override
183 public Collection<PropertyDescriptor> invoke(Name name) {
184 return computeProperties(name);
185 }
186 });
187 this.allDescriptors = storageManager.createLazyValue(new Function0<Collection<DeclarationDescriptor>>() {
188 @Override
189 public Collection<DeclarationDescriptor> invoke() {
190 return computeAllDeclarations();
191 }
192 });
193 }
194
195 @NotNull
196 @Override
197 @SuppressWarnings("unchecked")
198 public Collection<VariableDescriptor> getProperties(@NotNull Name name) {
199 return (Collection) properties.invoke(name);
200 }
201
202 @NotNull
203 @SuppressWarnings("unchecked")
204 private Collection<PropertyDescriptor> computeProperties(@NotNull Name name) {
205 return resolveFakeOverrides(name, (Collection) getSupertypeScope().getProperties(name));
206 }
207
208 @NotNull
209 @Override
210 public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
211 return functions.invoke(name);
212 }
213
214 @NotNull
215 private Collection<FunctionDescriptor> computeFunctions(@NotNull Name name) {
216 return resolveFakeOverrides(name, getSupertypeScope().getFunctions(name));
217 }
218
219 @NotNull
220 private JetScope getSupertypeScope() {
221 Collection<JetType> supertype = getTypeConstructor().getSupertypes();
222 assert supertype.size() == 1 : "Enum entry and its companion object both should have exactly one supertype: " + supertype;
223 return supertype.iterator().next().getMemberScope();
224 }
225
226 @NotNull
227 private <D extends CallableMemberDescriptor> Collection<D> resolveFakeOverrides(
228 @NotNull Name name,
229 @NotNull Collection<D> fromSupertypes
230 ) {
231 final Set<D> result = new HashSet<D>();
232
233 OverridingUtil.generateOverridesInFunctionGroup(
234 name, fromSupertypes, Collections.<D>emptySet(), EnumEntrySyntheticClassDescriptor.this,
235 new OverridingUtil.DescriptorSink() {
236 @Override
237 @SuppressWarnings("unchecked")
238 public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
239 OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, null);
240 result.add((D) fakeOverride);
241 }
242
243 @Override
244 public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
245 // Do nothing
246 }
247 }
248 );
249
250 return result;
251 }
252
253 @NotNull
254 @Override
255 public DeclarationDescriptor getContainingDeclaration() {
256 return EnumEntrySyntheticClassDescriptor.this;
257 }
258
259 @NotNull
260 @Override
261 public Collection<DeclarationDescriptor> getDescriptors(
262 @NotNull DescriptorKindFilter kindFilter,
263 @NotNull Function1<? super Name, ? extends Boolean> nameFilter
264 ) {
265 return allDescriptors.invoke();
266 }
267
268 @NotNull
269 private Collection<DeclarationDescriptor> computeAllDeclarations() {
270 Collection<DeclarationDescriptor> result = new HashSet<DeclarationDescriptor>();
271 for (Name name : enumMemberNames.invoke()) {
272 result.addAll(getFunctions(name));
273 result.addAll(getProperties(name));
274 }
275 return result;
276 }
277
278 @Override
279 public void printScopeStructure(@NotNull Printer p) {
280 p.println("enum entry scope for " + EnumEntrySyntheticClassDescriptor.this);
281 }
282 }
283 }