001    /*
002     * Copyright 2010-2015 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.kotlin.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.kotlin.descriptors.*;
025    import org.jetbrains.kotlin.diagnostics.Errors;
026    import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
027    import org.jetbrains.kotlin.lexer.JetTokens;
028    import org.jetbrains.kotlin.psi.*;
029    import org.jetbrains.kotlin.types.JetType;
030    import org.jetbrains.kotlin.types.SubstitutionUtils;
031    import org.jetbrains.kotlin.types.TypeConstructor;
032    import org.jetbrains.kotlin.types.TypeProjection;
033    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
034    
035    import javax.inject.Inject;
036    import java.util.*;
037    
038    import static org.jetbrains.kotlin.diagnostics.Errors.*;
039    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE;
040    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_PARAMETER;
041    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers;
042    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers;
043    
044    public class DeclarationsChecker {
045        private BindingTrace trace;
046        private ModifiersChecker modifiersChecker;
047        private DescriptorResolver descriptorResolver;
048    
049        @Inject
050        public void setTrace(@NotNull BindingTrace trace) {
051            this.trace = trace;
052        }
053    
054        @Inject
055        public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
056            this.descriptorResolver = descriptorResolver;
057        }
058    
059        @Inject
060        public void setModifiersChecker(@NotNull ModifiersChecker modifiersChecker) {
061            this.modifiersChecker = modifiersChecker;
062        }
063    
064        public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
065            for (JetFile file : bodiesResolveContext.getFiles()) {
066                checkModifiersAndAnnotationsInPackageDirective(file);
067            }
068    
069            Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = bodiesResolveContext.getDeclaredClasses();
070            for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : classes.entrySet()) {
071                JetClassOrObject classOrObject = entry.getKey();
072                ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
073    
074                checkSupertypesForConsistency(classDescriptor);
075                checkTypesInClassHeader(classOrObject);
076    
077                if (classOrObject instanceof JetClass) {
078                    JetClass jetClass = (JetClass) classOrObject;
079                    checkClass(bodiesResolveContext, jetClass, classDescriptor);
080                    descriptorResolver.checkNamesInConstraints(
081                            jetClass, classDescriptor, classDescriptor.getScopeForClassHeaderResolution(), trace);
082                }
083                else if (classOrObject instanceof JetObjectDeclaration) {
084                    checkObject((JetObjectDeclaration) classOrObject, classDescriptor);
085                }
086    
087                modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
088            }
089    
090            Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions();
091            for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) {
092                JetNamedFunction function = entry.getKey();
093                SimpleFunctionDescriptor functionDescriptor = entry.getValue();
094    
095                checkFunction(function, functionDescriptor);
096                modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor);
097            }
098    
099            Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties();
100            for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
101                JetProperty property = entry.getKey();
102                PropertyDescriptor propertyDescriptor = entry.getValue();
103    
104                checkProperty(property, propertyDescriptor);
105                modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor);
106            }
107    
108            for (Map.Entry<JetSecondaryConstructor, ConstructorDescriptor> entry : bodiesResolveContext.getSecondaryConstructors().entrySet()) {
109                ConstructorDescriptor constructorDescriptor = entry.getValue();
110                JetSecondaryConstructor declaration = entry.getKey();
111                modifiersChecker.reportIllegalModalityModifiers(declaration);
112                reportErrorIfHasIllegalModifier(declaration);
113                modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor);
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.isCompanionObjectConstraint());
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 isCompanionObjectConstraint) {
176            if (typeReference != null) {
177                JetType type = trace.getBindingContext().get(TYPE, typeReference);
178                if (type != null) {
179                    DescriptorResolver.checkUpperBoundType(typeReference, type, isCompanionObjectConstraint, 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                            Filter.REMOVE_IF_EQUAL_TYPE_IN_THE_SET.proceed(conflictingTypes);
204                            break;
205                        case IN_VARIANCE:
206                            // Filter out those who have supertypes in this set (common supertype)
207                            Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
208                            break;
209                        case OUT_VARIANCE:
210                            // Filter out those who have subtypes in this set (common subtype)
211                            Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
212                            break;
213                    }
214    
215                    if (conflictingTypes.size() > 1) {
216                        DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
217                        assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
218                        JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor);
219                        JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
220                        assert delegationSpecifierList != null;
221                        //                        trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
222                        trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
223                                             .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
224                                                 conflictingTypes));
225                    }
226                }
227            }
228        }
229    
230        private enum Filter {
231            REMOVE_IF_SUBTYPE_IN_THE_SET {
232                @Override
233                public boolean removeNeeded(JetType subject, JetType other) {
234                    return JetTypeChecker.DEFAULT.isSubtypeOf(other, subject);
235                }
236            },
237            REMOVE_IF_SUPERTYPE_IN_THE_SET {
238                @Override
239                public boolean removeNeeded(JetType subject, JetType other) {
240                    return JetTypeChecker.DEFAULT.isSubtypeOf(subject, other);
241                }
242            },
243            REMOVE_IF_EQUAL_TYPE_IN_THE_SET {
244                @Override
245                public boolean removeNeeded(JetType subject, JetType other) {
246                    return JetTypeChecker.DEFAULT.equalTypes(subject, other);
247                }
248            };
249    
250            private void proceed(Set<JetType> conflictingTypes) {
251                for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
252                    JetType type = iterator.next();
253                    for (JetType otherType : conflictingTypes) {
254                        boolean subtypeOf = removeNeeded(type, otherType);
255                        if (type != otherType && subtypeOf) {
256                            iterator.remove();
257                            break;
258                        }
259                    }
260                }
261            }
262    
263            public abstract boolean removeNeeded(JetType subject, JetType other);
264        }
265    
266        private void checkObject(JetObjectDeclaration declaration, ClassDescriptor classDescriptor) {
267            checkDeprecatedClassObjectSyntax(declaration);
268            reportErrorIfHasIllegalModifier(declaration);
269            if  (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) {
270                trace.report(LOCAL_OBJECT_NOT_ALLOWED.on(declaration, classDescriptor));
271            }
272        }
273    
274        private void checkDeprecatedClassObjectSyntax(@NotNull JetObjectDeclaration declaration) {
275            if (declaration.getClassKeyword() != null) {
276                trace.report(DEPRECATED_CLASS_OBJECT_SYNTAX.on(declaration));
277            }
278        }
279    
280        private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
281            checkOpenMembers(classDescriptor);
282            checkConstructorParameters(aClass);
283            checkTypeParameters(aClass);
284    
285            if (aClass.isTrait()) {
286                checkTraitModifiers(aClass);
287                checkConstructorInTrait(aClass);
288            }
289            else if (aClass.isAnnotation()) {
290                checkAnnotationClassWithBody(aClass);
291                checkValOnAnnotationParameter(aClass);
292            }
293            else if (aClass.isEnum()) {
294                checkEnumModifiers(aClass);
295                if (aClass.isLocal()) {
296                    trace.report(LOCAL_ENUM_NOT_ALLOWED.on(aClass, classDescriptor));
297                }
298            }
299            else if (aClass instanceof JetEnumEntry) {
300                checkEnumEntry((JetEnumEntry) aClass, classDescriptor);
301            }
302        }
303    
304        private void checkConstructorParameters(JetClass aClass) {
305            for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
306                PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
307                if (propertyDescriptor != null) {
308                    modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor);
309                }
310            }
311        }
312    
313        private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) {
314            // TODO: Support annotation for type parameters
315            for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
316                AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace);
317    
318                TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter);
319                if (typeParameter != null) {
320                    DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter);
321                }
322            }
323        }
324    
325        private void checkConstructorInTrait(JetClass klass) {
326            JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
327            if (primaryConstructorParameterList != null) {
328                trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructorParameterList));
329            }
330        }
331    
332        private void checkTraitModifiers(JetClass aClass) {
333            reportErrorIfHasIllegalModifier(aClass);
334            JetModifierList modifierList = aClass.getModifierList();
335            if (modifierList == null) return;
336            if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) {
337                trace.report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(aClass));
338            }
339            if (modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
340                trace.report(Errors.ABSTRACT_MODIFIER_IN_TRAIT.on(aClass));
341            }
342            if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) {
343                trace.report(Errors.OPEN_MODIFIER_IN_TRAIT.on(aClass));
344            }
345        }
346    
347        private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) {
348            if (classOrObject.getBody() != null) {
349                trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody()));
350            }
351        }
352    
353        private void checkValOnAnnotationParameter(JetClass aClass) {
354            for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
355                if (!parameter.hasValOrVarNode()) {
356                    trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter));
357                }
358            }
359        }
360    
361        private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) {
362            if (classCanHaveOpenMembers(classDescriptor)) return;
363    
364            for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
365                if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
366                JetNamedDeclaration member = (JetNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor);
367                if (member != null && member.hasModifier(JetTokens.OPEN_KEYWORD)) {
368                    trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
369                }
370            }
371        }
372    
373        private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
374            reportErrorIfHasIllegalModifier(property);
375            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
376            if (containingDeclaration instanceof ClassDescriptor) {
377                checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration);
378            }
379            else {
380                modifiersChecker.reportIllegalModalityModifiers(property);
381            }
382            checkPropertyInitializer(property, propertyDescriptor);
383            checkAccessors(property, propertyDescriptor);
384            checkDeclaredTypeInPublicMember(property, propertyDescriptor);
385        }
386    
387        private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) {
388            boolean hasDeferredType;
389            if (member instanceof JetProperty) {
390                hasDeferredType = ((JetProperty) member).getTypeReference() == null && DescriptorResolver.hasBody((JetProperty) member);
391            }
392            else {
393                assert member instanceof JetFunction;
394                JetFunction function = (JetFunction) member;
395                hasDeferredType = function.getTypeReference() == null && function.hasBody() && !function.hasBlockBody();
396            }
397            if ((memberDescriptor.getVisibility().isPublicAPI()) && memberDescriptor.getOverriddenDescriptors().size() == 0 && hasDeferredType) {
398                trace.report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member));
399            }
400        }
401    
402        private void checkPropertyAbstractness(
403                @NotNull JetProperty property,
404                @NotNull PropertyDescriptor propertyDescriptor,
405                @NotNull ClassDescriptor classDescriptor
406        ) {
407            JetPropertyAccessor getter = property.getGetter();
408            JetPropertyAccessor setter = property.getSetter();
409            JetModifierList modifierList = property.getModifierList();
410            ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
411    
412            if (abstractNode != null) { //has abstract modifier
413                if (!classCanHaveAbstractMembers(classDescriptor)) {
414                    String name = property.getName();
415                    trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor));
416                    return;
417                }
418                if (classDescriptor.getKind() == ClassKind.TRAIT) {
419                    trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property));
420                }
421            }
422    
423            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
424                JetExpression initializer = property.getInitializer();
425                if (initializer != null) {
426                    trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer));
427                }
428                JetPropertyDelegate delegate = property.getDelegate();
429                if (delegate != null) {
430                    trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate));
431                }
432                if (getter != null && getter.hasBody()) {
433                    trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter));
434                }
435                if (setter != null && setter.hasBody()) {
436                    trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter));
437                }
438            }
439        }
440    
441        private void checkPropertyInitializer(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
442            JetPropertyAccessor getter = property.getGetter();
443            JetPropertyAccessor setter = property.getSetter();
444            boolean hasAccessorImplementation = (getter != null && getter.hasBody()) ||
445                                                (setter != null && setter.hasBody());
446    
447            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
448                if (!property.hasDelegateExpressionOrInitializer() && property.getTypeReference() == null) {
449                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
450                }
451                return;
452            }
453            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
454            boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.TRAIT;
455            JetExpression initializer = property.getInitializer();
456            JetPropertyDelegate delegate = property.getDelegate();
457            boolean backingFieldRequired =
458                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
459    
460            if (inTrait && backingFieldRequired && hasAccessorImplementation) {
461                trace.report(BACKING_FIELD_IN_TRAIT.on(property));
462            }
463    
464            if (initializer == null && delegate == null) {
465                boolean error = false;
466                if (backingFieldRequired && !inTrait &&
467                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, propertyDescriptor))) {
468                    if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) {
469                        error = true;
470                        trace.report(MUST_BE_INITIALIZED.on(property));
471                    }
472                    else {
473                        error = true;
474                        trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property));
475                    }
476                }
477                if (!error && property.getTypeReference() == null) {
478                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
479                }
480                if (inTrait && property.hasModifier(JetTokens.FINAL_KEYWORD) && backingFieldRequired) {
481                    trace.report(FINAL_PROPERTY_IN_TRAIT.on(property));
482                }
483                return;
484            }
485    
486            if (inTrait) {
487                if (delegate != null) {
488                    trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate));
489                }
490                else {
491                    trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
492                }
493            }
494            else if (delegate == null) {
495                if (!backingFieldRequired) {
496                    trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
497                }
498                else if (property.getReceiverTypeReference() != null) {
499                    trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer));
500                }
501            }
502        }
503    
504        protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) {
505            reportErrorIfHasIllegalModifier(function);
506            DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
507            boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
508            checkDeclaredTypeInPublicMember(function, functionDescriptor);
509            if (containingDescriptor instanceof ClassDescriptor) {
510                ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
511                boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT;
512                if (hasAbstractModifier && !classCanHaveAbstractMembers(classDescriptor)) {
513                    trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor));
514                }
515                if (hasAbstractModifier && inTrait) {
516                    trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function));
517                }
518                boolean hasBody = function.hasBody();
519                if (hasBody && hasAbstractModifier) {
520                    trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
521                }
522                if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) {
523                    trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
524                }
525                if (!hasBody && !hasAbstractModifier && !inTrait) {
526                    trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
527                }
528                return;
529            }
530            modifiersChecker.reportIllegalModalityModifiers(function);
531            if (!function.hasBody() && !hasAbstractModifier) {
532                trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
533            }
534        }
535    
536        private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
537            for (JetPropertyAccessor accessor : property.getAccessors()) {
538                PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
539                assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText();
540                modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor);
541                modifiersChecker.reportIllegalModalityModifiers(accessor);
542            }
543            JetPropertyAccessor getter = property.getGetter();
544            PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
545            JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null;
546            if (getterModifierList != null && getterDescriptor != null) {
547                Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets
548                        .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD,
549                                    JetTokens.INTERNAL_KEYWORD));
550                if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
551                    for (ASTNode node : nodes.values()) {
552                        trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi()));
553                    }
554                }
555                else {
556                    for (ASTNode node : nodes.values()) {
557                        trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi()));
558                    }
559                }
560            }
561        }
562    
563        private void checkEnumModifiers(JetClass aClass) {
564            if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) {
565                trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass));
566            }
567            if (aClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
568                trace.report(ABSTRACT_MODIFIER_IN_ENUM.on(aClass));
569            }
570        }
571    
572        private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) {
573            DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration();
574            assert DescriptorUtils.isEnumClass(declaration) : "Enum entry should be declared in enum class: " + classDescriptor;
575            ClassDescriptor enumClass = (ClassDescriptor) declaration;
576    
577            List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers();
578            ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor();
579            if ((constructor == null || !constructor.getValueParameters().isEmpty()) && delegationSpecifiers.isEmpty()) {
580                trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry, enumClass));
581            }
582    
583            for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
584                JetTypeReference typeReference = delegationSpecifier.getTypeReference();
585                if (typeReference != null) {
586                    JetType type = trace.getBindingContext().get(TYPE, typeReference);
587                    if (type != null) {
588                        JetType enumType = enumClass.getDefaultType();
589                        if (!type.getConstructor().equals(enumType.getConstructor())) {
590                            trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass));
591                        }
592                    }
593                }
594            }
595        }
596    }