001 /*
002 * Copyright 2010-2014 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.resolve;
018
019 import com.google.common.collect.Multimap;
020 import com.google.common.collect.Sets;
021 import com.intellij.lang.ASTNode;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.*;
025 import org.jetbrains.jet.lang.diagnostics.Errors;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.types.*;
028 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
029 import org.jetbrains.jet.lexer.JetModifierKeywordToken;
030 import org.jetbrains.jet.lexer.JetTokens;
031
032 import javax.inject.Inject;
033 import java.util.*;
034
035 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
036 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
037 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE_PARAMETER;
038
039 public class DeclarationsChecker {
040 @NotNull
041 private BindingTrace trace;
042 @NotNull
043 private ModifiersChecker modifiersChecker;
044 @NotNull
045 private DescriptorResolver descriptorResolver;
046
047 @Inject
048 public void setTrace(@NotNull BindingTrace trace) {
049 this.trace = trace;
050 this.modifiersChecker = new ModifiersChecker(trace);
051 }
052
053 @Inject
054 public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
055 this.descriptorResolver = descriptorResolver;
056 }
057
058 public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
059 for (JetFile file : bodiesResolveContext.getFiles()) {
060 checkModifiersAndAnnotationsInPackageDirective(file);
061 }
062
063 Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = bodiesResolveContext.getDeclaredClasses();
064 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : classes.entrySet()) {
065 JetClassOrObject classOrObject = entry.getKey();
066 ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
067 if (!bodiesResolveContext.completeAnalysisNeeded(classOrObject)) continue;
068
069 checkSupertypesForConsistency(classDescriptor);
070 checkTypesInClassHeader(classOrObject);
071
072 if (classOrObject instanceof JetClass) {
073 JetClass jetClass = (JetClass) classOrObject;
074 checkClass(bodiesResolveContext, jetClass, classDescriptor);
075 descriptorResolver.checkNamesInConstraints(
076 jetClass, classDescriptor, classDescriptor.getScopeForClassHeaderResolution(), trace);
077 }
078 else if (classOrObject instanceof JetObjectDeclaration) {
079 checkObject((JetObjectDeclaration) classOrObject);
080 }
081
082 modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
083 }
084
085 Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions();
086 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) {
087 JetNamedFunction function = entry.getKey();
088 SimpleFunctionDescriptor functionDescriptor = entry.getValue();
089
090 if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue;
091 checkFunction(function, functionDescriptor);
092 modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor);
093 }
094
095 Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties();
096 for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
097 JetProperty property = entry.getKey();
098 PropertyDescriptor propertyDescriptor = entry.getValue();
099
100 if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue;
101 checkProperty(property, propertyDescriptor);
102 modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor);
103 }
104
105 }
106
107 private void reportErrorIfHasIllegalModifier(JetModifierListOwner declaration) {
108 if (declaration.hasModifier(JetTokens.ENUM_KEYWORD)) {
109 trace.report(ILLEGAL_ENUM_ANNOTATION.on(declaration));
110 }
111 if (declaration.hasModifier(JetTokens.ANNOTATION_KEYWORD)) {
112 trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration));
113 }
114 }
115
116 private void checkModifiersAndAnnotationsInPackageDirective(JetFile file) {
117 JetPackageDirective packageDirective = file.getPackageDirective();
118 if (packageDirective == null) return;
119
120 JetModifierList modifierList = packageDirective.getModifierList();
121 if (modifierList == null) return;
122
123 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
124 JetConstructorCalleeExpression calleeExpression = annotationEntry.getCalleeExpression();
125 if (calleeExpression != null) {
126 JetReferenceExpression reference = calleeExpression.getConstructorReferenceExpression();
127 if (reference != null) {
128 trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
129 }
130 }
131 }
132
133 ModifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY), trace);
134 }
135
136 private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) {
137 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
138 checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
139 }
140
141 if (!(classOrObject instanceof JetClass)) return;
142 JetClass jetClass = (JetClass) classOrObject;
143
144 for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
145 checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound());
146 checkFinalUpperBounds(jetTypeParameter.getExtendsBound(), false);
147 }
148
149 for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
150 checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
151 checkFinalUpperBounds(constraint.getBoundTypeReference(), constraint.isClassObjectConstraint());
152 }
153 }
154
155 private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) {
156 if (typeReference != null) {
157 JetType type = trace.getBindingContext().get(TYPE, typeReference);
158 if (type != null) {
159 DescriptorResolver.checkBounds(typeReference, type, trace);
160 }
161 }
162 }
163
164 private void checkFinalUpperBounds(@Nullable JetTypeReference typeReference, boolean isClassObjectConstraint) {
165 if (typeReference != null) {
166 JetType type = trace.getBindingContext().get(TYPE, typeReference);
167 if (type != null) {
168 DescriptorResolver.checkUpperBoundType(typeReference, type, isClassObjectConstraint, trace);
169 }
170 }
171 }
172
173 private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) {
174 Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
175 .buildDeepSubstitutionMultimap(classDescriptor.getDefaultType());
176 for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
177 Collection<TypeProjection> projections = entry.getValue();
178 if (projections.size() > 1) {
179 TypeConstructor typeConstructor = entry.getKey();
180 DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
181 assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
182 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
183
184 // Immediate arguments of supertypes cannot be projected
185 Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
186 for (TypeProjection projection : projections) {
187 conflictingTypes.add(projection.getType());
188 }
189 switch (typeParameterDescriptor.getVariance()) {
190 case INVARIANT:
191 // Leave conflicting types as is
192 break;
193 case IN_VARIANCE:
194 // Filter out those who have supertypes in this set (common supertype)
195 Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
196 break;
197 case OUT_VARIANCE:
198 // Filter out those who have subtypes in this set (common subtype)
199 Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
200 break;
201 }
202
203 if (conflictingTypes.size() > 1) {
204 DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
205 assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
206 JetClassOrObject psiElement = (JetClassOrObject) BindingContextUtils
207 .classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
208 JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
209 assert delegationSpecifierList != null;
210 // trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
211 trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
212 .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
213 conflictingTypes));
214 }
215 }
216 }
217 }
218
219 private enum Filter {
220 REMOVE_IF_SUBTYPE_IN_THE_SET {
221 @Override
222 public boolean removeNeeded(JetType subject, JetType other) {
223 return JetTypeChecker.DEFAULT.isSubtypeOf(other, subject);
224 }
225 },
226 REMOVE_IF_SUPERTYPE_IN_THE_SET {
227 @Override
228 public boolean removeNeeded(JetType subject, JetType other) {
229 return JetTypeChecker.DEFAULT.isSubtypeOf(subject, other);
230 }
231 };
232
233 private void proceed(Set<JetType> conflictingTypes) {
234 for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
235 JetType type = iterator.next();
236 for (JetType otherType : conflictingTypes) {
237 boolean subtypeOf = removeNeeded(type, otherType);
238 if (type != otherType && subtypeOf) {
239 iterator.remove();
240 break;
241 }
242 }
243 }
244 }
245
246 public abstract boolean removeNeeded(JetType subject, JetType other);
247 }
248
249 private void checkObject(JetObjectDeclaration declaration) {
250 reportErrorIfHasIllegalModifier(declaration);
251 }
252
253 private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
254 checkOpenMembers(classDescriptor);
255 if (c.getTopDownAnalysisParameters().isLazyTopDownAnalysis()) {
256 checkTypeParameters(aClass);
257 }
258 if (aClass.isTrait()) {
259 checkTraitModifiers(aClass);
260 checkConstructorInTrait(aClass);
261 }
262 else if (aClass.isAnnotation()) {
263 checkAnnotationClassWithBody(aClass);
264 checkValOnAnnotationParameter(aClass);
265 }
266 else if (aClass.isEnum()) {
267 checkEnumModifiers(aClass);
268 }
269 else if (aClass instanceof JetEnumEntry) {
270 checkEnumEntry((JetEnumEntry) aClass, classDescriptor);
271 }
272 }
273
274 private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) {
275 // TODO: Support annotation for type parameters
276 for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
277 AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace);
278
279 TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter);
280 if (typeParameter != null) {
281 DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter);
282 }
283 }
284 }
285
286 private void checkConstructorInTrait(JetClass klass) {
287 JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
288 if (primaryConstructorParameterList != null) {
289 trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructorParameterList));
290 }
291 }
292
293 private void checkTraitModifiers(JetClass aClass) {
294 reportErrorIfHasIllegalModifier(aClass);
295 JetModifierList modifierList = aClass.getModifierList();
296 if (modifierList == null) return;
297 if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) {
298 trace.report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(modifierList.getModifierNode(JetTokens.FINAL_KEYWORD).getPsi()));
299 }
300 if (modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
301 trace.report(Errors.ABSTRACT_MODIFIER_IN_TRAIT.on(aClass));
302 }
303 if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) {
304 trace.report(Errors.OPEN_MODIFIER_IN_TRAIT.on(aClass));
305 }
306 }
307
308 private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) {
309 if (classOrObject.getBody() != null) {
310 trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody()));
311 }
312 }
313
314 private void checkValOnAnnotationParameter(JetClass aClass) {
315 for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
316 if (!parameter.hasValOrVarNode()) {
317 trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter));
318 }
319 }
320 }
321
322 private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) {
323 for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
324 if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
325 JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), memberDescriptor);
326 if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) {
327 trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
328 }
329 }
330 }
331
332 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
333 reportErrorIfHasIllegalModifier(property);
334 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
335 if (containingDeclaration instanceof ClassDescriptor) {
336 checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration);
337 }
338 else {
339 modifiersChecker.checkIllegalModalityModifiers(property);
340 }
341 checkPropertyInitializer(property, propertyDescriptor);
342 checkAccessors(property, propertyDescriptor);
343 checkDeclaredTypeInPublicMember(property, propertyDescriptor);
344 }
345
346 private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) {
347 boolean hasDeferredType;
348 if (member instanceof JetProperty) {
349 hasDeferredType = ((JetProperty) member).getTypeRef() == null && DescriptorResolver.hasBody((JetProperty) member);
350 }
351 else {
352 assert member instanceof JetFunction;
353 JetFunction function = (JetFunction) member;
354 hasDeferredType = function.getReturnTypeRef() == null && function.hasBody() && !function.hasBlockBody();
355 }
356 if ((memberDescriptor.getVisibility().isPublicAPI()) && memberDescriptor.getOverriddenDescriptors().size() == 0 && hasDeferredType) {
357 trace.report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member));
358 }
359 }
360
361 private void checkPropertyAbstractness(
362 @NotNull JetProperty property,
363 @NotNull PropertyDescriptor propertyDescriptor,
364 @NotNull ClassDescriptor classDescriptor
365 ) {
366 JetPropertyAccessor getter = property.getGetter();
367 JetPropertyAccessor setter = property.getSetter();
368 JetModifierList modifierList = property.getModifierList();
369 ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
370
371 if (abstractNode != null) { //has abstract modifier
372 if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
373 String name = property.getName();
374 trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor));
375 return;
376 }
377 if (classDescriptor.getKind() == ClassKind.TRAIT) {
378 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property));
379 }
380 }
381
382 if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
383 JetType returnType = propertyDescriptor.getReturnType();
384 if (returnType instanceof DeferredType) {
385 returnType = ((DeferredType) returnType).getDelegate();
386 }
387
388 JetExpression initializer = property.getInitializer();
389 if (initializer != null) {
390 trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer));
391 }
392 JetPropertyDelegate delegate = property.getDelegate();
393 if (delegate != null) {
394 trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate));
395 }
396 if (getter != null && getter.hasBody()) {
397 trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter));
398 }
399 if (setter != null && setter.hasBody()) {
400 trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter));
401 }
402 }
403 }
404
405 private void checkPropertyInitializer(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
406 JetPropertyAccessor getter = property.getGetter();
407 JetPropertyAccessor setter = property.getSetter();
408 boolean hasAccessorImplementation = (getter != null && getter.hasBody()) ||
409 (setter != null && setter.hasBody());
410
411 if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
412 if (!property.hasDelegateExpressionOrInitializer() && property.getTypeRef() == null) {
413 trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
414 }
415 return;
416 }
417 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
418 boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.TRAIT;
419 JetExpression initializer = property.getInitializer();
420 JetPropertyDelegate delegate = property.getDelegate();
421 boolean backingFieldRequired =
422 Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
423
424 if (inTrait && backingFieldRequired && hasAccessorImplementation) {
425 trace.report(BACKING_FIELD_IN_TRAIT.on(property));
426 }
427
428 if (initializer == null && delegate == null) {
429 boolean error = false;
430 if (backingFieldRequired && !inTrait &&
431 Boolean.FALSE.equals(trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor))) {
432 if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) {
433 error = true;
434 trace.report(MUST_BE_INITIALIZED.on(property));
435 }
436 else {
437 error = true;
438 trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property));
439 }
440 }
441 if (!error && property.getTypeRef() == null) {
442 trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
443 }
444 if (inTrait && property.hasModifier(JetTokens.FINAL_KEYWORD) && backingFieldRequired) {
445 trace.report(FINAL_PROPERTY_IN_TRAIT.on(property));
446 }
447 return;
448 }
449
450 if (inTrait) {
451 if (delegate != null) {
452 trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate));
453 }
454 else {
455 trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
456 }
457 }
458 else if (delegate == null) {
459 if (!backingFieldRequired) {
460 trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
461 }
462 else if (property.getReceiverTypeRef() != null) {
463 trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer));
464 }
465 }
466 }
467
468 protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) {
469 reportErrorIfHasIllegalModifier(function);
470 DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
471 boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
472 checkDeclaredTypeInPublicMember(function, functionDescriptor);
473 if (containingDescriptor instanceof ClassDescriptor) {
474 ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
475 boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT;
476 boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS;
477 boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT;
478 if (hasAbstractModifier && !inAbstractClass && !inEnum) {
479 trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor));
480 }
481 if (hasAbstractModifier && inTrait) {
482 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function));
483 }
484 boolean hasBody = function.hasBody();
485 if (hasBody && hasAbstractModifier) {
486 trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
487 }
488 if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) {
489 trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
490 }
491 if (!hasBody && !hasAbstractModifier && !inTrait) {
492 trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
493 }
494 return;
495 }
496 modifiersChecker.checkIllegalModalityModifiers(function);
497 if (!function.hasBody() && !hasAbstractModifier) {
498 trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
499 }
500 }
501
502 private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
503 for (JetPropertyAccessor accessor : property.getAccessors()) {
504 modifiersChecker.checkIllegalModalityModifiers(accessor);
505 }
506 JetPropertyAccessor getter = property.getGetter();
507 PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
508 JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null;
509 if (getterModifierList != null && getterDescriptor != null) {
510 Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets
511 .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD,
512 JetTokens.INTERNAL_KEYWORD));
513 if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
514 for (ASTNode node : nodes.values()) {
515 trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi()));
516 }
517 }
518 else {
519 for (ASTNode node : nodes.values()) {
520 trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi()));
521 }
522 }
523 }
524 }
525
526 private void checkEnumModifiers(JetClass aClass) {
527 if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) {
528 trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass));
529 }
530 }
531
532 private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) {
533 DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration();
534 assert DescriptorUtils.isEnumClass(declaration) : "Enum entry should be declared in enum class: " + classDescriptor;
535 ClassDescriptor enumClass = (ClassDescriptor) declaration;
536
537 List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers();
538 ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor();
539 assert constructor != null;
540 if (!constructor.getValueParameters().isEmpty() && delegationSpecifiers.isEmpty()) {
541 trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry, enumClass));
542 }
543
544 for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
545 JetTypeReference typeReference = delegationSpecifier.getTypeReference();
546 if (typeReference != null) {
547 JetType type = trace.getBindingContext().get(TYPE, typeReference);
548 if (type != null) {
549 JetType enumType = enumClass.getDefaultType();
550 if (!type.getConstructor().equals(enumType.getConstructor())) {
551 trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass));
552 }
553 }
554 }
555 }
556 }
557 }