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