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