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 com.intellij.psi.PsiElement;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
026    import org.jetbrains.kotlin.descriptors.*;
027    import org.jetbrains.kotlin.diagnostics.Errors;
028    import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
029    import org.jetbrains.kotlin.lexer.JetTokens;
030    import org.jetbrains.kotlin.psi.*;
031    import org.jetbrains.kotlin.types.*;
032    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
033    
034    import java.util.Collection;
035    import java.util.Iterator;
036    import java.util.Map;
037    import java.util.Set;
038    
039    import static org.jetbrains.kotlin.diagnostics.Errors.*;
040    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE;
041    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_PARAMETER;
042    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers;
043    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers;
044    
045    public class DeclarationsChecker {
046        @NotNull private final BindingTrace trace;
047        @NotNull private final ModifiersChecker.ModifiersCheckingProcedure modifiersChecker;
048        @NotNull private final DescriptorResolver descriptorResolver;
049        @NotNull private final AnnotationChecker annotationChecker;
050    
051        public DeclarationsChecker(
052                @NotNull DescriptorResolver descriptorResolver,
053                @NotNull ModifiersChecker modifiersChecker,
054                @NotNull AnnotationChecker annotationChecker,
055                @NotNull BindingTrace trace
056        ) {
057            this.descriptorResolver = descriptorResolver;
058            this.modifiersChecker = modifiersChecker.withTrace(trace);
059            this.annotationChecker = annotationChecker;
060            this.trace = trace;
061        }
062    
063        public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
064            for (JetFile file : bodiesResolveContext.getFiles()) {
065                checkModifiersAndAnnotationsInPackageDirective(file);
066                annotationChecker.check(file, trace, null);
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                checkPrimaryConstructor(classOrObject, classDescriptor);
088    
089                modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
090            }
091    
092            Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions();
093            for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) {
094                JetNamedFunction function = entry.getKey();
095                SimpleFunctionDescriptor functionDescriptor = entry.getValue();
096    
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                checkProperty(property, propertyDescriptor);
107                modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor);
108            }
109    
110            for (Map.Entry<JetSecondaryConstructor, ConstructorDescriptor> entry : bodiesResolveContext.getSecondaryConstructors().entrySet()) {
111                ConstructorDescriptor constructorDescriptor = entry.getValue();
112                JetSecondaryConstructor declaration = entry.getKey();
113                checkConstructorDeclaration(constructorDescriptor, declaration);
114            }
115    
116        }
117    
118        private void checkConstructorDeclaration(ConstructorDescriptor constructorDescriptor, JetDeclaration declaration) {
119            modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor);
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            annotationChecker.check(packageDirective, trace, null);
139            ModifierCheckerCore.INSTANCE$.check(packageDirective, trace, null);
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());
153            }
154    
155            for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
156                checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
157                checkFinalUpperBounds(constraint.getBoundTypeReference());
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) {
171            if (typeReference != null) {
172                JetType type = trace.getBindingContext().get(TYPE, typeReference);
173                if (type != null) {
174                    DescriptorResolver.checkUpperBoundType(typeReference, type, 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                    removeDuplicateTypes(conflictingTypes);
196                    if (conflictingTypes.size() > 1) {
197                        DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
198                        assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
199                        JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor);
200                        assert psiElement != null;
201                        JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
202                        assert delegationSpecifierList != null;
203                        //                        trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
204                        trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
205                                             .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
206                                                 conflictingTypes));
207                    }
208                }
209            }
210        }
211    
212        private static void removeDuplicateTypes(Set<JetType> conflictingTypes) {
213            for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
214                JetType type = iterator.next();
215                for (JetType otherType : conflictingTypes) {
216                    boolean subtypeOf = JetTypeChecker.DEFAULT.equalTypes(type, otherType);
217                    if (type != otherType && subtypeOf) {
218                        iterator.remove();
219                        break;
220                    }
221                }
222            }
223        }
224    
225        private void checkObject(JetObjectDeclaration declaration, ClassDescriptor classDescriptor) {
226            if  (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) {
227                trace.report(LOCAL_OBJECT_NOT_ALLOWED.on(declaration, classDescriptor));
228            }
229        }
230    
231        private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
232            checkOpenMembers(classDescriptor);
233            checkTypeParameters(aClass);
234    
235            if (aClass.isInterface()) {
236                ASTNode traitKeyword = aClass.getNode().findChildByType(JetTokens.TRAIT_KEYWORD);
237                if (traitKeyword != null) {
238                    trace.report(Errors.DEPRECATED_TRAIT_KEYWORD.on(traitKeyword.getPsi()));
239                }
240    
241                checkConstructorInTrait(aClass);
242            }
243            else if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
244                checkAnnotationClassWithBody(aClass);
245                checkValOnAnnotationParameter(aClass);
246            }
247            else if (aClass instanceof JetEnumEntry) {
248                checkEnumEntry((JetEnumEntry) aClass, classDescriptor);
249            }
250        }
251    
252        private void checkPrimaryConstructor(JetClassOrObject classOrObject, ClassDescriptor classDescriptor) {
253            ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
254            JetPrimaryConstructor declaration = classOrObject.getPrimaryConstructor();
255            if (primaryConstructor == null || declaration == null) return;
256    
257            for (JetParameter parameter : declaration.getValueParameters()) {
258                PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
259                if (propertyDescriptor != null) {
260                    modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor);
261                    checkPropertyLateInit(parameter, propertyDescriptor);
262                }
263            }
264    
265            if (declaration.getModifierList() != null && !declaration.hasConstructorKeyword()) {
266                trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(declaration.getModifierList()));
267            }
268    
269            if (!(classOrObject instanceof JetClass)) {
270                trace.report(CONSTRUCTOR_IN_OBJECT.on(declaration));
271            }
272    
273            checkConstructorDeclaration(primaryConstructor, declaration);
274        }
275    
276        private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) {
277            // TODO: Support annotation for type parameters
278            for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
279                AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace);
280    
281                TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter);
282                if (typeParameter != null) {
283                    DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter);
284                }
285                annotationChecker.check(jetTypeParameter, trace, null);
286            }
287        }
288    
289        private void checkConstructorInTrait(JetClass klass) {
290            JetPrimaryConstructor primaryConstructor = klass.getPrimaryConstructor();
291            if (primaryConstructor != null) {
292                trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructor));
293            }
294        }
295    
296        private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) {
297            if (classOrObject.getBody() != null) {
298                trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody()));
299            }
300        }
301    
302        private void checkValOnAnnotationParameter(JetClass aClass) {
303            for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
304                if (!parameter.hasValOrVar()) {
305                    trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter));
306                }
307            }
308        }
309    
310        private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) {
311            if (classCanHaveOpenMembers(classDescriptor)) return;
312    
313            for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
314                if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
315                JetNamedDeclaration member = (JetNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor);
316                if (member != null && member.hasModifier(JetTokens.OPEN_KEYWORD)) {
317                    trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
318                }
319            }
320        }
321    
322        private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
323            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
324            if (containingDeclaration instanceof ClassDescriptor) {
325                checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration);
326            }
327            checkPropertyLateInit(property, propertyDescriptor);
328            checkPropertyInitializer(property, propertyDescriptor);
329            checkAccessors(property, propertyDescriptor);
330        }
331    
332        private void checkPropertyLateInit(@NotNull JetCallableDeclaration property, @NotNull PropertyDescriptor propertyDescriptor) {
333            JetModifierList modifierList = property.getModifierList();
334            if (modifierList == null) return;
335            PsiElement modifier = modifierList.getModifier(JetTokens.LATE_INIT_KEYWORD);
336            if (modifier == null) return;
337    
338            boolean hasBackingField =
339                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
340    
341            boolean hasDelegateOrInitializer = false;
342            boolean hasCorrespondingValueParameter = false;
343    
344            if (property instanceof JetProperty) {
345                hasDelegateOrInitializer = ((JetProperty) property).hasDelegateExpressionOrInitializer();
346            }
347            else if (property instanceof JetParameter) {
348                hasCorrespondingValueParameter = true;
349            }
350    
351            PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
352            PropertySetterDescriptor setter = propertyDescriptor.getSetter();
353    
354            boolean customGetterOrSetter = false;
355            if (getter != null) {
356                customGetterOrSetter = getter.hasBody();
357            }
358            if (setter != null) {
359                customGetterOrSetter |= setter.hasBody();
360            }
361    
362            boolean returnTypeIsNullable = true;
363            boolean returnTypeIsPrimitive = true;
364    
365            JetType returnType = propertyDescriptor.getReturnType();
366            if (returnType != null) {
367                returnTypeIsNullable = TypeUtils.isNullableType(returnType);
368                returnTypeIsPrimitive = KotlinBuiltIns.isPrimitiveType(returnType);
369            }
370    
371            if (!hasBackingField || hasCorrespondingValueParameter || hasDelegateOrInitializer || customGetterOrSetter
372                    || returnTypeIsNullable || returnTypeIsPrimitive || propertyDescriptor.getExtensionReceiverParameter() != null) {
373                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier));
374            }
375        }
376    
377        private void checkPropertyAbstractness(
378                @NotNull JetProperty property,
379                @NotNull PropertyDescriptor propertyDescriptor,
380                @NotNull ClassDescriptor classDescriptor
381        ) {
382            JetPropertyAccessor getter = property.getGetter();
383            JetPropertyAccessor setter = property.getSetter();
384            JetModifierList modifierList = property.getModifierList();
385    
386            if (modifierList != null && modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { //has abstract modifier
387                if (!classCanHaveAbstractMembers(classDescriptor)) {
388                    String name = property.getName();
389                    trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor));
390                    return;
391                }
392                if (classDescriptor.getKind() == ClassKind.INTERFACE) {
393                    trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property));
394                }
395            }
396    
397            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
398                JetExpression initializer = property.getInitializer();
399                if (initializer != null) {
400                    trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer));
401                }
402                JetPropertyDelegate delegate = property.getDelegate();
403                if (delegate != null) {
404                    trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate));
405                }
406                if (getter != null && getter.hasBody()) {
407                    trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter));
408                }
409                if (setter != null && setter.hasBody()) {
410                    trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter));
411                }
412            }
413        }
414    
415        private void checkPropertyInitializer(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
416            JetPropertyAccessor getter = property.getGetter();
417            JetPropertyAccessor setter = property.getSetter();
418            boolean hasAccessorImplementation = (getter != null && getter.hasBody()) ||
419                                                (setter != null && setter.hasBody());
420    
421            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
422                if (!property.hasDelegateExpressionOrInitializer() && property.getTypeReference() == null) {
423                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
424                }
425                return;
426            }
427            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
428            boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.INTERFACE;
429            JetExpression initializer = property.getInitializer();
430            JetPropertyDelegate delegate = property.getDelegate();
431            boolean backingFieldRequired =
432                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
433    
434            if (inTrait && backingFieldRequired && hasAccessorImplementation) {
435                trace.report(BACKING_FIELD_IN_TRAIT.on(property));
436            }
437    
438            if (initializer == null && delegate == null) {
439                boolean error = false;
440                if (backingFieldRequired && !inTrait && !propertyDescriptor.isLateInit() &&
441                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, propertyDescriptor))) {
442                    if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) {
443                        error = true;
444                        trace.report(MUST_BE_INITIALIZED.on(property));
445                    }
446                    else {
447                        error = true;
448                        trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property));
449                    }
450                }
451                if (!error && property.getTypeReference() == null) {
452                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
453                }
454                if (inTrait && property.hasModifier(JetTokens.FINAL_KEYWORD) && backingFieldRequired) {
455                    trace.report(FINAL_PROPERTY_IN_TRAIT.on(property));
456                }
457                return;
458            }
459    
460            if (inTrait) {
461                if (delegate != null) {
462                    trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate));
463                }
464                else {
465                    trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
466                }
467            }
468            else if (delegate == null) {
469                if (!backingFieldRequired) {
470                    trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
471                }
472                else if (property.getReceiverTypeReference() != null) {
473                    trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer));
474                }
475            }
476        }
477    
478        protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) {
479            DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
480            boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
481            if (containingDescriptor instanceof ClassDescriptor) {
482                ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
483                boolean inTrait = classDescriptor.getKind() == ClassKind.INTERFACE;
484                if (hasAbstractModifier && !classCanHaveAbstractMembers(classDescriptor)) {
485                    trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor));
486                }
487                if (hasAbstractModifier && inTrait) {
488                    trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function));
489                }
490                boolean hasBody = function.hasBody();
491                if (hasBody && hasAbstractModifier) {
492                    trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
493                }
494                if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) {
495                    trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
496                }
497                if (!hasBody && !hasAbstractModifier && !inTrait) {
498                    trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
499                }
500                return;
501            }
502            if (!function.hasBody() && !hasAbstractModifier) {
503                trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
504            }
505        }
506    
507        private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
508            for (JetPropertyAccessor accessor : property.getAccessors()) {
509                PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
510                assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText();
511                modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor);
512            }
513            JetPropertyAccessor getter = property.getGetter();
514            PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
515            JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null;
516            if (getterModifierList != null && getterDescriptor != null) {
517                Map<JetModifierKeywordToken, PsiElement> tokens = modifiersChecker.getTokensCorrespondingToModifiers(getterModifierList, Sets
518                        .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD,
519                                    JetTokens.INTERNAL_KEYWORD));
520                if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
521                    for (PsiElement token : tokens.values()) {
522                        trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(token));
523                    }
524                }
525                else {
526                    for (PsiElement token : tokens.values()) {
527                        trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(token));
528                    }
529                }
530            }
531        }
532    
533        private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) {
534            DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration();
535            if (DescriptorUtils.isEnumClass(declaration)) {
536                ClassDescriptor enumClass = (ClassDescriptor) declaration;
537    
538                if (!enumEntry.hasInitializer() && !DescriptorUtils.hasDefaultConstructor(enumClass)) {
539                    trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry));
540                }
541            }
542            else {
543                assert DescriptorUtils.isTrait(declaration) : "Enum entry should be declared in enum class: " +
544                                                              classDescriptor + " " +
545                                                              classDescriptor.getKind();
546            }
547        }
548    
549    }