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