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