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