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